java创建对象的五种方式

  • 一、使用new关键字
  • 二、使用clone方法
  • 三、使用反序列化
  • 四、使用反射
  • 五、使用Unsafe

一、使用new关键字

如 User user=new User();
执行这条语句,jvm做了什么?

  1. 首先在方法区的常量池中查看是否有new
    后面参数(也就是类名)的符号引用,并检查是否有类的加载信息也就是是否被加载解析和初始化过。如果已经加载过了就不在加载,否则执行类的加载全过程
  2. 加载完类后,大致做了如下三件事:
    a、给实例分配内存
    b、调用构造函数,初始化成员字段
    c、user对象指向分配的内存空间
    注意:new操作不是原子操作,b和c的顺序可能会调换

二、使用clone方法

当我们调用一个对象的clone方法,jvm就会创建一个新的对象,将前面对象的内容全部拷贝进去。用clone方法创建对象并不会调用任何构造函数。因为Object 类的 clone 方法的 原理是从内存中(堆内存)以二进制流的方式进行拷贝,重新分配一个内存块,那构造函数没有被执行也是非常正常的了.
使用clone方法创建对象的实例:

public class CloneTest implements Cloneable{private String name; private int age;public String getName() {return name;}public void setName(String name) {this.name = name;}public int getAge() {return age;}public void setAge(int age) {this.age = age;}public CloneTest(String name, int age) {super();this.name = name;this.age = age;}public static void main(String[] args) {try {CloneTest cloneTest = new CloneTest("酸辣汤",18);//todoCloneTest copyClone = (CloneTest) cloneTest.clone();System.out.println("newclone:"+cloneTest.getName());System.out.println("copyClone:"+copyClone.getName());} catch (CloneNotSupportedException e) {e.printStackTrace();}}}

输出:

newclone:酸辣汤copyClone:酸辣汤

注意:

1.clone是Object中的方法,Cloneable是一个标识接口,它表明这个类的对象是可以拷贝的。如果没有实现Cloneable接口却调用了clone()函数将抛出异常2.Object.clone()未做同步处理,线程不安全3.clone()有深拷贝和浅拷贝两种方式

三、使用反序列化

序列化是干什么的?
简单说就是为了保存在内存中的各种对象的状态(也就是实例变量,不是方法),并且可以把保存的对象状态再读出来。虽然你可以用你自 己的各种各样的方法来保存object states,但是Java给你提供一种应该比你自己好的保存对象状态的机制,那就是序列化。一句话概括:序列化是指将对象的状态信息转换为可以存储或传输的形式的过程。
java中要序列化的类必要实现Serializable接口
什么情况下需要序列化
a)当你想把的内存中的对象状态保存到一个文件中或者数据库中时候;
b)当你想用套接字在网络上传送对象的时候;
c)当你想通过RMI(远程方法调用)传输对象的时候;
使用反序列化创建对象实例:
1.对象要实现Serializable接口

import java.io.Serializable; public class Person implements Serializable { int age; int height; String name; public Person(String name, int age, int height){ this.name = name; this.age = age; this.height = height; } }

2、序列化与反序列化

