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

时间:2009-09-29 14:15:40

标签: c# java reflection scope

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

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

以下是示例

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

其中WriteToConsole()是特定于语言的,然后我可以运行以下内容来调用私有say()方法:

C#

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

爪哇

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

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

4 个答案:

答案 0 :(得分:18)

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

  • 为什么允许这样做?有时它可以派上用场。它应该小心对待,但它可能有用。

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

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

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

答案 1 :(得分:4)

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

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

答案 2 :(得分:1)

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

答案 3 :(得分:-2)

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

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

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

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

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