合成方法的优点是什么?

发布于 2024-08-25 14:53:10 字数 1656 浏览 9 评论 0原文

问题

一位朋友提出了一个有趣的问题。给定以下代码:

public class OuterClass {

    private String message = "Hello World";

    private class InnerClass {
        private String getMessage() {
            return message;
        }
    }

}

从外部类,如何打印 message 变量内容?当然,不允许更改方法或字段的可访问性。

(来源此处,但它是一篇法国博客)


解决方案

解决这个问题的代码如下:

try {
    Method m = OuterClass.class.getDeclaredMethod("access$000", OuterClass.class);
    OuterClass outerClass = new OuterClass();
    System.out.println(m.invoke(outerClass, outerClass));
} catch (Exception e) {
    e.printStackTrace();
}

请注意,access$000方法名称并不是真正标准的(即使这种格式是强烈推荐),有的JVM会将此方法命名为access$0。因此,更好的解决方案是检查合成方法:

Method method = null;
int i = 0;
while ((method == null) && (i < OuterClass.class.getDeclaredMethods().length)) {
    if (OuterClass.class.getDeclaredMethods()[i].isSynthetic()) {
        method = OuterClass.class.getDeclaredMethods()[i];
    }
    i++;
}
if (method != null) {
    try {
        System.out.println(method.invoke(null, new OuterClass()));
    } catch (Exception e) {
        e.printStackTrace();
    }
}

所以这个问题的有趣点是强调合成方法的使用。通过这些方法,我可以像在解决方案中一样访问私有字段。当然,我需要使用反射,而且我认为使用这种东西可能非常危险......

问题

对于我来说,作为一名开发人员,合成的兴趣是什么方法?使用合成材料有什么好处?

Problem

One friend suggested an interesting problem. Given the following code:

public class OuterClass {

    private String message = "Hello World";

    private class InnerClass {
        private String getMessage() {
            return message;
        }
    }

}

From an external class, how may I print the message variable content? Of course, changing the accessibility of methods or fields is not allowed.

(the source here, but it is a french blog)


Solution

The code to solve this problem is the following:

try {
    Method m = OuterClass.class.getDeclaredMethod("access$000", OuterClass.class);
    OuterClass outerClass = new OuterClass();
    System.out.println(m.invoke(outerClass, outerClass));
} catch (Exception e) {
    e.printStackTrace();
}

Note that the access$000 method name is not really standard (even if this format is the one that is strongly recommanded), and some JVM will name this method access$0. Thus, a better solution is to check for synthetic methods:

Method method = null;
int i = 0;
while ((method == null) && (i < OuterClass.class.getDeclaredMethods().length)) {
    if (OuterClass.class.getDeclaredMethods()[i].isSynthetic()) {
        method = OuterClass.class.getDeclaredMethods()[i];
    }
    i++;
}
if (method != null) {
    try {
        System.out.println(method.invoke(null, new OuterClass()));
    } catch (Exception e) {
        e.printStackTrace();
    }
}

So the interesting point in this problem is to highlight the use of synthetic methods. With these methods, I can access a private field as it was done in the solution. Of course, I need to use reflection, and I think that the use of this kind of thing can be quite dangerous...

Question

What is the interest - for me, as a developer - of a synthetic method? What can be a good situation where using the synthetic can be useful?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

浮萍、无处依 2024-09-01 14:53:10

正如您所演示的,Java 访问修饰符仅提供信息,可以通过使用反射来规避它们。所以你的问题大致相当于“绕过访问修饰符有什么好处?”除了恶意目的之外,我们还想到了调试;例如,您可以从库外部记录某些库内部的内部状态,而根本不必接触库代码本身。另一个例子是与脚本语言的合作;如果您在编译时不知道哪些类和方法可用,那么反射可能非常有用。例如,Jython 的内部结构到处都使用了大量的反射。

As you demonstrate, Java access modifiers are merely informative, and they can be circumvented by using reflection. So your questions is roughly equivalent to "what is the interest of circumventing an access modifier?" Apart from malicious purposes, debugging comes to mind; you could for instance log the internal state of some library's internals from outside the library, without having to touch the library code itself at all. Another example is co-operation with scripting languages; if you don't know on compile-time which classes and methods are available, reflection can be quite useful. For instance, Jython's internals uses huge amounts of reflection all around.

メ斷腸人バ 2024-09-01 14:53:10

作为一名开发人员,您对合成方法的兴趣是什么?好吧,对于初学者来说,不要调用它们(出于其他回答者已经解释的原因)。

但有一件有趣的事情需要记住,特别是如果您正在编写要在安全敏感环境中运行的 Java 代码,那就是合成方法可能会为攻击者提供进入您的私有字段的后门。

当然,要使此类漏洞真正发挥作用,还需要一些大的“如果”(我的意思是必要条件):

  1. 攻击者实际上必须在您的 JVM 中运行代码。大多数时候这不是问题,因为唯一运行的代码是您自己的。
  2. 攻击者的代码需要与您的内部类位于同一包中(因为合成方法被声明为包私有)。
  3. 攻击者的代码必须从与您的类相同的类加载器中加载。如果您让不受信任的代码在 JVM 中运行(条件#1),那么您最好为不受信任的代码使用单独的类加载器。

What is the interest - for you, as a developer - of a synthetic method? Well, for starters, don’t invoke them (for reasons other answerers have explained).

But there is one interesting thing to keep in mind, particularly if you're writing Java code to run in a security-sensitive environment, and that's that synthetic methods can potentially provide attackers a back-door to your private fields.

Of course, there are some big "ifs"--I mean, necessary conditions--for such a vulnerability to actually matter:

  1. The attacker actually has to be running code in your JVM. Most of the time this is not an issue, because the only code running is your own.
  2. The attacker's code needs to be in the same package as your inner class (because the synthetic method is declared package-private).
  3. The attacker's code must be loaded from the same classloader as your class. If you're letting untrusted code to run in your JVM (condition #1) then you'd better use a separate classloader for the untrusted code.
美人迟暮 2024-09-01 14:53:10

您永远不应该使用反射调用合成访问器方法,它们可能会发生变化,具体取决于您使用的编译器。例如,在我的计算机上的 jdk1.6 上运行您的解决方案失败,因为找不到 access$000 方法。

合成访问器是一种秘密的编译器黑客技术,旨在绕过内部类是 Java 1.1 的补充这一事实,并且 VM 规范从未更改以适应它们。

You should never invoke synthetic accessor methods using reflection, they're liable to change, depending on which compiler you use. For example, running your solution on jdk1.6 on my machine failed, since the access$000 method was not found.

Synthetic accessors are an under-the-covers compiler hack to get around the fact that inner classes were an addition to Java 1.1, and the VM spec was never changed to accommodate them.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文