反射:为什么会有像setAccessible()这样的方法?

4

我想知道,为什么发明Java的人会写像setAccessible(boolean flag)这样的方法呢?它使得访问修饰符(尤其是private)变得无用,并且无法保护字段、方法和构造函数免受访问。请看下面这个简单的例子:

public class BankAccount
{
    private double balance = 100.0;

    public boolean withdrawCash(double cash)
    {
        if(cash <= balance)
        {
            balance -= cash;
            System.out.println("You have withdrawn " + cash + " dollars! The new balance is: " + balance);
            return true;
        }
        else System.out.println("Sorry, your balance (" + balance + ") is less than what you have requested (" + cash + ")!");
        return false;
    }
}

import java.lang.reflect.Field;

public class Test
{
    public static void main(String[] args) throws Exception
    {
        BankAccount myAccount = new BankAccount();
        myAccount.withdrawCash(150);

        Field f = BankAccount.class.getDeclaredFields()[0];
        f.setAccessible(true);
        f.set(myAccount, 1000000); // I am a millionaire now ;)

        myAccount.withdrawCash(500000);
    }
}

OUTPUT:

Sorry, your balance (100.0) is less than what you have requested
(150.0)! You have withdrawn 500000.0 dollars! The new balance is: 500000.0


5
访问修饰符并不是真正的安全功能,因为在当前的操作系统中,您始终可以访问进程内存中的任何内存。 - Matthias Meid
5
因为它通常很有用。它们还提供了防止使用此功能的能力,通过运行一个配置了适当“SecurityManager”的程序。 - Alan Stokes
3
@Mudu -- 这完全不适用于Java。对于C++是正确的,但Java代码不能访问运行时未授权的任何内存。SecurityManager实例可以仲裁特定的代码是否可以访问私有方法。 - Ernest Friedman-Hill
3
@delnan -- 当然可以。但这并不意味着Java中的访问控制不是与Java代码相关的安全特性--它绝对是,并且整个Java安全模型都依赖于它。将成员设置为私有,再配合强制执行访问控制的SecurityManager,绝对可以防止JVM中的任何Java代码访问该成员。当然,本地代码或JVM外部的代码可能会做到这一点:但安全模型的目的不是防止计算机用户访问内存,而是防止不受信任的Java代码这样做。 - Ernest Friedman-Hill
2
在 C++ 中,它作为一个简单的预处理器 define private public。访问修饰符在 C++ 中也不是“无用”的。 - Tom Hawtin - tackline
显示剩余2条评论
2个回答

6

因为有一些代码是可信的,也就是说,如果一个本地应用程序想要这样做,也许没什么大不了的。但是对于 不受信任的代码,比如小程序、Web启动应用程序、RMI stubs 或任何其他下载的代码,都需要一个SecurityManager的控制,在这里(通常基于策略文件),有机会说“抱歉,查理”,并拒绝 setAccessible() 请求。


+1 很酷!有没有创建SecurityManager的教程或指南可供遵循? - Eng.Fouad
当然。这里是一个可以开始的地方。 - Ernest Friedman-Hill
2
请注意,从Java 2开始,很少需要子类化 SecurityManager。(也就是说,虽然可能有一些你想要使用它来做的事情,但配置是通过 ProtectionDomain/策略机制处理的。) - Tom Hawtin - tackline

2

Java程序一旦发布,任何人都可以反向工程或反编译它,所以如果有人真的非常想要,他们可能能够访问你的“私人”信息。

但是,您可以禁止在运行时中访问您的内容。例如,在使用他人代码之前,您可以禁用反射、文件访问等。

搜索ClassLoader和Security Manager以了解更多信息。 这里有一些相关信息。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接