Java中对象与引用

来源:互联网 发布:red hat linux的优点 编辑:程序博客网 时间:2024/06/01 09:16

 初学Java 时,在很长一段时间里,总觉得基本概念很模糊。后来才知道,在许多Java 书中,把对象和对象的引用混为一谈。

    如果分不清对象与对象引用,那实在没法很好地理解下面的面向对象技术,把自己的一点认识写下来,或许能让初学Java 的朋友们少走一点弯路。        

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

 class student{  

  int name;  

  int age;  

  int sex;  

}   

    有了这个类( 模板) ,就可以用它来创建对象:student stu1 = new student();

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

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

    2) 末尾的() 意味着,在对象创建后,立即调用student 类的构造函数,对刚生成的对象进行初始化。

构造函数是肯定有的。如果你没写,Java 会给你补上一个默认的构造函数。

    3) 左边的"student stu1" 创建了一个student 类引用变量。所谓student 类引用,就是以后可以用来指向某个

student 对象的对象引用,它指向的是某个student 对象的内存地址( 有点C 语言中指针的味道) 。

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

    我们可以把这条语句拆成两部分:student stu1; stu1 = new student(); 效果是一样的。

    这样写,就比较清楚了,有两个实体:一是对象引用变量(stu1) ,在Sun 公司的实现中, 对象的引用是一个句柄, 其中包含一对指针: 一个指针指向该对象的方法表,一个指向该对象的数据;另一个是对象本身( 就是new 出来的那个对象) 。

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

    有人说,它叫"student" 。不对,"student" 是类( 对象的创建模板) 的名字。一个student 类可以据此创建 出无数个对象,这些对象不可能全叫"student" 。对象连名都没有,没法直接访问它。我们只能通过 对象引用来间接访问对象。

    为了形象地说明对象、对象引用及它们之间的关系,可以做一个或许不很妥当的比喻:

    对象好比是一只没有线的风筝,引用变量是一根线,可以用来系风筝。如果只执行了第一条语句, 还没执行第二条,此时创建的引用变量stu1 还没指向任何一个对象,它的值是null ,引用变量可以 指向某个对象,或者为null 。这时stu1 是一根线,一根还没有系上任何一个风筝的线。

    执行了第二句后,一只新风筝做出来了,并被系在stu1 这根线上。我们抓住这根线,就等于抓住了那只风筝。

    再来一句:student stu2; 就又做了一根线,还没系上风筝。如果再加一句:stu2=stu1; 系上风筝了。

    这里,发生了复制行为。但是,要说明的是,对象本身并没有被复制,被复制的只是对象引用。

    结果是,stu2 也指向了stu1 所指向的对象,也就是两根线系的是同一只风筝。

    如果用下句再创建一个对象:stu2=new student(); 则引用变量stu2 改指向第二个对象。

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

    (1) 一个对象引用可以指向0 个或1 个对象( 一根线可以不系风筝,也可以系一个风筝) ,而且可以改指;

    (2) 一个对象可以有N 个引用指向它( 可以有N 条线系同一个风筝) 。

如果有下面语句:stu1=stu2;

    按上面的推断,stu1 也指向了第二个对象。这个没问题。问题是第一个对象呢?没有一条线系住它,它飞了。

    很多书里说,它被Java 的垃圾回收机制回收了,这不确切,准确地说,它已成为Java 垃圾回收机制的处理对象。

    至于什么时候真正被回收,那要看垃圾回收机制的心情了。由此看来,new student(); 该语句应该不合法吧,

    至少是没用的吧?不对,它是合法的,而且可用的。譬如,如果我们仅仅为了打印而生成一个对象, 就不需要用引用变量来系住它。最常见的就是打印字符System.out.println("I am Java!"); 字符串对象"I am Java!" 在打印后即被丢弃,有人把这种对象称之为临时对象。

 

 

java中的构造函数

原则:

1.构造方法不能声明返回类型,不能被static、final、synchronized、abstract、native修饰。

2.当某个类中没有自定义的构造方法时,编译器会自动为你产生一个缺省的构造方法,这是一个不带参数且没有任何代码的构造方法;但是一旦你为你的类定义了一个构造方法,不管是否带参数,那么编译器将不会再为你产生缺省的构造方法。

