我所设计的绝大部分类,我都会关注它们的不可变性。要想获得不可变性需要这样做:
使用构造方法来初始化所有的属性。
这些属性没有setter方法。
然而,这样的设计使得测试更加复杂甚至无法测试。为了能进行测试,你还需要一个public的无参构造方法。
其它需要无参构造方法的情况包括:
序列化对象的反序列化。
子类中没有调用父类的构造函数。
其它
下面是它的一些解决方案。
1. 实现一个public的无参构造方法
最简单的方式就是创建一个public的无参构造函数了,然后添加一个大的醒目的警告信息让开发人员别去使用这个方法。你可以想像得到,这种方法虽然简单,但是它无法强制约束什么,因为你得依赖开发人员的自觉性来遵循你的规则(或者更多地是他们得能在第一时间看到这段警告文档——这得赌一下了)。
这么做最大的限制就是你得能够修改类的代码。
2. 实现一个包可见的无参构造方法
测试时一个常见的方法就是将类的private方法的可见性改成包可见的,这样的话测试类只要和它们在一个包下面就可以进行测试了。同样的方法也适用于我们这个例子中:实现一个包可见的无参构造方法。
这需要测试类和这个创建了构造函数的类在同一个包底下。和情况1类似,你也得去修改类的代码。
3. 使用Unsafe来实现
JDK像一座埋藏的宝藏:它包含许多隐藏的闪亮的特性;sun.misc.Unsafe就是其中之一。当然了,正如它的名字和所在包所暗示的那样,它的使用是非常不推荐的。Unsafe提供了一个allocateInstance的方法来创建新的实例,而不用调用任何构造函数,也就是不需要调用任何初始化程序。
注意Unsafe只有实例方法,而它仅有的一个构造函数是私有的。。但它提供了一个私有的单例属性。要想获取这个属性的引用,你需要用到一点反射的逻辑,以及一个宽松的安全管理器(SecurityManager)。
Field field = Unsafe.class.getDeclaredField("theUnsafe");
field.setAccessible(true);
Unsafe unsafe = (Unsafe) field.get(null);
java.sql.Date date = (java.sql.Date) unsafe.allocateInstance(java.sql.Date.class);
这个方法最大的限制在在:
依赖公共API以外的类
使用反射来访问私有属性
只在Oracle的HotSpot JVM上可用
需要设置一个足够宽松的安全管理器
4. Objenesis
Objenesis是一个旨在不使用构造函数创建新的实例的一个框架。它基于Unsafe提供了一个抽象层。Objenesis在不同的JVM上也同样可用,包括不同版本的OpenJDK, Oracle的JRokkit和Dalvik(也就是Android的),它使用了不同的策略来适配不同的JVM以及不同的版本的组合。
上述的代码可以替换成这面这个:
Objenesis objenesis = new ObjenesisStd();
ObjectInstantiator instantiator = objenesis.getInstantiatorOf(java.sql.Date.class);
java.sql.Date date = (java.sql.Date) instantiator.newInstance();
System.out.println(date);
在Oracle的HotSpot上运行这段代码同样需要一个宽松的安全管理器,因为Objenesis使用的也是上面的Unsafe类。然而,不同的JVM可能会有不同的要求,这些Objenesis都替你处理了。
结论
尽管并不常见也没有专门的要求,但有时候还是需要不使用构造函数来创建实例的。万一碰上这样的情况,Objenesis框架为你提供了一个可移植的抽象层来实现这个,你只需要多增加一个额外的依赖就可以了。
原创文章转载请注明出处:
http://it.deepinmind.com
英文原文链接
分享到:
相关推荐
了解和熟练使用构造方法是Java面向对象编程的基础,下面将详细阐述Java构造方法的相关知识点。 一、构造方法的作用 构造方法的主要任务是在创建对象时设置对象的初始状态,为对象成员变量赋值。当一个类被实例化时...
Java构造方法是面向对象编程中的一个关键概念,用于初始化新创建的对象。在Java类中,构造方法是一个特殊的方法,它的名字必须与类名完全相同,没有返回类型,甚至不包括void关键字。当我们创建一个类的新实例时,...
### Java构造方法详解 #### 一、构造方法基础概念 构造方法是Java中一种特殊的方法,主要用于初始化新创建的对象。每个类至少有一个构造方法。如果程序员没有显式地定义构造方法,Java编译器会自动为类添加一个无...
Java 构造方法是编程语言中的一个重要概念,特别是在面向对象编程中,如Java。它们是类的特殊方法,用于初始化新创建的对象。当一个对象被创建时,构造方法会被自动调用,为对象的成员变量赋值,进行必要的设置,...
不过,如果构造方法创建了大量的临时对象或者资源,开发者需要确保在构造完成后及时释放这些资源,以避免内存泄漏。 总的来说,Java中带有不同构造方法的程序内存分析涉及构造方法的选择、内存的分配(包括栈和堆)...
Java构造方法 Java构造方法是一种特殊的方法,它是一个与类同名且没有返回值类型的方法。对象的创建就是通过构造方法来完成,其功能主要是完成对象的初始化。当类实例化一个对象时会自动调用构造方法。构造方法和...
下面详细解析Java构造方法的特性和使用方法。 构造方法的特性: 1. 方法名与类名相同:构造方法的名字必须与类名完全相同,这是Java语法规定的一部分,便于编译器识别并自动调用构造方法。 2. 构造方法无返回类型:...
Java构造方法解析 ...总结起来,Java构造方法是初始化类实例的关键工具,它们允许我们在创建对象时定制初始化过程,确保对象的正确状态。理解并熟练运用构造方法及其特性对于编写高效、可维护的Java代码至关重要。
- 在Java中,**创建对象**是使用类的模板来实例化一个具体的实例的过程。 - **创建对象**通常通过`new`关键字实现,例如: ```java Student student = new Student(); ``` - **对象**在内存中的存储状态分为两个...
在这个特定的程序中,我们看到了一个关于Java继承的实例,它演示了子类对象初始化时涉及的各个步骤,包括构造方法、初始化值、父类构造方法以及父类的初始化值。 首先,我们有一个名为`Parent`的父类,它有两个实例...
在Java编程语言中,子类继承父类时,构造方法起着至关重要的作用。它们用于初始化对象,并在创建新实例时执行特定的设置步骤。理解如何在子类中使用构造方法是掌握面向对象编程的关键部分。本文将深入探讨Java子类...
在Java中,每个类至少有一个构造方法,定义类时通常要定义一个构造方法以辅助创建类的实例。构造方法可以用来初始化与每个对象有关的变量。在Java中,构造方法是与类名称相同的公开的方法成员。如果用户没有显式定义...
在Java中,构造者模式通过隔离实例化过程和对象的构建过程,使得创建对象的过程更加灵活,同时也提高了代码的可读性和可维护性。下面我们将深入探讨这个模式的概念、结构以及如何在Java中实现。 1. **模式概念** ...
* 继承树中的从最高层开始的实例语句块{}、然后对应的构造函数、以及构造函数中调用的方法 * (如果是重写即子类将父类的实例方法重写类,则调用子类的,如果是隐藏即方法则父类中声明为静态方法,则调用父类本身的...
“深入理解Java构造器机理” 在 Java 编程语言中,构造器是一种特殊的方法,用于初始化对象的创建。它是 Java 类中最重要的一个概念。下面将深入讨论构造器的机理、执行顺序、作用及与其他概念的区别。 一、构造器...
但是,抽象类可以拥有构造方法,这是因为构造方法主要用于初始化对象,而不是创建对象。当子类实例化时,会调用抽象类中的构造方法进行初始化。 在Java中,实例化抽象类的一种常见方式是通过子类继承并实现抽象方法...
在给定的文件中,我们看到了一个名为`Circle`的类,它代表了一个圆,并提供了多种构造方法来创建圆的对象。此外,还提供了设置坐标、半径以及计算周长和面积的方法。下面,我们将深入探讨这个`Circle`类的实现细节...
Java构造方法是面向对象编程中一个至关...本文档中的实例详细解释了Java构造方法的使用,对于初学者来说是一份很好的参考资料。如果在学习过程中遇到任何问题,欢迎继续提问,我们将竭诚为您解答。感谢您对我们的支持!
Java中的构造方法是类的重要组成部分,它在对象创建过程中扮演着关键角色,主要负责对象的初始化。构造方法具有以下几个显著特点: 1. **与类名相同**:构造方法的方法名必须与类的名称完全一致。例如,如果有一个...
Java语言是一种面向对象的编程语言,在面向对象编程中,对象的创建是通过构造方法来实现的。构造方法是一种特殊的成员方法,它的名称与类名完全相同,并且没有返回值类型,连void都没有。构造方法在对象实例化的过程...