总结Java中的对象和引用

来源:互联网 发布:八叉树优化 编辑:程序博客网 时间:2024/06/11 02:56

之前看完了《java核心技术》,其中学习到了java传参是 传的是值还是引用的讨论,现在在看《java编程思想》时,更加理解了对象和引用的概念,结合两本书针对“对象和引用 ”的内容 做一次总结。

1.java中用引用操作对象

String s;

这句代码没有用“new”创建对象,这里只是创建一个引用,并没有对象和它进行关联。假设你对s做操作,比如:

String s;s.length();

这时候程序就直接报错了,因为这个引用没有和任何对象做关联。
对于String来说,这才是安全的做法

String s = "abcd";s.length();

2.java中引用和对象分别存在什么地方

一些基本类型的变量和对象的引用都是在栈内存中分配。堆内存用于存放由new创建的对象和数组。

用堆进行存储和清理要比栈进行存储和清理付出更多的时间,但是堆的灵活性更高,编译器不需要知道堆中数据的生命周期,即使栈中对象的引用不再关联对象,堆中的对象也会保留,直到java的垃圾回收机制回收 没有被任何对象的“引用” 引用过的对象,而栈的数据 需要明确它自己的生命周期,因为它在生命周期结束时会被释放内存。

3.java中的数组

当创建一个数组对象时,实际上就是创建了一个引用数组,每个引用都会初始化为null,如果试图使用一个还是null的引用,会报错。如果是new一个基本数据类型的数组,会被初始化置为0

String[] str = new String[5];System.out.println(Arrays.toString(str));//结果:[null, null, null, null, null]//如果是基本类型,会默认置为0int[] str1 = new int[5];System.out.println(Arrays.toString(str1));//结果:[0, 0, 0, 0, 0]

4.java对象的作用域
大多数语言都有作用域的概念,作用域决定了“引用”的可见性和生命周期

虽然a和b字符串内容相同,但是引用的是不同的字符串对象,而且b变量的生命周期更短

{     String a = "abcd";     {         String b = "abcd";     }}

有人这样想,能不能用作用域的特性来定义两个同名的变量(引用)

看似这段代码具有合理性,在更小的作用域里面,应该可以定义一个变量名为a的String,较大作用域的a变量在小作用域里被隐藏,但是事实上java不允许那么做,设计者认为这样会造成程序混乱。

{    String a = "abcd";    {        String a = "abcd";    }}

了解了作用域的范围,再讨论作用域结束以后,引用和对象都消失了吗?

{    Object a = new Object();}

引用a在作用域结束以后就消失了,但是new Object()并没有,a指向的Object对象仍然占据着内存空间,这应该是对象和引用分别存放在堆和栈内存的缘故(到现在还没看到具体的解释,以后会补充,这只是我的猜想),但是因为引用a的消失,你无法再操作这个Object对象,如果没有变量再引用它,这个对象最终的命运会被java的“垃圾回收器”回收,java垃圾回收机制的存在避免了 不用的对象无法及时销毁而导致内存溢出问题。

5.类中的成员变量默认值
根据面向对象的思想,java设计了类,如果是自己设计的类,里面也有其它的类成员,如果我们new一个类,而且是空参构造器,那么类中的对象都有自己的默认值。

基本数据类型的默认值参考下图,如果是非基本数据类型,那默认值就是null
这里写图片描述

6.方法里的参数

首先明确,java里面都是按值调用,准确的说,传递过来的是一个拷贝,但是针对基本数据类型和非基本数据类型又有不同的情况

基本类型: 方法得到的是值拷贝。所以对拷贝的修改不涉及对原值的修改。

非基本类型: 方法得到的仍然是拷贝,但不是值拷贝,是引用的拷贝

定义一个类

package JDK.Array;public class Man {    int age;}
public static void sum(int a, Man l) {    a++;    l.age = 2;}
int i = 1;Man man = new Man();man.age = 1;System.out.println("i:" + i + " man:" + man.age);Array_1.sum(i, man);System.out.println("i:" + i + " man:" + man.age);

结果是:

i:1 man:1i:1 man:2

基本数据类型没有变化,因为它是值拷贝,但是Man类因为传的是引用的拷贝,l变量和man变量都指向了对象,所以数据发生了变化。

很多人认为传参在非基本数据类型里是引用调用,这种说法是不对的,下面举一个反例:

public static void sum1(Man l, Man l1) {    Man temp = l;    l = l1;    l1 = temp;}
Man man = new Man();Man man1 = new Man();man.age = 1;man1.age = 0;System.out.println(" man:" + man.age + " man1:" + man1.age);Array_1.sum1(man, man1);System.out.println(" man:" + man.age + " man1:" + man1.age);

这一次创建了两个Man对象,同时传递给sum1方法,按照之前 按引用调用 的说法,进入方法后引用的对象发生了对调, 输出的结果应该是age 的值对调了。

man:1 man1:0man:0 man1:1

但是真正的结果是

 man:1 man1:0 man:1 man1:0

age字段的值没有发生对调,所以 l和l1是 man 和man1引用的拷贝,方法交换的是拷贝,不影响引用所指向的对象。

0 0
原创粉丝点击