`

生成对象-new、clone、序列化、反射

阅读更多

生成对象的四种方式

(1)通过new生成对象。这是我们最常用的方式,生成的对象置于内存中的堆空间中,堆空间的构成如下图所示

一个old区,一个eden区,两个survivor区。通常生成的对象会置于Eden区中,但是当生成的对象过大,超过jvm设置的一个值的时候,也会将该对象直接置于old区中。具体的关于创建对象时,jvm对于内存分配以及内存回收的相关知识,这里也就不再累述了。
 (2)利用clone复制对象,完成生成对象。

利用clone,在内存中进行数据块的拷贝,复制已有的对象,也是生成对象的一种方式。前提是类实现Cloneable接口,Cloneable接口没有任何方法,是一个空接口,也可以称这样的接口为标志接口,只有实现了该接口,才会支持clone操作。有的人也许会问了,java中的对象都有一个默认的父类Object。Object中有一个clone方法,为什么还必须要实现Cloneable接口呢,这就是cloneable接口这个标志接口的意义,只有实现了这个接口才能实现复制操作,因为jvm在复制对象的时候,会检查对象的类是否实现了Cloneable这个接口,如果没有实现,则会报CloneNotSupportedException异常。类似这样的接口还有Serializable接口、RandomAccess接口等。还有值得一提的是在执行clone操作的时候,不会调用构造函数。还有clone操作还会面临深拷贝和浅拷贝的问题。关于这方面的问题,网上有很多的相关知识了,不再累述了。由于通过复制操作得到对象不需要调用构造函数,只是内存中的数据块的拷贝,那是不是拷贝对象的效率是不是一定会比new的时候的快。答案:不是。显然jvm的开发者也意识到通过new方式来生成对象占据了开发者生成对象的绝大部分,所以对于利用new操作生成对象进行了优化。例如

public class Person implements Cloneable {

	private String name;
	
	private String address;
	
	public Person(String name,String address){
		this.name=name;
		this.address=address;
	}
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}
	public String getAddress() {
		return address;
	}
	public void setAddress(String address) {
		this.address = address;
	}
	
	public Object clone(){
		try {
			return super.clone();
		} catch (CloneNotSupportedException e) {
			throw new Error();
		}
	}
	public static void main(String[] args) throws Throwable {
		final int maxLoops=100000;
		long start=System.nanoTime();
		Person person = new Person("iteye", "iteye");
		for(int i=0;i<maxLoops;i++){
			person.clone();
		}
		long mid=System.nanoTime();
		System.out.println("利用clone生成10万个对象花的时间是:"+(mid-start)+"ns");
		for(int i=0;i<maxLoops;i++){
			new Person("iteye", "iteye");
		}
		System.out.println("利用clone生成10万个对象花的时间是:"+(System.nanoTime()-mid)+"ns");
	}
}

 得到的结果是:

利用clone生成10万个对象花的时间是:16695411ns

利用new生成10万个对象花的时间是:1668425ns

很显然还是new的效率高一些。但是这也并不是说复制的方式没有用。在构建一些复杂对象的时候,或者通过构造函数构造对象比较麻烦的时候,可以考虑这种方式。

(3)通过序列化生成对象

通过序列化方式生成对象是通过在内存中,将对象写入字节流,再从字节流中将其读取出来,这样就可以重建一个新对象,通过这种方式生成的对象与母对象之间不存在引用共享的问题,也就是相当于深拷贝了一个对象。

public class CloneUtils{
	
	public static <T extends Serializable> T clone(T obj){
		T cloneObj=null;
		
		try{
			ByteArrayOutputStream baos= new ByteArrayOutputStream();
			ObjectOutputStream oos= new ObjectOutputStream(baos);
			oos.writeObject(obj);
			oos.close();
			
			ByteArrayInputStream bais= new ByteArrayInputStream(baos.toByteArray());
			ObjectInputStream ois= new ObjectInputStream(bais);
			
			cloneObj=(T)ois.readObject();
			ois.close();
		}
		catch (Exception e) {
			e.printStackTrace();
		}
		return cloneObj;
	}
}

 以上代码提供了一个可以利用序列化方式生成对象的工具类。当然序列化本身的知识还有很多,读者请自行查阅相关资料。(注:Serializable也是接口,在第二种生成对象的方式中提到过)

 (4)可以通过反射,利用class对象生成对象。

  • 大小: 30.5 KB
3
3
分享到:
评论
4 楼 MrLee23 2013-07-05  
深拷贝的思路不错,值得借鉴
3 楼 raph_java 2013-07-05  
我再去研究下JDK动态代理是不是也算?
2 楼 ddlgyq 2013-07-04  
steafler 写道
还有一种就是反射也可创建对象

正解
1 楼 steafler 2013-07-04  
还有一种就是反射也可创建对象

相关推荐

    在Java中优雅而简洁的创建对象的方法总结

    这些方法包括常规的`new`操作符、反射、克隆以及反序列化。以下是对这些方法的详细解释: 1. **正常创建**: 使用`new`操作符是最基本的创建对象的方式,直接调用类的构造函数传递参数。例如: ```java public ...

    JAVA后端开发面试题

    - 反序列化:从磁盘或网络读取序列化的对象数据,通过ObjectInputStream的readObject()方法恢复对象。 5. String、StringBuffer和StringBuilder的区别 - String是不可变对象,创建新的字符串会生成新的对象,不...

    java高级工程师面试题

    综上所述,这些知识点覆盖了Java高级工程师面试中常见的几个领域,包括内存管理、垃圾回收机制、IO流处理、并发编程、锁机制、反射机制、类加载过程、对象序列化以及分布式唯一ID生成策略等。掌握这些核心概念和技术...

    华为IBM的java面试题

    - **序列化**:实现`Serializable`接口,然后通过序列化和反序列化来创建对象副本。 - **工厂模式**:定义一个创建产品对象但不需要指定具体类的接口。 #### 12. 类加载器中JDK API与Classpath和Web-INF中class的...

    java面试100题

    3. transient 变量修饰符,表示该变量在对象序列化时不会被持久化。 4. volatile 变量修饰符,表示该变量在多线程环境中始终保持最新的值。 六、反射机制 Java 反射机制是在运行状态中,对于任意一个类,都能够...

    Java中五种不同方法的创建对象

    通过序列化和反序列化,Java可以创建对象的副本,而无需调用构造函数。首先,确保类实现了`Serializable`接口,然后可以反序列化已保存的对象。例如: ```java ObjectInputStream in = new ObjectInputStream(new ...

    (版)2019Java面试题,常见面试题及答案汇总 (2).pdf

    - Java序列化用于将对象转换为字节流,便于存储和网络传输,需要实现Serializable接口。 - 动态代理可以创建在运行时生成的代理类,常用于拦截方法调用,例如AOP(面向切面编程)。 7. **对象拷贝**: - 克隆...

    最新Java面试大全

    - **反序列化**:将序列化的对象恢复为对象实例。 #### 29. 类加载器的加载方式 - **Bootstrap ClassLoader**:负责加载核心类库。 - **Extension ClassLoader**:加载扩展类库。 - **Application ClassLoader**:...

    NET程序员面试宝典

    - **序列化**:探讨对象序列化的实现方式。 - **循环、条件和概率**: - **foreach**:解释foreach循环的用法。 - **递归与回朔**:介绍递归算法及回朔法的基本原理。 - **条件语言**:讲解if-else等条件语句的...

    Android编程设计模式之原型模式实例详解

    例如,可以通过序列化和反序列化来实现深拷贝,或者使用工厂模式结合反射来创建新对象。 - 使用`clone()`方法创建对象可能并不总是比`new`关键字快,只有在构造新对象代价较大时,使用`clone()`才有性能优势。因此,...

    200个Java经典面试题总结附带答案.docx

    (序列化是将对象转换为字节流,用于网络传输或持久化) Java 异常 16. `throw` 和 `throws` 的区别?(`throw` 用于抛出异常,`throws` 用于声明异常) 17. `final`、`finally`、`finalize` 有什么区别?(`final...

    史上最全阿里巴巴 JAVA 面试题总览(书签完整版)

    反射创建类实例的三种方式包括:通过Class的newInstance方法、通过Constructor类、通过clone方法。 #### 13. Java中的单例模式实现 单例模式是一种常见的设计模式,用于确保某个类只有一个实例,并提供一个全局访问...

    java最新面试题50道精讲

    实现克隆通常需要实现`Cloneable`接口并重写`Object`的`clone()`方法,或者使用序列化技术。 Java中的多态性允许一个接口或超类引用多种类型的实例,提供了一种灵活性。多态性可以通过接口多态、继承多态和类型强制...

    java面试传问题

    14. **类的加载方式**:通过`new`关键字创建对象,通过反射`Class.forName()`加载并实例化,通过`clone()`复制对象,以及通过序列化和反序列化恢复对象状态。 15. **线程创建**:有两种方式,一是继承`Thread`类并...

    Java最常见的面试题208道.pdf

    58. 序列化用于持久化对象,当需要在网络间传输或存储对象时使用。 59. 动态代理是在运行时创建代理对象,常用于AOP(面向切面编程)。 五、对象拷贝 62. 实现对象克隆可以通过实现`Cloneable`接口并重写`clone()`...

    1剑盛二面准备试题.txt1剑盛二面准备试题.txt

    58. **Java序列化**:Java序列化是将对象状态转换为可保存或传输的格式的过程,用于对象的持久化。 59. **动态代理**:动态代理是指在运行时动态生成代理类和代理对象来实现某些功能。 60. **动态代理的实现**:...

    JAVA笔试题,面试题(吐血推荐)

    22. **创建实例的方式**:通过`clone`、反射、序列化等方式。 23. **垃圾回收算法**:包括标记-清除算法、复制算法、标记-整理算法等。 24. **线程池实现**:使用`ExecutorService`接口和`ThreadPoolExecutor`实现。...

    提高C#编程水平的50个要点

    可序列化类型可以方便地将对象状态转换为持久化的格式。 ```csharp [Serializable] public class MyClass { public string Name { get; set; } } ``` #### 26. 对需要排序的对象实现 `IComparable` 和 `IComparer`...

    java程序员面试大纲错过了金三银四你还要错过2018吗.docx

    5. **序列化协议**:如JSON、Protobuf、Thrift等,选择合适的序列化协议取决于数据结构复杂度、传输效率等因素。 6. **Netty的零拷贝技术**:通过直接缓冲区等技术减少数据在不同内存区域之间的拷贝次数,提高网络...

Global site tag (gtag.js) - Google Analytics