==运算符
Java中测量两个变量是否相等有两种方式:第一种是利用==运算符,第二种是利用equals()方法。
- 基本数据类型
使用==来判断变量是否相等,当变量是四类八种基本数据类型时,并且都是数值类型,则只要两个变量的值相同,就可返回true。
public class Test {
public static void main(String[] args) {
char a='A';
int b =65;
double c=65.0d;
System.out.println(a==b);//end=true
System.out.println(b==c);//end=true
System.out.println(a==c);//end=true
}
}
在上图代码中,char字符a的ascii码值为65,因此用==运算符来判断abc三个变量都能得到true。
- 引用类型
对于引用类型变量,只有当两个变量类型相同或者具有父子关系时才可使用,否则会报错。两个引用类型变量使用==运算符时,只有他们指向同一个对象时,才会返回true。
public static void main(String[] args) {
String a=new String("abc");
String b=new String("abc");
System.out.println(a==b);//end=false
}
上图程序中,变量a和变量b的值都是abc,但是a和b的引用不同,因此会返回false.
字符串常量池
对于新手而言,String有许多非常容易疑惑的地方:如"abc"和new String(“abc”)有什么不同?解决这个问题,我们需要理解Java字符串常量池机制。
字符串常量池的位置
字符串常量池位于方法区中,当创建一个字符串时,首先检测常量池中是否存在该字符串,存在则直接返回该字符串的引用,不存在则在字符串常量池中创建该字符串,并返回引用。JVM保证常量池中相同的字符串直接量只有一个,不会产生多个副本。
String a="我爱学习";
String b="我爱"+"学习";
String c="学习";
final String d="学习";
String e="我爱"+c;
String f="我爱"+d;
System.out.println(a==b);//end=true,因为b在编译阶段可以确定下来,
//因此b直接返回字符串常量池中的引用,所以相等。
System.out.println(a==e);//变量e="我爱"+c;变量c在编译时不能确定下来,因此返回false
System.out.println(a==f);
/*end=true 变量d加入final修饰符,final会告诉编译器变量d这个数据不会修改,在编译时直接将变量d替换成"学习",因此编译时变量f可以确定下来为"我爱学习",直接返回字符串常量池的引用,故a==f
*/
当使用new String(“abc”)时,JVM虚拟机首先在常量池中检查是否存在"abc",不存在则创建”abc“字符串,然后调用String类的构造器在堆内存中在创建一个新的String对象,值为abc,并返回堆内存中对象的引用。简单地说,使用new String()会创建两个对象。
String a=new String("abc");
String b="abc";
System.out.println(a==b);//end=false
上图中,声明a变量时,JVM首先在字符串常量池中创建"abc"对象,又在堆内存中创建"abc"对象,然后将堆内存中对象的引用返回给a。声明b变量时,JVM在字符串常量池中发现"abc",直接将常量池中对象的引用返回给b。变量a和变量b的内容相同,但一个是常量池的引用,一个是堆内存的引用。因此a==b的结果为false
equals()方法
equals()方法是Object类提供的一个实例方法,用于判断两个引用类型变量是否相等,点开Object类的源码可发现,这个方法判断两个对象是否相等和==运算符没有区别,因此Object类的这个方法意义不大,我们在实际开发中往往会重写这个方法。
//Object类源码
public boolean equals(Object obj) {
return (this == obj);
}
String类重写了equals()方法,只要两个字符串的序列相同,就可返回true。因此下列代码中运行结果全为true。
String a="我爱学习";
String b="我爱"+"学习";
String c="学习";
final String d="学习";
String e="我爱"+c;
String f="我爱"+d;
System.out.println(a.equals(b));//end=true
System.out.println(a.equals(e));//end=true
System.out.println(a.equals(f));//end=true
实际开发中,我们通常需要重写equals方法。重写方法时,相等的条件是由业务要求决定的,因此equals()方法的实现也是由业务要求决定的。
通常而言,重写quals()方应该满足下列条件:
- 自反性:对于任何非空引用值 x,x.equals(x) 都应返回 true。
- 对称性:对于任何非空引用值 x 和 y,当且仅当 y.equals(x) 返回 true 时,x.equals(y) 才应返回 true。
- 传递性:对于任何非空引用值 x、y 和 z,如果 x.equals(y) 返回 true,并且 y.equals(z) 返回 true,那么 x.equals(z) 应返回 true。
- 一致性:对于任何非空引用值 x 和 y,多次调用 x.equals(y) 始终返回 true 或始终返回 false,前提是对象上 equals 比较中所用的信息没有被修改。
- 对于任何非空引用值 x,x.equals(null) 都应返回 false。