基本语法

关键字

定义:被Java语言赋予了特殊含义,用做专门用途的字符串(单词)

特点:关键字中所字母都为小写

具体哪些关键字:

img

img

保留字

保留字:现Java版本尚未使用,但以后版本可能会作为关键字使用

具体哪些保留字:goto 、const

注意:自己命名标识符时要避免使用这些保留字

标识符

定义:凡是自己可以起名字的地方都叫标识符

涉及到的结构:

包名、类名、接口名、变量名、方法名、常量名

规则:(必须要遵守。否则,编译不通过)

img

规范:(可以不遵守,不影响编译和运行。但是要求大家遵守)

img

注意点:

  • 在起名字时,为了提高阅读性,要尽量意义,“见名知意”
  • Java采用unicode字符集,因此标识符也可以使用汉字声明,但是不建议使用

变量

变量的概念

内存中的一个存储区域

该区域的数据可以在同一类型范围内不断变化

变量是程序中最基本的单元

变量的作用

用于在内存中保存数据

使用变量注意

  • Java中每个变量必须先声明,后使用
  • 使用变量名来访问这块区域的数据
  • 变量的作用域:其定义所在的一对{ }内
  • 变量只有在其作用域内才有效
  • 同一个作用域内,不能定义重名的变量

变量的分类

按数据类型分类

img

详细说明
  1. 整型:byte(1字节=8bit) \ short(2字节) \ int(4字节) \ long(8字节)

    ① byte范围:-128 ~ 127

    ② 声明long型变量,必须以”l”或”L”结尾

    ③ 通常,定义整型变量时,使用int型。

​ ④整型的常量,默认类型是:int型

1576394322214

  1. 浮点型:float(4字节) \ double(8字节)

​ ① 浮点型,表示带小数点的数值

​ ② float表示数值的范围比long还大

​ ③ 定义float类型变量时,变量要以”f”或”F”结尾

​ ④ 通常,定义浮点型变量时,使用double型。

​ ⑤ 浮点型的常量,默认类型为:double

1576394353823

  1. 字符型:char (1字符=2字节)

​ ① 定义char型变量,通常使用一对’’,内部只能写一个字符

​ ② 表示方式:1.声明一个字符 2.转义字符 3.直接使用 Unicode 值来表示字符型常量

1576394398689

Unicode码空间为U+0000到U+10FFFF,一共1114112个码位,其中U+0000 到U+FFFF的部分被称为基本多语言面(Basic Multilingual Plane,BMP)。U+10000及以上的字符称为增补字符。在Java中(Java1.5之后),增补字符使用两个char型变量来表示。第一个char型变量的范围称为“高代理部分”(high-surrogates range,从”uD800到”uDBFF,共1024个码位), 第二个char型变量的范围称为low-surrogates range(从”uDC00到”uDFFF,共1024个码位),这样使用surrogate pair可以表示的字符数一共是1024的平方计1048576个,加上BMP的65536个码位,去掉2048个非法的码位,正好是1,112,064个码位。

UTF-16表示的增补字符怎样才能被正确的识别为增补字符,而不是两个普通的字符呢?答案是通过看它的第一个char是不是在高代理范围内,第二个char是不是在低代理范围内来决定,这也意味着,高代理和低代理所占的共2048个码位(从0xD800到0xDFFF)是不能分配给其他字符的。

  1. 布尔型:boolean

​ ① 只能取两个值之一:true 、 false

​ ② 常常在条件判断、循环结构中使用

按声明的位置分类

在方法体外,类体内声明的变量称为成员变量

在方法体内部声明的变量称为局部变量

img

注意:二者在初始化值方面的异同:

同:都有生命周期

异:局部变量除形参外,需显式初始化

定义变量的格式

数据类型 变量名 = 变量值;

数据类型 变量名;

变量名 = 变量值;

变量使用的注意点

① 变量必须先声明,后使用(声明包括定义与赋值),否则出现编译错误

