92

在 Java 中,private访问修饰符被认为是安全的,因为它在类之外是不可见的。那么外界也不知道这种方法。

但我认为Java反射可以用来打破这个规则。考虑以下情况:

public class ProtectedPrivacy{

  private String getInfo(){
     return "confidential"; 
  }

}  

现在从另一个班级我会得到信息:

public class BreakPrivacy{

   public static void main(String[] args) throws Exception {
       ProtectedPrivacy protectedPrivacy = new ProtectedPrivacy();
       Method method = protectedPrivacy.getClass().getDeclaredMethod("getInfo", null);
       method.setAccessible(true);
       Object result = method.invoke(protectedPrivacy);
       System.out.println(result.toString());
   }
} 

此时我只是认为私有方法仍然是安全的,因为要执行上述操作,我们必须知道方法名称。但是,如果包含由其他人编写的私有方法的类,我们将无法看到这些方法。

但是由于下面的代码行,我的观点变得无效。

Method method[] = new ProtectedPrivacy().getClass().getDeclaredMethods();

现在这method[]包含了上面需要做的所有事情。我的问题是,有没有办法避免使用 Java 反射做这种事情?

我从Java 文档中引用了一些观点来澄清我的问题。

选择访问级别的提示:

如果其他程序员使用您的类,您要确保不会发生误用错误。访问级别可以帮助您做到这一点。使用对特定成员有意义的最严格的访问级别。除非您有充分的理由不这样做,否则请使用私有。

4

7 回答 7

95

这取决于您所说的“安全”是什么意思。如果您使用允许此类事情的安全管理器运行,那么是的,您可以通过反射做各种令人讨厌的事情。但是在那种环境中,库可能只是被修改以使方法公开。

在这样的环境中,访问控制实际上是“建议”——您实际上是在信任代码可以很好地运行。如果您信任正在运行的代码,则应使用限制性更强的安全管理器。

于 2013-11-08T10:25:23.700 回答
40

访问修饰符与安全性无关。事实上,您可以而且应该将访问修饰符视为安全的反面——它不是为了保护您的数据或算法,而是为了保护人们免于了解您的数据和算法的要求。这就是为什么默认修饰符是包的原因——如果他们正在处理他们可能已经需要知道的包。

除了对数据和代码方法的了解之外,还有责任知道何时以及如何使用它。你不会在你的 inIt 方法上设置 private 以防止有人发现它,你这样做是因为(a)他们不会知道你只在 foo 之后调用它并且只有当 bar = 3.1415 和(b)因为知道这对他们没有好处。

访问修饰符可以用一个简单的短语“TMI,伙计,我不需要知道”来概括。

于 2013-11-08T16:39:36.703 回答
7

通过说“安全”,您正在保护您或其他开发人员,他们正在使用您的 API 来避免通过调用您的私有方法来损害对象。但是如果你或他们真的需要调用这个方法,他们可以用反射来完成。

于 2013-11-08T10:26:20.250 回答
6

问题是你想从谁那里拯救它。在我看来,您的代码的这样一个客户在这里是不知所措的。

任何试图访问private上述类成员的代码(由您或其他人编写)基本上都是在自掘坟墓。private成员不构成公共API 的一部分,如有更改,恕不另行通知。如果客户端碰巧以上述方式使用了其中一个这样的私有成员,那么如果它升级到修改了私有成员的 API 的更新版本,它就会中断。

于 2013-11-08T11:09:06.257 回答
5

private不是为了安全,而是为了保持代码干净和防止错误。它允许用户模块化代码(以及它是如何开发的),而不必担心其他模块的所有细节

一旦你发布了你的代码,人们就可以弄清楚它是如何工作的。如果您最终希望代码在计算机上运行,​​则无法“隐藏”逻辑。即使编译成二进制也只是一种混淆程度。

因此,您无法设置 API 来执行您不希望其他人能够调用的特殊操作。对于 Web API,您可以将想要控制的方法放在服务器端。

于 2013-11-09T06:58:43.727 回答
5

假设您信任 API 的客户端程序员,另一种看待方式是他们使用这些特定功能的“安全性”程度。

你的公开可用的函数应该为你的代码提供一个清晰的、有据可查的、很少改变的接口。您的私有函数可以被视为实现细节,并且可能会随着时间而改变,因此直接使用并不安全。

如果客户端程序员竭尽全力规避这些抽象,他们在某种程度上声明他们知道自己在做什么。更重要的是,他们知道它不受支持,并且可能会停止使用您的代码的未来版本。

于 2013-11-08T11:05:17.570 回答
5

有了设施,就有责任。有些事情你不能做,有些事情你可以做但你不应该做。

私有修饰符以最受限制的方式提供/使用。不应在类外可见的成员应定义为私有的。但正如我们所见,这可以用反射来打破。但这并不意味着你不应该使用私有的——或者它们是不安全的。它是关于你应该明智地或以建设性的方式使用事物(如反思)。

于 2013-11-08T10:50:35.630 回答