Java中equals和==的比较:

String类型的常量池主要有2种使用方法:

1 直接使用双引号声明出来的String字符串对象会直接储存在常量池中。

2 如果不是用双引号声明的String对象,可以用String提供的intern方法。intern方***从字符串常量池种查询当前字符串是否存在,如果不存在就会将当前字符串放入常量池中。

Java中2种创建字符串的方式的分析:



String s1="abc";
String s2="abc";
System.out.print(s1==s2)   //true


分析:
采用字面方式创建一个字符串时,jvm首先会去字符串常量池去寻找受否存在“abc”这个对象,如果不存在,则在字符串常量池中创建“abc”这个对象,然后将池中“abc”这个对象的引用地址返回给“abc”对象的引用s1,这样s1会指向字符串常量池中“abc”这个对象中;如果存在。则不创建任何对象,直接将池中“abc”这个对象的地址返回,赋给引用s2,因为s1,s2都是指向同一个字符串常量池的“abc”对象,所以为:true
String s3=new String("xyz");
String s4=new String("xyz");
System.out.print(s3==s4); //false


分析:
采用new关键字新建一个字符串对象时,JVM首先在字符串池中查找有没有"xyz"这个字符串对象,如果有,则不在池中再去创建"xyz"这个对象了,直接在堆中创建一个"xyz"字符串对象,然后将堆中的这个"xyz"对象的地址返回赋给引用s3,这样,s3就指向了堆中创建的这个"xyz"字符串对象;如果没有,则首先在字符串池中创建一个"xyz"字符串对象,然后再在堆中创建一个"xyz"字符串对象,然后将堆中这个"xyz"字符串对象的地址返回赋给s3引用,这样,s3指向了堆中创建的这个"xyz"字符串对象。s4则指向了堆中创建的另一个"xyz"字符串对象。s3 、s4是两个指向不同对象的引用,结果当然是false
/** * Returns a canonical representation for the string object. * <p> * A pool of strings, initially empty, is maintained privately by the * class {@code String}. * <p> * When the intern method is invoked, if the pool already contains a * string equal to this {@code String} object as determined by * the {@link #equals(Object)} method, then the string from the pool is * returned. Otherwise, this {@code String} object is added to the * pool and a reference to this {@code String} object is returned. * <p> * It follows that for any two strings {@code s} and {@code t}, * {@code s.intern() == t.intern()} is {@code true} * if and only if {@code s.equals(t)} is {@code true}. * <p> * All literal strings and string-valued constant expressions are * interned. String literals are defined in section 3.10.5 of the * <cite>The Java&trade; Language Specification</cite>. * * @return a string that has the same contents as this string, but is * guaranteed to be from a pool of unique strings. */
    public native String intern();

String的intern方法中看到,这个方法是一个 native 的方法,但注释写的非常明了。“ 当调用 intern方法时,如果池已经包含一个等于此String对象的字符串(用equals(oject)方法确定),则返回池中的字符串。否则,将此String对象添加到池中,并返回此String对象的引用。“

==和equals的区别比较:

equals是Object类下的一个方法:源码如下:

public boolean equals(Object obj) {
    //this - s1
    //obj - s2
    return (this == obj);
   //此处使用的是等号比较两个对象 也就是说Object类下的equals()方和和==是一样的,
   //都是比较的是对象的内存地址(堆内存),由此可见,在没有从写equeals()方法之前 
    //使用equeals()方法判断和使用==判断的结果是一样的
}

实质上在很多的类中都是从写了equals()方法的 比如:String,Date ,Integer 例如:String类中equals()方法被重写了:源码如下(JDK10):

public boolean equals(Object anObject) {
    if (this == anObject) {
        return true;
    }
    if (anObject instanceof String) {
        String aString = (String)anObject;
        if (coder() == aString.coder()) {
            return isLatin1() ? StringLatin1.equals(value, aString.value)
                              : StringUTF16.equals(value, aString.value);
        }
    }
    return false;
}
//从写的equals()方法比较的是String的内容是否相等

有了上面的理论基础再加上字符串常量池的知识:我们可以很容易分析判断String中的equals和==的问题:

public class StringDemo {
2     public static void main(String[] args) {
3         String s1 = "Hello";
4         String s2 = "Hello";
5         System.out.println(s1 == s2);   // true 字符串常量池 s1和s2连两个不同的引用指向同一个内存地址
6     }
7 }
public class StringDemo {
 2     public static void main(String args[]) {
 3         String str1 = "Hello";
 4         String str2 = new String("Hello");
 5         String str3 = str2; // 引用传递
 6         System.out.println(str1 == str2); // false
 7         System.out.println(str1 == str3); // false
 8         System.out.println(str2 == str3); // true
 9         System.out.println(str1.equals(str2)); // true
10         System.out.println(str1.equals(str3)); // true
11         System.out.println(str2.equals(str3)); // true
12     }
13 }

面试题:请解释字符串比较之中“==”和equals()的区别?
==:比较的是两个字符串内存地址(堆内存)的数值是否相等,属于数值比较;
equals():比较的是两个字符串的内容,属于内容比较。