equals和==区别(简单介绍了一下装箱和拆箱操作)

引入

==

  • 基本数据类型(也称原始数据类型) :byte,short,char,int,long,float,double,boolean。他们之间的比较,应用双等号(==),比较的是他们的值。
  • 复合数据类型(类):当他们用(==)进行比较的时候,比较的是他们在内存中的存放地址(确切的说,是堆内存地址)。
  • 注:对于第二种类型,除非是同一个new出来的对象,他们的比较后的结果为true,否则比较后结果为false。因为每new一次,都会重新开辟堆内存空间。

equals

  • JAVA当中所有的类都是继承于Object这个超类的,在Object类中定义了一个equals的方法,这个方法的初始行为是比较对象的内存地址,但在一些类库当中这个方法被复写了,如String、Integer、Date。在这些类当中equals有其自身的实现,而不再是比较类在堆内存中的存放地址了。
    所以说,对于复合数据类型之间进行equals比较,在没有覆写equals方法的情况下,他们之间的比较还是内存中的存放位置的地址值,跟双等号(==)的结果相同;如果被复写,按照复写的要求来。

小结

  • “==”比较的是值【变量(栈)内存中存放的对象的(堆)内存地址】
  • equal用于比较两个对象的值是否相同【不是比地址】
  • 【特别注意】Object类中的equals方法和“==”是一样的,没有区别,而String类,Integer类等等一些类,是重写了equals方法,才使得equals和“==不同”,所以,当自己创建类时,自动继承了Object的equals方法,要想实现不同的等于比较,必须重写equals方法。
  • "=="比"equal"运行速度快,因为"=="只是比较引用.

Integer 和 int

代码块

public class Test {
    public static void main(String args[]){
        test1();
        test2();
    }

    public static  void test2(){
        System.out.println("既有基本数据类型,又有对应的类(这里用Integer和int举例 1231):");
        Integer a1 = new Integer(1231);
        Integer a2 = new Integer(1231);
        System.out.println("Integer new Integer");
        System.out.println("== —> "+(a1 == a2));//new 出来两个对象,==比较的是地址
        System.out.println("equals —> "+(a1.equals(a2)));//equals比较的是值

        Integer b1 = 1231;
        Integer b2 = 1231;//这里会调用Integer.valueof();
        System.out.println("Integer 直接赋值:");
        System.out.println("== —> "+(b1 == b2));//b1、b2自动装箱产生的对象,其值都是1231,那么这里很特殊的是1231正好不在-128<=i7<=127这个范围内的,那么会重新new出一个对象
        System.out.println("equals —> "+(b1.equals(b2)));

        int c1 = 1231;
        int c2 = 1231;
        System.out.println("基本数据类型int 直接赋值:");
        System.out.println("== —> "+(c1 == c2));//“==”对于基本数据类型,判断两个变量的值是否相等
        System.out.println("没有equals方法");

        int d1 = new Integer(1231);
        int d2 = new Integer(1231);
        System.out.println("基本数据类型int new Integer:");
        System.out.println("== —> "+(d1 == d2));//c1、c2拆箱产生的对象,调用的是Integer.intValue的方法
        System.out.println("没有equals方法");

        int e1 = 1231;
        int e2 = new Integer(1231);
        System.out.println("一个int new Integer,一个直接赋值");
        System.out.println("== —> "+(e1 == e2));
        System.out.println("没有equals方法");

        Integer f1 = 1231;
        Integer f2 = new Integer(1231);
        System.out.println("一个Integer new Integer,一个Integer直接赋值");
        System.out.println("== —> "+(f1 == f2));//f1是从IntegerCache取的数据,而f2是new出来的一个对象,自然不一样
        System.out.println("equals —> "+(f1.equals(f2)));
    }