img

② 变量都定义在其作用域内。在作用域内,它是有效的。换句话说,出了作用域,就失效了

③ 同一个作用域内,不可以声明两个同名的变量

基本数据类型变量间运算规则

涉及到的基本数据类型

除了boolean之外的其他7种

boolean类型数据只允许取值true和false,无null

java虚拟机中没有任何供boolean值专用的字节码指令,java语言表达所操作的boolean值,在编译之后都使用java虚拟机中的int数据类型代替,true用1表示,false用0表示

自动类型转换(只涉及7种基本数据类型)

1576394756595

结论:当容量小的数据类型的变量与容量大的数据类型的变量做运算时,结果自动提升为容量大的数据类型

​ byte 、char 、short –> int –> long –> float –> double

特别的:当byte、char、short三种类型的变量做运算时,结果为int型,否则编译不通过

说明:此时的容量大小指的是,表示数的范围的大和小。比如:float容量要大于long的容量

强制类型转换(只涉及7种基本数据类型)

自动类型提升运算的逆运算

1.需要使用强转符:()

2.注意点:强制类型转换,可能导致精度损失

3.通常,字符串不能直接转换为基本类型,但通过基本类型对应的包装类则可以实现把字符串转换成基本类型

如: String a = “43”; int i = Integer.parseInt(a);

boolean类型不可以转换为其它的数据类型

String与8种基本数据类型间的运算

  1. String属于引用数据类型,翻译为:字符串

  2. 声明String类型变量时,使用一对””

  3. String可以和8种基本数据类型变量做运算,且运算只能是连接运算:+

  4. 运算的结果仍然是String类型

避免:

1
String s = 123;//编译错误

1
2
3
String s1 = "123";

int i = (int)s1;//编译错误

进制

编程中涉及的进制及表示方式

img

二进制的使用说明:

计算机底层的存储方式

所有数字在计算机底层都以二进制形式存在。

二进制数据的存储方式

所有的数值,不管正负,底层都以补码的方式存储。

原码、反码、补码的说明:

正数:三码合一

负数:

img

进制间的转换

img

运算符

算术运算符

1
+ - * / % (前)++ (后)++ (前)-- (后)--

典型代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
//除号:/
int num1 = 12;
int num2 = 5;
int result1 = num1 / num2;
System.out.println(result1);//2
// %:取余运算
//结果的符号与被模数的符号相同
//开发中,经常使用%来判断能否被除尽的情况。
int m1 = 12;
int n1 = 5;
System.out.println("m1 % n1 = " + m1 % n1);

int m2 = -12;
int n2 = 5;
System.out.println("m2 % n2 = " + m2 % n2);

int m3 = 12;
int n3 = -5;
System.out.println("m3 % n3 = " + m3 % n3);

int m4 = -12;
int n4 = -5;
System.out.println("m4 % n4 = " + m4 % n4);
//(前)++ :先自增1,后运算
//(后)++ :先运算,后自增1
int a1 = 10;
int b1 = ++a1;
System.out.println("a1 = " + a1 + ",b1 = " + b1);

int a2 = 10;
int b2 = a2++;
System.out.println("a2 = " + a2 + ",b2 = " + b2);

int a3 = 10;
++a3;//a3++;
int b3 = a3;
//(前)-- :先自减1,后运算
//(后)-- :先运算,后自减1

int a4 = 10;
int b4 = a4--;//int b4 = --a4;
System.out.println("a4 = " + a4 + ",b4 = " + b4);

特别说明

  1. (前)++ :先自增1,后运算

    (后)++ :先运算,后自增1

  2. (前)– :先自减1,后运算

    (后)– :先运算,后自减1

  3. 连接符:+

    只能使用在String与其他数据类型变量之间使用

案例

img

