2024-03-09
版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。 本文链接:https://www.skjava.com/mianshi/baodian/detail/1245115059

实例对象的创建,我详细小伙伴们一定熟悉得不能再熟悉了,那你知道 Java 中创建对象到底有多少种方法吗?这里大明哥将介绍 6 中方式来创建一个 Java 对象:

  1. 使用 new 关键字
  2. 使用 Class 类的newInstance()
  3. 使用 clone() 方法
  4. 使用 Constructor 类的 newInstance()
  5. 使用对象的反序列化
  6. 使用 ObjectFactory 或其他工厂方法

使用 new 关键字

这是最常见也是最简单的创建对象的方式,当使用 new 关键字时,Java 为对象分配内存,并调用类的构造函数初始化对象。

User user = new User("大明哥",18);

这种方式是我们大多数标准对象创建的方式。

使用 Class 类的newInstance()

每个类都是 Class 类的实例,我们可以通过 Class 对象的 newInstance() 来创建类的实例,这通常是通过反射来实现的。

User user = User.class.newInstance();

需要注意的是Class类的newInstance() 使用的是类的public 的无参构造器,也就是说如果我们创建的对象没有无参构造器,则会报如下错误:

Exception in thread "main" java.lang.InstantiationException: com.xxxx.User
  at java.base/java.lang.Class.newInstance(Class.java:719)
  at com.xxxx.feature.MainTest.main(MainTest.java:5)
Caused by: java.lang.NoSuchMethodException: com.xxxx.User.<init>()
  at java.base/java.lang.Class.getConstructor0(Class.java:3761)
  at java.base/java.lang.Class.newInstance(Class.java:706)
  ... 1 more

当我们需要在运行时动态地创建对象,且只知道类名时,这种方式非常有用。但要注意,它只能调用无参构造函数。还有需要注意的是,该方法是 Java 9 后被标注为过时了

使用 clone() 方法

如果一个类实现了 Cloneable 接口,那么它可以通过调用对象的 clone() 方法来创建一个新的对象副本。要使用 clone() 我们必须先实现Cloneable接口并复写Object的****clone()

public class User implements Cloneable{
    private String name;

    private Integer age;

    @Override
    public User clone() throws CloneNotSupportedException {
        return (User) super.clone();
    }
}

使用 clone() 克隆一个对象:

User user1 = new User("大明哥",18);
User user2 = user1.clone();

System.out.println("user1="+user1);
System.out.println("user2="+user2);
System.out.println(user1 == user2);

执行结果:

user1=User(name=大明哥, age=18)
user2=User(name=大明哥, age=18)
false

完成了内容的克隆,而且我们发现 user2 是一个全新的对象。

使用 Constructor 类的 newInstance()

这种方式同样是一种反射机制。可以通过获取类的 Constructor 对象,然后调用其 newInstance() 方法来创建实例。这种方式与Class类的newInstance()方法很像,但是比它强大多了:

  1. 构造函数不再必须是无参的
  2. 构造函数不再必须是 public

我们 User 对象如下:

public class User{
    private String name;

    private Integer age;
    
    // private 的无参构造函数
    private User(){
        this.name = "大明哥1号";
        this.age = 35;
    }

    // public 的有参构造函数
    public User(String name,Integer age) {
        this.name = name;
        this.age = age;
    }
}

验证

    public static void main(String[] args) throws Exception {
        // 返回 public 和非public 的构造函数,也包括 private 的
        Constructor<?>[] declaredConstructors = User.class.getDeclaredConstructors();
        // 只返回 public 的构造函数
        Constructor<?>[] constructors = User.class.getConstructors();

        Constructor<?> noArgsConstructor = declaredConstructors[0];
        Constructor<?> haveArgsConstructor = declaredConstructors[1];

        noArgsConstructor.setAccessible(true); // 非public的构造必须设置true才能用于创建实例
        Object user1 = noArgsConstructor.newInstance();
        Object user2 = declaredConstructors[1].newInstance("大明哥", 18);

        System.out.println(user1);
        System.out.println(user2);
    }

运行结果:

User(name=大明哥1号, age=35)
User(name=大明哥, age=18)

使用对象的反序列化

对象在序列化过程中被写入一个流中,之后可以从该流中反序列化来创建对象。在这个过程中,并不调用任何构造函数。

ObjectInputStream in = new ObjectInputStream(new FileInputStream("data.obj"));
User user = (User) in.readObject();

关于 Java 序列化文章,大明哥用了四篇文章详细阐述了 Java 的序列化:

  1. Java 序列化之深入理解 Java 序列化和反序列化
  2. Java 序列化之教你破坏单例模式
  3. Java 序列化之 Hessian
  4. Java 序列化之 ProtoBuf

使用 ObjectFactory 或其他工厂方法

工厂方法是一种创建对象的设计模式,它使用一个专门的工厂类来创建对象实例。

User user = UserFactory.createUser();

这种方法在需要对对象创建进行更细粒度控制的场景中非常有用,例如实现依赖注入或在创建对象时应用某些特定的配置。

阅读全文