Java 是面向对象的语言,不可避免的,“对象”这个概念是 Java 语言的核心部分,这里来简单讨论一下在 Java 中创建一般对象的方法。

  总结下来有以下4种创建对象的方法:

  • 使用 new 关键字调用对象的构造器;
  • 使用 Java 反射的 newInstance() 方法;
  • 使用 Object 类的 clone() 方法;
  • 使用对象流 ObjectInputStream 的 readObject() 方法读取序列化对象;

1.      使用 new 关键字

  最常见的 Java 对象的构造方法,通过调用类提供的构造器创建对象。

2.      使用 newInstance() 方法

  Java 反射中有一个 newInstance() 方法,可以创建对象,步骤如下:

  • 获取要创建的类的 Class 对象。
  • 如果只需要调用这个类的访问权限为 public 无参构造器,直接使用 Class 类的实例方法 newInstance()。
  • 获取 Class 对象的构造器对象,通过调用 Class 类的实例方法 getDeclaredConstractors() 来获取构造器对象的数组。(获取所有构造器,无视访问权限的限制,数组顺序按照代码中的顺序决定)
  • 如果调用的构造器是 private 的,需要调用 Constractor 类的父类 AccessibleObject 类的实例方法 setAccessible(true) 来打破访问限制。
  • 使用 Constractor 类的实例方法 newInstance()。

  示例代码:

 public class MethodNewInstance {

     public static void main(String[] args) throws Exception {

         // 得到类对象
Class<?> clazz = Class.forName("com.gerrard.create.method_newInstance.ObjectToCreate");
// 类对象的 newInstance() 方法,只能调用公有的无参构造器
clazz.newInstance(); // 得到构造器对象数组(不管是私有还是公有的构造器)
Constructor<?>[] cons = clazz.getDeclaredConstructors();
cons[1].newInstance();
cons[2].newInstance("Gerrard");
// 先打破私有构造器不可访问的限制
cons[0].setAccessible(true);
cons[0].newInstance("Gerrard", "Info");
}
}

MethodNewInstance

  备注:

  • 获取 Class 对象的方法有3个,此处不多赘述。
  • 获取 Constractor 对象的方法有4个,此处不多赘述。

3.      使用 clone() 方法

  Object 类是所有类的直接或间接父类,Object 类中提供了 实例方法 clone(),在给定对象的基础上,创建一个完全相同的对象。步骤如下:

  • 想要使用 clone() 方法创建对象的类,实现 Cloneable 接口。
  • 在类的内部,重写 Object 类的 clone() 方法。

  示例代码:

 public class ObjectToCreate implements Cloneable {

     // 重写 Object 类的 clone() 方法(native 方法)
public ObjectToCreate clone() {
ObjectToCreate obj = null;
try {
obj = (ObjectToCreate) super.clone();
} catch (CloneNotSupportedException e) {
// 没有实现 Cloneable 接口就会抛出这个异常
e.printStackTrace();
}
return obj;
}
}

ObjectToCreate

  备注:

  • 没有实现 Cloneable 接口,会抛出 CloneNotSupportedException 异常。
  • Object 类提供的 clone() 方法,是浅复制。
  • Object 类的 clone() 方法,是 native 方法。

4.      使用反序列化的 readObject() 方法

  这个方法一共分两步:

  • 将对象序列化,存储到一个文件中。
  • 从文件中反序列化,得到类对象。

  序列化:

  • 想要序列化对象的类,实现 Serializable 接口。
  • 使用文件输出流 FileOutputStream 创建存储序列化之后对象的文件。
  • 使用对象输出流 ObjectOutputStream 的实例方法 writeObject(obj)。
  • 判断类中是否存在,名为writeReplace(),返回类型为 Object 的方法,若有,写入这个方法的返回值;否则,写入 obj 对象。

  反序列化:

  • 使用文件输入流 FileInputStream 找到存储序列化对象的文件。
  • 使用对象输入流 ObjectInputStream 的实例方法 readObject()。
  • 判断类中是否存在,名为readResolve(),返回类型为 Object 的方法,若有读取这个对象;否则,反序列化文件中的对象流。

  示例代码:

 public class ObjectToCreate implements Serializable {

     private static final long serialVersionUID = 1L;

     private Object writeReplace(){
return new Integer(1);
} private Object readResolve(){
return new Double(2);
}
}