取余运算的结果的符号与被模数的符号相同

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
//除法运算
public class Demo02 {
public static void main(String[] args) {
int a = -10;
int b = 2;
System.out.println(a/b);

int c = 10;
int d = 2;
System.out.println(c/d);

int e = 10;
int f = -2;
System.out.println(e/f);

int g = -10;
int h = -2;
System.out.println(g/h);
}
1
2
3
4
-5
5
-5
5

除法运算符号与正常运算一致

img

答案为32

算术运算符的注意问题

如果对负数取模,可以把模数负号忽略不记,如:5%-2=1。 但被模数是

负数则不可忽略。此外,取模运算的结果不一定总是整数。

  • 对于除号“/”,它的整数除和小数除是有区别的:整数之间做除法时,只

保留整数部分而舍弃小数部分。

例如:int x=3510;x=x/1000*1000; x的结果是? x=3000

1
2
3
4
5
6
7
public class BaceTest {
public static void main(String[] args) {
int x=3510;
x=x/1000*1000;
System.out.println(x);
}
}

输出结果

1
3000
  • “+”除字符串相加功能外,还能把非字符串转换成字符串.例如:

System.out.println(“5+5=”+5+5); //打印结果是? 5+5=55 ?

赋值运算符

1
=  +=  -=  *=  /=  %=

典型代码

当“=”两侧数据类型不一致时,可以使用自动类型转换或使用强制类型转换原则进行处理

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
int i2,j2;
//连续赋值
i2 = j2 = 10;
//***************
int i3 = 10,j3 = 20;
int num1 = 10;
num1 += 2;//num1 = num1 + 2;
System.out.println(num1);//12

int num2 = 12;
num2 %= 5;//num2 = num2 % 5;
System.out.println(num2);

short s1 = 10;
//s1 = s1 + 2;//编译失败
s1 += 2;//结论:不会改变变量本身的数据类型
System.out.println(s1);

特别说明

运算结果的符号与等号右边的相同

1
2
3
4
5
6
7
8
//开发中,如果希望变量实现+2的操作,有几种方法?(前提:int num = 10;)
//方式一:num = num + 2;
//方式二:num += 2; (推荐)

//开发中,如果希望变量实现+1的操作,有几种方法?(前提:int num = 10;)
//方式一:num = num + 1;
//方式二:num += 1;
//方式三:num++; (推荐)

思考1

1
2
3
4
short s = 3;  
s = s+2; ①
s += 2; ②
①和②有什么区别?

1576412749142

思考2

1
2
3
4
5
int i = 1;
i *= 0.1;
System.out.println(i);
i++;
System.out.println(i);

运算的结果不会改变变量本身的数据类型

img

思考3

1
2
3
4
5
int m = 2;
int n = 3;
n *= m++;
System.out.println("m=" + m);//m=3
System.out.println("n=" + n);//n=6

思考4

1
2
3
int n = 10;
n += (n++) + (++n);
System.out.println(n);//32

比较运算符

== != > < >= <= instanceof

1576414191888

典型代码

1
2
3
4
5
6
7
8
9
10
int i = 10;
int j = 20;

System.out.println(i == j);//false
System.out.println(i = j);//20

boolean b1 = true;
boolean b2 = false;
System.out.println(b2 == b1);//false
System.out.println(b2 = b1);//true

特别说明

  1. 比较运算符的结果是boolean类型

  2. > < >= <= ,只能使用在数值类型的数据之间

  3. == 和 !=, 不仅可以使用在数值类型数据之间,还可以使用在其他引用类型变量之间

1
2
3
4
5
6
7
Account acct1 = new Account(1000);

Account acct2 = new Account(1000);

boolean b1 = (acct1 == acct2);//比较两个Account是否是同一个账户。false

boolean b2 = (acct1 != acct2);//true

逻辑运算符

逻辑与& 短路与&& 逻辑或| 短路或|| 逻辑非! 逻辑异或^

1576414464865

注意:

