生成对象的四种方式
(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对象生成对象。
相关推荐
这些方法包括常规的`new`操作符、反射、克隆以及反序列化。以下是对这些方法的详细解释: 1. **正常创建**: 使用`new`操作符是最基本的创建对象的方式,直接调用类的构造函数传递参数。例如: ```java public ...
- 反序列化:从磁盘或网络读取序列化的对象数据,通过ObjectInputStream的readObject()方法恢复对象。 5. String、StringBuffer和StringBuilder的区别 - String是不可变对象,创建新的字符串会生成新的对象,不...
综上所述,这些知识点覆盖了Java高级工程师面试中常见的几个领域,包括内存管理、垃圾回收机制、IO流处理、并发编程、锁机制、反射机制、类加载过程、对象序列化以及分布式唯一ID生成策略等。掌握这些核心概念和技术...
- **序列化**:实现`Serializable`接口,然后通过序列化和反序列化来创建对象副本。 - **工厂模式**:定义一个创建产品对象但不需要指定具体类的接口。 #### 12. 类加载器中JDK API与Classpath和Web-INF中class的...
3. transient 变量修饰符,表示该变量在对象序列化时不会被持久化。 4. volatile 变量修饰符,表示该变量在多线程环境中始终保持最新的值。 六、反射机制 Java 反射机制是在运行状态中,对于任意一个类,都能够...
通过序列化和反序列化,Java可以创建对象的副本,而无需调用构造函数。首先,确保类实现了`Serializable`接口,然后可以反序列化已保存的对象。例如: ```java ObjectInputStream in = new ObjectInputStream(new ...
- Java序列化用于将对象转换为字节流,便于存储和网络传输,需要实现Serializable接口。 - 动态代理可以创建在运行时生成的代理类,常用于拦截方法调用,例如AOP(面向切面编程)。 7. **对象拷贝**: - 克隆...
- **反序列化**:将序列化的对象恢复为对象实例。 #### 29. 类加载器的加载方式 - **Bootstrap ClassLoader**:负责加载核心类库。 - **Extension ClassLoader**:加载扩展类库。 - **Application ClassLoader**:...
- **序列化**:探讨对象序列化的实现方式。 - **循环、条件和概率**: - **foreach**:解释foreach循环的用法。 - **递归与回朔**:介绍递归算法及回朔法的基本原理。 - **条件语言**:讲解if-else等条件语句的...
例如,可以通过序列化和反序列化来实现深拷贝,或者使用工厂模式结合反射来创建新对象。 - 使用`clone()`方法创建对象可能并不总是比`new`关键字快,只有在构造新对象代价较大时,使用`clone()`才有性能优势。因此,...
(序列化是将对象转换为字节流,用于网络传输或持久化) Java 异常 16. `throw` 和 `throws` 的区别?(`throw` 用于抛出异常,`throws` 用于声明异常) 17. `final`、`finally`、`finalize` 有什么区别?(`final...
反射创建类实例的三种方式包括:通过Class的newInstance方法、通过Constructor类、通过clone方法。 #### 13. Java中的单例模式实现 单例模式是一种常见的设计模式,用于确保某个类只有一个实例,并提供一个全局访问...
实现克隆通常需要实现`Cloneable`接口并重写`Object`的`clone()`方法,或者使用序列化技术。 Java中的多态性允许一个接口或超类引用多种类型的实例,提供了一种灵活性。多态性可以通过接口多态、继承多态和类型强制...
14. **类的加载方式**:通过`new`关键字创建对象,通过反射`Class.forName()`加载并实例化,通过`clone()`复制对象,以及通过序列化和反序列化恢复对象状态。 15. **线程创建**:有两种方式,一是继承`Thread`类并...
58. 序列化用于持久化对象,当需要在网络间传输或存储对象时使用。 59. 动态代理是在运行时创建代理对象,常用于AOP(面向切面编程)。 五、对象拷贝 62. 实现对象克隆可以通过实现`Cloneable`接口并重写`clone()`...
58. **Java序列化**:Java序列化是将对象状态转换为可保存或传输的格式的过程,用于对象的持久化。 59. **动态代理**:动态代理是指在运行时动态生成代理类和代理对象来实现某些功能。 60. **动态代理的实现**:...
22. **创建实例的方式**:通过`clone`、反射、序列化等方式。 23. **垃圾回收算法**:包括标记-清除算法、复制算法、标记-整理算法等。 24. **线程池实现**:使用`ExecutorService`接口和`ThreadPoolExecutor`实现。...
可序列化类型可以方便地将对象状态转换为持久化的格式。 ```csharp [Serializable] public class MyClass { public string Name { get; set; } } ``` #### 26. 对需要排序的对象实现 `IComparable` 和 `IComparer`...
5. **序列化协议**:如JSON、Protobuf、Thrift等,选择合适的序列化协议取决于数据结构复杂度、传输效率等因素。 6. **Netty的零拷贝技术**:通过直接缓冲区等技术减少数据在不同内存区域之间的拷贝次数,提高网络...