这是我参与8月更文挑战的第8天,活动详情查看:8月更文挑战
概述
每位学习Java的童鞋,对于对象及对象的创建都非常熟悉了(甚至比对自己的「对象」还要熟)。但是除了new方式创建对象,大家还有了解对象的其他创建方式吗?今天我们就聊聊Java创建对象的所有方式。
创建对象的方式可以分为两大类:调用了构造函数和没有调用改造函数
-
调用了构造函数
-
new方式创建对象
-
通过反射创建对象
-
-
没有调用构造函数
-
通过clone方式创建对象
-
反序列化创建对象
-
new方式创建对象
通过new方式创建对象,是我们最常见和最常用的创建对象方式。创建方式很简单,直接通过new语法创建。实际创建过程并不简单。
对象的创建流程: 1.类加载检查,先检查类是否被加载过,若没有加载,则先执行相应的类加载 2.分配内存,根据堆内存是否规整来确定分配内存方式。若规整,则采取对撞指针的方式进行内存分配(内存划分已使用和未使用两部分);如不规整,则通过空闲列表的形式分配内存(虚拟机会维护一个列表,记录哪些内存是可用的) 3.初始化零值 4.设置对象头,对象头包括两部分信息:存储对象自身的运行时数据(哈希码、GC分代年龄,锁状态标志等),另一部分是类型指针,指向它的类元数据指针,确定这个对象是哪个类的实例 5.执行init方法,成员变量实例化对应的值
package com.carrywei.bread.object;
public class Computer {
// 类型
private String type;
// 颜色
private String color;
public Computer(String type, String color) {
System.out.println("我是" + color + type + "电脑");
}
public static void main(String[] args) {
// new方式创建对象
Computer newComputer = new Computer("MacBook Pro", "深空灰色");
}
}
通过反射创建对象
通过反射创建对象也是我们熟知的一种创建对象方式。
Java的反射(reflection)机制是指在程序的运行状态中,可以构造任意一个类的对象,可以了解任意一个对象所属的类,可以了解任意一个类的成员变量和方法,可以调用任意一个对象的属性和方法。
代码:
// 有参构造函数,通过反射创建对象
Class cls = Class.forName("com.carrywei.bread.object.Computer");
Class[] paramTypes = { String.class, String.class };
Object[] params = { "小米笔记本", "银色"};
Constructor con = cls.getConstructor(paramTypes);
Computer reflectionComputer = (Computer) con.newInstance(params);
通过clone方式创建对象
clone方式创建对象的核心就是实现clone方法,然后调用原对象创建的clone方法创建新的对象
public class Computer implements Cloneable{
// 其他部分省略
// ...
@Override
public Computer clone(){
try {
Computer computer = (Computer) super.clone();
return computer;
} catch (CloneNotSupportedException e) {
e.printStackTrace();
return null;
}
}
public static void main(String[] args) {
Computer newComputer = new Computer("MacBook Pro", "深空灰色");
Computer cloneComputer = newComputer.clone();
}
}
反序列方式创建对象
Java序列化是指将Java对象转为字节序列的过程,反序列化为把字节序列恢复为Java对象的过程。
对象能被序列化和反序列化的前提:类实现Serializable接口。
反序列化创建对象编码
// 通过反序列化方式创建对象
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
try {
// 将对象序列化到内存
ObjectOutputStream objectOutputStream = new ObjectOutputStream(byteArrayOutputStream);
objectOutputStream.writeObject(newComputer);
// 从内存反序列化
ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(byteArrayOutputStream.toByteArray());
ObjectInputStream objectInputStream = new ObjectInputStream(byteArrayInputStream);
Computer serializeComputer = (Computer) objectInputStream.readObject();
} catch (IOException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
小结
通过以上四种方式创建对象的完整代码:
package com.carrywei.bread.object;
import java.io.*;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
/**
* Created by on 2021/8/8.
* 描述:电脑
*/
public class Computer implements Cloneable, Serializable {
// 类型
private String type;
// 颜色
private String color;
public Computer() {
System.out.println("我是空电脑");
}
public Computer(String type, String color) {
System.out.println("我是" + color + type + "电脑");
}
@Override
public Computer clone(){
try {
Computer computer = (Computer) super.clone();
return computer;
} catch (CloneNotSupportedException e) {
e.printStackTrace();
return null;
}
}
public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException,
IllegalAccessException, InvocationTargetException, InstantiationException {
Computer newComputer = new Computer("MacBook Pro", "深空灰色");
Class cls = Class.forName("com.carrywei.bread.object.Computer");
// 通过反射方式创建对象
System.out.println("-----------通过反射方式创建对象---------");
Class[] paramTypes = { String.class, String.class };
Object[] params = { "小米笔记本", "银色"};
Constructor con = cls.getConstructor(paramTypes);
Computer reflectionComputer = (Computer) con.newInstance(params);
// clone 方法创建对象
System.out.println("-----------clone 方法创建对象---------");
Computer cloneComputer = newComputer.clone();
System.out.println(newComputer == cloneComputer);
// 通过反序列化方式创建对象
System.out.println("---------通过反序列化方式创建对象-----------");
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
try {
// 将对象序列化到内存
ObjectOutputStream objectOutputStream = new ObjectOutputStream(byteArrayOutputStream);
objectOutputStream.writeObject(newComputer);
// 从内存反序列化
ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(byteArrayOutputStream.toByteArray());
ObjectInputStream objectInputStream = new ObjectInputStream(byteArrayInputStream);
Computer serializeComputer = (Computer) objectInputStream.readObject();
System.out.println(newComputer == serializeComputer);
} catch (IOException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
}
// 输出结果:
我是深空灰色MacBook Pro电脑
-----------通过反射方式创建对象---------
我是银色小米笔记本电脑
-----------clone 方法创建对象---------
false
---------通过反序列化方式创建对象-----------
false
从输出结果,我们看出:
-
new方式和反射创建对象,是会调用构造函数的,而clone方式和反序列化方式并不会调用构造函数
-
通过clone和反序列化方式创建的对象跟原对象并不相同,这两种方式创建对象也是设计模式中的原型模式的实现方式。 (想了解更多关于原型模式的内容,可以阅读我之前的文章《原型模式:快速复制已有实例创建新的实例》)