  • 逻辑运算符用于连接布尔型表达式,在Java中不可以写成3<x<6,应该写成x>3 & x<6 。
  • “&”和“&&”的区别:
    单&时,左边无论真假,右边都进行运算;
    双&时,如果左边为真,右边参与运算,如果左边为假,那么右边不参与运算。
  • “|”和“||”的区别同理,||表示:当左边为真,右边不参与运算。
  • 异或( ^ )与或( | )的不同之处是:当左右都为true时,结果为false。

典型代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
//区分& 与 &&
//相同点1:& 与 && 的运算结果相同
//相同点2:当符号左边是true时,二者都会执行符号右边的运算
//不同点:当符号左边是false时,&继续执行符号右边的运算。&&不再执行符号右边的运算。
//开发中,推荐使用&&
boolean b1 = true;
b1 = false;
int num1 = 10;
if(b1 & (num1++ > 0)){
System.out.println("我现在在北京");
}else{
System.out.println("我现在在南京");
}
System.out.println("num1 = " + num1);
boolean b2 = true;
b2 = false;
int num2 = 10;
if(b2 && (num2++ > 0)){
System.out.println("我现在在北京");
}else{
System.out.println("我现在在南京");
}
System.out.println("num2 = " + num2);
// 区分:| 与 ||
//相同点1:| 与 || 的运算结果相同
//相同点2:当符号左边是false时,二者都会执行符号右边的运算
//不同点3:当符号左边是true时,|继续执行符号右边的运算,而||不再执行符号右边的运算
//开发中,推荐使用||
boolean b3 = false;
b3 = true;
int num3 = 10;
if(b3 | (num3++ > 0)){
System.out.println("我现在在北京");
}else{
System.out.println("我现在在南京");
}
System.out.println("num3 = " + num3);
boolean b4 = false;
b4 = true;
int num4 = 10;
if(b4 || (num4++ > 0)){
System.out.println("我现在在北京");
}else{
System.out.println("我现在在南京");
}
System.out.println("num4 = " + num4);

【特别说明的】

1.逻辑运算符操作的都是boolean类型的变量。而且结果也是boolean类型

img

位运算符

<< >> >>> & | ^ ~

image-20200128180155231

image-20200128180422533

典型代码

1
2
3
4
5
6
7
8
9
10
11
12
int i = 21;
i = -21;
System.out.println("i << 2 :" + (i << 2));
System.out.println("i << 3 :" + (i << 3));
System.out.println("i << 27 :" + (i << 27));

//0当成false,1当成true
int m = 12;
int n = 5;
System.out.println("m & n :" + (m & n));
System.out.println("m | n :" + (m | n));
System.out.println("m ^ n :" + (m ^ n));

【面试题】 你能否写出最高效的2 * 8的实现方式?

答案:2 << 3 或 8 << 1

特别说明

  1. 位运算符操作的都是整型的数据

  2. << :在一定范围内,每向左移1位,相当于 * 2, >> :在一定范围内,每向右移1位,相当于 / 2

典型题目

1.交换两个变量的值

img

2.实现60的二进制到十六进制的转换

img

img

位运算符是直接对整数的二进制进行的运算

img

img

image-20200128225027277

image-20200128225054282

image-20200128225117434

三元运算符

(条件表达式)? 表达式1 : 表达式2

典型代码

1.获取两个整数的较大值

2.获取三个数的最大值

特别说明

  1. 说明

① 条件表达式的结果为boolean类型

② 根据条件表达式真或假,决定执行表达式1,还是表达式2.

如果表达式为true,则执行表达式1。

如果表达式为false,则执行表达式2。

③ 表达式1 和表达式2要求是一致的。

④ 三元运算符可以嵌套使用

  1. 凡是可以使用三元运算符的地方,都可以改写为if-else

反之,不成立。

