Java从入门到放弃(1)Java的基础知识、标识符、变量、运算符

前言

做了这么久的Java开发,也非常喜欢这门语言,却对它本身了解不多。而我又报名参加了2020年的蓝桥杯Java组,并且打算参加软件杯和C4,为了能把这些比赛打好,在下学期的Java程序设计课里拿个高分(虽然能不能选上这门课还不一定),也为了能对Java语言有一个更深入、系统的了解,不在以后的开发中对语言本身感到困惑,所以打算写这个系列,从零开始重新学习Java基础知识,并对第一次学习掌握得不好的部分重新记录。

参考资料

《Java核心技术》
Java300集及其资料

菜鸟教程

javac和java命令做了什么?

我们在安装好JDK之后开始写HelloWorld程序时,都会用到javacjava两条命令。那么这两条命令为我们做了些什么呢?

javac命令启动了一个Java编译器,它把后缀名为.java的Java源码文件编译成了后缀名为.class的字节码文件。java命令则启动了JRE——Java运行时环境(Java Runtime Environment)和JVM——Java虚拟机(Java Virtual Machine),装载刚才编译好的.class文件并以解释的方式执行其中的字节码。

(图片来自Java300集)

所以,我们可以很清楚地看出为什么Java是半编译半解释的语言——因为源码需要先编译成字节码,字节码在JVM中又是解释执行的。

这里如果展开了说还会涉及到Java语言、JVM的底层原理,比如JVM是怎么加载这个类,怎么执行其中的字节码,还有JIT即时编译、双委派模型之类的,这里先不考虑这些细节,在后面学习JVM基础知识的部分再去详细展开。

JDK、JRE和JVM的关系

JRE并不等于JVM。

除了JVM之外,JRE其实还包含一些库函数和必须的文件,所以JRE其实是包含JVM的。

JDK则在JRE的基础上又增加了编译器、调试器等开发需要的东西。

JDK的目录结构

  • bin:二进制文件,比如javajavac之类的,也就是我们用到的命令
  • db:存放一些数据
  • include:一些需要包含的头文件
  • jre:就是JRE
  • lib:库目录,存放了一些jar包
  • src.zip:JDK源码,不过为啥我macOS版的Java11没这个呢?

标识符

标识符其实就是一个名字,用来给变量、包、类等命名。

标识符有一定的规则——

  • 所有的标识符都应该以字母(A-Z 或者 a-z),美元符($)、或者下划线(_)开始
  • 首字符之后可以是字母(A-Z 或者 a-z),美元符($)、下划线(_)或数字的任何字符组合
  • class等Java关键字不能用作标识符

注意:Java使用的是Unicode标准字符集,所以可以用中文命名变量。

数据类型

在Java中,一共有8种基本类型(primitive type),其中有4种整型、2种浮点类型、1种用于表示Unicode 编码的字符单元的字符类型char和1种用于表示真值的boolean类型。

除此之外,都是引用数据类型。它们占四个字节,用来表示一个对象的地址(类似于C++的指针)。

注意:Java有一个能够表示任意精度的算术包,通常被称为大数值(BigDecimal),但它并不是一种新的Java类型,而是一个Java对象。

变量的类型、长度与范围

整数类型

类型 长度 取值范围
int 4字节 -2147483648~2147483647
short 2字节 -32768~32767
long 8字节 -9223372036854775808~9223372036854775807(-2^64~2^64-1)
byte 1字节 -128~127

注意:

