天天看点

JDK源码解读由浅入深(一) 从源码分析equals和==一、下载JDK二、Object三、String.class四、拓展,String对象做比较。五、探究字符串a去了哪里?

好久没写代码,也不知为何,上一趟csdn,难的看不懂,简单的不屑看,眼高手低说的就是我了。。

也不知道从什么地方提高自己,对我来说,什么东西似乎都能说上一点,但是再往后,知识储备就不足了,再继续写下去也怕误人子弟。也许有生之年,我能补完自己之前埋下的坑呢?。。

这次准备长期写下去的就是源码解读,有一说一,我不喜欢像某些csdn的5年,10年的账号一样,一天到晚发一些基础知识,啃老本,我甚至怀疑到底是这些人是真的水平太低,还是这些初级Java都会的基础知识太难学??

这一篇在写的时候也是感觉很水很low,但是看源码对于初级Java来说确实进步很大。(其实我就是懒,想水。)

闲话不多说,这一次我准备解读源码,从jdk开始,再到ssm框架,有生之年也许能写完?TAT

先说一下源码解读的流程。

一、下载JDK

我相信大家都下载了jdk环境,而在jdk安装路径下就有jdk的源码文件

JDK源码解读由浅入深(一) 从源码分析equals和==一、下载JDK二、Object三、String.class四、拓展,String对象做比较。五、探究字符串a去了哪里?

如果是使用eclipse的童鞋,点开class文件之后点击弹出的按钮,选择src.zip文件即可。

如果用idea就简单很多,我使用的就是idea。

二、Object

既然是由浅入深,我们就从万物起源----->object类开始说起。

这个类是所有类的父类,在Java代码层面上,他本身并没有太多的问题可说,但是经常会有初级Java面试问equals方法和==的区别。

equals()方法从哪里来呢?自然就是Object类来的。

我们来看下equals()方法的源码:

//Object类的equals()方法
    public boolean equals(Object obj) {
        return (this == obj);
    }
           

现在,真相已经出来了,equals方法和==号是完全等价的。

但是面试的答案可不是这么回答的,所以我一向很讨厌死记硬背,也完全没有必要死记硬背。

经常会有人说:equals方法比较的是值,而==比较的是地址。

现在看来这种说法并不对,对于Object类来说,equals方法和==号是完全等价的

也就是说只要我们不重写equals方法,那么,==和equals是不分家的。真要说有什么不一样的话,那就是equals方法被空对象调用时会发生空指针异常,而==不会。

三、String.class

那么上面的说法是从哪里来的?

其实罪魁祸首就是他:

String.class

让我们看下String类的equals方法:

//首先咱们得清楚,1.8版本String类的底层实际上就是一个字符数组(在更新的JDK中实用字节数组优化了)
private final char value[];

public boolean equals(Object anObject) {
        //即便是String类,第一步也是地址是否相等。
        if (this == anObject) {
            return 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;
    }
           

由此可见,对于仅有重写了equals方法时才会比较不同,否则equals方法和==是完全相等的。

四、拓展,String对象做比较。

大家都知道,两个new出来的对象肯定不相等(这里指==号做比较)

//此处两个字符串都是new出来的,因此==比较的结果是false,但是由于内容相同,所以equals方法比较的结果是true。
String a = new String("helloworld");
String b = new String("helloworld");
           

但是字符串就比较恶心了,因为字符串可以不需要new出来。。。

String a = "helloworld";
String b = new String("helloworld");
           

上面的a和b用==比较的结果肯定是不相等的,但是这是为什么呢?

首先看下String的构造方法

public String(String original) {
        //value便是存储字符串的字符数组。
        this.value = original.value;
        this.hash = original.hash;
    }
           

字符串a,b和他们对应的value数组的关系大概就是如下了:

JDK源码解读由浅入深(一) 从源码分析equals和==一、下载JDK二、Object三、String.class四、拓展,String对象做比较。五、探究字符串a去了哪里?

如果比较的是a.value == b.value 的话,返回结果一定为true,但是

a,b并不是同一个人啊,就像你爸的儿子是你,你妈的儿子也是你,但是你爸!=你妈

五、探究字符串a去了哪里?

对于字符串a

String a = "helloworld";
           

这个a到底去了哪里?

事实上,jvm虚拟机对于这些在代码中的常量,会直接在类加载的时候加载到常量池(如果重复的话则直接把已经在常量池存在的常量的引用返回),因此字符串a是直接指向常量池的"helloworld";

而new出来的字符串b,则是放在堆上,一个在常量池,一个在堆,它们之间的地址引用做比较自然不会相等~

但是如果是直接传引用的话,最后两个变量的引用都是指向一个对象,那么就是相等的。

String a = "helloworld";
String b = "helloworld";
a==b?//结果为true,创建a时,helloworld直接进常量池,创建b时,常量池已经存在helloworld,将常量池helloworld的引用返回给b
           
String a = new String("helloworld");
String b = "helloworld";
a==b?//结果为false。
//创建a时,在常量池创建helloworld,接着再用常量池的helloworld为模板,在堆上创建新变量helloworld,然后将堆上的helloworld的引用给a。
//创建b时,拿到常量池的helloworld的引用即可。
//a指向的是堆,b指向的是常量池,永远不可能相等。
           
String a = "helloworld";
String b = a;
a==b?//结果为true,任何直接传递引用的方式传值,都会导致两个变量指向同一个对象。