想看更多请移步我的个人博客:Java中创建对象的5种方式 - 猿馆
方法 | 是否调用构造方法 |
---|---|
new关键字 | 调用了构造方法 |
Class类的newInstance()方法 | 调用了构造方法 |
Constructor类的newInstance()方法 | 调用了构造方法 |
clone() | 没有调用构造方法 |
反序列化 | 没有调用构造方法 |
1.使用new关键字
最常见 、 最简单 , 可调用任意的构造方法 (无参的和带参数的)
Example example = new Example(); // 调用无参构造方法 创建Example对象。
Example example = new Example("我是example "); // 调用有参构造方法 创建Example对象。
2.使用Class类的newInstance()方法
只能调用无参的构造方法 创建对象、
弱类型的,效率比使用new低、
Class class = Class.forName("com.pojo.Example"); // 首先得到 目标类的 Class类对象
Example example = class.newInstance(); // 调用Class类的 newInstance()方法,会调用目标类的默认构造方法,并返回一个目标对象
// 或者:
Example example = Example.class.newInstance(); //直接在类名后跟 .class,获取Class对象,再跟 .newInstance(),返回目标对象。
3.使用Constructor类的newInstance()方法
调用有参数的 和 私有的 构造方法
Example example = Example.class.getConstructor().newInstance(); //注意是getConstructor(),不是getConstructors()
上面是调用无参public构造方法,下面是调用有参public 和 有参非public 构造方法:
Constructor constructor2 = Example.class.getConstructor(String.class); // 有String类型参数的public构造方法
Example example = constructor2.newInstance("sfasaffe");
Constructor constructor3 = Example.class.getConstructor(String.class); // 有String类型参数的非public构造方法
constructor3 .setAccessible(true); // 要设置访问许可,不然没有权限访问private构造方法,会抛出异常
Example example = constructor3.newInstance("调用私有构造方法");
上面的两种newInstance()方法都抛出了异常,所以通过这种方法创建对象要进行异常处理。
这两种newInstance()被称为反射。
4.使用clone()方法
无论何时我们调用一个对象的clone方法,jvm就会创建一个新的对象,将前面对象的内容全部拷贝进去。用clone方法创建对象并不会调用任何构造方法 。
Example example = new Example ();
Example example2 = example.clone();
条件:实现Cloneable接口并实现其定义的clone()方法
注意,Java默认的clone()方法是浅拷贝。
所谓浅拷贝,也就是对于数值类型(基本数据类型,如int、float…包括String)的成员变量,是拷贝值,对于对象类型(如数组、object…)的成员变量,是拷贝引用。
也就是说,如果A对象有一个 List 类型的成员变量,那么它的拷贝对象B修改了自己List的值,原来A对象的 List 的值也会发生改变。
解决办法:在重写的clone()方法中手动 拷贝 对象类型 的成员变量
如:
public Example clone() throws CloneNotSupportedException{
Example example = (Example)super.clone();
example.arrayList = (ArrayList<String>) this.arrayList.clone(); // 注意,这里 手动拷贝的对象,必须也要实现Cloneable接口
return example;
}
5.使用反序列化
当我们序列化和反序列化一个对象,jvm会给我们创建一个单独的对象。在反序列化时,jvm创建对象并不会调用任何构造方法 。
为了反序列化一个对象,我们需要让我们的类实现Serializable接口
ObjectInputStream in = new ObjectInputStream(new FileInputStream("data.object"));
Example example = (Example ) in.readObject();