长整型数值有一个后缀 L 或 l (如 4000000000L) 十六进制数值有一个前缀 0x 或 0X ( 如 0xCAFEL 八进制有一个前缀0,例如,010 对应八进制中的 8。 很显然, 八进制表示法比较容易混淆, 所以建议最好不要使用八进制常数。并且,由于l容易和数字1、大写的I混淆,所以一般都使用大写的L表示长整型数。

从 Java 7 开始, 加上前缀 0b 或 0B 就可以写二进制数。 例如, 0b1001就是 9。 另外, 同样是 从Java7开始,还可以为数字字面量加下划线,如用1_000_000表示一百万,不会影响到编译结果。

关于boolean的长度问题

Java规范中并没有明确地指出boolean类型的长度。但是,并不能说boolean的长度就不确定了:

在《Java虚拟机规范》一书中的描述:“虽然定义了boolean这种数据类型,但是只对它提供了非常有限的支持。在Java虚拟机中没有任何供boolean值专用的字节码指令,Java语言表达式所操作的boolean值,在编译之后都使用Java虚拟机中的int数据类型来代替,而boolean数组将会被编码成Java虚拟机的byte数组,每个元素boolean元素占8位”。也就是说JVM规范指出boolean当做int处理,也就是4字节,boolean数组当做byte数组处理,这样我们可以得出boolean类型占了单独使用是4个字节,在数组中是确定的1个字节。
from: https://blog.csdn.net/YuanMxy/article/details/74170745

虽说单独使用的boolean是跟int一样占用四个字节,但是booleanint不能相互转换。

浮点类型

类型 长度 取值范围
float 4字节 大约 ± 3.402 823 47E+38F (有效位数为 6 ~ 7 位)
double 8字节 大约 ± 1.797 693 134 862 315 70E+308 (有效位数为 15 位)

浮点数不仅可以用小数点表示,也可以用科学计数法来表示,例如314e2314E2

注意:float类型的数值有一个后缀F或f (例如,3.14F) 没有后缀F的浮点数值(如3.14) 默 认为 double 类型。当然, 也可以在浮点数值后面添加后缀 D 或 d ( 例如,3.14D)。

注意2:Java中有三个特殊的浮点数值,它们可以用一些特殊的常量来表示:

  • 正无穷大——Double.POSITIVE_INFINITY
  • 负无穷大——Double.NEGATIVE_INFINIT
  • NaN(不是一个数字)——Double.NaN

可以用Double.isXxx方法,例如Double.isNaN来检测需要检测的数是不是这三个常数。

注意3:与C/C++一样,浮点数类型在计算时可能会产生误差,因为浮点数并不是精确存储的,可能产生舍入误差,所以也最好不要比较两个浮点数。如果业务要求不能产生误差或者必须要比较两个浮点数,需要使用BigInteger(整数)或者BigDecimal(浮点数)类。

注意4:Java提供了PI与E的近似值常量——Math.PIMath.E

字符类型

char类型可以表示的字符范围为\u0000\uffff

注意:Unicode转义序列会在解析代码之前被处理,所以必须小心注释中的\u,它们可能会引起一些意想不到的错误。

自动类型转换

下图为Java不同数值类型之间的合法转换(实线代表不会损失精度,虚线代表会损失精度。图片来自《Java核心技术》):

强制类型转换

Java的强制类型转换与C/C++基本相同,但是在面向对象部分,有些情况下不可以使用强制类型转换,这一点在后面复习面向对象时再详细总结。

变量

变量的本质

变量的本质其实就是内存中的一个可操作、固定长度的存储空间(不过据说boolean的长度是不确定的),在内存中的地址是确定的,但是里面放置什么值是由程序运行决定的。我们可通过变量名来访问对应的存储空间,从而操纵这个存储空间里存储的值。

Java是一种强类型语言,声明变量必须在变量名前先声明其类型,但是在Java11中,能自动推断出类型的可以不显示指定类型而使用var关键字指定,非常方便。

变量在使用前必须声明, 只有在变量声明以后,才能为其分配相应长度的存储空间,所以在使用变量之前必须声明。

注意:使用没有初始化局部的变量会报错,但是声明了变量不使用则不会报错(这跟Go语言不一样)。

变量的分类

Java的变量与C++一样,分为三种:

  • 局部变量
  • 静态变量
  • 成员变量/实例变量

成员变量的初值

成员变量从属于对象,生命周期伴随对象始终。

成员变量如果没有初始化,会有一个默认值:

类型 默认值
byte 0
short 0
int 0
long 0
float 0.0
double 0.0
char '\u0000'
boolean false
String等引用类型 null

静态变量

静态变量(使用static声明的变量)从属于类,是生命周期最长的,生命周期为从类的加载到类的卸载。

常量

与C/C++不同,常量使用final关键字声明,一旦有值,其值就不能发生变化。

final关键字除了用于常量(不能修改的变量)之外,还有以下作用:

  1. 使用final修饰的类不能被继承
  2. 使用final修饰的方法不能被重写

这在后面复习面向对象的时候再详细学习。

虽然Java不使用const修饰常量,但是const是Java的一个保留关键字,不能使用。

运算符

Java中有以下运算符(图片来自Java300集):

算术运算符

除了++--以外都属于二元运算符,二元运算符运算时遵守以下规则:

  1. 如果两个操作数有一个为Long, 则结果也为long。
  2. 没有long时,结果为int。即使操作数全为short,byte,结果也是int。
  3. 如果两个操作数有一个为double,则结果为double。
  4. 只有两个操作数都是float,则结果才为float。
  5. 取模操作其操作数可以为浮点数,但是一般使用整数。结果是“余数”,“余数”符号和左边操作数相同,如:7%3=1,-7%3=-1,7%-3=1。

++--的运算规则与C/C++等语言相同。

赋值运算与结合赋值运算

Java一共有以下几种结合赋值运算符:

  • +=
  • -=
  • *=
  • \=
  • %=

用法与C/C++相同。

注意:如果整数除以0会抛出一个异常,而浮点数除以0则会得到无穷大或者是NaN。

关系运算符

Java的关系运算符一共有以下几种:

  • ==
  • !=
  • >
  • <
  • >=
  • <=

用法同样与C/C++相同。

逻辑运算符

Java 沿用了 C++ 的做法,使用&&表示逻辑“与”运算符,使用||表示逻辑“或”运算符。从 != 运算符可以想到,感叹号!就是逻辑非运算符。&&和||运算符是按照“短路”方式来求值的: 如果第一个操作数已经能够确定表达式的值,第二个操作数就不必计算了。

位运算符

Java中的位运算符与C/C++的基本相同,个人感觉这些东西在实际开发中很难用到,除非是在性能要求非常高的地方。

(图片来自Java300集)

运算符的优先级

Java运算符的优先级也与C/C++基本相同。在实际使用中一般很少会遇到需要考虑优先级的问题,一般都使用小括号来解决运算符的优先级带来的问题,因为小括号的优先级最高。

(图片来自Java300集)

评论

发表评论