java常见生成对象的五种方式

daanshenghuo      2022-05-05     648

关键词:

作为Java开发者,我们每天创建很多对象,但我们通常使用依赖管理系统,比如Spring去创建对象。然而这里有很多创建对象的方法,我们会在这篇文章中学到。

Java中有5种创建对象的方式,下面给出它们的例子还有它们的字节码。

技术图片

如果你运行了末尾的的程序,你会发现方法1,2,3用构造函数创建对象,方法4,5没有调用构造函数。

1、使用new关键字

这是最常见也是最简单的创建对象的方式了。通过这种方式,我们可以调用任意的构造函数(无参的和带参数的)。

Employee emp1 = new Employee();
0: new           #19          // class org/programming/mitra/exercises/Employee
3: dup
4: invokespecial #21          // Method org/programming/mitra/exercises/Employee."":()V

2、使用Class类的newInstance方法

我们也可以使用Class类的newInstance方法创建对象。这个newInstance方法调用无参的构造函数创建对象。

我们可以通过下面方式调用newInstance方法创建对象:

Employee emp2 = (Employee)
Class.forName("org.programming.mitra.exercises.Employee").newInstance();

或者

Employee emp2 = Employee.class.newInstance();
51: invokevirtual    #70    // Method java/lang/Class.newInstance:()Ljava/lang/Object;

3、使用Constructor类的newInstance方法

和Class类的newInstance方法很像, java.lang.reflect.Constructor类里也有一个newInstance方法可以创建对象。

我们可以通过这个newInstance方法调用有参数的和私有的构造函数。大家也可以看下《instanceof、isInstance、isAssignableFrom》这篇文章。

Constructor<Employee> constructor = Employee.class.getConstructor();
Employee emp3 = constructor.newInstance();
111: invokevirtual  #80  // Method java/lang/reflect/Constructor.newInstance:([Ljava/lang/Object;)Ljava/lang/Object;

newInstance方法内部调用Constructor的newInstance方法。这也是众多框架,如Spring、Hibernate、Struts等使用后者的原因。

4、使用clone方法

无论何时我们调用一个对象的clone方法,jvm就会创建一个新的对象,将前面对象的内容全部拷贝进去。用clone方法创建对象并不会调用任何构造函数。

要使用clone方法,我们需要先实现Cloneable接口并实现其定义的clone方法。

Employee emp4 = (Employee) emp3.clone();’
162: invokevirtual #87  // Method org/programming/mitra/exercises/Employee.clone ()Ljava/lang/Object;

5、使用反序列化

当我们序列化和反序列化一个对象,jvm会给我们创建一个单独的对象。在反序列化时,jvm创建对象并不会调用任何构造函数。推荐大家看《关于Java序列化你应该知道的一切》这篇文章

为了反序列化一个对象,我们需要让我们的类实现Serializable接口。

ObjectInputStream in = new ObjectInputStream(new FileInputStream("data.obj"));
Employee emp5 = (Employee) in.readObject();
261: invokevirtual  #118
// Method java/io/ObjectInputStream.readObject:()Ljava/lang/Object;

我们从上面的字节码片段可以看到,除了第1个方法,其他4个方法全都转变为invokevirtual(创建对象的直接方法),第一个方法转变为两个调用,new和invokespecial(构造函数调用)。

例子

让我们看一看为下面这个Employee类创建对象:

class Employee implements Cloneable, Serializable {
   private static final long serialVersionUID = 1L;
   private String name;
   public Employee() {
       System.out.println("Employee Constructor Called...");
   }
   public String getName() {
       return name;
   }
   public void setName(String name) {
       this.name = name;
   }
   @Override
   public int hashCode() {
       final int prime = 31;
       int result = 1;
       result = prime * result + ((name == null) ? 0 : name.hashCode());
       return result;
   }
   @Override
   public boolean equals(Object obj) {
       if (this == obj)
           return true;
       if (obj == null)
           return false;
       if (getClass() != obj.getClass())
           return false;
       Employee other = (Employee) obj;
       if (name == null) {
           if (other.name != null)
               return false;
       } else if (!name.equals(other.name))
           return false;
       return true;
   }
   @Override
   public String toString() {
       return "Employee [name=" + name + "]";
   }
   @Override
   public Object clone() {
       Object obj = null;
       try {
           obj = super.clone();
       } catch (CloneNotSupportedException e) {
           e.printStackTrace();
       }
       return obj;
   }
}