  1. 如果程序既可以使用三元运算符,又可以使用if-else结构,那么优先选择三元运算符。原因:简洁、执行效率高。

img

image-20200128232604441

我们可以在代码中,查看某种类型的取值范围,代码如下:

1
2
3
4
5
6
public static void main(String[] args) {
// Byte 取值:-128 ~ 127
System.out.println(String.format("Byte 取值:%d ~ %d", Byte.MIN_VALUE, Byte.MAX_VALUE));
// Int 取值:-2147483648 ~ 2147483647
System.out.println(String.format("Int 取值:%d ~ %d", Integer.MIN_VALUE, Integer.MAX_VALUE));
}

包装类型

我们知道 8 种基本数据类型都有其对应的包装类,因为 Java 的设计思想是万物既对象,有很多时候我们需要以对象的形式操作某项功能,比如说获取哈希值(hashCode)或获取类(getClass)等。

包装类特性有哪些

1. 功能丰富

包装类本质上是一个对象,对象就包含有属性和方法,比如 hashCode、getClass 、max、min 等。

2. 可定义泛型类型参数

包装类可以定义泛型,而基本类型不行。

比如使用 Integer 定义泛型,代码:

1
List<Integer> list = new ArrayList<>();

如果使用 int 定义就会报错,代码:

1
List<int> list = new ArrayList<>(); // 编译器代码报错

3. 序列化

因为包装类都实现了 Serializable 接口,所以包装类天然支持序列化和反序列化。比如 Integer 的类图如下:

Integer 类图

4. 类型转换

包装类提供了类型转换的方法,可以很方便的实现类型之间的转换,比如 Integer 类型转换代码:

1
2
3
4
String age = "18";
int ageInt = Integer.parseInt(age) + 2;
// 输出结果:20
System.out.println(ageInt);

5. 高频区间的数据缓存

此特性为包装类很重要的用途之一,用于高频区间的数据缓存,以 Integer 为例来说,在数值区间为 -128~127 时,会直接复用已有对象,在这区间之外的数字才会在堆上产生。

我们使用 == 对 Integer 进行验证,代码如下:

1
2
3
4
5
6
7
8
9
10
11
public static void main(String[] args) {
// Integer 高频区缓存范围 -128~127
Integer num1 = 127;
Integer num2 = 127;
// Integer 取值 127 == 结果为 true(值127 num1==num2 => true)
System.out.println("值127 num1==num2 => " + (num1 == num2));
Integer num3 = 128;
Integer num4 = 128;
// Integer 取值 128 == 结果为 false(值128 num3==num4 => false)
System.out.println("值128 num3==num4 => " + (num3 == num4));
}

从上面的代码很明显可以看出,Integer 为 127 时复用了已有对象,当值为 128 时,重新在堆上生成了新对象。

为什么会产生高频区域数据缓存?我们查看源码就能发现“线索”,源码版本 JDK8,源码如下:

1
2
3
4
5
public static Integer valueOf(int i) {
if (i >= IntegerCache.low && i <= IntegerCache.high)
return IntegerCache.cache[i + (-IntegerCache.low)];
return new Integer(i);
}

由此可见,高频区域的数值会直接使用已有对象,非高频区域的数值会重新 new 一个新的对象。

各包装类高频区域的取值范围:

  • Boolean:使用静态 final 定义,就会返回静态值
  • Byte:缓存区 -128~127
  • Short:缓存区 -128~127
  • Character:缓存区 0~127
  • Long:缓存区 -128~127
  • Integer:缓存区 -128~127

包装类的注意事项