    public static  void test1(){
        System.out.println("既有基本数据类型,又有对应的类(这里用Integer和int举例 123):");
        Integer a1 = new Integer(123);
        Integer a2 = new Integer(123);
        System.out.println("Integer new Integer");
        System.out.println("== —> "+(a1 == a2));//new 出来两个对象,==比较的是地址
        System.out.println("equals —> "+(a1.equals(a2)));//equals比较的是值

        Integer b1 = 123;
        Integer b2 = 123;//这里会调用Integer.valueof();
        System.out.println("Integer 直接赋值:");
        System.out.println("== —> "+(b1 == b2));//b1、b2自动装箱产生的对象,其值都是123,那么这里很特殊的是123正好在-128<=i7<=127这个范围内的,那么会去IntegerCache中取,既然都是去IntegerCache中去取,那么自然该对象应该是一个对象,那么再堆中的地址应该是一样的,所以在判读两个对象是不是== 的时候,会输出true
        System.out.println("equals —> "+(b1.equals(b2)));

        int c1 = 123;
        int c2 = 123;
        System.out.println("基本数据类型int 直接赋值:");
        System.out.println("== —> "+(c1 == c2));//“==”对于基本数据类型,判断两个变量的值是否相等
        System.out.println("没有equals方法");

        int d1 = new Integer(123);
        int d2 = new Integer(123);
        System.out.println("基本数据类型int new Integer:");
        System.out.println("== —> "+(d1 == d2));//c1、c2拆箱产生的对象,调用的是Integer.intValue的方法
        System.out.println("没有equals方法");

        int e1 = 123;
        int e2 = new Integer(123);
        System.out.println("一个int new Integer,一个直接赋值");
        System.out.println("== —> "+(e1 == e2));
        System.out.println("没有equals方法");

        Integer f1 = 123;
        Integer f2 = new Integer(123);
        System.out.println("一个Integer new Integer,一个Integer直接赋值");
        System.out.println("== —> "+(f1 == f2));//f1是从IntegerCache取的数据,而f2是new出来的一个对象,自然不一样
        System.out.println("equals —> "+(f1.equals(f2)));
    }
}

运行结果

既有基本数据类型,又有对应的类(这里用Integer和int举例 123):
Integer new Integer
== —> false
equals —> true
Integer 直接赋值:
== —> true
equals —> true
基本数据类型int 直接赋值:
== —> true
没有equals方法
基本数据类型int new Integer:
== —> true
没有equals方法
一个int new Integer,一个直接赋值
== —> true
没有equals方法
一个Integer new Integer,一个Integer直接赋值
== —> false
equals —> true
既有基本数据类型,又有对应的类(这里用Integer和int举例 1231):
Integer new Integer
== —> false
equals —> true
Integer 直接赋值:
== —> false
equals —> true
基本数据类型int 直接赋值:
== —> true
没有equals方法
基本数据类型int new Integer:
== —> true
没有equals方法
一个int new Integer,一个直接赋值
== —> true
没有equals方法
一个Integer new Integer,一个Integer直接赋值
== —> false
equals —> true

源码分析
Integer装箱源码(主要是Integer.valueOf方法)

    /**
     * Returns an {@code Integer} instance representing the specified
     * {@code int} value.  If a new {@code Integer} instance is not
     * required, this method should generally be used in preference to
     * the constructor {@link #Integer(int)}, as this method is likely
     * to yield significantly better space and time performance by
     * caching frequently requested values.
     *
     * This method will always cache values in the range -128 to 127,
     * inclusive, and may cache other values outside of this range.
     *
     * @param  i an {@code int} value.
     * @return an {@code Integer} instance representing {@code i}.
     * @since  1.5
     */
    public static Integer valueOf(int i) {
        if (i >= IntegerCache.low && i <= IntegerCache.high)
            return IntegerCache.cache[i + (-IntegerCache.low)];
        return new Integer(i);
    }

IntegerCache类

/**
     * Cache to support the object identity semantics of autoboxing for values between
     * -128 and 127 (inclusive) as required by JLS.
     *
     * The cache is initialized on first usage.  The size of the cache
     * may be controlled by the {@code -XX:AutoBoxCacheMax=<size>} option.
     * During VM initialization, java.lang.Integer.IntegerCache.high property
     * may be set and saved in the private system properties in the
     * sun.misc.VM class.
     */

    private static class IntegerCache {
        static final int low = -128;
        static final int high;
        static final Integer cache[];

        static {
            // high value may be configured by property
            int h = 127;
            String integerCacheHighPropValue =
                sun.misc.VM.getSavedProperty("java.lang.Integer.IntegerCache.high");
            if (integerCacheHighPropValue != null) {
                try {
                    int i = parseInt(integerCacheHighPropValue);
                    i = Math.max(i, 127);
                    // Maximum array size is Integer.MAX_VALUE
                    h = Math.min(i, Integer.MAX_VALUE - (-low) -1);
                } catch( NumberFormatException nfe) {
                    // If the property cannot be parsed into an int, ignore it.
                }
            }
            high = h;

            cache = new Integer[(high - low) + 1];
            int j = low;
            for(int k = 0; k < cache.length; k++)
                cache[k] = new Integer(j++);

            // range [-128, 127] must be interned (JLS7 5.1.7)
            assert IntegerCache.high >= 127;
        }

        private IntegerCache() {}
    }

数值在-128<=x<=127这个范围内的,那么会去IntegerCache中取。超过这个范围回去new一个对象。
Integer拆箱源码(主要是Integer.intValue方法)