ObjectToCreate

 public class MethodSerialable {

     public static void main(String[] args) {

         // 默认路径是项目的根路径
final String fileName = "./file/serialable.txt"; ObjectToCreate o1 = new ObjectToCreate(); // 序列化
try (FileOutputStream fos = new FileOutputStream(fileName);
ObjectOutputStream oos = new ObjectOutputStream(fos);) {
oos.writeObject(o1);
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
}

MethodSerialable

 public class MethodAntiSerialable {

     public static void main(String[] args) {
// 默认路径是项目的根路径
final String fileName = "./file/serialable.txt";
Object o2 = null;
// 反序列化
try (FileInputStream fio = new FileInputStream(fileName); ObjectInputStream ois = new ObjectInputStream(fio);) {
o2 = ois.readObject();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
System.out.println(o2);
}
}

MethodAntiSerialable

  备注:

  • 在类中,writeReplace() 和 readResoleve() 是两个非常特殊的方法,其特征签名需要严格限制:方法名限定,参数个数限定为0,返回类型必须是 Object,不能为 Object 的子类,但是可以抛出不同的异常。访问修饰符没有限制,但一般推荐为 private,防止误操作。其特殊的地方还在于将其设为 private 方法,没有其他方法调用的情况下,编译器不会发出警告。

5.      总结

  Java 创建对象的4种方法:第一种是最常用的;第二种方法深入至源码会指向 sun.reflect.ConstructorAccessor 类,JDK 中似乎没有提供继续深入下去的源码,但是既然是调用构造器的方法,那么与第一种方法一样,创建的对象是存储在堆(Heap)中的;第三种方法是要实现特定的接口才可以使用,而且是通过调用 native 方法,也就是非 Java 代码(很大可能是 C)实现的,也就是说,这个方法产生的对象,可能不会被 GC 回收(个人的想法),因为 GC 是用来回收 Java 代码创造的对象,所以要慎用;第四种方法在序列化的时候,需要实现特定的接口,而在反序列化时就不关心这一点了,它是将对象暂存于其他媒介中,在反序列化的时候将对象存于堆中。

第001弹:Java 中创建对象的4种方式的更多相关文章

  1. Java中创建对象的几种方式

    Java中创建对象的五种方式: 作为java开发者,我们每天创建很多对象,但是我们通常使用依赖注入的方式管理系统,比如:Spring去创建对象,然而这里有很多创建对象的方法:使用New关键字.使用Cl ...

  2. Java中创建对象的五种方式

    我们总是讨论没有对象就去new一个对象,创建对象的方式在我这里变成了根深蒂固的new方式创建,但是其实创建对象的方式还是有很多种的,不单单有new方式创建对象,还有使用反射机制创建对象,使用clone ...

  3. 【转】Java中创建对象的5种方式

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

  4. 第一弹:Java 中创建对象的4种方式

    Java 是面向对象的语言,不可避免的,"对象"这个概念是 Java 语言的核心部分,这里来简单讨论一下在 Java 中创建一般对象的方法. 总结下来有以下4种创建对象的方法: 使 ...

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

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

  6. Java中创建对象的5种方式 &&new关键字和newInstance()方法的区别

    转载:http://www.kuqin.com/shuoit/20160719/352659.html 用最简单的描述来区分new关键字和newInstance()方法的区别:newInstance: ...

  7. Java技术——Java中创建对象的5种方式

    此文为译文 原文连接:https://dzone.com/articles/5-different-ways-to-create-objects-in-java-with-ex 0. 前言 作为Jav ...

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

    Java中有5种创建对象的方式,下面给出它们的例子还有它们的字节码 Employee类: class Employee implements Cloneable, Serializable { pri ...

  9. Java中创建对象的5种方法

    将会列举5种方法去创建 Java 对象,以及他们如何与构造函数交互,并且会有介绍如何去使用这些方法的示例. 作为一个 Java 开发人员,我们每天都会创建大量的 Java 对象,但是我们通常会使用依赖 ...

随机推荐

  1. 卓越管理的秘密(Behind Closed Doors)

    或许提到本书甚至本书的作者Johanna Rothman我们会感到些许陌生,那么提起她的另一本获得素有软件界奥斯卡之称的Jolt生产效率大奖的名著<项目管理修炼之道>,会不会惊讶的发现,原 ...

  2. Ubuntu下手动安装NextCloud

    安装环境:阿里云VPS Ubuntu 16.04   一. 安装Apache2 sudo apt-get install apache2 安装完成后,浏览器访问http://your ip/,出现It ...

  3. vue validate多表单验证思考 之前写过一个里外层,现在觉得不合适,应该平行的写,然后都给ret,最后判断ret 再做出反应,这样整体表单的所有验证就都报验证,然后最后提交的时候把组件内的对象合并到总的对象,再提交

    vue validate多表单验证思考 之前写过一个里外层,现在觉得不合适,应该平行的写,然后都给ret,最后判断ret 再做出反应,这样整体表单的所有验证就都报验证,然后最后提交的时候把组件内的对象 ...

  4. OO作业第二单元总结

    目录 一.设计策略 1 2 3 二.程序分析 1 2 3 S.O.L.I.D分析 三.Bug分析 1 2 3 四.互测策略 五.心得体会 一.设计策略 1 第一次完成的是一个傻瓜电梯,简单来说,就是来 ...

  5. FastText算法

    转载自: https://www.cnblogs.com/huangyc/p/9768872.html 0. 目录 1. 前言 2. FastText原理 2.1 模型架构 2.2 层次SoftMax ...

  6. lua 分割字符串

    -- 参数:待分割的字符串,分割字符 -- 返回:子串表.(含有空串) function split(str, split_char) local sub_str_tab = {} while tru ...

  7. LLDB详解

    LLDB的Xcode默认的调试器,它与LLVM编译器一起,带给我们更丰富的流程控制和数据检测的调试功能.平时用Xcode运行程序,实际走的都是LLDB.熟练使用LLDB,可以让你debug事半功倍 L ...

  8. websocket 踩坑记录

    ssh execute command error: can't connect str to butes ssh 发送下一次指令回传的是上一次指令的结果 ssh 始终停留在 root 目录内 ssh ...

  9. k8s的pod生命周期

    pod的生命周期: 1.init container 2.main contianer (1) post start hook :容器启动后做什么操作(可以命令查看kubectl explain po ...

  10. .Net Core依赖注入中TryAddEnumerable 和TryAddTransient方法的区别

    .Net Core依赖注入添加的每个服务,最终都会转换为一个ServiceDescriptor的实例,ServiceDescriptor包含以下属性: Lifetime:服务的生命周期(Singlet ...