关于java中的==,equal,new,= 的一些相关知识,有点乱

栈与堆都是Java用来在Ram中存放数据的地方。与C++不同,Java自动管理栈和堆,程序员不能直接地设置栈或堆。

Java 的是一个运行时数据区,类的对象从中分配空间。这些对象通过new、newarray、anewarray和multianewarray等指令建立,它们不需要程序代码来显式的释放。堆是由垃圾回收来负责的堆的优势是可以动态地分配内存大小,生存期也不必事先告诉编译器,因为它是在运行时动态分配内存的,Java的垃圾收集器会自动收走这些不再使用的数据。但缺点是,由于要在运行时动态分配内存,存取速度较慢。

的优势是,存取速度比堆要快,仅次于寄存器(register),栈数据可以共享。但缺点是,存在栈中的数据大小与生存期必须是确定的,缺乏灵活性。栈中主要存放一些基本类型的变量 (,int, short, long, byte, float, double, boolean, char)和对象句柄。

栈有一个很重要的特殊性,就是存在栈中的数据可以共享。假设我们同时定义:

   int a = 3;

int b = 3;

编译器先处理int a = 3;首先它会在栈中创建一个变量为a的引用,然后查找栈中是否有3这个值,如果没找到,就将3存放进来,然后将a指向3。接着处理int b = 3;在创建完b的引用变量后,因为在栈中已经有3这个值,便将b直接指向3。这样,就出现了a与b同时均指向3的情况。

这时,如果再令a=4;那么编译器会重新搜索栈中是否有4值,如果没有,则将4存放进来,并令a指向4;如果已经有了,则直接将a指向这个地址。因此a值的改变不会影响到b的值。

要注意这种数据的共享与两个对象的引用同时指向一个对象的这种共享是不同的,因为这种情况a的修改并不会影响到b, 它是由编译器完成的,它有利于节省空间。而一个对象引用变量修改了这个对象的内部状态,会影响到另一个对象引用变量。

String是一个特殊的包装类数据。可以用:

String str = new String("abc");

String str = "abc";

两种的形式来创建,第一种是用new()来新建对象的,它会在存放于堆中。每调用一次就会创建一个新的对象。 而第二种是先在栈中创建一个对String类的对象引用变量str,然后查找栈中有没有存放"abc",如果没有,则将"abc"存放进栈,并令str指向”abc”,如果已经有”abc” 则直接令str指向“abc”。

比较类里面的数值是否相等时,用equals()方法;当测试两个包装类的引用是否指向同一个对象时,用==,下面用例子说明上面的理论。

String str1 = "abc";

String str2 = "abc";

System.out.println(str1==str2); //true

可以看出str1和str2是指向同一个对象的。

String str1 =new String ("abc");

String str2 =new String ("abc");

System.out.println(str1==str2); // false

new的方式是生成不同的对象。每一次生成一个的对象。

因此用第一种方式创建多个”abc”字符串,在内存中其实只存在一个对象而已. 这种写法有利与节省内存空间. 同时它可以在一定程度上提高程序的运行速度,因为JVM会自动根据栈中数据的实际情况来决定是否有必要创建新对象。而对于String str = new String("abc");的代码,则一概在堆中创建新对象,而不管其字符串值是否相等,是否有必要创建新对象,从而加重了程序的负担。

另 一方面, 要注意: 我们在使用诸如String str = "abc";的格式定义类时,总是想当然地认为,创建了String类的对象str。担心陷阱!对象可能并没有被创建!而可能只是指向一个先前已经创建的对象。只有通过new()方法才能保证每次都创建一个新的对象。