  • int 的默认值是 0,而 Integer 的默认值是 null。
  • 推荐所有包装类对象之间的值比较使用 equals() 方法,因为包装类的非高频区数据会在堆上产生,而高频区又会复用已有对象,这样会导致同样的代码,因为取值的不同,而产生两种截然不同的结果。代码示例:
1
2
3
4
5
6
7
8
9
10
11
12
13
public static void main(String[] args) {
// Integer 高频区缓存范围 -128~127
Integer num1 = 127;
Integer num2 = 127;
// Integer 取值 127 == 结果为 true(值127 num1==num2 => true)
System.out.println("值127 num1==num2 => " + (num1 == num2));
Integer num3 = 128;
Integer num4 = 128;
// Integer 取值 128 == 结果为 false(值128 num3==num4 => false)
System.out.println("值128 num3==num4 => " + (num3 == num4));
// Integer 取值 128 equals 结果为 true(值128 num3.equals(num4) => true)
System.out.println("值128 num3.equals(num4) => " + num3.equals(num4));
}
  • Float 和 Double 不会有缓存,其他包装类都有缓存。
  • Integer 是唯一一个可以修改缓存范围的包装类,在 VM optons 加入参数:

-XX:AutoBoxCacheMax=666 即修改缓存最大值为 666

示例代码如下:

1
2
3
4
5
6
7
8
9
10
11
public static void main(String[] args) {
Integer num1 = -128;
Integer num2 = -128;
System.out.println("值为-128 => " + (num1 == num2));
Integer num3 = 666;
Integer num4 = 666;
System.out.println("值为666 => " + (num3 == num4));
Integer num5 = 667;
Integer num6 = 667;
System.out.println("值为667 => " + (num5 == num6));
}

执行结果如下:

1
2
3
值为-128 => true
值为666 => true
值为667 => false

由此可见将 Integer 最大缓存修改为 666 之后,667 不会被缓存,而 -128~666 之间的数都被缓存了。

相关面试题

1. 以下 Integer 代码输出的结果是?

1
2
3
4
5
Integer age = 10;
Integer age2 = 10;
Integer age3 = 133;
Integer age4 = 133;
System.out.println((age == age2) + "," + (age3 == age4));

答:true,false

2. 以下 Double 代码输出的结果是?

1
2
3
4
5
Double num = 10d;
Double num2 = 10d;
Double num3 = 133d;
Double num4 = 133d;
System.out.println((num == num2) + "," + (num3 == num4));

答:false,false

3. 以下程序输出结果是?

1
2
3
4
int i = 100;
Integer j = new Integer(100);
System.out.println(i == j);
System.out.println(j.equals(i));

A:true,true
B:true,false
C:false,true
D:false,false

答:A

题目分析:有人认为这和 Integer 高速缓存有关系,但你发现把值改为 10000 结果也是 true,true,这是因为 Integer 和 int 比较时,会自动拆箱为 int 相当于两个 int 比较,值一定是 true,true

4. 以下程序执行的结果是?

1
2
final int iMax = Integer.MAX_VALUE;
System.out.println(iMax + 1);

A:2147483648
B:-2147483648
C:程序报错
D:以上都不是

答:B

题目解析:这是因为整数在内存中使用的是补码的形式表示,最高位是符号位 0 表示正数,1 表示负数,当执行 +1 时,最高位就变成了 1,结果就成了 -2147483648。

5. 以下程序执行的结果是?

1
2
3
4
5
6
Set<Short> set = new HashSet<>();
for (short i = 0; i < 5; i++) {
set.add(i);
set.remove(i - 1);
}
System.out.println(set.size());

A:1
B:0
C:5
D:以上都不是

答:5

题目解析:Short 类型 -1 之后转换成了 Int 类型,remove() 的时候在集合中找不到 Int 类型的数据,所以就没有删除任何元素,执行的结果就是 5。

6. short s=2;s=s+1; 会报错吗?short s=2;s+=1; 会报错吗?

答:s=s+1 会报错,s+=1 不会报错,因为 s=s+1 会导致 short 类型升级为 int 类型,所以会报错,而 s+=1 还是原来的 short 类型,所以不会报错。

7. float f=3.4; 会报错吗?为什么?

答:会报错,因为值 3.4 是 double 类型,float 类型级别小于 double 类型,所以会报错。如下图所示:

报错示例图

8. 为什么需要包装类?

答:需要包装类的原因有两个。

① Java 的设计思想是万物既对象,包装类体现了面向对象的设计理念;
② 包装类包含了很多属性和方法,比基本数据类型功能多,比如提供的获取哈希值(hashCode)或获取类(getClass)的方法等。

9. 基本类 int 和包装类 Integer,在 -128~127 之间都会复用已有的缓存对象,这种说法正确吗?

答:不正确,只有包装类高频区域数据才有缓存。

10. 包装类 Double 和 Integer 一样都有高频区域数据缓存,这种说法正确吗?

答:不正确,基本数据类型的包装类只有 Double 和 Float 没有高频区域的缓存。

11. 包装类的值比较要使用什么方法?

答:包装类因为有高频区域数据缓存,所以推荐使用 equals() 方法进行值比较。

12. 包装类有哪些功能?

答:包装类提供的功能有以下几个。

