(1)new关键字
使用new关键字创建对象,这是我们最常见的也是最简单的创建对象的方式,通过这种方式我们还可以调用任意的构造器(无参的和有参的)。
ClassName myClass = new ClassName();
注意:
- 当我们使用
new
创建了一个对象时,会在栈中创建myClass
这个引用,并且在堆中开辟一块空间存放对象的值,然后让myClass
这个引用指向堆中新建的ClassName
对象的值; - 不管每次创建的对象的值是否相同,每次用
new
创建对象时,在栈中创建的引用都是不一样的,即地址都是不一样的。
(2)Class.newInstance
这是我们运用反射创建对象时最常用的方法。
Class
类的newInstance
使用的是类的public
的无参构造方法。因此也就是说使用此方法创建对象的前提是必须有public
的无参构造器才行:
ClassName myClass = ClassName.class.newInstance();
ClassName myClass = (ClassName)Class.foeName("ClassName").newInstance();
(3)Constructor.newInstance
该方法和Class
类的newInstance
方法很像,但是比它强大很多。
java.lang.relect.Constructor
类里也有一个newInstance
方法可以创建对象。
我们可以通过这个newInstance
方法调用有参数(不再必须是无参)的和私有的构造函数(不再必须是public
)。
Constructor<ClassName> constructor = ClassName.class.getConstructor();
ClassName class = constructor.newInstance();
两种newInstance方法的区别
Class
类位于java
的lang
包中,
Constructor
是java
反射机制的一部分Class
类的newInstance
只能触发无参数的构造方法创建对象,
Constructor
类的newInstance
能触发有参数或者任意参数的构造方法来创建对象。Class
类的newInstance
需要其构造方法是public
的或者对调用方法可见的,
Constructor
类的newInstance
可以在特定环境下调用私有构造方法来创建对象。Class
类的newInstance
抛出类构造函数的异常,
Constructor
类的newInstance
包装了一个InvocationTargetException
异常。
(4)Clone方法
无论何时我们调用一个对象的clone
方法,JVM
就会创建一个新的对象,将前面的对象的内容全部拷贝进去,用clone
方法创建对象并不会调用任何构造函数。
要使用clone
方法,我们必须先实现Cloneable
接口并复写Object
的clone
方法(因为Object的这个方法是protected
的,若不复写,外部也调用不了)。
public class ClassName implements Cloneable {
...
// 访问权限写为public,并且返回值写为myclass
@Override
public ClassName clone() throws CloneNotSupportedException {
return (ClassName) super.clone();
}
...
}
public class Main {
public static void main(String[] args) throws Exception {
ClassName myClass = new ClassName();
Object clone = myclass.clone();
//ClassName clone = (ClassName)myClass.clone();
}
}
注意:
clone()
方法只会进行浅复制,也就是说只会在栈中再创建一个引用指向原来的对象的值所处的堆空间中,堆中的对象的值还是原来的并没有重新创建;- 使用clone()方法并不需要调用造函数
(5)反序列化
要想通过反序列化创建对象,就必须现将某个对象序列化
概念:
1.序列化:将java对象转化为字节流或字符流的过程
作用:
(1)便于在网络上进行传输;
(2)将java
字节序列永久保存在硬盘上,通常放在文件中,所以序列化也可以叫做持久化。
2.反序列化:将字节流或字符流对象转化成java对象的过程
/**
* 使用反序列化创建对象
* 当序列化和反序列化一个对象时,JVM会创建一个单独的对象。
* 在反序列化时,JVM创建对象并不会调用任何构造函数,
* 为了反序列化一个对象,需要让我们的ClassName类实现Serializable接口
*/
@Test
public void function() {
String filePath = "F:\\Tests\\data.obj";
try {
//序列化过程
ObjectOutputStream objectOutputStream = new ObjectOutputStream(new FileOutputStream(filePath));
objectOutputStream.writeObject(new ClassName());
objectOutputStream.close();
//反序列化过程
ObjectInputStream inputStream = new ObjectInputStream(new FileInputStream(filePath));
ClassName myClass = (ClassName) inputStream.readObject();
inputStream.close();
} catch (IOException | ClassNotFoundException e) {
e.printStackTrace();
}
}
备注:JDK序列化、反序列化特别特别耗内存。
Java创建实例对象是不是必须要通过构造函数/构造器/构造方法?
创建对象方式 | 是否调用了构造器 |
---|---|
new关键字 | 是 |
Class.newInstance | 是 |
Constructor.newInstance | 是 |
Clone | 否 |
反序列化 | 否 |
答案:Java创建实例对象,并不一定必须要调用构造函数/构造器/构造方法的。