下面的Java程序中,我们将用5种方式创建Employee对象。你可以从GitHub找到这些代码。

public class ObjectCreation {
   public static void main(String... args) throws Exception {
       // By using new keyword
       Employee emp1 = new Employee();
       emp1.setName("Naresh");
       System.out.println(emp1 + ", hashcode : " + emp1.hashCode());
       // By using Class class‘s newInstance() method
       Employee emp2 = (Employee) Class.forName("org.programming.mitra.exercises.Employee")
                              .newInstance();
       // Or we can simply do this
       // Employee emp2 = Employee.class.newInstance();
       emp2.setName("Rishi");
       System.out.println(emp2 + ", hashcode : " + emp2.hashCode());
       // By using Constructor class‘s newInstance() method
       Constructor<Employee> constructor = Employee.class.getConstructor();
       Employee emp3 = constructor.newInstance();
       emp3.setName("Yogesh");
       System.out.println(emp3 + ", hashcode : " + emp3.hashCode());
       // By using clone() method
       Employee emp4 = (Employee) emp3.clone();
       emp4.setName("Atul");
       System.out.println(emp4 + ", hashcode : " + emp4.hashCode());
       // By using Deserialization
       // Serialization
       ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream("data.obj"));
       out.writeObject(emp4);
       out.close();
       //Deserialization
       ObjectInputStream in = new ObjectInputStream(new FileInputStream("data.obj"));
       Employee emp5 = (Employee) in.readObject();
       in.close();
       emp5.setName("Akash");
       System.out.println(emp5 + ", hashcode : " + emp5.hashCode());
   }
}

程序会输出:

