本篇为Java基础语法【上】,包含关键字、标识符、注释、原码反码补码、常量与变量、运算符这六部分内容。
关键字
定义:被Java语言赋予了特殊含义的单词。
特点:关键字中所有字母都为小写。
标识符
定义:在程序中自定义的一些名称。由26个英文字母大小写
,数组:0-9
,符号:_$
组成。
定义合法标识符规则:
- 数字不可以开头
- 不可以使用关键字
注意:
- Java中严格区分大小写
- 在命名时,为了提高阅读性,要尽量有意义
main
不是关键字,因为函数名称都是标识符,只是JVM识别main
函数,函数头的格式必须固定
注释
格式:
- 单行注释
//
- 多行注释
/* */
- 文档注释
/** */
用途:
- 注解说明
- 调试程序
其中,单行注释中可以嵌套单行/多行注释,多行注释中可以嵌套单行注释,但不能嵌套多行注释;对于单行和多行注释,被注释的文字,不会被编译到字节码(.class
)文件中,因此不会被JVM解释执行;文档注释为Java特有的注释,其中注释内容可以被JDK提供的工具javadoc.exe
所解析,生成一套以网页文件形式体现的该程序的说明文档。
文档注释的一般写法:
/**
* 用于操作数组的工具类,其中包含获取最值、排序等功能。
* @author LoisHuang
* @version 2019/7/9
*/
public class ArrayTool
{
/**
* 获取整型数组的最大值
* @param arr 接收一个int类型的数组
* @return 该数组的最大的元素值
*/
public static int getMax(int[] arr)
{
...
}
}
注意可以通过javadoc
命令生成说明文档的类和方法必须是由public
或protected
修饰的,故私有的方法不用加文档注释,用多行注释写明功能即可。
tips:
- 面试:上机题,写注释
- 在看代码的时候,可以通过写注释来检验是否看懂(代码只是思想的一种表现形式)
原码反码补码
(毕向东的Java基础教程中没有单独讲这一节的内容,但我认为对于后面的常量/变量以及运算符的理解非常有用。)
注意:原码和反码只是为了求负数的补码,在计算机中没有原码、反码的存在,只有补码。
原码
- 正数的原码就是它本身
假设使用一个字节存储整数,整数10的原码是:0000 1010
- 负数用最高位是1表示负数
假设使用一个字节存储整数,整数-10的原码是:1000 1010
反码
- 正数的反码和原码一样
假设使用一个字节存储整数,整数10的反码是:0000 1010
- 负数的反码是负数的原码按位取反(0变1,1变0),符号位不变
假设使用一个字节存储整数,整数-10的反码是:1111 0101
补码
再次强调,整数的补码才是在计算机中的存储形式。
- 正数的补码和原码一样
假设使用一个字节存储整数,整数10的补码是:0000 1010
(第三次强调:这一串是10这个整数在计算机中存储形式) - 负数的补码是负数的反码加1
假设使用一个字节存储整数,整数-10的补码是:1111 0110
(第三次强调:这一串是-10这个整数在计算机中存储形式)
在计算机中,为什么不用原码和反码,而是用补码呢?
因为在使用原码、反码计算时不准确,使用补码计算时才准确。
-
使用原码计算10-10
0000 1010 (10的原码)
+ 1000 1010 (-10的原码)
------------------------------------------------------------
1001 0100 (结果为:-20,很显然答案是否定的。) -
使用反码计算10-10
0000 1010 (10的反码)
+ 1111 0101 (-10的反码)
------------------------------------------------------------
1111 1111 (结果为反码,转换成原码为:1000 0000,最终的结果为:-0,很显然答案是否定的。) -
使用补码计算10-10
0000 1010 (10的补码)
+ 1111 0110 (-10的补码)
------------------------------------------------------------
1 0000 0000 (使用的1个字节存储,只能存储8位,第9位的1没地方存,就被丢弃了。故结果为:0。)
常量与变量
常量
概念:表示不能改变的值。
分类:
- 整数常量:所有整数
- 小数常量:所有小数
- 布尔(
boolean
)型常量:较为特有,只有true/false
两个数值。 - 字符常量:将一个数字、字母或符号用单引号
' '
标识 - 字符串常量:将一个或者多个字符用双引号
" "
标识 - null常量:只有一个
null
数值
在Java中,整数有四种表现形式:二/八/十/十六进制。因为十进制非0开头,所以其他进制的写法,要前补0用于区分。二进制:0b
或 0B
开头;八进制:0
开头;十六进制:0x
或0X
开头;负数前面加 -
。
变量
概念:内存中的一个存储区域,该区域有自己的名称(变量名)和类型(数据类型),数据可以在同一类型范围内不断变化。
变量使用的两个条件:有初始值和特定作用域。
数据类型:Java是强类型语言,对于每一种数据都定义了明确的具体数据类型,在内存中会分配不同大小的内存空间。
- 整数类型的存储空间大小分别为1, 2, 4, 8byte,最常用的类型是
byte
和int
,默认类型为int
; - 浮点型的存储空间大小分别为4, 8byte,默认类型为
double
; - 字符型(
char
)的存储空间大小为2byte。
注意:由于整数类型默认为int
,因此若一个大于int
类型范围的整数常量赋值给long
类型的变量时,结尾应该加上l
,同理浮点型常量赋值给float
类型的变量时,结尾加上f
。
Example1
long a = 1234567891234l;
float b = 2.3f;
类型转换&类型提升
针对于Java基础数据类型。
- 自动类型转换(隐式类型转换)
-
两种类型是彼此兼容的
-
转换的目的类型占得空间范围一定要大于转化的源类型
正向过程:由低字节向高字节自动转换,byte->short->int->long->float->double
。
Example1-1short i = 5; int j = i;
Example1-2
byte b = 4; //注意4为int类型(任何整数都为int)
编译器会判断4是否在byte范围内,如果在,则会做自动强转。
-
强制类型转换(显示类型转换)
格式:目标类型 变量 =(目标类型)源类型变量/常量
逆向过程:使用强制转换,可能丢失精度,如int a=(int)3.14;
。
Example2-1int i = 5; byte j = (int)i;
Example2-2
byte b; b = 3; b = (byte)b*3 //编译出错,因为(byte)的运算级别比*高,所以会先转换b后再*3 b = (byte)(b*3) //正确
-
数据类型自动提升(注意以下讨论的是二元操作符)
Java定义了若干使用于表达式的类型提升规则:
a. 如果两个操作数其中有一个是double
类型,另一个操作就会转换为double
类型;
b. 否则,如果其中一个操作数是float
类型,另一个将会转换为float
类型;
c. 否则,如果其中一个操作数是long
类型,另一个会转换为long
类型;
d. 否则,两个操作数都转换为int
类型。
(例外:final
修饰的byte
、short
、char
变量相加后不会被自动提升)
Example3-1System.out.println('a'); //输出字母a System.out.println('a' + 1); //输出98
char
型自动提升为int
型。
Example3-2byte a = 1; byte b = 2; a = a + b; //自动类型提升成int,编译出错 a += b; //自加没有自动类型提升问题
把高字节转成低字节,需要作强制类型转换:
a=(byte)(a+b);
Example3-3byte b1 = 1, b2 = 2, b3, b6; final byte b4 = 4,b5 = 6; b6 = b4 + b5; b3 = b1 + b2; //会发生编译错误 System.out.println(b3 + b6);
没有
final
修饰的变量相加后会被自动提升为int
型,与目标类型byte
不相容,需要强制转换(向下转型)。
Example3-4int x; int x1 = Integer.MAX_VALUE; int x2 = 2; x = x1 + x2; System.out.println(x); //输出结果为-2147483647(其中Integer.MAX_VALUE为2147483647)
默认
int
类型,运算一旦超出范围,会自动舍弃,保留原有位数。
注:Java内置Unicode
国际标准码表,ASCII
为美国标准码表,GBK
为中国标准码表,任何国家的码表都兼容ASCII
码表。
运算符
注意:运算符都是有结果的。
算术运算符
+
正号,-
负号+
,-
,*
,/
,%
,加减乘除取模++
自增(前),++
自增(后),--
自减(前),--
自减(后)+
字符串相加,连接符
Example1:整数除法运算
int x = 6370;
x = x / 1000; //x的结果为?
对于除号/
,它的整数除和小数除是有区别的:整数之间做除法时,只保留整数部分而舍弃小数部分。Java为强类型语言,因此x/1000
,两个int
类型运算的值仍然为int
类型。
Example2:负数取模运算
System.out.println(-5 % 2); //输出-1
System.out.println(5 % -2); //输出1
涉及到负数的模运算,只参考被模数(第一个数)。
Example3-1:自增运算
int a = 3, b;
b = a++;
实际上运算过程为:由于a本身涉及到与b的运算,因此会先开辟一个临时变量,存储a当前的值(怕a的值改变),如temp=3
;而赋值运算需要等右边的运算先计算完成,于是现在计算右边的a++
,计算完a+1
后赋值给a,于是a=4
;最后再将temp赋值给b,如下图所示:
Example3-2:自增运算
int i = 3;
i = i++;
System.out.println("i=" + i); //输出i=3;
i = i++
实际运算过程可理解为:
temp = i;
i = i + 1;
i = temp;
Example4-1:字符串相加
System.out.println(3 +"2");//输出32
System.out.println("5+5=" + 5 + 5);//输出5+5=55
+
除字符串相加功能外,还能把非字符串转换成字符串。
第一步"5+5=5"+5
,第二步"5+5=55"
;若要输出10,则可改为System.out.println("5+5="+(5+5));
,输出5+5=10
。
任何数据只要和字符串进行+
运算,都叫做相连接。用处如下:
Example4-2:同时输出a与b的值
int a = 4, b = 5;
System.out.println("a=" + a +",b=" + b);
Example5:注意
int a = 3;
a + 1; //编译错误:a+1不是语句
System.out.println("a=" + a);
赋值运算符
符号: =
, +
,=
,-=
, *=
, /=
, %=
Example1:+=
简单示例
int a, b, c;
a = b = c = 4;
a += 2; //将左右两边的和赋给左边
Example2-1
short s = 3;
s = s + 4;//编译错误,可能损失精度
System.out.println("s=" + s);
Example2-2
short s = 3;
s += 4;
System.out.println("s=" + s); //输出s=7;
s = s + 4
:编译失败,其为两次运算,s会被提升为int型,运算后的结果还是int型,无法赋值给short型。s += 4
:编译通过,其是赋值运算,为一次运算,与s = 3
类似;+=
运算符在给s赋值时,自动完成了强转操作,其在内存中的形式为s = (short)(s + 4)
。
比较运算符
符号:==
,!=
,<
, >
,<=
,>=
instanceof
检查是否是类的对象,"Hello" instanceof String
结果为true
。
注意:比较运算符的结果都是boolean
型。
逻辑运算符
定义:用来连接两个boolean
类型的表达式,结果为boolean
型。
面试题 ——&
与&&
的区别:&
:左边无论真假,右边都进行运算。&&
:若左边为真,右边参与运算;若左边为假,右边则不参与运算。|
与||
的区别同理,||
:左边为真,右边不参与运算。
位运算符
注意在计算机系统中,数值一律用补码来表示和存储。
位运算是直接对二进制进行运算。特定情况下,计算方便,速度快,支持面广;如果用算数方法,速度慢,逻辑复杂。位运算不限于一种语言,它是计算机的基本运算方法。
-
<<
相当于乘以2的倍数。
应用:最有效率的方式算出2乘以8的值,首选位运算(左移三位)。 -
>>
符号位(最高位)是什么,就拿什么补空位。
正数的右移相当于除法,右移n位就除以2的n次方(n表示移动位数),如100>>4
等效100/2^4
负数的右移不等于除法,即负数右移不能按除以2的n次方计算。 -
>>>
数据右移时,高位出现的空位,无论原高位是什么,空位都用0补。 -
&
应用:取一个数中的指定位。
例如:设X=1010 1110
,取X的低四位,用X & 0000 1111=0000 1110
即可得到。
方法:找一个数,对应X
要取的位,该数的对应位为1,其余位为零,此数与X
进行“与运算”可以得到X中的指定位。 -
^
应用:
1)与1相异或,使特定位翻转
方法:找一个数,对应X
要翻转的位,该数的对应为1,其余位为零,此数与X
对应位异或即可。
例如:X=1010 1110
,使X
低四位翻转,用X^0000 1111=1010 0001
即可得到。
2)与0相异或,保留原值
例如:X^0000 0000 =1010 1110
3)交换两个变量的值int a = 3, b = 5;
a. 借助第三个变量来实现//开发时,使用第三方变量的形式,因为阅读性强 int c; c = a; a = b; b = c;
b. 利用加减法实现两个变量的交换
//这种方式不要用,因为如果两个整数的数值过大,会超出int范围,数据会变化 a = a + b; // a = 3 + 5;a = 8; b = a - b; // 3+5-5 = 3;b = 3; a = a - b; // 3+5-3 = 5; a = 5;
c. 用位异或运算来实现,效率最高
原理:一个数异或同一个数两次,结果还是这个数(即是一个数异或本身等于0且异或运算符合交换律)。//面试的时候用,阅读性差 a = a ^ b; // a = 3 ^ 5; b = a ^ b; // b = (3 ^ 5) ^ 5; b = 3; a = a ^ b; // a = (3 ^ 5) ^ 3; a = 5;
-
~
对一个二进制数按位取反,即将0变为1,1变0。
注意计算机中数值一律用补码来表示和存储,因此负数取反过程:先用原码表示,再转化为补码,补码取反,最后转化为原码,才是负数取反的值。
三元运算符
格式:(条件表达式)?表达式1:表达式2
如果条件为true,运算后的结果是表达式1;如果条件为false,运算后的结果是表达式2;
Example1:获取两个整数中的较大的整数
int a = 3, b = 4;
int max = a > b ? a : b;
Example2:获取三个整数中的较大的整数
int o = 3, p = 4, q = 5;
//易读的写法
int temp = o > p ? o : p;
int max = temp > q : temp : q;
//阅读性较差的写法
int max = (o > p ? o : p) > q : (o > p ? o : p) : q;