Java内存分配及equals和==号的详细讲解

来源:互联网 发布:华为人工智能布局 编辑:程序博客网 时间:2024/05/18 00:17

从图中我们可以很清晰的看出,程序通过加载器从硬盘中加载到内存中,并且保存到不同的位置,通俗的说就是new出来的东西存放在heap(堆区),局部变量存放在stack(栈区),静态变量和字符串常量存放在data segment(数据段)中,逻辑代码存放在code segment(代码段)中

通过下面的代码来解释变量存放的位置:

class A{private int id;public A(){}}public class MyJVM {public static void main(String[] args) {A a = new A();/** * 这句代码的含义: * 1.a本身的内存是在栈区分配的,属于局部变量 * 2.new A() 是指在堆区动态分配一块区域,当做A的对象 * 3. a = new A() 表示堆中的内存赋给了a * 4. 所以a指向了堆中的一块内存,所以可以理解为a代表了堆中的一块内存 * */}}

理解了上面的内存分配下面我们来探讨一下equals()方法:

Object类的equals()方法简介:

1:所有的类都从Object类中继承了equals()方法

2:Object类中的equals()方法源码:

public boolean equals(Object obj) {return this == obj;}
从源码可以看出Object中的equals()方法是直接判断this和obj本身的值是否相等,即用来判断调用equals()的对象和形参obj所引用的对象是否是同一对象,所谓的同一对象就是指内存中同一块存储单元,只有内容相同且内存单元相同才会返回true,否则就返回false。


为什么要重写equals()方法或者说何时应该重写equals()方法!

从Object中equals()的源码可以看出要使两个对象相等必须内容相等且内存地址也相同,但是现实生活中很多时候只要内容相同,我们就认为这两个对象相等,很明显,原生态的equals()方法是无法满足我们需求的,这个时候我们就需要重写equals()方法,使得只要两个对象的内容相同,那么这两个对象就相同。

总而言之:如果希望不同内存但内容相同的两个对象的相等时,我们就需要重写equals()方法。

我们通过一个例子来理解:

class A{private int id;public A(){}public A(int id){this.id = id;}}public class MyJVM {public static void main(String[] args) {A a1 = new A(2);A a2 = new A(2);if (a1.equals(a2)){System.out.println("a1和a2相等");} else {System.out.println("a1和a2不想等");}}}

程序的输出结果是a1和a2不相等。原因是因为虽然他们的内容一样都是2,但是他们在内存中的地址不一样,是两个不同的对象。

修改程序【重写父类equals()方法】:

class A {private int id;public A() {}public A(int id) {this.id = id;}/*重写父类的equals()方法*/public boolean equals(Object obj) {A a = (A) obj;/*只要他们的内容(即id的数值大小)相等就返回true*/if (this.id == a.id) {return true;} else {return false;}}}public class MyJVM {public static void main(String[] args) {A a1 = new A(2);A a2 = new A(2);if (a1.equals(a2)) {System.out.println("a1和a2相等");} else {System.out.println("a1和a2不想等");}}}

此时程序输出:a1和a2相等.因为我们重写了父类的equals()方法,而方法的内容就是只要l两个对象的内容相等就返回true就认为这两个对象相等,不考虑内存地址。


我们再来看一个demo:

public class StringEqualsTest {public static void main(String[] args) {String str1 = new String("china");String str2 = new String("china");System.out.println(str1.equals(str2));}}

很多人都会以为上述程序的输出结果会是false,理由很简单嘛,因为这是两个对象,虽然内容一样,但是在内存中的地址并不一样,你要是这么想,恭喜你,说明你掌握了equals()方法的比较原理。但是很遗憾的告诉你,输出结果是true,即str1和str2相等,原因也很简单:String类内部已经实现了equals()方法,这下应该明白了吧,其实像String类、Integer类、Double类内部都已经实现equals()方法,不需要我们再去实现了。


说完了equals()方法,我们再来看看另一个比较两个对象是否相等的工具:等号"=="

== 比较的是两个对象的内容和在内存中的存放地址是否相等,只有两者都相等时才会返回true,否则返回false。

如下代码:

public class StringEqualsTest {public static void main(String[] args) {String str1 = new String("china");String str2 = new String("china");System.out.println(str1 == str2);}}

根据我们刚才说的"=="的比较原理,输出结果显然是false,也是在我们预料之中的。因为这两个对象在内存中的地址不一样嘛。


我们再来看一个例子:

public class StringEqualsTest {public static void main(String[] args) {String str1 = "china";String str2 = "china";System.out.println(str1 == str2);}}

很多人会以为上述程序的输出结果会是false,因为他们在内存中的地址不一样嘛,但是很遗憾,程序的输出结果是true,str1 == str2;

至于原因嘛,我们还得回到文章开头提到不同内容在内存中的存储位置,根据文章开头那个图我们可以看出,str1和str2是存在栈区的,因为他们属于局部变量嘛,然而字符串"abc"呢?它是存在堆区吗?呵呵...不是啊!!!!字符串"china"存放的位置是data segment【数据区域】,他们是同一份拷贝,所以str1和str2指向的是同一个内容。


上面这幅图很好的体现了,为什么 String str1 = new String("china")和String str2 = new String("china") 的str1不等于str2了,因为new String("china")是动态分配的,所以对象保存在堆区,且保存的地址不一致;

String str1 = "china" 和String str2 = "china" 的str1 等于str2 因为字符串常量"china"是保存在内存中的data segment【数据区】,且是同一份拷贝。


下面说一下使用等号"=="比较对象的情景:

1:基本数据类型:byte,short,char,int,long,float,double,boolean 应用双等号(==)比较他们的值。

2:在反射的的知识中比较两个类的字节码是否相等我们也可以使用双等号(==)


0 0
原创粉丝点击