在最底层,java中的数据是通过使用操作符来操作的。
几乎所有操作符都只能操作基本类型。例外的操作符“=”“==”“!=”能操作所有对象。
String类支持“+”和“+=”。此时“+”意味着字符串连接,当编辑器察觉到一个String后面有一个“+”,而后又紧跟一个非String元素,就会尝试将非String元素转换为String。
赋值
“=”意思是“取右值把它复制给左值”,右值可以是任何常数、变量或者表达式。但左值必须是一个明确的、已命名的变量,必须有一个物理空间可以存储等号右边的值。
基础类型存储了实际的数值,并非指向一个对象的引用,所以赋值时候是直接将一个地方的内容复制到另一个地方。例如,对基本数据类型使用a=b,那么b的内容就复制给了a,而b根本不会受修改的影响。
但对象赋值就会出现别名现象:
public class Test {
public static void main(String[] args){
int b = 2;
int a = b;
System.out.println("a=" + a + ",b=" + b);
a = 10;
System.out.println("a=" + a + ",b=" + b);
Thank t1 = new Thank();
Thank t2 = new Thank();
t1.level = 9;
t2.level = 27;
System.out.println("t1:level=" + t1.level + ",t2:level=" + t2.level);
t1 = t2;
System.out.println("t1:level=" + t1.level + ",t2:level=" + t2.level);
t1.level = 49;
System.out.println("t1:level=" + t1.level + ",t2:level=" + t2.level);
}
}
结果:
a=2,b=2
a=10,b=2
t1:level=9,t2:level=27
t1:level=27,t2:level=27
t1:level=49,t2:level=49
将一个对象传递给方法时,也会产生别名问题:
public class Letter {
char c;
}
public class Test {
public static void main(String[] args){
Letter l = new Letter();
l.c = 'X';
System.out.println(l.c);
f(l);
System.out.println(l.c);
}
static void f(Letter y){
y.c = 'Z';
}
}
结果:
X
Z
关系操作符
“>”“<”“<=”“>=”“!=”“==”适用于所有基本类型
==和!=比较的是对象的引用。比较对象的实际内容,必须使用所有对象都是适用的equals()。
public class Test {
public static void main(String[] args){
Integer i1 = new Integer(47);
Integer i2 = new Integer(47);
System.out.println(i1 == i2);
System.out.println(i1.equals(i2));
}
}
结果:
false
true
public class Test {
public static void main(String[] args){
Letter l1 = new Letter();
Letter l2 = new Letter();
l1.c = l2.c = 'X';
System.out.println(l1.equals(l2));
}
}
结果 false
equals的默认行为也是比较引用,所以除非自己在新类中覆盖equals方法(Integer中覆盖了equals),才能达到预期效果。
integer覆盖equals代码:
public boolean equals(Object obj) {
if (obj instanceof Integer) {
return value == ((Integer)obj).intValue();
}
return false;
}
短路
一旦明确无误地确定整个表达式的值,就不再计算表达式余下部分。
public class Test {
public static void main(String[] args){
int i = 0;
if(test1(i) && test2(i)){
System.out.println("i大于0小于10");
}
}
static boolean test1(int i){
System.out.println("test1判断结果:" + (i > 0));
return i > 0;
}
static boolean test2(int i){
System.out.println("test2判断结果:" + (i < 10));
return i < 10;
}
}
结果:test1判断结果:false
第一个测试已经生成了false,已经可以确定test1(i) && test2(i)的结果为false,没必要继续计算剩余的表达式。
类型转换操作符
类型转换(cast)原意是“模型铸造”。
窄化转换(narrowing conversion)将能容纳更多信息的数据类型转换成无法容纳那么多信息的类型,必须进行显式的类型转换。
扩展转换(widening conversion)则不必。基本数据类型除布尔型以外允许转换成别的基本数据类型。“类”数据类型不允许进行类型转换,必须采用特殊方法(类族之间)。
截尾和舍入
public class Test {
public static void main(String[] args){
float f = 0.7f;
int i = (int) f;
//float和double转成整型总会对数据进行截尾
System.out.println(i);
//截尾
System.out.println(Math.round(f));
}
}
提升
表达式中出现最大的数据类型决定了表达式最终结果的数据类型。
结果溢出
public class Test {
public static void main(String[] args){
int i = Integer.MAX_VALUE;
System.out.println(i);
int i1 = i * 2;
System.out.println(i1);
byte b1=67;
byte b2=89;
//156=(00000000)(00000000)(00000000)(10011100)=-100
System.out.println((byte)(b1+b2));
}
}
结果:
2147483647
-2
-100