复制构造函数和构造函数_和构造函数一起玩

复制构造函数和构造函数

不可变性是设计大多数类时要照顾的一个属性。 实现不变性要求:

  • 构造函数初始化所有属性
  • 这些属性没有设置器

但是,这种设计阻止或使测试变得更加复杂。 为了允许(或简化)测试,需要一个公共的无参数构造函数。

需要使用无参数构造函数的其他用例包括:

  • 序列化对象的反序列化
  • 子类化,没有父类的构造函数调用
  • 等等

有两种解决方案。

1.编写一个公共的无参数构造函数

最简单的方法是创建一个公共的无参数构造函数,然后添加一个明亮的Javadoc以警告开发人员不要使用它。 您可以想象,在这种情况下,简单并不意味着它会执行任何操作,因为您基本上是依靠开发人员愿意遵循指令的(或者甚至更多地取决于他们阅读指令的能力-一个冒险的赌注)。

但是,最大的限制是您需要能够更改类代码。

2.编写包可见的无参数构造函数

用于测试的常见方法是将类私有方法的可见性更改为包可见的,因此可以通过位于同一包中的测试类对其进行测试。 在我们的案例中可以使用相同的方法:编写一个包可见的无参数构造函数。

这要求测试类与已创建构造函数的类位于同一包中。 与上述情况1一样,您还需要更改类代码。

3.不安全地玩

JDK就像是一个隐藏的宝藏:它包含许多隐藏和闪亮的功能; sun.misc.Unsafe类就是其中之一。 当然,正如其名称和包装所暗示的那样,强烈建议不要使用它。 Unsafe提供了allocateInstance(Class<?>)方法来创建新实例, 而无需调用任何构造函数或初始化程序。

注意Unsafe仅具有实例方法,其唯一的构造函数为private ...,但提供了private singleton属性。 要获得对此属性的引用,需要一点反射的黑魔法以及宽松的安全管理器(默认情况下)。

Fieldfield=Unsafe.class.getDeclaredField("theUnsafe");
field.setAccessible(true);
Unsafeunsafe=(Unsafe)field.get(null);
java.sql.Datedate=(java.sql.Date)unsafe.allocateInstance(java.sql.Date.class);
System.out.println(date);

这种方法的主要限制包括:

  • 依赖公共API之外的类
  • 使用反射访问私有字段
  • 仅在Oracle的HotSpot JVM中可用
  • 设置足够宽松的安全管理器

4.肥胖症

Objenesis是一个框架,其唯一目标是在不调用构造函数的情况下创建新实例。 它在Oracle HotSpot JVM中的Unsafe类上提供了一个抽象层。 通过使用适用于每个JVM /版本对的策略,Objenesis还可以在许多不同版本的不同JVM(包括OpenJDK,Oracle的JRockit和Dalvik( Android))上工作。

上面的代码可以替换为以下代码:

Objenesisobjenesis=newObjenesisStd();
ObjectInstantiatorinstantiator=objenesis.getInstantiatorOf(java.sql.Date.class);
java.sql.Datedate=(java.sql.Date)instantiator.newInstance();
System.out.println(date);

在Oracle的HotSpot上运行此代码仍然需要宽松的安全管理器,因为Objenesis将使用上述Unsafe类。 但是,此类要求因JVM而异,由Objenesis处理。

结论

尽管这是非常少见且专门的要求,但有时可能需要创建没有构造函数调用的实例。 在这种情况下,Objenesis框架提供了一个可移植的抽象方法,以增加单个依赖项为代价。

翻译自: https://blog.frankel.ch/playing-with-constructors/

复制构造函数和构造函数

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值