Java 创建对象的几种方式

概述

Java 作为面向对象程序开发语言,对象的创建和回收尤为重要。JVM 垃圾收集器完成了对象回收的工作,而对象创建的操作需要程序员自行开发,本篇博客我就来简单介绍几种 Java 常见创建对象的几种方式。


类结构

本篇博客所有对象创建都基于如下类结构:

class Temp implements Serializable, Cloneable {

    private static final long serialVersionUID = -5143483767663524643L;
    private int id;
    private String str;
    
    public Temp() {
    }
    
    public Temp(int id, String str) {
        this.id = id;
        this.str = str;
    }
    
    @Override
    protected Object clone() throws CloneNotSupportedException {
        Temp result = (Temp) super.clone();
        result.str = new String(this.str);
        return result;
    }
}

如上所示,SerializableCloneable 都是为了方便不同方式创建对象,在用到时会特别说明。


new 关键字

new 关键字是平时开发过程中最常用的对象创建手段,一般在代码中这样表示:

Temp temp1 = new Temp();
Temp temp2 = new Temp(1,"xiaoming");

通过 new 关键字创建对象也是所有方式中最简单的,只需按照上述代码执行即可。其中 temp1 是参数未赋值的对象,temp2 是已经赋值的对象,根据不同的构造方法,我们可以初始化不同的属性。


clone() 克隆

clone() 方法是 Object 类方法,所有类都可以通过继承重写该方法。该方法在实际开发过程中用的较少,但使用起来相当方便,一般在代码中这样表示:

Temp temp1 = new Temp(1,"xiaoming");
try {
    Temp temp2 = (Temp)temp1.clone();
} catch (CloneNotSupportedException e) {
    e.printStackTrace();
}

clone() 方法的返回值类型是 Object 类型,因此需要强转为 Temp 类型。需要注意的一点是,clone() 分深克隆和浅克隆,关于这块的内容可以 点击这里 查看我之前的博客。


对象序列化与反序列化

对象序列化是指将内存中的对象信息序列化为流文件,这样就可以在磁盘中长期保存。既然对象可以序列化为流文件,那么流文件当然也可以反序列化为对象,也就是说我们可以通过反序列的形式创建新的对象。

Java 代码中序列化和反序列化通过实现 Serializable 接口实现,在代码中一般这样表示:

SerializableTest s = new SerializableTest();
s.setId(1);
s.setName("liming");

// 序列化过程
ObjectOutputStream oo = new ObjectOutputStream(new FileOutputStream("D://1.txt"));
oo.writeObject(s);
oo.close();

// 反序列化过程
ObjectInputStream oi = new ObjectInputStream(new FileInputStream("D://1.txt"));
SerializableTest ss = (SerializableTest) oi.readObject();
oi.close();

反序列化会生成一个全新的对象,其中它的引用类型变量也是新的对象。关于序列化和反序列化详细内容可以 点击这里 参考我之前的博客。


反射

反射是指通过 Class 类对象或者 java.lang.reflect 包下的反射类动态创建对象。一般反射在框架中使用较多,Java 使用最广泛的 Spring 框架中就使用了反射。

下面我给出通过反射创建对象的两种方案:

Class<?> type = Temp.class;
// 使用 Class 类
Temp temp1 = (Temp) type.newInstance();
Field field1 = type.getDeclaredField("id");
field1.setAccessible(true);
Field field2 = type.getDeclaredField("str");
field2.setAccessible(true);
field1.set(temp1, 1);
field2.set(temp1, "xiaoming");

// 使用 Constructor 类
Constructor constructor = type.getConstructor(int.class, String.class);
Temp temp2 = (Temp) constructor.newInstance(1, "小明");

反射同样会常见全新对象,它是通过类的 Class 对象在 jvm 运行期间创建的。关于反射的详细知识可以 点击这里 查看我之前的博客。


UnSafe 类

顾名思义,UnSafe 类是一个不安全的,它不能通过 new 直接创建,必须借助上面我们提到的反射创建。其中该类主要用在 CAS 操作中,CAS 中所有方法底层都是通过调用 UnSafe 类方法实现的。

UnSafe 类不安全的主要原因是由于它直接操作内存,因此一旦出现问题后果不堪设想。下面我给出通过 UnSafe 类创建对象的示例代码:

Field field = Unsafe.class.getDeclaredField("theUnsafe");
field.setAccessible(true);
Unsafe unsafe = (Unsafe) field.get(null);

Class<?> type = Temp.class;
Temp temp = (Temp) unsafe.allocateInstance(Temp.class);
Field field1 = type.getDeclaredField("id");
Field field2 = type.getDeclaredField("str");
unsafe.putInt(temp, unsafe.objectFieldOffset(field1), 1);
unsafe.putObject(temp, unsafe.objectFieldOffset(field2), "xiaoming");

一般情况下除特殊情况,慎用这个类,一旦操作失误就可能导致内存层面的错误,内存层面的错误通过修改代码完全无法修复,只能重启应用。关于 CAS 和 UnSafe 类更详细的知识可以 点击这里 查看我之前的博客。


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值