由于String类的immutable(不变的)性质,当String变量需要经常变换其值时,应该考虑使用StringBuffer类,以提高程序效率。

  1. equals是一个方法,超类Object方法而言,==和equals一样的,原代码如下:

    public boolean equals(Object obj) { return (this == obj);//证明.内部用的就是==符号 }

    ==是比较两个对象是否恒等,不仅比较对象的数据,也比较对象的内存地址。

    但是每个类可以重写equals方法,可满足自己的需求,就是说可以实现跟==不同的功能! 例如:String类就重写了equals()方法,使之用于比较两个字符串的数据,而非对象的内存地址!

    2.关于abstract class与interface,原理上比较复杂,可以参考下面内容:

    1) 抽象的意义

    在大型工程中,实现的技术比较复杂,模块多,代码量大,涉及编程的相关人员较多,角色和任务也不尽相同,为了合理安排软件工程的开发工作,需要一部分资深程序员先对程序框架做整体设计,然后其他程序员在建立好的框架基础上再做更细致的编程,就好比"建一座大厦要先建好钢筋混凝土框架再垒墙砖"一样,抽象类和方法就是起到"建立框架"的作用。

    类似的,接口是一个更"纯粹"的抽象类,使用接口可以很好的克服Java不支持多继承父类的限制,达到多继承的效果。

    接口和抽象类类似,只是接口更关心功能组成,而不关心功能的实现,这部分工作由继承它们的具体子类完成。

    2) 应用时如何选择抽象类或接口?

    如何选择该使用抽象类还是接口?这是一个比较有深度的问题!我们可以从两个角度考虑此问题:

    其一:从代码的使用上考虑如何选择。

    接口与抽象类的区别如下:

    Ø 接口是一种“纯粹”的抽象类,它所有的方法都是抽象的(即只有声明,没有定义);而抽象类可以允许包含有定义的方法;

    Ø 子类可以实现多个接口,但只能继承一个抽象类;

    Ø 一个子类如果实现了一个接口,那么子类必须重写这个接口里的所有方法;抽象类的子类可以不重写抽象父类的所有方法,甚至可以不重写抽象父类的抽象方法,但这个子类会自然成为抽象类。

    通过上面的对比,我们知道在代码的使用上如何选择使用抽象类还是接口。当然,需要重点提出的是:因为抽象类的子类可以不重写抽象父类的所有方法,所以有时使用抽象类代码更简练(例如后面要讲述的适配器类);而在另外一些情况下(比如要实现多继承效果),就必须要使用接口了。

    其二:从构架程序的设计思想的角度上考虑如何选择。

    抽象类的作用是实现行为,而不是定义行为,构建应用工程时如果需要定义行为,那么最好由接口来完成。比如,要创建一个程序构架,这个构架将由一些紧密相关的类构成,且所有类都会共享一个公共的行为实现,就可以使用抽象类。如果要创建将由一些不是由这些类对象必须采用的功能,就最好使用接口。

equals 方法(是String类从它的超类Object中继承的)被用来检测两个对象是否相等,即两个对象的内容是否相等。

java语言的本意来说:如果没有重写(override

新类的equals(),则该方法和==操作符一样在两个变量指向同一对象时返回真,(即比较的是引用而不是内容)

但是java推荐的是使用equals()方法来判断两个对象的内容是否一样.比如StringDateFile类就已经通过覆盖equals()方法来比较对象内容而不是引用

==用于比较引用和比较基本数据类型时具有不同的功能:

比较基本数据类型,如果两个值相同,则结果为true

而在比较引用时,如果引用指向内存中的同一对象,结果为true

JAVA的对象存储机制里,new出来的一定是对象,而对象在内存中的存贮位置在Heap(堆)中,而基本类型在程序中出现的比较频繁(注:JAVA中的基本类型为8中,分别是:boolean,char,byte,short,int,long,float,double),所以通过new产生这些对象而将其放入在heap中效率反而不高,所以JAVA直接采取C/C++的方式,也就是不以new来分配其空间,而是产生一种所谓的“automatic”变量(不在是reference的形式),来解决效率的问题,此类变量直接放数据值,并且置于stack(栈)中,因为stack在空间的分配和释放上,效率要好的多。而恰恰是这种在内存中位置的不同,在stack中为基本类型变量分配空间时,如果stack中有一样的数据时,将不在创建新的数据,所以导致这个时候比较的两个基本类型值时,即使用==也是true。

例1:

  1. public class Test {   
      
        public static void main(String[] args) {   
      
            float f=4.2F;   
             Float g=new Float(4.2F);   
             Double d=new Double(4.2);   
      
             System.out.println(f==g); //----输出true   
             System.out.println(d==f);//-------输出false   
             System.out.println(d.equals(f));//-------输出false   
             System.out.println(d.equals(g));//-------输出false   
             System.out.println(g.equals(4.2));//-------输出false   
      
             System.out.println(4.2==d); //----输出true   
             System.out.println(4.2f==g);//----输出true   
             System.out.println(4.2f==d); //-------输出false   
               
               
             String s="aaa";   
             String d1="aaa";   
             System.out.println(s==d1);   //----输出true   
      
      
             String s1=new String("aaa");   
             String d11="aaa";   
             System.out.println(s1==d11);   //-------输出false   
      
      
             s1 = new String("sony");  //创建的是字符串对象   
             s1.equals("sony"); //返回true   
             System.out.println(s1 == "sony");  //返回false   
            //如果   
             s1 = "sony";   
             System.out.println(s1 == "sony"); //返回true   
      
         }   
      
    }  
     
    

      

例 2

public class MyClass {   
  
    /**
      * @param args
      */  
    static String s1 = "I am unique!";   
  
    public static void main(String[] args) {   
        // TODO Auto-generated method stub   
  
         String s2 = "I am unique!";   
         String s3 = new String(s1);               
         System.out.println(s1 == s2);           //----输出true        
         System.out.println(s1.equals(s2));      //----输出true       
         System.out.println(s3 == s1);             //-------输出false   
         System.out.println(s3.equals(s1));           //----输出true   
        
  
     }   
  
}