精华内容
下载资源
问答
  • 对象的引用对象本身的区别: java中没有指针的概念,取而代之的是引用(这个和c++中的引用不是一个意思),这个引用是一个变量而已,存放在栈里面(你可以理解栈和堆是计算机存储器中的不同位置,但是都是用类...

    对象的引用和对象本身的区别:

    • java中没有指针的概念,取而代之的是引用(这个和c++中的引用不是一个意思),这个引用是一个变量而已,存放在栈里面(你可以理解栈和堆是计算机存储器中的不同位置,但是都是用类存储数据的),变量内容是它所指向的那个对象(存放在堆里)的起始地址
    • 举个例:Boy b = new Boy();
    • Boy是一个class,类只是一个对象构造方式的描述,需要new Boy()后,此时就根据这个类描述的构造规则实实在在构造出来了一个对象(对象是一个实体,会在存储器中实实在在占用一块内存(就像一个数组一样),里面包括了所定义的变量,函数等等),那么这一块内存有一个有个起始地址对吧,这个起始地址就赋值给了b这个变量,很明显b的内容就是一个地址而已,假如你的计算机是64位的,那么我们可以认为这个b变量就是64位的int型变量而已,给这个变量b取个名字,就叫做对象的引用
    • 上面的解释可能有些地方不是很严谨,但是原理完全是正确的,对于理解这个内容足够了

    java中函数的形参会不会改变实参的内容:

    • 这里我举个例
    • void func(int a)
    • {  a=3;  }
    • int c=1;
    • func(c);     // 执行完后,此时c变量的值还是1,为什么呢,因为函数都是用值传递的方式
    • 记住c是基本类型数据(int,char,long,float等),所以呀,我们分析一波,发现这跟c语言一样嘛,肯定是交换不了的
    • 那怎么才能改变基本数据类型的实参的值呢,通过数组方式:

    • int c = 1;

    • int[] arr={c};

    • void func(int[] arr)

    • { arr[0] = 3;}

    • func(arr);  // 执行完后,c=3,因为是按照数组方式,实际上是传进来了数组的地址,那么函数里面相当于是对这个地址所指向的空间进行赋值,这不就是指针的原理吗,所以就能实现改变实参的值

     

    • void func(Boy a)
    • {  a.age = 3;  }
    • Boy c=new Boy(5);
    • func(c); 
    •    // 执行完后,引用c所指向的对象的内容已经变了,因为函数里面是对传进来的那个地址的内容做了改变,所以当然会影响形参所指向那个对象了,这里其实就跟c语言传进来了变量的地址(指针)是一个意思
    展开全文
  • 对象引用对象存放的地址和区别

    千次阅读 2020-04-17 00:15:08
    在java的学习当中,很多时候并没有能很好分清把对象对象引用。如果没能很好认识分清这两者的关系,就可能会很难理解一些指针的移动的代码。 JAVA中基本类型变量存储在栈中,引用类型的对象存储在栈中,对象的...

    在java的学习当中,很多时候并没有能很好分清把对象和对象的引用。如果没能很好认识分清这两者的关系,就可能会很难理解一些指针的移动的代码。

    JAVA中基本类型变量存储在栈中,引用类型的对象存储在栈中,对象的引用地址存储在堆中。

    我们先定义一个简单的类:

    public class DemoClass {
        private String name;
    }
    

    有了这个模板,就可以用它来创建对象:
    DemoClass demo= new DemoClass ();
    通常把这条语句的动作称之为创建一个对象,其实,它包含了四个动作。
    1)右边的“ new DemoClass”,是以DemoClass类为模板,在堆空间里创建一个DemoClass类对象(也简称为DemoClass对象)。
    2)末尾的()意味着,在对象创建后,立即调用DemoClass类的构造函数,对刚生成的对象进行初始化。
    3)左边的“DemoClass”创建了一个DemoClass类引用变量。所谓DemoClass类引用,就是以后可以用来指向DemoClass对象的对象引用。
    4)“=”操作符使对象引用指向刚创建的那个DemoClass对象。
    我们可以把这条语句拆成两部分:
    DemoClass demo; --对象引用变量
    demo= new DemoClass (); --对象本身
    效果是一样的。这样写,就比较清楚了,有两个实体:一是对象引用变量,一是对象本身。

    通过上面知识我们来看两个相对复杂一点demo,这个例子中通过tempHead 改变对实体对象指向的改变,使其tempHead 一直指向链表的末尾。head 指向链表头部

    public class TempClass {
    
        @Test
       public void replaceSingleNode(){
            //定义一个请求头对象
           SingleLinkedNode head = new SingleLinkedNode(0);
           //定义tempHead的引用名 将指向  new SingleLinkedNode(0) 这个对象本身
           SingleLinkedNode tempHead=head;
           for (int i = 1; i <=5 ; i++) {
               //tempHead.next 引用名  将指向 new SingleLinkedNode(i)本身
               tempHead.next = new SingleLinkedNode(i);
               //tempHead引用名  指向  tempHead 的下个对象本身
               tempHead = tempHead.next;
           }
           //这个时候head 这个引用名 实际指向  new SingleLinkedNode(0);
           System.out.println("请求头:"+head);
           //这个时候 tempHead 这个应用名实际指向  new SingleLinkedNode(i); 当i=5的时候
           System.out.println("运输对象:"+tempHead);
       }
    
    
        @Data
        class SingleLinkedNode{
            private int value;
            private SingleLinkedNode next;
    
            public SingleLinkedNode(int value) {
                this.value = value;
            }
    
        }
    
    
    
    
    
    }
    
    

    打印内容

    请求头:TempClass.SingleLinkedNode(value=0, next=TempClass.SingleLinkedNode(value=1, next=TempClass.SingleLinkedNode(value=2, next=TempClass.SingleLinkedNode(value=3, next=TempClass.SingleLinkedNode(value=4, next=TempClass.SingleLinkedNode(value=5, next=null))))))
    运输对象:TempClass.SingleLinkedNode(value=5, next=null)
    

    我们的出 tempHead = tempHead.next; 只是改变tempHead 这个引用对象,而不是直接对对象进行替换,我这里再用一个双链表来作证这一结论。在双链表中如果是不是覆盖,那最后tempHead就应该保留整条链表数据,只是tempHead指向链表末尾的字段。

    public class TempClass {
    
        
        @Test
        public void replaceDoubleNode(){
            //定义一个请求头对象
            DoubleLinkedNode head = new DoubleLinkedNode(0);
            //定义tempHead的引用名 将指向  new SingleLinkedNode(0) 这个对象本身
            DoubleLinkedNode tempHead=head;
            for (int i = 1; i <=5 ; i++) {
                //newNode 引用名  将指向 new SingleLinkedNode(i)实体本身
                DoubleLinkedNode newNode = new DoubleLinkedNode(i);
                //tempHead.tail 这个引用 指向new DoubleLinkedNode(i);实体
                tempHead.tail =newNode;
                //newNode 这个引用 指向tempHead 的实体
                newNode.front = tempHead;
                //将tempHead 指向  tempHead.tail 实体 ,也就是 new DoubleLinkedNode(i) 实体本身
                tempHead = tempHead.tail;
            }
            System.out.println("请求头:"+head);
            System.out.println("运输对象:"+tempHead);
        }
    
    
    
    
    
    
    
        class DoubleLinkedNode{
            private int value;
            private DoubleLinkedNode front;
            private DoubleLinkedNode tail;
    
            public DoubleLinkedNode(int value) {
                this.value = value;
            }
        }
    }
    
    

    在这里插入图片描述

    希望通过这里讲解说明,能够很好的认识引用和对象本身的区别

    展开全文
  • 浅谈一下JAVA对象对象引用以及对象赋值

    万次阅读 多人点赞 2013-09-19 00:50:29
    浅谈一下JAVA对象对象引用以及对象赋值   今天有班级同学问起JAVA对象引用是什么。正好趁着这次机会,自己总结一下JAVA对象对象引用以及对象赋值。自己总结了所看到的网上相关方面的不少帖子,整理汇总形成...
     
    

       浅谈一下JAVA对象,对象引用以及对象赋值

             今天有班级同学问起JAVA对象的引用是什么。正好趁着这次机会,自己总结一下JAVA对象,对象引用以及对象赋值。自己总结了所看到的网上相关方面的不少帖子,整理汇总形成下面的文章。

     

    Java对象及其引用

        初学Java,总是会自觉或不自觉地把Java和C++相比较。在学习Java类与对象章节的时候,发现教科书和许多参考书把对象和对象的引用混为一谈。可是,如果分不清对象与对象引用, 那实在没法很好地理解下面的面向对象技术。把自己的一点认识写下来,或许能让初学Java的朋友们少走一点弯路。

        为便于说明,我们先定义一个简单的类:

        class Vehicle {

            int passengers;      

            int fuelcap;

            int mpg;

         }

        有了这个模板,就可以用它来创建对象:

           Vehicle veh1 = new Vehicle();

        通常把这条语句的动作称之为创建一个对象,其实,它包含了四个动作。

        1)右边的“new Vehicle”,是以Vehicle类为模板,在堆空间里创建一个Vehicle类对象(也简称为Vehicle对象)。

        2)末尾的()意味着,在对象创建后,立即调用Vehicle类的构造函数,对刚生成的对象进行初始化。构造函数是肯定有的。如果你没写,Java会给你补上一个默认的构造函数。

        3)左边的“Vehicle veh 1”创建了一个Vehicle类引用变量。所谓Vehicle类引用,就是以后可以用来指向Vehicle对象的对象引用。

        4)“=”操作符使对象引用指向刚创建的那个Vehicle对象。

        我们可以把这条语句拆成两部分:

        Vehicle veh1;

        veh1 = new Vehicle();

    效果是一样的。这样写,就比较清楚了,有两个实体:一是对象引用变量,一是对象本身。

        在堆空间里创建的实体,与在数据段以及栈空间里创建的实体不同。尽管它们也是确确实实存在的实体,但是,我们看不见,也摸不着。不仅如此,我们仔细研究一下第二句,找找刚创建的对象叫什么名字?有人说,它叫“Vehicle”。不对,“Vehicle”是类(对象的创建模板)的名字。

        一个Vehicle类可以据此创建出无数个对象,这些对象不可能全叫“Vehicle”。

        对象连名都没有,没法直接访问它。我们只能通过对象引用来间接访问对象。

        为了形象地说明对象、引用及它们之间的关系,可以做一个或许不很妥当的比喻。对象好比是一只很大的气球,大到我们抓不住它。引用变量是一根绳, 可以用来系汽球。

        如果只执行了第一条语句,还没执行第二条,此时创建的引用变量veh1还没指向任何一个对象,它的值是null。引用变量可以指向某个对象,或者为null。

        它是一根绳,一根还没有系上任何一个汽球的绳。执行了第二句后,一只新汽球做出来了,并被系在veh1这根绳上。我们抓住这根绳,就等于抓住了那只汽球。

        再来一句:

        Vehicle veh2;

    就又做了一根绳,还没系上汽球。如果再加一句:

           veh2 = veh1;

    系上了。这里,发生了复制行为。但是,要说明的是,对象本身并没有被复制,被复制的只是对象引用。结果是,veh2也指向了veh1所指向的对象。两根绳系的是同一只汽球。

        如果用下句再创建一个对象:

    veh2 = new Vehicle();

    则引用变量veh2改指向第二个对象。

        从以上叙述再推演下去,我们可以获得以下结论:

        (1)一个对象引用可以指向0个或1个对象(一根绳子可以不系汽球,也可以系一个汽球);

        (2)一个对象可以有N个引用指向它(可以有N条绳子系住一个汽球)。

        如果再来下面语句:

           veh1 = veh2;

        按上面的推断,veh1也指向了第二个对象。这个没问题。问题是第一个对象呢?没有一条绳子系住它,它飞了。多数书里说,它被Java的垃圾回收机制回收了。这不确切。正确地说,它已成为垃圾回收机制的处理对象。至于什么时候真正被回收,那要看垃圾回收机制的心情了。

        由此看来,下面的语句应该不合法吧?至少是没用的吧?

        new Vehicle();

    不对。它是合法的,而且可用的。譬如,如果我们仅仅为了打印而生成一个对象,就不需要用引用变量来系住它。最常见的就是打印字符串:

        System.out.println(“I am Java!”);

    字符串对象“I am Java!”在打印后即被丢弃。有人把这种对象称之为临时对象。对象与引用的关系将持续到对象回收。

      

    另一个角度分析Java对象和引用以及与其密切相关的参数传递

        先看下面的程序:

        StringBuffer s;

        s = new StringBuffer("Hello World!");

        第一个语句仅为引用(reference)分配了空间,而第二个语句则通过调用类(StringBuffer)的构造函数StringBuffer(String str)为类生成了一个实例(或称为对象)。这两个操作被完成后,对象的内容则可通过s进行访问——在Java里都是通过引用来操纵对象的。

        Java对象和引用的关系可以说是互相关联,却又彼此独立。彼此独立主要表现在:引用是可以改变的,它可以指向别的对象,譬如上面的s,你可以给它另外的对象,如:

    s = new StringBuffer("Java");这样一来,s就和它指向的第一个对象脱离关系。

        从存储空间上来说,对象和引用也是独立的,它们存储在不同的地方,对象一般存储在堆中,而引用存储在速度更快的堆栈中。

        引用可以指向不同的对象,对象也可以被多个引用操纵,如:

        StringBuffer s1 = s;

    这条语句使得s1和s指向同一个对象。既然两个引用指向同一个对象,那么不管使用哪个引用操纵对象,对象的内容都发生改变,并且只有一份,通过s1和s得到的内容自然也一样,(String除外,因为String始终不变,String s1=”AAAA”; String s=s1,操作s,s1由于始终不变,所以为s另外开辟了空间来存储s,)如下面的程序:

        StringBuffer s;

        s = new StringBuffer("Java");

        StringBuffer s1 = s;

        s1.append(" World");

        System.out.println("s1=" + s1.toString());//打印结果为:s1=Java World

        System.out.println("s=" + s.toString());//打印结果为:s=Java World

        上面的程序表明,s1和s打印出来的内容是一样的,这样的结果看起来让人非常疑惑,但是仔细想想,s1和s只是两个引用,它们只是操纵杆而已,它们指向同一个对象,操纵的也是同一个对象,通过它们得到的是同一个对象的内容。这就像汽车的刹车和油门,它们操纵的都是车速,假如汽车开始的速度是80,然后你踩了一次油门,汽车加速了,假如车速升到了120,然后你踩一下刹车,此时车速是从120开始下降的,假如下降到60,再踩一次油门,车速则从60开始上升,而不是从第一次踩油门后的120开始。也就是说车速同时受油门和刹车影响,它们的影响是累积起来的,而不是各自独立(除非刹车和油门不在一辆车上)。所以,在上面的程序中,不管使用s1还是s操纵对象,它们对对象的影响也是累积起来的(更多的引用同理)。

     

        只有理解了对象和引用的关系,才能理解参数传递。

        一般面试题中都会考Java传参的问题,并且它的标准答案是Java只有一种参数传递方式:那就是按值传递,即Java中传递任何东西都是传值。如果传入方法的是基本类型的东西,你就得到此基本类型的一份拷贝。如果是传递引用,就得到引用的拷贝。

        一般来说,对于基本类型的传递,我们很容易理解,而对于对象,总让人感觉是按引用传递,看下面的程序:

        public class ObjectRef {

        //基本类型的参数传递

            public static void testBasicType(int m) {

                 System.out.println("m=" + m);//m=50

                 m = 100;

                 System.out.println("m=" + m);//m=100

            }

        //参数为对象,不改变引用的值

            public static void add(StringBuffer s) {

                s.append("_add");

            }

        //参数为对象,改变引用的值

           public static void changeRef(StringBuffer s) {

               s = new StringBuffer("Java");

           }

        public static void main(String[] args) {

            int i = 50;

            testBasicType(i);

            System.out.println(i);//i=50

            StringBuffer sMain = new StringBuffer("init");

            System.out.println("sMain=" + sMain.toString());//sMain=init

            add(sMain);

            System.out.println("sMain=" + sMain.toString());//sMain=init_add

            changeRef(sMain);

            System.out.println("sMain=" + sMain.toString());//sMain=init_add

        }

    }

    以上程序的允许结果显示出,testBasicType方法的参数是基本类型,尽管参数m的值发生改变,但并不影响i。

        add方法的参数是一个对象,当把sMain传给参数s时,s得到的是sMain的拷贝,所以s和sMain指向同一个对象,因此,使用s操作影响的其实就是sMain指向的对象,故调用add方法后,sMain指向的对象的内容发生了改变。

        在changeRef方法中,参数也是对象,当把sMain传给参数s时,s得到的是sMain的拷贝,但与add方法不同的是,在方法体内改变了s指向的对象(也就是s指向了别的对象,牵着气球的绳子换气球了),给s重新赋值后,s与sMain已经毫无关联,它和sMain指向了不同的对象,所以不管对s做什么操作,都不会影响sMain指向的对象,故调用changeRef方法前后sMain指向的对象内容并未发生改变。

        对于add方法的调用结果,可能很多人会有这种感觉:这不明明是按引用传递吗?对于这种问题,还是套用Bruce Eckel的话:这依赖于你如何看待引用,最终你会明白,这个争论并没那么重要。真正重要的是,你要理解,传引用使得(调用者的)对象的修改变得不可预期。

     public   class   Test

      public int   i,j;  
        public   void   test_m(Test   a){    

              Test   b   =  new   Test();
              b.i   =   1;
              b.j   =   2;
              a   =   b;
        }
        public   void   test_m1(Test a){   

            a.i   =   1;
            a.j   =   2;
        }
        public   static   void   main(String   argv[]){ 

              Test  t =  new   Test();
              t.i   =   5;
              t.j   =   6;
              System.out.println( "t.i   =   "+   t.i   +   "   t.j=   "   +   t.j); //5,6
              t.test_m(t);
              System.out.println( "t.i   =   "+   t.i   +   "   t.j=   "   +   t.j); //5,6,a和t都指向了一个对象,而在test_m中s又指向了另一个对象,所以对象t不变!!!

              t.test_m1(t);

              System.out.println( "t.i   =   "+   t.i   +   "   t.j=   "   +   t.j); //1,2

        }

    }

    答案只有一个:Java里都是按值传递参数。而实际上,我们要明白,当参数是对象时,传引用会发生什么状况(就像上面的add方法)。

    =========================================================================

        楼主,这样来记这个问题
        如下表达式:
    A a1 = new A();
    它代表A是类,a1是引用,a1不是对象,new A()才是对象,a1引用指向new A()这个对象。

        在JAVA里,“=”不能被看成是一个赋值语句,它不是在把一个对象赋给另外一个对象,它的执行过程实质上是将右边对象的地址传给了左边的引用,使得左边的引用指向了右边的对象。JAVA表面上看起来没有指针,但它的引用其实质就是一个指针,引用里面存放的并不是对象,而是该对象的地址,使得该引用指向了对象。在JAVA里,“=”语句不应该被翻译成赋值语句,因为它所执行的确实不是一个赋值的过程,而是一个传地址的过程,被译成赋值语句会造成很多误解,译得不准确。 

        再如:
    A a2;
    它代表A是类,a2是引用,a2不是对象,a2所指向的对象为空null;

        再如:
    a2 = a1;
    它代表,a2是引用,a1也是引用,a1所指向的对象的地址传给了a2(传址),使得a2和a1指向了同一对象。

        综上所述,可以简单的记为,在初始化时,“=”语句左边的是引用,右边new出来的是对象。
    在后面的左右都是引用的“=”语句时,左右的引用同时指向了右边引用所指向的对象。

        再所谓实例,其实就是对象的同义词。

     

        如果需要赋值,就需要类实现Cloneable接口,实现clone()方法。

     
    class D implements Cloneable{//实现Cloneable接口
     String sex;
     D(String sex){
      this.sex=sex;
     }
     @Override
     protected Object clone() throws CloneNotSupportedException {
      // 实现clone方法
      return super.clone();
     }
    }

      赋值的时候:

     
    D d=new D("男");
    D d2=(D) d.clone();//把d赋值给d2

        如果类中的变量不是主类型,而是对象,也需要调用该对象的clone()方法
    下面是一个完整的例子:

     

    public class Test2 {  public static void main(String[] args) throws CloneNotSupportedException {   // TODO Auto-generated method stub   D d=new D("男");   C c=new C("张三","20",d);   C new_c=(C) c.clone();//调用clone方法来赋值   new_c.name="李四";   d.sex="女";//d   System.out.println(c.d.sex);   System.out.println(c.name);    }   }   class C implements Cloneable{  String name;  String age;  D d;  C(String name,String age,D d) throws CloneNotSupportedException{   this.name=name;   this.age=age;   this.d=(D) d.clone();//调用clone方法来赋值,这样即便外部的d发生变化,c里的也不会变  }  @Override  protected Object clone() throws CloneNotSupportedException {   // TODO Auto-generated method stub   return super.clone();  } } class D implements Cloneable{//实现Cloneable接口  String sex;  D(String sex){   this.sex=sex;  }  @Override  protected Object clone() throws CloneNotSupportedException {   // 实现clone方法   return super.clone();  } }

     

     

     

    Java强引用、 软引用、 弱引用、虚引用

          既然讨论到了java的引用问题,自然就会想到java的引用分为几种情况,下面详细说一下Java的四种引用。

     1、对象的强、软、弱和虚引用
        在JDK 1.2以前的版本中,若一个对象不被任何变量引用,那么程序就无法再使用这个对象。也就是说,只有对象处于可触及(reachable)状态,程序才能使用它。从JDK 1.2版本开始,把对象的引用分为4种级别,从而使程序能更加灵活地控制对象的生命周期。这4种级别由高到低依次为:强引用、软引用、弱引用和虚引用。

                  图1

    图1为对象应用类层次
        1)强引用(StrongReference)
        强引用是使用最普遍的引用。如果一个对象具有强引用,那垃圾回收器绝不会回收它。当内存空间不足,Java
    虚拟机宁愿抛出OutOfMemoryError错误,使程序异常终止,也不会靠随意回收具有强引用的对象来解决内存不足的问题。
        2)软引用(SoftReference)
        如果一个对象只具有软引用,则内存空间足够,垃圾回收器就不会回收它;如果内存空间不足了,就会回收这些对象的内存。只要垃圾回收器没有回收它,该对象就可以被程序使用。软引用可用来实现内存敏感的高速缓存(下文给出示例)。
        软引用可以和一个引用队列(ReferenceQueue)联合使用,如果软引用所引用的对象被垃圾回收器回收,Java虚拟机就会把这个软引用加入到与之关联的引用队列中。

    3) 弱引用(WeakReference)
        弱引用与软引用的区别在于:弱引用的对象拥有更短暂的生命周期。在垃圾回收器线程扫描它所管辖的内存区域的过程中,一旦发现了只具有弱引用的对象,不管当前内存空间足够与否,都会回收它的内存。不过,由于垃圾回收器是一个优先级很低的线程,因此不一定会很快发现那些只具有弱引用的对象。
        弱引用可以和一个引用队列(ReferenceQueue)联合使用,如果弱引用所引用的对象被垃圾回收,Java虚拟机就会把这个弱引用加入到与之关联的引用队列中。

     4)虚引用(PhantomReference)
        “虚引用”顾名思义,就是形同虚设,与其他几种引用都不同,虚引用并不会决定对象的生命周期。如果一个对象仅持有虚引用,那么它就和没有任何引用一样,在任何时候都可能被垃圾回收器回收。虚引用主要用来跟踪对象被垃圾回收器回收的活动。虚引用与软引用和弱引用的一个区别在于:虚引用必须和引用队列(ReferenceQueue)联合使用。当垃圾回收器准备回收一个对象时,如果发现它还有虚引用,就会在回收对象的内存之前,把这个虚引用加入到与之 关联的引用队列中。
     
        程序可以通过判断引用队列中是否已经加入了虚引用,来了解被引用的对象是否将要被垃圾回收。如果程序发现某个虚引用已经被加入到引用队列,那么就可以在所引用的对象的内存被回收之前采取必要的行动。
    2、对象可及性的判断
        在很多时候,一个对象并不是从根集直接引用的,而是一个对象被其他对象引用,甚至同时被几个对象所引用,从而构成一个以根集为顶的树形结构。如图2所示

        在这个树形的引用链中,箭头的方向代表了引用的方向,所指向的对象是被引用对象。由图可以看出,从根集到一个对象可以由很多条路径。比如到达对象5的路径就有①-⑤,③-⑦两条路径。由此带来了一个问题,那就是某个对象的可达性如何判断:
        单条引用路径可达性判断:在这条路径中,最弱的一个引用决定对象的可达性。
        多条引用路径可达性判断:几条路径中,最强的一条的引用决定对象的可达性。
        比如,我们假设图2中引用①和③为强引用,⑤为软引用,⑦为弱引用,对于对象5按照这两个判断原则,路径①-⑤取最弱的引用⑤,因此该路径对对象5的引用为软引用。同样,③-⑦为弱引用。在这两条路径之间取最强的引用,于是对象5是一个软可达对象。


    3、使用软引用构建敏感数据的缓存


    3.1 为什么需要使用软引用

        首先,我们看一个雇员信息查询系统的实例。我们将使用一个Java语言实现的雇员信息查询系统查询存储在磁盘文件或者
    数据库中的雇员人事档案信息。作为一个用户,我们完全有可能需要回头去查看几分钟甚至几秒钟前查看过的雇员档案信息(同样,我们在浏览WEB页面的时候也经常会使用“后退”按钮)。这时我们通常会有两种程序实现方式:一种是把过去查看过的雇员信息保存在内存中,每一个存储了雇员档案信息的Java对象的生命周期贯穿整个应用程序始终;另一种是当用户开始查看其他雇员的档案信息的时候,把存储了当前所查看的雇员档案信息的Java对象结束引用,使得垃圾收集线程可以回收其所占用的内存空间,当用户再次需要浏览该雇员的档案信息的时候,重新构建该雇员的信息。很显然,第一种实现方法将造成大量的内存浪费,而第二种实现的缺陷在于即使垃圾收集线程还没有进行垃圾收集,包含雇员档案信息的对象仍然完好地保存在内存中,应用程序也要重新构建一个对象。我们知道,访问磁盘文件、访问网络资源、查询数据库等操作都是影响应用程序执行性能的重要因素,如果能重新获取那些尚未被回收的Java对象的引用,必将减少不必要的访问,大大提高程序的运行速度。

     
    3.2 如果使用软引用
        SoftReference的特点是它的一个实例保存对一个Java对象的软引用,该软引用的存在不妨碍垃圾收集线程对该Java对象的回收。也就是说,一旦SoftReference保存了对一个Java对象的软引用后,在垃圾线程对这个Java对象回收前,SoftReference类所提供的get()方法返回Java对象的强引用。另外,一旦垃圾线程回收该Java对象之后,get()方法将返回null。看下面代码:
        MyObject  aRef  =  new   MyObject();
        SoftReference  aSoftRef = new  SoftReference( aRef );
        此时,对于这个MyObject对象,有两个引用路径,一个是来自SoftReference对象的软引用,一个来自变量aRef的强引用,所以这个MyObject对象是强可及对象。
    随即,我们可以结束aRef对这个MyObject实例的强引用:
        aRef  =  null ;
        此后,这个MyObject对象成为了软可达对象。如果垃圾收集线程进行内存垃圾收集,并不会因为有一个SoftReference对该对象的引用而始终保留该对象。Java虚拟机的垃圾收集线程对软可达对象和其他一般Java对象进行了区别对待:软可及对象的清理是由垃圾收集线程根据其特定算法按照内存需求决定的。也就是说,垃圾收集线程会在虚拟机抛出OutOfMemoryError之前回收软可及对象,而且虚拟机会尽可能优先回收长时间闲置不用的软可达对象,对那些刚刚构建的或刚刚使用过的软可达对象会被虚拟机尽可能保留。在回收这些对象之前,我们可以通过:
        MyObject  anotherRef =(MyObject) aSoftRef .get()
        重新获得对该实例的强引用。而回收之后,调用get()方法就只能得到null了。
     
    3.3 使用ReferenceQueue清除失去了软引用对象的SoftReference
        作为一个Java对象,SoftReference对象除了具有保存软引用的特殊性之外,也具有Java对象的一般性。所以,当软可及对象被回收之后,虽然这个SoftReference对象的get()方法返回null,但这个SoftReference对象已经不再具有存在的价值,需要一个适当的清除机制,避免大量SoftReference对象带来的内存泄漏。在java.lang.ref包里还提供了ReferenceQueue。如果在创建SoftReference对象的时候,使用了一个ReferenceQueue对象作为参数提供给SoftReference的构造方法,如:
        ReferenceQueue  queue  =  new   ReferenceQueue();
        SoftReference   ref = new   SoftReference( aMyObject ,  queue );
        那么当这个SoftReference所软引用的aMyOhject被垃圾收集器回收的同时,ref所强引用的SoftReference对象被列入ReferenceQueue。也就是说,ReferenceQueue中保存的对象是Reference对象,而且是已经失去了它所软引用的对象的Reference对象。另外从ReferenceQueue这个名字也可以看出,它是一个队列,当我们调用它的poll()方法的时候,如果这个队列中不是空队列,那么将返回队列前面的那个Reference对象。
        在任何时候,我们都可以调用ReferenceQueue的poll()方法来检查是否有它所关心的非强可达对象被回收。如果队列为空,将返回一个null,否则该方法返回队列中前面的一个Reference对象。利用这个方法,我们可以检查哪个SoftReference所软引用的对象已经被回收。于是我们可以把这些失去所软引用的对象的SoftReference对象清除掉。常用的方式为:
        SoftReference ref =  null ;
        while  ((ref = (SoftReference)q .poll()) !=  null ) {
         // 清除 ref
        }
        理解了ReferenceQueue的工作机制之后,我们就可以开始构造一个Java对象的高速缓存器了。
     
    3.4通过软可及对象重获方法实现Java对象的高速缓存
        利用Java2平台垃圾收集机制的特性以及前述的垃圾对象重获方法,我们通过一个雇员信息查询
    系统的小例子来说明如何构建一种高速缓存器来避免重复构建同一个对象带来的性能损失。我们将一个雇员的档案信息定义为一个Employee类:
    public   class  Employee {
         private  String  id ; // 雇员的标识号码
         private  String  name ; // 雇员姓名
         private  String  department ; // 该雇员所在部门
         private  String  Phone ; // 该雇员联系电话
         private   int   salary ; // 该雇员薪资
         private  String  origin ; // 该雇员信息的来源


         // 构造方法
         public  Employee(String id) {
            this . id  = id;
           getDataFromlnfoCenter();
        }


         // 到数据库中取得雇员信息
         private   void  getDataFromlnfoCenter() {
            // 和数据库建立连接井查询该雇员的信息,将查询结果赋值
            // 给 name, department, plone, salary等变量
            // 同时将 origin赋值为 "From DataBase"
        }
    ……
    }
        这个Employee类的构造方法中我们可以预见,如果每次需要查询一个雇员的信息。哪怕是几秒中之前刚刚查询过的,都要重新构建一个实例,这是需要消耗很多时间的。下面是一个对Employee对象进行缓存的缓存器的定义:
     
    import  java.lang.ref.ReferenceQueue;
    import  java.lang.ref.SoftReference;
    import  java.util.Hashtable;


    public   class  EmployeeCache {
         static  private  EmployeeCache  cache ; // 一个 Cache实例
         private  Hashtable<String, EmployeeRef>  employeeRefs ; // 用于 Chche内容的存储
         private  ReferenceQueue<Employee>  q ; // 垃圾 Reference的队列

         // 继承 SoftReference,使得每一个实例都具有可识别的标识,
         // 并且该标识与其在 HashMap内的 key相同。
         private class EmployeeRef extends SoftReference<Employee> {
            private  String  _key  =  "" ;


            public  EmployeeRef(Employee em, ReferenceQueue<Employee> q) {
                super (em, q);
                _key  = em.getID();
           }
        }

         // 构建一个缓存器实例
         private  EmployeeCache() {
            employeeRefs  =  new  Hashtable<String,EmployeeRef>();
            q  =  new  ReferenceQueue<Employee>();
        }

         // 取得缓存器实例
         public   static synchronized EmployeeCache getInstance() {
           if  (cache == null){
                cache = new EmployeeCache();
           }
           return cache ;
        }


         // 以软引用的方式对一个 Employee对象的实例进行引用并保存该引用
         private   void  cacheEmployee(Employee em) {
           cleanCache(); // 清除垃圾引用
           EmployeeRef ref =  new  EmployeeRef(em,  q );
            employeeRefs .put(em.getID(), ref);
        }

         // 依据所指定的 ID号,重新获取相应 Employee对象的实例
         public  Employee getEmployee(String ID) {
           Employee em =  null ;
            // 缓存中是否有该 Employee实例的软引用,如果有,从软引用中取得。
            if  ( employeeRefs .containsKey(ID)) {
               EmployeeRef ref = (EmployeeRef)  employeeRefs .get(ID);
               em = (Employee) ref.get();
           }
            // 如果没有软引用,或者从软引用中得到的实例是 null,重新构建一个实例,
            // 并保存对这个新建实例的软引用
            if  (em ==  null ) {
               em =  new  Employee(ID);
               System. out .println( "Retrieve From EmployeeInfoCenter. ID="  + ID);
                this .cacheEmployee(em);
           }
            return  em;
        }


         // 清除那些所软引用的 Employee对象已经被回收的 EmployeeRef对象
         private   void  cleanCache() {
           EmployeeRef ref =  null ;
            while  ((ref = (EmployeeRef)  q .poll()) !=  null ) {
                employeeRefs .remove(ref. _key );
           }
        }

    }

    结语:

           上述是从自己见过的感觉对理解Java对象,对象引用以及对象赋值,目前最优价值的帖子中挑选而来。希望对大家有用。

     

     

    主要参考资料

    http://blog.sina.com.cn/s/blog_4cd5d2bb0100ve9r.html

    http://bxkqzjt521.blog.163.com/blog/static/202818420119102362458/

    http://www.2cto.com/kf/201207/139522.html

     

     

    展开全文
  • 对于刚接触不久面向对象的真小白童鞋来说,类的对象对象的实例,对象引用引用变量的问题以及莫过于没得对象虽然博主也没得对象,本文将逐个逐个讲解! 1.何谓对象? 在Java中有一句比较流行的话,叫做“万物皆...

    对于刚接触不久面向对象的真小白童鞋来说,类的对象,对象的实例,对象的引用,引用变量的问题以及莫过于没得对象虽然博主也没得对象,本文将逐个逐个讲解!

    1.何谓对象?

    在Java中有一句比较流行的话,叫做“万物皆对象”,这是Java语言设计之初的理念之一。要理解什么是对象,需要跟类一起结合起来理解。下面这段话引自《Java编程思想》中的一段原话:

    “按照通俗的说法,每个对象都是某个类(class)的一个实例(instance),这里,‘类’就是‘类型’的同义词。”

    从这一句话就可以理解到对象的本质,简而言之,它就是类的实例,比如所有的人统称为“人类”,这里的“人类”就是一个类(物种的一种类型),而具体到每个人,比如张三这个人,它就是对象,就是“人类”的实例。

    2.何谓对象引用?

    我们先看一段话,这段话同样来自于《Java编程思想》:

    “每种编程语言都有自己的数据处理方式。有些时候,程序员必须注意将要处理的数据是什么类型。你是直接操纵元素,还是用某种基于特殊语法的间接表示(例如C/C++里的指针)来操作对象。所有这些在
    Java
    里都得到了简化,一切都被视为对象。因此,我们可采用一种统一的语法。尽管将一切都“看作”对象,但操纵的标识符实际是指向一个对象的“引用”(reference)。”

    很显然,从这段话可以看出对象和对象引用不是一回事,是两个完全不同的概念。举个例子,我们通常会用下面这一行代码来创建一个对象:

     Person per = new Person("张三");
    

    有小白童鞋会说,这里的per是一个对象,是Person类的一个实例。也有小白童鞋会说,这里的per并不是真正的对象,而是指向所创建的对象的引用。到底哪种说法是对的?我们先不急着纠结哪种说法是对的,再看两行代码:

     Person person;
      person = new Person("张三");
    

    这两行代码实现的功能和上面的一行代码是完全一样的。大家都知道,在Java中new是用来在堆上创建对象用的,如果per是一个对象的话,那么第二行为何还要通过new来创建对象呢?

    由此可见,per并不是所创建的对象,是什么?上面的一段话说的很清楚,“操纵的标识符实际是指向一个对象的引用”,也就是说per是一个引用,是指向一个可以指向Person类的对象的引用。真正创建对象的语句是右边的new Person("张三");因此这里的per是一个引用,是指向一个可以指向Person类的对象的引用。

    简单来说,对象的引用意思是定义一个变量,这个变量指向的是一个对象

    Object  obj=new Object();
    //Object:类
    //obj:对象的引用
    //new Object():对象
    

    3.何谓对象实例?

    首先,没有“对象的实例”这一说法,只有类的实例,而类的实例,指的就是类的对象,说白了就是对象。
    但是还是有很多人这样叫,那怎么理解对象实例呢?比如说人类中有个叫宜春的程序员,宜春就是人类的一个实例

    String s = new String("YiChun");
    

    s 就是 String类中的一个实例

    关于对象实例官方没有给其概念,其实有很多概念官方都没有给的,什么父类声明指向子类对象、方法签名等概念都是没有的 ,只是人们经常这么用这么说就习惯了。因此关于实例对象大体可以理解为对象引用的意思

    4.何谓引用变量?

    引用变量就是用引用类型声明的变量,这种变量叫引用类型变量。如:

    People people;  //其中people就是引用变量,People是一个类属于引用类型
    

    5、对象与对象引用碰撞火花

    从对象引用出发:

    一个对象引用可以指向零个或一个对象

    从对象出发:

    一个对象可以被一个或多个对象引用

    怎么理解捏?小白童鞋脑壳逐渐变大…

    5、1. 从对象引用出发:一个对象引用可以指向零个或一个对象

    首先先来理解第一句话:从对象引用出发:一个对象引用可以指向零个或一个对象

    public static void main(String[] args) {
          Two t; //一个对象引用可以指向零个对象
          t=new Two();//一个对象引用可以指向一个对象
          t=new String();//一个对象引用不可以指向 >1个对象
        }
    

    试想一下这样的代码会出现啥情况?是的,它会编译失败
    在这里插入图片描述
    看完上面这个例子就能说明了么?我们接着看下面这个代码:

     public static void main(String[] args) {
            String str;
            str=new String("string1");
            str=new String("string2");
        }
    

    我们知道,凡是new都能创建出一个对象,我们发现上面代码String对象引用str一个new了两次,而且上面代码编译也不报错,的的确确是创建了两个对象,那这怎么说?小白童鞋还没说完,把博主按在马桶盖盖上…

    别急,我们再看看上面代码输出啥

      public static void main(String[] args) {
            String str; 
            str=new String("string1");
            str=new String("string2");
            System.out.println(str);
        }
        
     运行结果: string2
    

    这说明啥?说明现在str是下一个对象的引用。上一个对象被垃圾回收了,因为上一个对象(也就是string1)不能被再次使用了。因此上面这个程序可以这样理解:

     public static void main(String[] args) {
       String str;//一个对象引用str指向零个对象
       str=new String("string1");//一个对象引用str指向一个对象string1
       str=new String("string2");//注意:这里对象引用str并不是指向第二个对象string2,而是将之前指向第一个对象string1的引用重新指向了另一个对象string2
    }
    

    对象引用str并不是指向第二个对象string2,而是将之前指向第一个对象string1的引用重新指向了另一个对象string2,因此从对象引用出发:一个对象引用可以指向零个或一个对象!

    这个时候,小白童鞋渐渐松开了把博主按在马桶盖盖上的双手…

    5、2. 从对象出发:一个对象可以被一个或多个对象引用

    我们再来理解一下第二句话:从对象出发,一个对象可以被一个或多个对象引用

    小白童鞋同样不解,于是又用双手把博主按在马桶盖盖上…

    看下面这个程序:

       Demo demo1,demo2,demo3;
       demo1=new Demo();
       demo2=demo1;
       demo3=demo2;
    

    怎么理解?看的有点晕?会不会感觉后面两句代码就是对象引用=对象引用…

    其实要弄清除这个,首先你得弄清楚java虚拟机内存,弄清楚变量(对象引用)和对象是如何存储的,对象引用是存储在栈内存中,而对象是存储在堆内存中。分析如下:

    Demo demo1,demo2,demo3;//创建多个对象引用,都存储在栈中
    demo1=new Demo();//创建一个Demo对象,存储在堆中,并将demo1指向这个对象,相当于加了一个链
    demo2=demo1;//demo2与demo1一样,都指向堆中Demo对象
    demo3=demo2;//demo3与demo2一样,都指向堆中Demo对象
    

    首先,每个对象只有一个地址值,new Demo()是创建了一个对象,demo1是这个对象的地址值,用来找到这个对象,demo2=demo1是把new Demo()这个对象的地址值由demo1改为了demo2,后面的demo3=demo2也是只改变了对象的地址值,对象本身的空间大小都没有变化,变的,是这个对象的地址值,也就是c里面所谓的指针。

    这个时候,小白童鞋渐渐松开了把博主按在马桶盖盖上的双手…

    最后,我们再看看一个网上关于对象与对象引用很流行的程序与分析,代码如下:

    UserType ut = new UserType();  // ut是引用,实际的对象在内存里。
    ut = new UserType(); /*现在ut是另一个对象的引用,先前的对象被垃圾回收了(因为先前的对象不能被再次使用了)。*/
    UserType ut2;  // 定义了一个引用ut2,他不引用任何对象,不能使用。。。。
    ut2 = new UserType(); // 然ut2成为一个对象的引用。
    UserType ut3 = new UserType();
    UserType ut4 = new UserType();
    ut3 = ut4;   // 现在ut3引用ut4的对象,这里不是赋值。。。
    int a = 5;
    int b = 4;
    a = b;  // 这里是赋值。 a b 依然引用不同的对象
    

    6、最后要相信的真理

    对于面向对象语言,如java,首先,请小白童鞋相信一句话:一切皆为对象。然后相信另一句话:变量只是一个零时的储存地点。引用类型的变量只是一个普通变量,储存了引用类型的地址。对象的创建是直接在内存中分配一个内存。

    最后再梳理一下

    引用类型变量 就 相当于 电脑上的快捷方式; 对象就相当于 你 磁盘里面 安装的游戏,它 实实在在 占用你的空间内存; 而变量 只是快捷方式

    说白了基本数据类型变量就像是直接放在柜子里的东西,而引用数据类型变量就是这个柜子对应编码的钥匙。钥匙号和柜子对应。

    到这里文章就结束了喔,小白童鞋,你何识着咩啊~

    最后,若有不足或者不正之处,欢迎指正批评,感激不尽!

    欢迎各位关注我的公众号,一起探讨技术,向往技术,追求技术…

    在这里插入图片描述
    小白童鞋关注了我的公众号之后,又用双手把博主按在马桶盖盖上…

    展开全文
  • Java引用对象

    千次阅读 2018-12-11 10:09:03
    局部变量仍然储存在栈中,但它们持有这个对象的指针而不是这个对象本身(更让C++程序员困惑的是这些指针被叫做“引用”)。下面这个Java方法,有一个 Integer 变量引用一个从 String 解析而来的值: 1 2 3...
  • 吃人的那些 Java 名词:对象引用、堆、栈

    万次阅读 多人点赞 2019-09-05 15:57:09
    作为一个有着 8 年 Java 编程经验的 IT 老兵,说起来很惭愧,我被 Java 当中的四五个名词一直困扰着:**对象引用、堆、栈、堆栈**(栈可同堆栈,因此是四个名词,也是五个名词)。每次我看到这几个名词,都隐隐...
  • Java基础知识面试题(2020最新版)

    万次阅读 多人点赞 2020-02-19 12:11:27
    Java语言有哪些特点 简单易学(Java语言的语法与C语言和C++语言很接近) 面向对象(封装,继承,多态) 平台无关性(Java虚拟机实现平台无关性) 支持网络编程并且很方便(Java语言诞生本身就是为简化网络编程设计...
  • 值对象与引用对象

    千次阅读 2014-06-03 22:16:43
    概念介绍 对象对象引用
  • 对象对象引用

    千次阅读 多人点赞 2018-06-02 01:41:28
    最近初学java对于对象对象引用以及实例化有诸多迷惑,查了很多博客和API,现整理自己的理解如下:Java是一种面向对象的语言,采用类和对象的概念。Java中每个对象都有一种类型,即对象所属的类。类有两个主要...
  • js 对象实现值引用而不是对象引用

    千次阅读 2018-09-28 16:19:22
    js 对象实现值引用而不是对象引用 var str = JSON.stringify(datas); var dsj = JSON.parse(str); //dsj引用datas的值而不是数据地址
  • 上述规则中,会被GC回收的是弱引用实例引用对象,而非弱引用实例本身 如果显式地声明了一个变量E e = new E();指向一个对象,而这个对象e被WeakReference实例持有引用,则由于对象引用被变量e持有,对象并不符合...
  • Java对象对象引用,参数传递

    千次阅读 2018-07-01 19:45:46
    在Java中,万物皆对象! 比如定义一个学生类 public class Student { private int id; private String name; private int age; public Student() { // TODO Auto-generated constructor stub su...
  • 下面将介绍python的对象引用和 del删除引用1. 首先介绍下python的对象引用1)Python中不存在传值调用,一切传递的都是对象引用,也可以认为是传址调用。即Python不允许程序员选择采用传值或传引用。Python参数传递...
  • 在上面的代码中,是使用类A的对象好,还是对象指针比较好呢?很多时候,我们都没有深刻考虑过这两种情况,似乎在一个类中 都可以满足我们的需求。这种问题在stackoverflow上当然有回复: t’s very
  • 对象引用对象的指针 (常指针与常引用)const 左定值,右定向,修饰不变参
  • 问题:添加一个对象到集合中时,集合里面存放的是对象的引用还是对象本身?   答:对象的引用。以下代码可以证明: Java代码  import java.util.ArrayList;  import java.util.List;  ...
  • C++的对象引用

    千次阅读 2018-01-17 21:09:36
    在求解表达式的时候,如果需要一个地方存储其运算结果,编译器会创建一个没命名的对象,这就是临时对象。C++程序员通常用temporary这个术语来代替temporary object。 用函数返回值初始化临时对象
  • 浅谈java对象引用对象赋值

    千次阅读 多人点赞 2017-01-05 15:11:46
    一、Java对象及其引用  初学Java,总是会自觉或不自觉地把Java和C++相比较。在学习Java类与对象章节的时候,发现教科书和许多参考书把对象对象引用混为一谈。可是,如果分不清对象对象引用, 那实在没法很...
  • Java中对象的赋值与引用

    万次阅读 多人点赞 2017-07-28 19:52:34
    Java中对象的赋值与引用详解
  • 为了弄清楚python函数传参到底是传值还是传引用的问题,进行了下面的小实验(以列表对象为例): (1)如何让两个变量指向同一个对象?: a = [1,2,3,4] b = a[:] c = a print('id(a)={}'.format(id(a))) print('...
  • 未将对象引用设置到对象的实例

    千次阅读 2019-04-17 21:03:13
    总结出现“未将对象引用设置到对象的实例” 错误,一般是下面的原因: 1、ViewState 对象为Null。 2、DateSet 为空。 3、sql语句或Datebase的原因导致DataReader空。 4、声明字符串变量时未赋空值就应用变量。 ...
  • 转载注明出处:... 首先出错了,一定要学会Debug,Debug,Debug. 一、网络上的一般说法 ...1、ViewState 对象为Null。 2、DateSet 空。 3、sql语句或Datebase的原因导致DataReader空。 4、声明字
  • C++ 类this及返回自身对象引用看这一篇就明白this及返回自身对象引用 this及返回自身对象引用 this:调用成员函数的时候,编译器负责把对象地址传(&myTime)递给成员函数中隐藏的this形参。 在系统角度来...
  • c++返回函数局部对象引用

    千次阅读 2015-05-25 14:58:15
    函数千万不要返回局部对象引用或指针  局部变量在函数里面,当函数执行结束后将释放局部变量,如果返回引用或批针这个时候引用或指针指向所指向的内存空间已经释放。指针和引用将是垂悬指针。很危险! 但是如果...
  • 本文通过对象的创建步骤中的检查加载->分配内存->内存空间初始化->设置->对象初始化,对象的内存布局,什么是垃圾的两种算法以及四种引用,讲述JVM中对象引用
  • 当返回对象时,C++编译器将调用类默认的拷贝构造函数,...若定义的是返回对象的函数,此处会直接返回对象本身不会再创建一个匿名对象  利用操作符重载的例子加以说明 #include "iostream"using namesp
  • 因为对象参数往往是引用传参形式,所以很多时候,我们往往会通过调用一个函数,然后直接想当然的认为该值已经发生变化,然而,情况并非如此,这得需要看看方法里到底做了些什么,请看下边这个例子: private ...
  • 句柄、引用、指针与对象

    千次阅读 2016-04-15 09:24:17
    (2)引用对象的别名,其实质就是功能受限但是安全性更高的指针; (3)句柄是指针的指针,句柄实际上是一个数据,是一个Long (整长型)的数据。句柄是一个标识符,是拿来标识对象或者项目的,它就象我们的姓名一样。 ...
  • 看网上的介绍,对于字符串常量池中到底保存的是字符串对象,还是字符串对象引用,众说纷纭… 看 jdk1.8 对 intern() 的说明. When the intern method is invoked, if the pool already contains a string equal to ...
  • java中的五种引用数据类型(对象类型)

    万次阅读 多人点赞 2019-01-20 14:38:23
    Java有 5种引用类型(对象类型):类 接口 数组 枚举 标注 引用类型:底层结构和基本类型差别较大 JVM的内存空间: (1). Heap 堆空间:分配对象 new Student() (2). Stack 栈空间:临时变量 Student stu (3)...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 575,595
精华内容 230,238
关键字:

引用就是对象本身