Java 对象生命周期
一直对Java对象的实例化、对象、对象的引用、堆 栈存放的内容迷惑不解。看了 Java编程思想,理解似乎又深了一层。
对象和对象的引用
Java 编程思想中,把对象的引用比喻成了遥控器,对象比喻成了电视机,我们是通过遥控器操作电视机的,想改换频道或者调整声音,只需要操作遥控器就可以了,并且遥控器可以独立于电视机存在,也就是说你有一个引用,并不需要一定要与一个对象进行关联,例如
String s;
但这里所创建的只是引用,并不是对象。如果此时像s发送一个消息,就会返回 一个运行时错误。这是因为此时s实际上没有与任何事物相关联。
在这里,引用可以理解为定义的变量或者对象名,实际要操作的内容才是对象,对象是类的一个个体,具体的实现样式,比如有Student 类,Student jack; jack 只是Student的对象的一个名字,Student 有很多属性和方法,如果不实例化jack,jack将不可能操作Student的对象的任何属性和方法,只有实例化,赋给jack一个对象,才能操作类中的属性和方法。
对象存储的位置
程序运行时,对象是怎样进行放置安排的呢?特别是内存怎么分配的,有5个不同的地方可以存放数据:
- 1) 寄存器:位于CPU中,根据需求进行分配,不能直接进行控制,也感觉不到它的运行;
- 2) 堆栈:就是所谓的栈,在内存中,通过堆栈指针可以从处理器那里获得直接支持,堆栈指针若向下移动则分配新的内存,若向上移动,则释放内存。存储速度仅次于寄存器。创建程序时,java 系统必须知道存储在堆栈内所有项的确切生命周期,以便于上下移动堆栈指针
- 3)堆:一种通用的内存池,用于存放所有的java对象,堆不同于堆栈的好处是,编译器不需要知道存储的数据在堆里存放多长时间。因此在堆里分配内存有很大的灵活性。当需要一个对象时,只需要用new写一行简单的代码,当执行代码时会自动的在堆里进行内存分配。
- 4)常量存储:常量值通常存放在程序代码内部
- 5)非内存存储区域:如果数据完全存活于程序之外,那么他可以不受程序的任何控制,在程序没有运行时也可以存储,两个基本的例子是流对象和持久化对象。在流对象中,对象转化成字节流,通常被发送给另一台机器。持久化对象被存放于磁盘上,因此即使程序终止,它人可以保持自己的状态,在需要时又可以恢复成常规的对象。
综上可以大致理解为:new创建的对象存在于堆中,这块内存区域也是经常会溢出的地方,你不知道会执行多少次new;堆栈(栈)中存放得是常量及基本数据类型 和 对象的引用,因为这些都是固定的,程序运行之前就知道的大小。
静态属性和非静态属性
用Static修饰的成员变量或方法是静态成员变量和静态方法。静态成员变量和静态方法都是属于类的,生命周期跟类一直同在。对象的成员变量在对象被创建时生成,对象消亡时消亡,如下的例子:
在C中想最终调用A中aPrint方法,中间经过了B,B中的两个变量是通过实例化赋值的,在访问C时,b对象已经无效了,name 和 id 的值也随着无效了,所以最终运行的结果提示:name = null
代码块
例如:
package com.test;
public class A {
private String name;
private String id;
public A(String name, String id) {
this.name = name;
this.id = id;
}
public void aPrint(){
System.out.println("name = " + name);
}
}
package com.test;
public class B {
public String name;
public String id;
public B(String name, String id) {
this.name = name;
this.id = id;
}
A a = new A(name,id);
public void bPrint() {
a.aPrint();
}
}
package com.test;
public class C {
public static void main(String[] args) {
String name = "test";
String id = "123";
B b = new B(name,id);
b.bPrint();
}
}
把 B 改成
package com.test;
public class B {
public static String name;
public String id;
public B(String id) {
this.id = id;
}
A a = new A(name,id);
public void bPrint() {
a.aPrint();
}
}
在运行结果:
name的值不在为空。