Java中“==”和equal()的区别

来源:互联网 发布:java运行无法加载主类 编辑:程序博客网 时间:2024/06/07 02:08

java中的数据类型可以分为两类,

1、基本数据类型:byte、short、int、char、long、float、double、boolean。

他们之间的比较使用“==”,比较的是它们的值。

2、复合数据类型(类):

当他们用“==”进行比较时,比较的是他们在内存中的存放地址,所以,只有同一个new 出来的对象,他们的比较结果是true,其他为false,java当中所有的类都继承于Object这个基类,在Object这个基类中定义了一个equal方法,这个方法的初始行为是比较两个对象的内存地址,但在一些类库中这个方法被覆盖掉了,如String、Interger、Date,在这几个类中equal有其自身的实现,而不再是比较内存中的存放地址。

在复合数据类型之间进行equal比较,在没有重写equal的情况下,他们之间的比较还是基于内存中存放地址的比较,所以比较后的结果与“==”相同,

public class TestString { public static void main(String[] args) {String s1 = "Monday";String s2 = "Monday";if (s1 == s2){System.out.println("s1 == s2");}else{System.out.println("s1 != s2");}}}
以上结果:s1 == s2 ,s1与s2引用同一个“Monday”对象

public class TestString {public static void main(String[] args) {String s1 = "Monday";String s2 = new String("Monday");if (s1 == s2){System.out.println("s1 == s2");}else{System.out.println("s1 != s2");}if (s1.equals(s2)) {System.out.println("s1 equals s2");}else{System.out.println("s1 not equals s2");}}}
以上结果:s1 != s2     s1 equals s2,  s1与s2引用两个不同的“Monday”String对象。

以上两种情况的出现是由于字符串缓冲池的存在,程序在运行的时候会创建一个字符串缓冲池,当使用s2 = “Monday”这样的语句创建对象时,程序会首先在字符串缓冲池中寻找相同值的对象。第一个程序中,s1先被放到了这个缓冲池中,当创建s2的时候,程序在缓冲池中找到了具有相同值的s1,于是就直接将s2引用至s1所引用的对象“Monday”。


public class TestString {public static void main(String[] args) {String s1 = "Monday";String s2 = new String("Monday");s2 = s2.intern();if (s1 == s2){System.out.println("s1 == s2");}else{System.out.println("s1 != s2");}if (s1.equals(s2)) {System.out.println("s1 equals s2");}else{System.out.println("s1 not equals s2");}}}
这次输出 s1 == s2      s1 equals s2

