为什么你能在Java和.Net中反映和调用(不是那么)私有方法

在Java和C#中,都可以通过reflection调用私有方法(如下所示)。

  • 为什么允许这样做?
  • 这样做的后果是什么?
  • 它应该在未来的语言版本中被删除吗?
  • 其他语言/平台是否允许这样做?如果我在Java和C#中都有这个类

这是一个例子

public class Foo { private void say() { WriteToConsoleMethod("Hello reflected world"); } } 

WriteToConsole()是特定于语言的,然后我可以运行以下命令来调用private say()方法:

C#

 Foo f = new Foo(); var fooType = f.GetType(); var mi = fooType.GetMethod("say", BindingFlags.NonPublic | BindingFlags.Instance); mi.Invoke(f, null); 

Java的

 Foo f = new Foo(); Method method = f.getClass().getDeclaredMethod("say", null); method.setAccessible(true); method.invoke(f, null); 

正如你所看到的,它并不明显,但也不难。

在Java和.NET中,仅当您具有足够的权限时才允许这样做。 直接从命令行运行的代码(通常)以“完全信任”模式运行。 如果您尝试在更严格的环境中执行相同的操作,则会失败。 访问控制更多地是关于封装而不是安全性。 如果你是在完全信任的情况下运行,你可能已经有足够的权限来启动原生方法直接在内存中捅…

  • 为什么允许? 有时它可以很方便。 它应该小心对待,但它可能是有用的。

  • 有什么后果? 你的代码变得脆弱; 你正在以一种它不期望的方式与一种类型进行交互。

  • 它应该在未来的语言版本中被删除吗? 它首先是一个平台function而不是语言function,但不,我不认为它应该删除。

  • 其他语言/平台是否允许这样做? 我不确定……但我不会感到惊讶。

这是允许的,因为访问限制并不意味着安全措施。

这有点像把锁放在你的房子上 – 它们是一种威慑力,但它们对那些想要使用殴打的公羊打破门的人毫无作用。

如果由于某种原因,您需要确保不适当的呼叫者无法调用某种方法(如果存在某种密码/安全风险),请查看.net中的代码访问安全性。 有一种方法可以告诉运行时只允许具有特定Authenticode签名的调用者调用方法。

C ++的私有/受保护/公共模型变得流行,因为C ++变得流行,而不是因为它是一个好主意。

有很多库设置私有的方法,真的不应该有; 一些程序员将几乎所有东西设置为私有而不理解为什么你会这样做,并且一些IDE在它可能不应该创建私有集的脚手架代码时。

结果是许多库都有好的,有用的想法,但在他们的方法中的某处有错误,并且这些方法通常被标记为私有。 private / protected / public的问题以及随之而来的正常约束是您无法计划其他人将来使用您的代码。 即使你以某种方式设法编写无错误的代码(你不会这样做),流行的图书馆仍然会找到你未曾预料到的未来用途。 作者无法确定在编写它们时是否需要访问,覆盖,调整哪些方法和变量。 这太重要了。

所以你发现这个reflection技巧打破了这个模型,但事实是它应该更容易打破,而不是更难。 我不会把这看作是一个错误。

实际上在.Net中,您可以使用Reflector将此方法更进一步,避免代码中的实时reflection调用,以避免在发现错误代码标记为私有时产生的性能损失。 如果您这样做,请尽量避免在您编写的新代码中使用私有声明,以便对利用您的工作的下一位作者感到高兴。