3.父类的构造方法不能被子类继承。子类不能直接通过方法名调用父类的一个构造方法,而是要通过super关键字调用父类的一个构造方法,super语句必须位于子类构造方法的第一行。

4.当你试图调用某个类的某一构造方法(暂定名为a方法)来产生该类的一个实例时,将首先需要调用其父类的构造方法,此时有两种情况:(1)a方法中显示地用super关键字调用了父类的某一构造方法(是否带参都行)(注意此时super句必需出现在a方法的第一行);(2)a方法中没有显示地用super关键字调用了父类的某一构造方法,此时编译器在编译子类时会a方法中的第一行加上super();语句。

5.当一个类有几个构造方法时如果想在一个构造方法(暂定名为a)中调用另一个构造方法(暂定名为b),需要使用this关键字而不是用方法名直接调用且this句必需放在第一行;在这种情况下,如果通过this关键字调用的构造方法b中显示地调用了父类的某一构造方法时,编译器不会再在a方法中添加super();来调用父类的缺省构造方法。

 


也谈Java值传递-到底传递了什么?

java里面只有值传递,这是不变的真理,不过由于对象类型的特殊性,有些人还是会疑惑 值传递?还是 引用传递?

可能主要是这句话造成的: 在Java中方法参数的传递,对象是传递引用,基本数据类型是传递值。

如果java里面只有值传递,为何又要说对象是 引用传递?

对于 基本数据类型 是值传递,相信没有人会有疑惑。那对象到底传递了什么?

其实这源于JAVA在解释其变量类型时的一个混淆:JAVA里面只有8种基本数据类型和对象类型

于是便有了 基本数据类型是传递值,对象是传递引用

其实如果把对象类型也解释成一种基本数据类型 ,那就不会出现 对象是传递引用 这句话让人疑惑的话了

下文将 对象类型 看成一种新的基本类型, 姑且称之为 olong (object long),即 所有对象变量 都是 olong,虽然在java书写时可以写成具体的对象类型,如 Long a; 但其传递实质是  olong a;

让我们来重新认识 olong 吧:

赋值:


long a = 1234;

olong oa = new Long(1234); //Long oa = new Long(1234);


传递:

long b = a;

olong ob =oa;  //Long ob = oa;

 

改变:

b = 4321;

ob = new Long(4321); //ob = new Long(4321);


改变了什么?:

System.out.println(a); //输出 1234

System.out.println(b); //输出 4321

System.out.println(oa.longValue()); //输出 1234

System.out.println(ob.longValue()); //输出 4321


到底传递了什么:

long:

long a = 1234; //a的值1234

long b = a;//值传递 b的值1234;a的值1234

b = 4321;//b的值被改变为4321;但a不受影响,依然是1234


olong:

long类型的变量保存和传递的是其指代的基本类型的值,那么olong呢?

可以认为olong类型的变量保存和传递的是一个指向具体对象的内存地址,

olong oa = new Long(1234);//假设new Long生成的对象的地址为0001,则oa的值为0001

olong ob =oa; //值传递,ob的值0001;oa的值0001

ob = new Long(4321);//ob的值被赋予一个新的对象的地址,假设为0002,但oa的值不受影响,依然为0001

因此olong类型的赋值结果与long类型的表现一致,也是值传递


为什么对象是传递引用?

其实这句话也不错,因为olong变量本身就是一个引用,引用了一个对象(的内存地址)

但其实质是 值传递!只不过因为 olong 的值 还有一个 别名 叫做 引用,所以就被叫做了一个让人迷惑的新词:引用传递!


总结:

olong的引入只是为了方便解释Java对象的值传递,说明在参数传递过程中,对象变量的传递和基本变量的传递是没有本质区别的,所以,在Java中,没有 引用传递,只有值传递!




再啰嗦下    

如下表达式:
  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出来的是对象。
在后面的左右都是引用的“=”语句时,左右的引用同时指向了右边引用所指向的对象。


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

1 0
原创粉丝点击