public class ObjectCreation {
Employee Constructor Called...
Employee [name=Naresh], hashcode : -1968815046
Employee Constructor Called...
Employee [name=Rishi], hashcode : 78970652
Employee Constructor Called...
Employee [name=Yogesh], hashcode : -1641292792
Employee [name=Atul], hashcode : 2051657
Employee [name=Akash], hashcode : 63313419

你还知道别的吗?

常见的五种单例模式实现方式

--主要:   饿汉式(线程安全,调用效率高,但是不能延时加载)   懒汉式(线程安全,调用效率低,但是可以延时加载)--其他:   双重检测锁式(由于JVM底层内部模型原因,偶尔会出现问题... 查看详情

六:数据存储的五种方式

...  2.偏好设置    3.NSKeydeArchiver归档(存储自定义对象) 一、plist(XML属性列表归档)只能存取对象类文件第一种方式:(四个文件夹都可以取出路径)1//获取沙盒路径2NSString*home=NSHomeDirectory();3//获取documents的路径两种方 查看详情

list去重的五种方式

...用steam的distinct()方法返回一个由不同数据组成的流,通过对象的equals()方法进行比较。收集所有区域数据List使用Collectors.toList()。Java程序,用于在不使用Set的情况下从java中的arraylist中删除重复项。输出结果5.双重for循环去重 查看详情

css的五种定位方式

CSS中一共有五种定位: position:static;默认值 position:absolute;绝对定位 position:relative;相对对定位 position:fixed;固定定位 position:sticky;粘性定位其中,粘性定位是CSS3新增加的兼容性比较差定位的作用: 在正常情况下,可... 查看详情

spring事务配置的五种方式

Spring事务配置的五种方式   前段时间对Spring的事务配置做了比较深入的研究,在此之间对Spring的事务配置虽说也配置过,但是一直没有一个清楚的认识。通过这次的学习发觉Spring的事务配置只要把思路理清,还是比较... 查看详情

carson带你学java:解决生产者消费者问题的五种实现方式(代码片段)

...t类里的两个方法,所有Object子类都可使用这2个方法//对象的监视器对锁对象的锁定(也就是代码中的lock对象),注意是调用锁对象的wait()/nofity()publicclassTestprivatestaticIntegercount=0;privatefinalIntegerFULL=5;privatestati... 查看详情

carson带你学java:解决生产者消费者问题的五种实现方式(代码片段)

...t类里的两个方法,所有Object子类都可使用这2个方法//对象的监视器对锁对象的锁定(也就是代码中的lock对象),注意是调用锁对象的wait()/nofity()publicclassTestprivatestaticIntegercount=0;privatefinalIntegerFULL=5;privatestati... 查看详情

andriod中数据存储的五种方式

数据存储在开发中是使用最频繁的,在这里主要介绍Android平台中实现数据存储的5种方式,分别是:1使用SharedPreferences存储数据2文件存储数据3SQLite数据库存储数据4使用ContentProvider存储数据5网络存储数据 下面将为大家一一详... 查看详情

j2ee常见的五种模式是啥

工厂模式:客户类和工厂类分开。消费者任何时候需要某种产品,只需向工厂请求即可。消费者无须修改就可以接纳新产品。缺点是当产品修改时,工厂类也要做相应的修改。如:如何创建及如何向客户端提供。建造模式:将产... 查看详情

css清除浮动的五种方式

清除浮动是一件功德无量的事情23333这里记录一下清除浮动的多种方式 *首先要明确的是,为什么要清除浮动?A影响其他元素定位父盒子高度为0,子盒子全部浮动、定位,子盒子不会撑开父盒子,下面的元素会到子盒子的下... 查看详情

list去除重复数据的五种方式,舒服~(代码片段)

以下介绍五种-不同的方法去除Java中ArrayList中的重复数据1.使用LinkedHashSet删除arraylist中的重复数据LinkedHashSet是在一个ArrayList删除重复数据的最佳方法。LinkedHashSet在内部完成两件事:删除重复数据保持添加到其中的数据的顺序... 查看详情

list去除重复数据的五种方式(代码片段)

List在Java开发中用得非常多,数据处理方面,咱们经常需要对重复数据去重。以下介绍五种-不同的方法去除Java中ArrayList中的重复数据1、使用LinkedHashSet删除arraylist中的重复数据LinkedHashSet是在一个ArrayList删除重复数据的最... 查看详情

关于线程池的五种实现方式,中软国际java机试(代码片段)

在这里,还有创建一个只有单个线程的可以定时执行线程池(Executors.newSingleThreadScheduledExecutor())这些都是上面的线程池扩展开来了,不详细介绍了。3介绍线程池的七大参数上面我们也说到了线程池有五种实现方... 查看详情

javascript常见的五种数组去重(转载)

JavaScript的数组去重问题在许多面试中都会遇到,现在做个总结    先来建立一个数组vararr=[1,2,3,3,2,‘我‘,‘我‘,34,‘我的‘,NaN,NaN]; ▓▓▓▓▓▓第一种    思路:建立一个临时数组,用for循环去依次判断arr中的... 查看详情

读取属性配置文件的五种方式(代码片段)

读取属性配置文件的五种方式读取属性配置文件的五种方式读取属性配置的示例属性配置文件方式一:使用注解@Value读取属性配置方式二:使用注解@ConfigurationProperties读取属性配置方式三:使用注解@PropertySou... 查看详情

字符串拼接的五种方式

参考技术A 虽然字符串是不可变的,但是还是可以通过新建字符串的方式来进行字符串的拼接。常用的字符串拼接方式有五种,分别是使用+、使用concat、使用StringBuilder、使用StringBuffer以及使用StringUtils.join。具体的使用方式... 查看详情

hibernate缓存中@cache的cacheconcurrencystrategy的五种缓存方式

使用方法缓存的注解写法如下,加在Entity的java类上:@Cache(usage=CacheConcurrencyStrategy.NONSTRICT_READ_WRITE)五种情况及说明1、CacheConcurrencyStrategy.NONE简介说明:不适用,默认2、CacheConcurrencyStrategy.READ_ONLY简介说明:只读模式,在此模式下... 查看详情

java线程的五种基本状态是什么?

Java线程具有五种基本状态1、新建状态(New):当线程对象对创建后,即进入了新建状态,如:Threadt=newMyThread();2、就绪状态(Runnable):当调用线程对象的start()方法(t.start();ÿ 查看详情