原 来,(java.lang.String的intern()方法"abc".intern()方法的返回值还是字符串"abc",表面上看起来好像这个方 法没什么用处。但实际上,它做了个小动作:检查字符串池里是否存在"abc"这么一个字符串,如果存在,就返回池里的字符串;如果不存在,该方法会 把"abc"添加到字符串池中,然后再返回它的引用。

java的内存分配策略

java程序运行时的内存分配策略可以分为三种:静态、栈式、堆式。

静态存储分配是指在编译时就能确定数据在运行时刻的存储空间需求,因此在编译时就可以分配确切的、固定的内存空间,这种分配策略要求程序中不能有可变的数据结构(如可变数组)的存在,也不允许嵌套或者递归的结构存在,它们都会导致编译程序时无法计算准确的存储空间需求。

栈式存储分配亦可以称为动态存储分配,是由一个类似堆栈的运行栈来实现的,和静态存储分配相反,在编译的时候,程序对数据区的存储空间需求是未知的,只有在运行的时候才能确定,但是规定在运行中进入一个程序模块时,必须知道该程序模块所需要的数据区大小才能够为其分配内存,和我们在数据结构所知道的栈一样,栈式存储分配按照先进后出的原则进行分配。

静态存储分配要求在编译时就知道变量、数据的存储空间需求,栈式存储分配要求在运行时程序入口处知道所有的存储需求,而堆式存储分配则专门负责在编译时与在运行时模块入口处都无法确定存储要求的数据结构的内存分配,比如可变长度串和对象实例,堆由大片的可利用块和空闲块组成,堆中的内存可以按照任意顺序分配和释放。

堆和栈的比较

从堆和栈的功能及作用来通俗的比较这两者可以发现,堆主要是用来存放对象的,栈主要是用来执行程序的。

所有的方法调用都是通过栈来进行的,所有的局部变量,形式参数都是从栈中分配内存空间的。实际上也不是什么分配,只是从栈顶向上用就行,就好像工厂中的传送带(conveyor belt)一样,Stack Pointer会自动指引你到放东西的位置,你所要做的只是把东西放下来就行.退出函数的时候,修改栈指针就可以把栈中的内容销毁.这样的模式速度最快, 当然要用来运行程序了.需要注意的是,在分配的时候,比如为一个即将要调用的程序模块分配数据区时,应事先知道这个数据区的大小,也就说是虽然分配是在程序运行时进行的,但是分配的大小多少是确定的,不变的,而这个"大小多少"是在编译时确定的,不是在运行时。

堆是应用程序在运行的时候请求操作系统分配给自己内存,由于从操作系统管理的内存分配,所以在分配和销毁时都要占用时间,因此用堆的效率非常低.但是堆的优点在于,编译器不必知道要从堆里分配多少存储空间,也不必知道存储的数据要在堆里停留多长的时间,因此,用堆保存数据时会得到更大的灵活性。事实上,面向对象的多态性,堆内存分配是必不可少的,因为多态变量所需的存储空间只有在运行时创建了对象之后才能确定.在C++中,要求创建一个对象时,只需用 new命令编制相关的代码即可。执行这些代码时,会在堆里自动进行数据的保存.当然,为达到这种灵活性,必然会付出一定的代价:在堆里分配存储空间时会花掉更长的时间!这也正是导致我们刚才所说的效率低的原因。

JVM中的堆和栈

JVM是基于堆栈的虚拟机,JVM为每个新创建的线程都分配一个堆栈,对于一个java程序来说,它的运行就是通过对堆栈的操作来完成的,堆栈以帧为单位保存线程的状态,JVM对堆栈只进行两个操作,以帧为单位的出栈和压栈操作。

b.我们知道,某个线程正在执行的方法称为此线程的当前方法.我们可能不知道,当前方法使用的帧称为当前帧。当线程激活一个Java方法,JVM就会在线程的Java堆栈里新压入一个帧。这个帧自然成为了当前帧.在此方法执行期间,这个帧将用来保存参数,局部变量,中间计算过程和其他数据.这个帧在这里和编译原理中的活动纪录的概念是差不多的。

从java的这种分配机制来看,堆栈可以这样理解,堆栈是操作系统在建立某个线程或者进程时为线程建立的存储区域,该区域具有先进后出的特点。

每一个Java应用都唯一对应一个JVM实例,每一个实例唯一对应一个堆。应用程序在运行中所创建的所有类实例或数组都放在这个堆中,并由应用所有的线程共享.跟C/C++不同,Java中分配堆内存是自动初始化的。Java中所有对象的存储空间都是在堆中分配的,但是这个对象的引用却是在堆栈中分配,也就是说在建立一个对象时从两个地方都分配内存,在堆中分配的内存实际建立这个对象,而在堆栈中分配的内存只是一个指向这个堆对象的指针(引用)而已。

堆中存放的是创建的对象,JAVA字符串对象内存实现时,在堆中开辟了一快很小的内存,叫字符串常量池,用来存放特定的字符串对象。
e.通俗来讲java堆栈
Java堆:
1.程序运行中动态分配内存大小
2.java的垃圾回收器自动回收不再使用的数据
Java栈:
1.栈数据可以共享
2.存在栈中的数据大小与生存期必须是确定的。
3.栈中主要存放一些基本类型的变量(,int, short, long, byte, float, double, boolean, char)和对象引用。

二、String是一个特殊的包装类数据。可以用:
String str = new String("abc");
使用new创建字符串对象的步骤如下,每调用一次就会创建一个新的对象。
1. 首先在堆(不是常量池)中创建一个包含指定内容的字符串对象,并将字符串引用指向该对象。
2. 去字符串常量池中查看,是否有包含该内容的对象。
3. 若有,则将new出来的字符串对象与字符串常量池中内容相同的对象联系起来。
4. 若没有,则在字符串常量池中再创建一个包含该内容的字符串对象,并将堆中的对象与字符串常量池中新创建出来的对象联系起来。
字符串特殊的内存机制带来的好处,即是:只比较两个字符串联系的常量池中对象是否为同一个即可,不论字符串大小,比较速度一样。
String str = "abc";
1.先在栈中创建一个对String类的对象引用变量str
2.然后查找堆中常量池里有没有存放"abc"
3.如果没有,则将"abc"存放进常量池,并令str指向”abc”
4.如果已经有"abc"则直接令str指向“abc”。

三、特殊情况
127 以下的整数是相等的 
Integer i=100; 
Integer j=100; 
System.out.println(i==j); // 打印 true
128以上就作为不同对象处理了
Integer i=200; 
Integer j=200; 
System.out.println(i==j); //打印false



0 0