  • 功能丰富:包装类包含了有 hashCode、getClass 、max、min 等方法;
  • 可定义泛型类型参数:例如 List list = new ArrayList<>(); ;
  • 序列化:包装类实现了 Serializable 接口,所以包装类天然支持序列化和反序列化;
  • 类型转换:包装类提供了方便的类型转换方法,比如 Integer 的 parseInt() 方法;
  • 高频区域数据缓存:高频区域可使用已有的缓存对象。

详见正文“包装类型”部分内容。

13. 泛型可以为基本类型吗?为什么?

答:泛型不能使用基本数据类型。泛型在 JVM(Java虚拟机)编译的时候会类型檫除,比如代码 List list 在 JVM 编译的时候会转换为 List list ,因为泛型是在 JDK 5 时提供的,而 JVM 的类型檫除是为了兼容以前代码的一个折中方案,类型檫除之后就变成了 Object,而 Object 不能存储基本数据类型,但可以使用基本数据类型对应的包装类,所以像 List list 这样的代码是不被允许的,编译器阶段会检查报错,而 List list 是被允许的。

14. 选择包装类还是基本类的原则有哪些?

答:我们知道正确的使用包装类,可以提供程序的执行效率,可以使用已有的缓存,一般情况下选择基本数据类型还是包装类原则有以下几个。

① 所有 POJO 类属性必须使用包装类;
② RPC 方法返回值和参数必须使用包装类;
③ 所有局部变量推荐使用基本数据类型。

15. 基本数据类型在 JVM 中一定存储在栈中吗?为什么?

答:基本数据类型不一定存储在栈中,因为基本类型的存储位置取决于声明的作用域,来看具体的解释。