import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; import java.io.ObjectInputStream; import java.io.ObjectOutputStream; public class MyTestSer { /*** Java对象的序列化与反序列化*/ public static void main(String[] args) { Person zhangsan = new Person("zhangsan", 30, 170); Person lisi = new Person("lisi", 35, 175); Person wangwu = new Person("wangwu", 28, 178); try { //需要一个文件输出流和对象输出流;文件输出流用于将字节输出到文件,对象输出流用于将对象输出为字节 ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream("person.ser")); out.writeObject(zhangsan); out.writeObject(lisi); out.writeObject(wangwu); } catch (IOException e) { e.printStackTrace(); } try { ObjectInputStream in = new ObjectInputStream(new FileInputStream("person.ser")); Person one = (Person) in.readObject(); Person two = (Person) in.readObject(); Person three = (Person) in.readObject(); System.out.println("name:"+one.name + " age:"+one.age + " height:"+one.height); System.out.println("name:"+two.name + " age:"+two.age + " height:"+two.height); System.out.println("name:"+three.name + " age:"+three.age + " height:"+three.height); } catch (Exception e) { e.printStackTrace(); } } }

运行结果:

name:zhangsan age:30 height:170  //todoname:lisi age:35 height:175 name:wangwu age:28 height:178

android中的场景
1.组件间(如activity间)的对象传递 (实现Parcelable或Serializable接口)
2.使用 Binder进行进程间的通讯传递的对象必须实现Parcelable接口

Serializable是java的序列化接口,使用简单但是开销比较大,序列化和反序列化都涉及到大量的I/O操作,效率相对较低。Parcelable是Android提供的序列化方法,更适用于Android平台,效率很高,但是使用起来比较麻烦.Parcelable主要用在内存序列化上,序列化存储设备或将序列化后的对象通过网络传输建议使用Serializable。

四、使用反射

通过反射来创建类对象的实例,有两个步骤:

  1. 首先我们得拿到类对象的Class

如何获取? 有三种方式(反射章节会详细讲解)

  • 类.class,如Person.class
  • 对象.getClass()
  • Class.forName(“类全路径”)

2.通过反射创建类对象的实例对象

在拿到类对象的Class后,就可以通过Java的反射机制来创建类对象的实例对象了,主要分为两种方式:

  • Class.newInstance()
  • 调用类对象的构造方法

举个栗子:
首先准备一个Person的类:

public class Person {private String name;private int age;public Person() {}public Person(String name, int age) {this.name = name;this.age = age;}public String getName() {return name;}public void setName(String name) {this.name = name;}public int getAge() {return age;}public void setAge(int age) {this.age = age;}@Overridepublic String toString() {return "Person{" +"name='" + name + '\'' +", age=" + age +'}';}}

使用Class.newInstance()创建对象:

public class ClassNewInstance {public static void main(String[] args) throws IllegalAccessException, InstantiationException {Person person = Person.class.newInstance();person.setAge(18);person.setName("酸辣汤");System.out.println(person);}}

运行结果:

Person{name='酸辣汤', age=18}

注意 :newInstance创建对象实例的时候会调用无参的构造函数,所以必需确保类中有无参数的可见的构造函数,否则将会抛出异常。

调用类对象的构造方法——Constructor
Constructor是Java反射机制中的构造函数对象,获取该对象的方法有以下几种:

  • Class.getConstructors():获取类对象的所有可见的构造函数
  • Class.getConstructor(Class… paramTypes):获取指定的构造函数

获取类对象所有的构造方法并遍历:

public class ConstructorInstance {public static void main(String[] args) {Class p = Person.class;for(Constructor constructor : p.getConstructors()){System.out.println(constructor);}}}

运行结果:

public com.eft.reflect.Person()public com.eft.reflect.Person(java.lang.String,int)

获取指定的构造方法
通过Class.getConstructor(Class… paramTypes)即可获取类对象指定的构造方法,其中paramTypes为参数类型的Class可变参数,当不传paramTypes时,获取的构造方法即为默认的构造方法。

public class ConstructorInstance {public static void main(String[] args) throws Exception {Class p = Person.class;Constructor constructor1 = p.getConstructor();//获取默认的构造方法Constructor constructor2 = p.getConstructor(String.class,int.class);//获取指定的构造方法System.out.println(constructor1);System.out.println(constructor2);}}

运行结果:

public com.eft.reflect.Person()public com.eft.reflect.Person(java.lang.String,int)

通过构造方法创建对象
Constructor对象中有一个方法newInstance(Object … initargs),这里的initargs即为要传给构造方法的参数,如Person(String,int),通过其对应的Constructor实例,调用newInstance方法并传入相应的参数,即可通过Person(String,int)来创建类对象的实例对象。
测试代码如下:

public class ConstructorInstance {public static void main(String[] args) throws Exception {Class p = Person.class;Constructor constructor = p.getConstructor(String.class,int.class);Person person = (Person) constructor.newInstance("酸辣汤",18);System.out.println(person); }}

运行结果:

Person{name='酸辣汤', age=18}

五、使用Unsafe

sun.misc.Unsafe中提供allocateInstance方法,仅通过Class对象就可以创建此类的实例对象,而且不需要调用其构造函数、初始化代码、JVM安全检查等。它抑制修饰符检测,也就是即使构造器是private修饰的也能通过此方法实例化,只需提类对象即可创建相应的对象。由于这种特性,allocateInstance在java.lang.invoke、Objenesis(提供绕过类构造器的对象生成方式)、Gson(反序列化时用到)中都有相应的应用。
直接看例子

package cn.eft.llj.unsafe;
import java.lang.reflect.Field;import sun.misc.Unsafe;
public class Demo9 {static Unsafe unsafe;static {//获取Unsafe对象try {Field field = Unsafe.class.getDeclaredField("theUnsafe");field.setAccessible(true);unsafe = (Unsafe) field.get(null);} catch (Exception e) {e.printStackTrace();}}static class C1 {private String name;private C1() {System.out.println("C1 default constructor!");}private C1(String name) {this.name = name;System.out.println("C1 有参 constructor!");}public void test(){System.out.println("执行了test方法");}}public static void main(String[] args) throws InstantiationException {C1 c= (C1) unsafe.allocateInstance(C1.class);System.out.println(c);c.test();}
}

输出结果:

cn.eft.llj.unsafe.Demo9$C1@6bc7c054执行了test方法

java创建对象的五种方式相关推荐

  1. Java 创建对象的 6 种方式,总有一种适合你

    创建对象的 6 种方式 假设有个女朋友类: @Data @NoArgsConstructor @AllArgsConstructor class GirlFriend {private String ...

  2. java clone方法_干货满满:Java中创建对象的五种方式详解

    通常来说,对象具有状态和行为,变量用来表明对象的状态,方法表明对象所具有的行为. 作为Java开发者,我们通常都是使用依赖管理系统,比如Spring去创建Java对象,但使用管理系统创建对象并不是唯一 ...

  3. java创建对象的几种方式

    前言,今日面试被问到创建对象是否一定要通过构造器,当时回答错误,查询分析后记录. 创建对象的几种方式: 第一种,也是最常用.一直接触到的方法:通过new 创建对象.这种方法需要用到构造器   Demo ...

  4. 【JDBC篇】Java连接数据库的五种方式,及什么是URL?

    目录 URL介绍: 连接数据库的五种方式 方式一: 方式二: 方式三: 方式四: 方式五:(最终版) URL介绍: JDBC URL 用于标识一个被注册的驱动程序,驱动程序管理器通过这个 URL 选择 ...

  5. Java基础之创建对象的五种方式

    第一种:直接new 效率最高 Person person1 = new Person("person1",22); 第二种:Class类的newInstance 可以new 无参的 ...

  6. Java创建对象的四种方式

    1. new 2. clone 3. 通过反射newInstance 4. 反序列化 5. String s = "abc"(这个是比较特殊的) 以String类为例 String ...

  7. Java创建对象的4种方式

    使用new关键字 通过new关键字直接在堆内存上创建对象,这样很方便的调用对象的有参和无参的构造函数. Student stu1 = new Student("lihua"); C ...

  8. Java创建对象的5种方式

    说明 Java有5种方式来创建对象: 使用 new 关键字(最常用):         ObjectName obj = new ObjectName(); 使用反射的Class类的newInstan ...

  9. java创建对象_java 创建对象的五种方式

    通过 Class 对象的 getConstructor 可以获取 java.lang.reflect.Constructor 对象 Constructor 对象用来描述类的构造方法,通过给 getCo ...

最新文章

  1. LeetCode: 929. Unique Email Addresses
  2. 微软研究员在ImageNet计算机视觉识别挑战中实现里程碑式突破
  3. U3D打apk包的常见错误
  4. stand up meeting 12/8/2015
  5. 链表题目--1 删除链表中所有等于val的值
  6. ethtool用法 linux_Linux命令之Ethtool用法详解
  7. 设计模式学习笔记——单例(Singleton)模式
  8. table中强制不换行
  9. 【GNN框架系列】DGL第一讲:使用Deep Graph Library实现GNN进行节点分类
  10. python删除文本框内容_js清除文本框内容
  11. Laravel之数据库操作与Eloquent模型使用总结
  12. 生信格式 | bigwig,bw (基因组浏览器绘制)
  13. LVM管理体系(二)通过扩展LV扩展逻辑卷(操作步骤)
  14. 安卓开发中许多应用到的资源
  15. 百度工程师带你探秘C++内存管理(理论篇)
  16. numpy高维矩阵reshape
  17. RANSAC(随机采样一致算法)原理及openCV代码实现
  18. nc网页版java插件下载_spring-nc
  19. 微电子所等在二维材料异质结构光电器件研究中取得进展
  20. c语言中的牛顿割线法

热门文章

  1. 日本某地发生了一件谋杀案
  2. 栽培员工,让他强大到可以离开
  3. 【语音增强论文解读 02】DCCRN: Deep Complex Convolution Recurrent Network for Phase-AwareSpeech Enhancement
  4. 最全面的微信小程序渲染图片的方式
  5. antd Upload组件使用,出现闪动问题
  6. Nature重磅!在机器人骨架上首次生成人类肌腱细胞
  7. 编程之美之一摞烙饼的排序1
  8. Element el-icon 图标组件详解
  9. 手机web端唤醒qq客户端以及电脑web端唤醒qq客户端
  10. java角度_Java Math.toDegrees()弧度转换成角度