如何确保无法使用反射从 class 外部创建具有私有构造函数的 class 实例?
How to make sure instance of a class with a private constructor can not be created from outside of the class using Reflection?
我知道可以使用反射创建具有私有构造函数的 class 实例,但是有什么方法可以确保 class 的实例只能在相同 class 使用自己的私有构造函数?
让我们举一个带有私有构造函数的 class 测试的例子。
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
class Test
{
private Test() //private constructor
{
}
}
public class Sample{
public static void main(String args[]) throws ClassNotFoundException, InstantiationException, IllegalAccessException, NoSuchMethodException, SecurityException, IllegalArgumentException, InvocationTargetException
{
Class c=Class.forName("Test"); //specify class name in quotes
//----Accessing private constructor
Constructor con=c.getDeclaredConstructor();
con.setAccessible(true);
Object obj=con.newInstance();
}
}
我的问题是 - 有什么方法可以确保 class 的实例只能在同一个 class 中创建,而不是使用反射或任何其他方法从外部创建?
您在评论中提到的一种方法是使用 Exception,另一种方法是使用 Thread.currentThread()
package app.test;
public class Test19 {
..
private Test19() {
if (Thread.currentThread().getStackTrace()[1].getClassName() == "app.test.Test19") {
// initialize member fields etc.
} else {
throw new IllegalAccessException();
}
}
}
有多种方法可以防止创建 - 但很难判断哪一种适合您的 use-case:
在构造函数中抛出异常
您可以无条件地抛出异常 - 使其(几乎)无法实例化实例 - 或者仅在特定条件下抛出。
一些条件可以是:
- 检查调用者 - 例如使用
StackWalker
。
- 将“秘密”密码传递给构造函数。 JMH does this 例如。
使用 Java 个模块。
由于其他模块无法深入反映到其他命名模块中,Constructor.setAccessible
将无法在您自己的模块之外的 class 上工作。
当然,此限制不适用于您自己的模块 - 但您应该能够控制自己的模块 ;)。
安装一个SecurityManager
.
阻止 Constructor.setAccessible
成功返回。
但是安全管理器已被弃用,因此我不推荐使用它。
注意:大多数解决方案都可以通过某种方式规避。有时可以添加额外的防御措施。但到头来,就成了猫捉老鼠的游戏。
我知道可以使用反射创建具有私有构造函数的 class 实例,但是有什么方法可以确保 class 的实例只能在相同 class 使用自己的私有构造函数?
让我们举一个带有私有构造函数的 class 测试的例子。
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
class Test
{
private Test() //private constructor
{
}
}
public class Sample{
public static void main(String args[]) throws ClassNotFoundException, InstantiationException, IllegalAccessException, NoSuchMethodException, SecurityException, IllegalArgumentException, InvocationTargetException
{
Class c=Class.forName("Test"); //specify class name in quotes
//----Accessing private constructor
Constructor con=c.getDeclaredConstructor();
con.setAccessible(true);
Object obj=con.newInstance();
}
}
我的问题是 - 有什么方法可以确保 class 的实例只能在同一个 class 中创建,而不是使用反射或任何其他方法从外部创建?
您在评论中提到的一种方法是使用 Exception,另一种方法是使用 Thread.currentThread()
package app.test;
public class Test19 {
..
private Test19() {
if (Thread.currentThread().getStackTrace()[1].getClassName() == "app.test.Test19") {
// initialize member fields etc.
} else {
throw new IllegalAccessException();
}
}
}
有多种方法可以防止创建 - 但很难判断哪一种适合您的 use-case:
在构造函数中抛出异常
您可以无条件地抛出异常 - 使其(几乎)无法实例化实例 - 或者仅在特定条件下抛出。
一些条件可以是:
- 检查调用者 - 例如使用
StackWalker
。 - 将“秘密”密码传递给构造函数。 JMH does this 例如。
- 检查调用者 - 例如使用
使用 Java 个模块。
由于其他模块无法深入反映到其他命名模块中,
Constructor.setAccessible
将无法在您自己的模块之外的 class 上工作。
当然,此限制不适用于您自己的模块 - 但您应该能够控制自己的模块 ;)。安装一个
SecurityManager
.阻止
Constructor.setAccessible
成功返回。
但是安全管理器已被弃用,因此我不推荐使用它。
注意:大多数解决方案都可以通过某种方式规避。有时可以添加额外的防御措施。但到头来,就成了猫捉老鼠的游戏。