  • 当基本数据类型为局部变量的时候,比如在方法中声明的变量,则存放在方法栈中的,当方法结束系统会释放方法栈,在该方法中的变量也会随着栈的销毁而结束,这也是局部变量只能在方法中使用的原因;
  • 当基本数据类型为全局变量的时候,比如类中的声明的变量,则存储在堆上,因为全局变量不会随着某个方法的执行结束而销毁。

16. 以下程序执行的结果是?

1
2
3
4
5
6
7
Integer i1 = new Integer(10);
Integer i2 = new Integer(10);
Integer i3 = Integer.valueOf(10);
Integer i4 = Integer.valueOf(10);
System.out.println(i1 == i2);
System.out.println(i2 == i3);
System.out.println(i3 == i4);

A:false,false,false
B:false,false,true
C:false,true,true
D:true,false,false

答:B

题目解析:new Integer(10) 每次都会创建一个新对象,Integer.valueOf(10) 则会使用缓存池中的对象。

17. 3*0.1==0.3 返回值是多少?

答:返回值为:false。

题目解析:因为有些浮点数不能完全精确的表示出来,如下代码:

System.out.println(3 * 0.1);

返回的结果是:0.30000000000000004。

文章目录
  1. 1. 基本语法
    1. 1.1. 关键字
    2. 1.2. 保留字
    3. 1.3. 标识符
    4. 1.4. 变量
      1. 1.4.1. 变量的概念
      2. 1.4.2. 变量的作用
      3. 1.4.3. 使用变量注意
      4. 1.4.4. 变量的分类
        1. 1.4.4.1. 按数据类型分类
          1. 1.4.4.1.1. 详细说明
      5. 1.4.5. 按声明的位置分类
      6. 1.4.6. 定义变量的格式
      7. 1.4.7. 变量使用的注意点
      8. 1.4.8. 基本数据类型变量间运算规则
        1. 1.4.8.1. 涉及到的基本数据类型
        2. 1.4.8.2. 自动类型转换(只涉及7种基本数据类型)
        3. 1.4.8.3. 强制类型转换(只涉及7种基本数据类型)
        4. 1.4.8.4. String与8种基本数据类型间的运算
    5. 1.5. 进制
      1. 1.5.1. 编程中涉及的进制及表示方式
      2. 1.5.2. 二进制的使用说明:
        1. 1.5.2.1. 计算机底层的存储方式
        2. 1.5.2.2. 二进制数据的存储方式
        3. 1.5.2.3. 原码、反码、补码的说明:
        4. 1.5.2.4. 进制间的转换
    6. 1.6. 运算符
      1. 1.6.1. 算术运算符
        1. 1.6.1.1. 典型代码
        2. 1.6.1.2. 案例
      2. 1.6.2. 赋值运算符
        1. 1.6.2.1. 典型代码
        2. 1.6.2.2. 特别说明
        3. 1.6.2.3. 思考1
        4. 1.6.2.4. 思考2
        5. 1.6.2.5. 思考3
        6. 1.6.2.6. 思考4
      3. 1.6.3. 比较运算符
        1. 1.6.3.1. 典型代码
        2. 1.6.3.2. 特别说明
      4. 1.6.4. 逻辑运算符
        1. 1.6.4.1. 典型代码
      5. 1.6.5. 位运算符
        1. 1.6.5.1. 典型代码
        2. 1.6.5.2. 特别说明
        3. 1.6.5.3. 典型题目
      6. 1.6.6. 三元运算符
        1. 1.6.6.1. 典型代码
        2. 1.6.6.2. 特别说明
      7. 1.6.7.
      8. 1.6.8. 包装类型
        1. 1.6.8.0.1. 包装类特性有哪些
    7. 1.6.9. 包装类的注意事项
    8. 1.6.10. 相关面试题
      1. 1.6.10.1. 1. 以下 Integer 代码输出的结果是?
      2. 1.6.10.2. 2. 以下 Double 代码输出的结果是?
      3. 1.6.10.3. 3. 以下程序输出结果是?
      4. 1.6.10.4. 4. 以下程序执行的结果是?
      5. 1.6.10.5. 5. 以下程序执行的结果是?
      6. 1.6.10.6. 6. short s=2;s=s+1; 会报错吗?short s=2;s+=1; 会报错吗?
      7. 1.6.10.7. 7. float f=3.4; 会报错吗?为什么?
      8. 1.6.10.8. 8. 为什么需要包装类?
      9. 1.6.10.9. 9. 基本类 int 和包装类 Integer,在 -128~127 之间都会复用已有的缓存对象,这种说法正确吗?
      10. 1.6.10.10. 10. 包装类 Double 和 Integer 一样都有高频区域数据缓存,这种说法正确吗?
      11. 1.6.10.11. 11. 包装类的值比较要使用什么方法?
      12. 1.6.10.12. 12. 包装类有哪些功能?
      13. 1.6.10.13. 13. 泛型可以为基本类型吗?为什么?
      14. 1.6.10.14. 14. 选择包装类还是基本类的原则有哪些?
      15. 1.6.10.15. 15. 基本数据类型在 JVM 中一定存储在栈中吗?为什么?
      16. 1.6.10.16. 16. 以下程序执行的结果是?
      17. 1.6.10.17. 17. 3*0.1==0.3 返回值是多少?
|