对一个对象进行操作时,真正操作的是对象的引用。
别名问题
一个对象有两个以上的引用
Trank a = new Trank();
Trank b = a;
一元加减操作符
“+”,“-”能将较小的类型提升为int
++,–
前缀 ++a,先运算,再返回
后缀 --a,先返回
关系操作符 < > <= >= == !=
前面四个是数字类型的比较符,后面两个还可以作为对象的比较符,后者就会涉及equals的问题。对于数字比较要区分包装类型和基本数据类型两种,处理方式是不同的。
Integer n1 = new Integer(47);
Integer n2 = new Integer(47);
System.out.println("n1 == n2:" + (n1 == n2)); // false
System.out.println("n1.equals(n2):" + n1.equals(n2)); // true
Integer n3 = 47;
Integer n4 = 47;
System.out.println("n3 == n4:" + (n3 == n4)); // true
Integer n5 = 128;
Integer n6 = 128;
System.out.println("n5 == n6:" + (n5 == n6)); // false
Integer是包装类型,每次new的时候都会在堆里新建一个内存,n1和n2是不同的内存块,用 == 比较时是比较的内存地址,所以n1 == n2会返回false,而equals比较的是实际的值,所以n1.equals(n2)返回true。
Integer n3 = 47;会自动进行装箱,所以n3和n4应该是指向不同内存的,而n3 == n4返回true就很奇怪了,所以装箱指向的是同一个内存?好吧假设是这样的,那n5 == n6却是false?
其实Integer n3 = 47; 在编译时会自动写成Integer n3 = Integer.valueOf(47);为了证明这个问题,便看了一下编出来的机器码。
// 源码
public static void main(String[] args) {
Integer v1 = 4;
Integer v2 = Integer.valueOf(4);
}
// 机器码
public static void main(java.lang.String[]);
Code:
0: iconst_4
1: invokestatic #2 // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
4: astore_1
5: iconst_4
6: invokestatic #2 // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
9: astore_2
10: return
}
从4,6两行可以看出来,确实是默认调用的valueOf方法,进入该方法查看
@HotSpotIntrinsicCandidate
public static Integer valueOf(int i) {
return i >= -128 && i <= Integer.IntegerCache.high ? Integer.IntegerCache.cache[i + 128] : new Integer(i);
}
从实现来看,当valueOf的入参在-128-[Integer.IntegerCache.high]之间时,返回的时同一个缓存对象,在此范围外时,在重新new一个新对象出来。所以问题解决了。
其中Integer.IntegerCache.high这个值是从JVM虚拟机中读出来的VM.getSavedProperty(“java.lang.Integer.IntegerCache.high”)一般都是127.
逻辑操作符
短路:一旦能够明确无误地确认整个表达式的值,就不再计算表达式的余下部分了。
直接常数
后缀字符
L-long
F-float
D-double
前缀字符
0x-16进制数,后面跟着0-9和a-f
0-八进制,后面只能跟0-7,如果输入08会报编译错误
用toBinaryString()可以转为二进制表示
指数记数法
1.37e-43 = 1.37 * 10^-43
编译器通常将指数作为double处理,float使用时要进行强转
按位操作符
与,&,同一则一
或,|,同零则零
异或,^,相同则零
非,~,一则零
移位操作符
操作 | 符号 | 解释 |
---|---|---|
左移 | << | 在低位补零 |
有符号右移 | >> | 在高位按“符号扩展”,正数高位补零,负数,高位补一 |
无符号右移 | >>> | “零扩展”无论正负高位补零 |
char,byte,short位处理是会被转成int,结果也是int。所以“位移”与“符号”连用,char,byte,short慎用,会被先转成int再截断
字符串操作符+和+=
非字符串类型会默认调用toString方法,如果是null则填“null”
类型转换操作符
窄化转换 | 必须强转,面临信息丢失危险| |
截尾和舍入 | 浮点->整型,截尾,舍入,用Math.round() |
提升 | float+double->double,int+long->long |