一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第19天,点击查看活动详情。
1.Java对象生命周期
永远记住:Java创建对象的根本途径就是调用构造方式!!! ,但是调用构造方法不一定创建对象(子类创建对象会调用父类的构造方法,但是没有创建父类的对象)
一个Java类的完整生命周期,经历:1.加载 2.连接 3.初始化 4.使用 5.卸载
1.1 JVM内存区域
Java的核心机制:JVM(Java虚拟机-跨平台)和GC(垃圾自动回收机制)
内存区域的介绍:
(1)堆内存(Heap):用于存放类的对象实例(保存对象地址),共享
(2)栈内存(Stack):Java虚拟机栈,是由一个一个栈帧组成的**后进先出的栈式结构,栈帧中存放的是运行时产生局部变量、方法等信息。当调用一个方法的时候,虚拟机栈中就会创建一个栈帧存放这些数据的内存**,当方法调用完毕之后,栈帧消失。如果方法被其他方法调用,则**继续在栈帧顶部创建新的栈帧(尽量少使用递归调用)**
(3)方法区:Java中虚拟机中有一块区域(共享)存放已经**加载的类信息(创建Class对象):属性和方法**、常量、静态变量(全局数据区域、static修饰共享数据)以及方法代码的内存区域
(4)常量池:使用final关键字修饰的变量,常量池是方法区的一部分,主要是用来存放常量和李忠的符号引用等信息(java.lang.String)
1.2 初始化
如果一个类被直接易用,就会触发类的初始化,在Java中,直接引用情况如下:(什么是虚引用)
- 通过
new关键创建对象、读取或者设置类的静态变量、调用类的静态方法 - 初始化子类的时候,会触发父类中的初始化(继承)
- 作为程序入口直接运行的时候,也可以直接调用
main方法
创建对象的时候,调用构造方法,会对
成员变量(实例变量)进行初始化操作,静态变量的信息在类加载的时候就已经存放到方法区域中了。
1.3 卸载
在类使用之后,如果满足以下的情况,类就会被卸载(回收):
- 该类所有的实例已经被
GC(被回收),也就是Java的堆内存中不存储该类的任何实例 - 加载该类的ClassLoader已经被回收
- 该类对应的
java.lang.Class对象(类被加载就创建了Class对象,所有创建实例都是由同一个Class对象创建的),没有被任何地方引用的时候,无法在任何地方通过反射方位该类的方法。
2.Java创建对象的方式
(1)使用new关键字:最常用的方式,可以调用任意的构造方法(无参还是有参)
(2)使用Class类的newInstance方法创建对象,但是该方法只能调用无参数的构造方法
(3)通过反射获取构造方法对象(Constructor)使用newInstance,可以调用有参或者无参的所有的构造方法
(4)使用clone克隆方法:源对象,当我们使用clone的时候,JVM就会创建一个新对象,但是使用clone方法,不会调用任何的构造方法,类必须要实现Cloneable接口
(5)序列化:当我们使用序列化和反序列创建一个对象的时候,JVM会创建一个新的对象,反序列的时候不会调用任何构造方法,但是必须要实现java.io.Serializable
public class Test01 {
public static void main(String[] args) throws Exception {
Student s1 = new Student();
System.out.println("s1 = " + s1);
Student s2 = new Student("悟空");
System.out.println("s2 = " + s2);
Student s3 = Student.class.newInstance();
System.out.println("s3 = " + s3);
Class<Student> clazz = (Class<Student>) Class.forName("com.pangsir.model.Student");
Student s4 = clazz.newInstance();
System.out.println("s4 = " + s4);
Constructor<Teacher> c1 = Teacher.class.getDeclaredConstructor();//获取无参数
Teacher t1 = c1.newInstance();
System.out.println("t1 = " + t1);
Constructor<Teacher> c2 = Teacher.class.getDeclaredConstructor(String.class);
c2.setAccessible(true);
Teacher t2 = c2.newInstance("八戒");
System.out.println("t2 = " + t2);
}
}
public class 克隆 {
public static void main(String[] args) throws Exception {
Dog d1 = new Dog("小白");
System.out.println("d1 = " + d1);
System.out.println("d1.getName() = " + d1.getName());
System.out.println("=============");
Dog d2 = (Dog)d1.clone();
System.out.println("d2 = " + d2);
System.out.println("d2.getName() = " + d2.getName());
}
}
public class 序列化 {
public static void main(String[] args) throws Exception {
Cat cat = new Cat();
cat.setName("小白..."+ Math.random());
OutputStream out = new FileOutputStream("D:/Cat.kk");
ObjectOutputStream oos = new ObjectOutputStream(out);
oos.writeObject(cat);//数据写入到Cat.kk文件
oos.close();
}
}
public class 反序列化 {
public static void main(String[] args) throws Exception {
InputStream in = new FileInputStream("D:/Cat.kk");
ObjectInputStream ois = new ObjectInputStream(in);
Cat cat = (Cat)ois.readObject();
System.out.println("cat = " + cat);
}
}
3.实例变量初始化
实例变量,在创建对象的时候,由构造进行初始化(也可以直接调用公开的setter方法,再次进行赋值)
public class Pig implements Serializable {
public String name;
public Pig(){
System.out.println("Pig无参数");
}
public Pig(String name){
System.out.println("Pig有参数");
this.name=name;
}
public String getName() {
return name;
}
public void setName(String name) {
System.out.println(this.name+",已经在构造方法的时候赋值");
this.name = name;
}
@Override
public String toString() {
return "Cat{" +
"name='" + name + '\'' +
'}';
}
}
package com.pangsir.test;
import com.pangsir.model.Dog;
import com.pangsir.model.Pig;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
public class 实例变量初始化 {
public static void main(String[] args) throws Exception {
Pig p1 = new Pig();
System.out.println("p1 = " + p1);
System.out.println("================");
Pig p2 = new Pig("小红");
System.out.println("p2 = " + p2);
System.out.println("================");
Pig p3 = new Pig();
p3.setName("小白");
System.out.println("p3 = " + p3);
System.out.println("================");
Constructor<Pig> c1 = Pig.class.getDeclaredConstructor(String.class);
c1.setAccessible(true);
Pig p4 = c1.newInstance("小绿");
System.out.println("p4 = " + p4);
System.out.println("================");
Field nameField = Pig.class.getDeclaredField("name");
nameField.setAccessible(true);
//重新赋值
nameField.set(p4,"小黑");
System.out.println("p4 = " + p4);
}
}