zoukankan      html  css  js  c++  java
  • 第001弹:Java 中创建对象的4种方式

      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()。

      示例代码:

     1 public class MethodNewInstance {
     2 
     3     public static void main(String[] args) throws Exception {
     4 
     5         // 得到类对象
     6         Class<?> clazz = Class.forName("com.gerrard.create.method_newInstance.ObjectToCreate");
     7         // 类对象的 newInstance() 方法,只能调用公有的无参构造器
     8         clazz.newInstance();
     9 
    10         // 得到构造器对象数组(不管是私有还是公有的构造器)
    11         Constructor<?>[] cons = clazz.getDeclaredConstructors();
    12         cons[1].newInstance();
    13         cons[2].newInstance("Gerrard");
    14         // 先打破私有构造器不可访问的限制
    15         cons[0].setAccessible(true);
    16         cons[0].newInstance("Gerrard", "Info");
    17     }
    18 }
    MethodNewInstance

      备注:

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

    3.      使用 clone() 方法

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

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

      示例代码:

     1 public class ObjectToCreate implements Cloneable {
     2 
     3     // 重写 Object 类的 clone() 方法(native 方法)
     4     public ObjectToCreate clone() {
     5         ObjectToCreate obj = null;
     6         try {
     7             obj = (ObjectToCreate) super.clone();
     8         } catch (CloneNotSupportedException e) {
     9             // 没有实现 Cloneable 接口就会抛出这个异常
    10             e.printStackTrace();
    11         }
    12         return obj;
    13     }
    14 }
    ObjectToCreate

      备注:

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

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

      这个方法一共分两步:

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

      序列化:

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

      反序列化:

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

      示例代码:

     1 public class ObjectToCreate implements Serializable {
     2 
     3     private static final long serialVersionUID = 1L;
     4     
     5     private Object writeReplace(){
     6         return new Integer(1);
     7     }
     8     
     9     private Object readResolve(){
    10         return new Double(2);
    11     }
    12 }
    ObjectToCreate
     1 public class MethodSerialable {
     2 
     3     public static void main(String[] args) {
     4 
     5         // 默认路径是项目的根路径
     6         final String fileName = "./file/serialable.txt";
     7 
     8         ObjectToCreate o1 = new ObjectToCreate();
     9 
    10         // 序列化
    11         try (FileOutputStream fos = new FileOutputStream(fileName);
    12                 ObjectOutputStream oos = new ObjectOutputStream(fos);) {
    13             oos.writeObject(o1);
    14         } catch (FileNotFoundException e) {
    15             e.printStackTrace();
    16         } catch (IOException e) {
    17             e.printStackTrace();
    18         }
    19     }
    20 }
    MethodSerialable
     1 public class MethodAntiSerialable {
     2 
     3     public static void main(String[] args) {
     4         // 默认路径是项目的根路径
     5         final String fileName = "./file/serialable.txt";
     6         Object o2 = null;
     7         // 反序列化
     8         try (FileInputStream fio = new FileInputStream(fileName); ObjectInputStream ois = new ObjectInputStream(fio);) {
     9             o2 = ois.readObject();
    10         } catch (FileNotFoundException e) {
    11             e.printStackTrace();
    12         } catch (IOException e) {
    13             e.printStackTrace();
    14         } catch (ClassNotFoundException e) {
    15             e.printStackTrace();
    16         }
    17         System.out.println(o2);
    18     }
    19 }
    MethodAntiSerialable

      备注:

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

    5.      总结

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

  • 相关阅读:
    GB28181 流媒体几种数据传输模式UDP、TCP(被动、主动)
    LiveGBS
    利用ffmpeg采集纯音频推流到LiveQing实现RTMP、FLV、HLS web直播与录像回放
    LiveQing高性能RTMP、FLV、HLS视频流媒体服务器软件如何自定义修改成自己的服务软件名称
    LiveQing
    LiveQing直播流媒体服务解决直播录像存储、直播录像回看、直播录像计划排班配置
    GB28181流媒体服务LiveGBS前端源码(vue+webpack)
    LiveNVR
    华为、科达、海康、大华等厂家摄像头通过非标方式(RTSP)接入流媒体服务实现WEB直播与录像
    LiveNVR RTSP流媒体服器软件通过按需直播降低企业服务带宽
  • 原文地址:https://www.cnblogs.com/jing-an-feng-shao/p/6070627.html
Copyright © 2011-2022 走看看