/**
     * Returns the value of this {@code Integer} as an
     * {@code int}.
     */
    public int intValue() {
        return value;
    }

从源码可以看出,当包装器类型和基本数据类型进行“==”比较时,包装器类型会自动拆箱为基本数据类型。

基本类型 占用空间(Byte) 表示范围 包装器类型
boolean 1/8 true、false Boolean
char 2 -128~127 Character
byte 1 -128~127 Byte
short 2 -2ˆ15~2ˆ15-1 Short
int 4 -2ˆ31~2ˆ31-1 Integer
long 8 -2ˆ63~2ˆ63-1 Long
float 4 -3.403E38~3.403E38 Float
double 8 -1.798E308~1.798E308 Double

以下感觉写的比较好的博客:
Java自动装箱与拆箱及其陷阱
Java 的Integer、int与new Integer到底怎么回事?

String

Java的虚拟机在内存中开辟出一块单独的区域,用来存储字符串对象,这块内存区域被称为字符串缓冲池。当使用 String a = "abc" 这样的语句进行定义一个引用的时候,首先会在字符串缓冲池中查找是否已经相同的对象,如果存在,那么就直接将这个对象的引用返回给a,如果不存在,则需要新建一个值为"abc"的对象,再将新的引用返回a。
String a = new String("abc");这样的语句明确告诉JVM想要产生一个新的String对象,并且值为"abc",于是就在堆内存中的某一个小角落开辟了一个新的String对象。

  • ==  在比较引用的情况下,会去比较两个引用的内存地址是否相等。
    String str1 = "abc";
    String str2 = "abc";
    System.out.println(str1 == str2);
    System.out.println(str1.equals(str2));
    String str2 = new String("abc");
    System.out.println(str1 == str2);
    System.out.println(str1.equals(str2));
以上代码将会输出
true
true
false
true
**第一个true:**因为在str2赋值之前,str1的赋值操作就已经在内存中创建了一个值为"abc"的对象了,然后str2将会与str1指向相同的地址。
**第二个true:**因为`String`已经重写了`equals`方法:为了方便大家阅读我贴出来,并且在注释用进行分析:
```
public boolean equals(Object anObject) {
//如果比较的对象与自身内存地址相等的话
//就说明他两指向的是同一个对象
//所以此时equals的返回值跟==的结果是一样的。
if (this == anObject) {
    return true;
}
//当比较的对象与自身的内存地址不相等,并且
//比较的对象是String类型的时候
//将会执行这个分支
if (anObject instanceof String) {
    String anotherString = (String)anObject;
    int n = value.length;
    if (n == anotherString.value.length) {
        char v1[] = value;
        char v2[] = anotherString.value;
        int i = 0;
        //在这里循环遍历两个String中的char
        while (n-- != 0) {
            //只要有一个不相等,那么就会返回false
            if (v1[i] != v2[i])
                return false;
            i++;
        }
        return true;
    }
}
return false;

}
```

自定义类

public class Test {
    public static void main(String args[]){
        test();
    }

    public static void test(){
        A a = new A(1);
        A b = new A(1);
        System.out.println(a==b);
        System.out.println(a.equals(b));
    }
    static class A {
        private int a;
        public A(int a){
            this.a =a ;
        }
    }
}

这时候输出的结果两个都是false,因为A类是Objcet的子类,在没有重写equals方法的时候,调用equals方法其实是调用Object的equals的方法,而Object类中的equals方法和“==”是一样的,比较的还是内存中的存放地址
Object的equals的源码

public boolean equals(Object obj) {
        return (this == obj);
}

重写Object的equals方法(类似于String的equals方法)

public class Test {
    public static void main(String args[]){
        test();
    }

    public static void test(){
        A a = new A(1);
        A b = new A(1);
        System.out.println(a==b);
        System.out.println(a.equals(b));
    }
    static class A {
        private int a;
        public A(int a){
            this.a =a ;
        }
        public boolean equals(Object obj) {
            if (this == obj) {
                return true;
            }
            if (obj == null) {
                return false;
            }
            if (!(obj instanceof A)) {
                return false;
            }
            A other = (A) obj;
            return a==other.a;
        }
    }
}

这里返回值第一个是false,第二个是true

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 158,847评论 4 362
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,208评论 1 292
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 108,587评论 0 243
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 43,942评论 0 205
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,332评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,587评论 1 218
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,853评论 2 312
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,568评论 0 198
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,273评论 1 242
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,542评论 2 246
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,033评论 1 260
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,373评论 2 253
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,031评论 3 236
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,073评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,830评论 0 195
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,628评论 2 274
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,537评论 2 269

推荐阅读更多精彩内容