需要注意的是我们自定义的类的equals方法是可以自己重写的,也就是说判断标准可以自己定,不过面试中应该都是针对Object类和String类的equals方法
面试这么回答就可以
1)对于==,比较的是值是否相等
如果作用于基本数据类型的变量,则直接比较其存储的 “值”是否相等;
如果作用于引用类型的变量,则比较的是所指向的对象的地址
2)对于equals方法,注意:equals方法不能作用于基本数据类型的变量,equals继承Object类,比较的是是否是同一个对象
如果没有对equals方法进行重写,则比较的是引用类型的变量所指向的对象的地址;
诸如String、Date等类对equals方法进行了重写的话,比较的是所指向的对象的内容。
————————————————
版权声明:本文为CSDN博主「小小鱼儿小小林」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/qq_27471405/article/details/81010094
==和equals在默认的情况下都是比较地址
==比较基本数据类型时,比较的是值是否相等(变量值)
==比较引用类型,比较引用指向的值(堆中内存对象的地址)
==比较的是栈中的值
引用类型至少占两块内存
比较基本数据类型实际上是比较栈中到的数值是否相等(基本数据类型在栈中分配)
比较引用类型比较的是指向的堆中的地址是否相等
引用保存的就是地址值
对于基本数据类型:(byte,short,char,int,float,double,long,boolean),比较的是值,他们是作为常量在方法区中的常量池里面以HashSet策略存储起来的,对于这样的字符串 “123” 也是相同的道理,在常量池中,一个常量只会对应一个地址,因此不管是再多的 123,“123” 这样的数据都只会存储一个地址,所以所有他们的引用都是指向的同一块地址,因此基本数据类型和String常量是可以直接通过==来直接比较的。
————————————————
版权声明:本文为CSDN博主「goforitaaa」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/goforitaaa/article/details/91416373
equals默认比较的是地址,这个方法最初定义在Object上,默认的实现是比较地址
Object a=new Object();
Object b=new Object();
System.out.println(a.equals(b));//false
System.out.println(a==b);//false
我们看看equals的源码,就是用==实现的
public boolean equals(Object obj) {
return (this == obj);
}
对于自定义的类,如果要比较内容是否相等,就需要重写equals方法
String类就重写了equals方法(就是先判断是不是String类,然后把每一个字符取出来判断)
/**
* Compares this string to the specified object. The result is {@code
* true} if and only if the argument is not {@code null} and is a {@code
* String} object that represents the same sequence of characters as this
* object.
*
* @param anObject
* The object to compare this {@code String} against
*
* @return {@code true} if the given object represents a {@code String}
* equivalent to this string, {@code false} otherwise
*
* @see #compareTo(String)
* @see #equalsIgnoreCase(String)
*/
public boolean equals(Object anObject) {
if (this == anObject) {//判断当前对象与要比较的对象的地址是否相等
return true;//地址相等则返回true
}
if (anObject instanceof String) {//地址不相等,先判断是不是String的实例
String anotherString = (String)anObject;
int n = value.length;
if (n == anotherString.value.length) {
char v1[] = value;
char v2[] = anotherString.value;
int i = 0;
while (n-- != 0) {//依次判断每个字符
if (v1[i] != v2[i])
return false;
i++;
}
return true;
}
}
return false;//不是String的实例,直接返回false
}
public static void main(String[] args) {
String s1=new String("123");
String s2=new String("123");
System.out.println(s1==s2);//false,两次new了对象,地址不一样
System.out.println(s1.equals(s2));//true
String s3="123";
String s4="123";
System.out.println(s3==s4);//true,指向常量池的同一个地址
System.out.println(s3.equals(s4));//true
System.out.println(s3==s1);//false,s1指向堆中的地址,s3指向常量池的地址
System.out.println(s3.equals(s1));//true
String s5="123123";
String s6=s3+s4;//因为字符串是不可变的对象,做相加会创建新的对象
System.out.println(s5==s6);//false ,s6拼接字符串会创建对象
System.out.println(s5.equals(s6));//true
final String s7="123";
final String s8="123";
String s9=s7+s8;//因为加了final,s7和s8是常量,不是变量了
System.out.println(s5==s9);//true
System.out.println(s5.equals(s9));//true
final String s10=s3+s4;//s3和s4是变量,相加就会new,所以下边是false
System.out.println(s5==s10);//false
System.out.println(s5.equals(s10));//rue
}
}
JVM把内存划分成两种:一种是栈内存,一种是堆内存。 当我们创建一个对象(new Object)时,就会调用对象的构造函数来开辟空间,将对象数据存储到堆内存中,与此同时在栈内存中生成对应的引用,当我们在后续代码中调用的时候用的都是栈内存中的引用。还需注意的一点,基本数据类型是存储在栈内存中。
①在函数中定义的一些基本类型的变量和对象的引用变量(变量名)都在函数的栈内存中分配。
②当在一段代码块定义一个变量时,Java就在栈中为这个变量分配内存空间,当超过变量的作用域后,Java会自动释放掉为该变量所分配的内存空间,该内存空间可以立即被另作他用。
③堆内存用来存放由new创建的对象(包括由基本类型包装起来的类:Integer、String、Double,实际上每个基本类型都有他的包装类)和数组。
————————————————
版权声明:本文为CSDN博主「goforitaaa」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/goforitaaa/article/details/91416373
String s1 = "hello";
String s2 = "hello";
System.out.println( s1==s2); //true
s1.equals(s2);//true
上面的判断当执行String s1 = “hello”;这条语句时,会在堆中的字符常量池里找”hello”这个字符串,若没有找到,则将”hello”这个字符串放入字符串常量池中.而在栈中开辟一块名为s1的空间存放”hello”,这块空间的引用.当执行String s2 = “hello”;这条语句时,会在堆中的字符串常量池里找”hello”这个字符串,很显然,可以找到,于是便把字符常量池里”hello”这个字符串的引用地址赋给s2,因此s1与s2存放的都是堆中字符常量池中的同一个”hello”的引用
————————————————
版权声明:本文为CSDN博主「goforitaaa」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/goforitaaa/article/details/91416373
==比较的是变量(栈)内存中存放的对象的(堆)内存地址,用来判断两个对象的地址是否相同,即是否是指相同一个对象。比较的是真正意义上的指针操作。equals用来比较的是两个对象的内容是否相等,由于所有的类都是继承自java.lang.Object类的,所以适用于所有对象,如果没有对该方法进行覆盖的话,调用的仍然是Object类中的方法,而Object中的equals方法返回的却是 ==的判断。String s=“abcd"是一种非常特殊的形式,和new 有本质的区别。它是java中唯一不需要new 就可以产生对象的途径。以String s=“abcd”;形式赋值在java中叫直接量,它是在常量池中而不是象new一样放在压缩堆中。 这种形式的字符串,在JVM内部发生字符串拘留,即当声明这样的一个字符串后,JVM会在常量池中先查找有有没有一个值为"abcd"的对象,如果有,就会把它赋给当前引用.即原来那个引用和现在这个引用指点向了同一对象, 如果没有,则在常量池中新创建一个"abcd”,下一次如果有String s1 = “abcd”;又会将s1指向"abcd"这个对象,即以这形式声明的字符串,只要值相等,任何多个引用都指向同一对象.
而String s = new String(“abcd”);和其它任何对象一样.每调用一次就产生一个对象,只要它们调用。
也可以这么理解: String str = “hello”; 先在内存中找是不是有"hello"这个对象,如果有,就让str指向那个"hello".
如果内存里没有"hello",就创建一个新的对象保存"hello". String str=new String (“hello”) 就是不管内存里是不是已经有"hello"这个对象,都新建一个对象保存"hello"。
————————————————
版权声明:本文为CSDN博主「MrBoringBigFish」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/qq_36522306/article/details/80550210
非String类,例如StringBuffer类 没有重写equals方法,所以不比较内容。==和equals都是比较的内存地址
StringBuffer stringBuffer = new StringBuffer("aaa");
StringBuffer stringBuffer2 = new StringBuffer("aaa");
System.out.println(stringBuffer == stringBuffer2); // false
System.out.println(stringBuffer.equals(stringBuffer2)); // false
可以看到,我点击equals,直接跳转到了Object类下面,这是因为StringBuffer类 没有重写equals方法
包装类
对于基本数据的包装类型(Byte, Short, Character,Integer,Float, Double,Long, Boolean)除了Float和Double之外,其他的六种都是实现了常量池的,因此对于这些数据类型而言,一般我们也可以直接通过==来判断是否相等。
例1
Integer a1=127;
Integer a2=127;
Integer a3=new Integer(127);
System.out.println(a1==a2);//true
System.out.println(a1==a3);//false
System.out.println(a1.equals(a3));//true
根据Integer的equals方法,可以得出,如果obj是Integer类型且value值相等,那么就返回true
public boolean equals(Object obj) {
if (obj instanceof Integer) {
return value == ((Integer)obj).intValue();
}
return false;
}
对于a1 == a2为true,是因为定义一个Integer变量时,会默认进行Integer.valueOf(a)操作,high的值为127,low的值为-128,当进行这个方法时如果值在-128-127之间,返回的值也就是地址是相同的,所以a1和a2的地址相同,a1==a2自然为true
public static Integer valueOf(int i) {
if (i >= IntegerCache.low && i <= IntegerCache.high)
return IntegerCache.cache[i + (-IntegerCache.low)];
return new Integer(i);
}
例2
Integer a1=128;
Integer a2=128;
Integer a3=new Integer(128);
System.out.println(a1==a2);//false
System.out.println(a1==a3);//false
System.out.println(a1.equals(a3));//true
Integer 在常量池中的存储范围为[-128,127],127在这范围内,因此是直接存储于常量池的,而128不在这范围内,所以会在堆内存中创建一个新的对象来保存这个值,所以m,n分别指向了两个不同的对象地址,故而导致了不相等。
简要的说就是在Integer类中有一个静态内部类IntegerCache,在IntegerCache类中有一个Integer数组,用以缓存当数值范围为-128~127时的Integer对象。
例3
int a1=127;
Integer a2=127;
System.out.println(a1==a2);//true
System.out.println(a2.equals(a1));//true
int a3=128;
Integer a4=128;
System.out.println(a3==a4);//true
System.out.println(a4.equals(a3));//true
int和int之间,用==比较,肯定为true,基本数据类型没有equals方法
int和integer比较,Integer会自动拆箱,==和equals结果都为true
int和new Integer之间比较,Integer会自动拆箱,调用intValue方法,所以==和equals结果都为true
Integer和Integer之间
1)直接赋值:
会进行自动装箱,所以当值在[-128,127]时,在这个区间内赋值不会创建新的对象,而是直接从缓存中获取已经创建好的Integer对象. 而当大于这个区间的时候,就会创建新的对象;
所以在进行==比较的时候,在[-127,128]区间内的值比较结果为true;大于该区间的值比较结果为false;
2)当Integer与Integer进行equals比较时,由于Integer重写了equals方法,比较的是内容,所以结果为true;
3)integer和new integer:
new integer会创建新的对象,存储在堆中,而integer在[-127,128]中是从缓存中取;所以integer和new integer进行 == 比较,结果为false,若进行equals比较,结果为true
4)new integer 和 new integer之间比较:
进行 == 比较的时候结果为false,进行equals比较的时候结果为true
一般类的比较
Scanner scanner = new Scanner(System.in);
Scanner scanner2 = new Scanner(System.in);
System.out.println(scanner.equals(scanner2)); //false
Scanner sc = scanner;
System.out.println(scanner.equals(sc)); //true
执行第一条语句Scanner scanner = new Scanner(System.in); 时在堆中开辟了一块内存存放Scanner对象,在栈内存中开辟一块名为scanenr的内存存放Scanner对象的引用.
执行第二条语句Scanner scanner2 = new Scanner(System.in); 时时在堆中另外开辟了一块内存存放Scanner对象,在栈内存中开辟一块名为scanenr2的内存存放Scanner对象的引用.
因为这里调用的是一般对象的equals方法,因此比较的是两个对象是否属于同一个对象,显然不是同一个对象.
可见在非String类中, ==和equals的作用都是一样的,只不过在String类中重写了equals方法,才会变得这么复杂!!!
推荐阅读
== 和equals区别
Integer对象范围(-128-127)之间
Integer的自动拆装箱的陷阱(整型数-128到127的值比较问题)
Java面试题 :byte b = (byte)128; 定义变量语句是否正确
int和integer------比较(equals和==)