狗万体育app

编辑:文章阅读网发表日期:浏览:5

热门搜索 string  作用域  堆栈  拷贝  变量  66人阅读 

狗万体育app

之前看完了《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 ] //如果是基本类型,会默认置为 0 int[] 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 :1 i :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 .sum 1(man, man1) System .out .println ( " man:" + man .age + " man1:" + man1 .age )

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

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

但是真正的结果是

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

age字段的值没有发生对调,所以 l和l1是 man 和man1引用的拷贝,方法交换的是拷贝,不影响引用所指向的对象。狗万体育app
上一篇:
下一篇:

诗歌诗句《你在我心里》

诗歌诗句《在我失眠的时候》

诗歌诗句《邀约李白慢慢聊》

诗歌大全《春风送暖入屠苏》

诗歌诗句《驶向北方的火车》