Java 有没有办法在运行时将方法添加到类定义中?

Java 有没有办法在运行时将方法添加到类定义中?,java,Java,还有一个更好的问题(链接如下)。我的问题鼓励了糟糕的编码实践,但没有概述这些实践的风险 原来的问题如下: 有没有办法在运行时将方法添加到类定义中 例如,假设我有以下接口 public interface Singleton<T> { @StaticContract T getInstanceStatic(); } 公共接口单例{ @静态合同 T getInstanceStatic(); } 在运行时,我将扫描所有类,查找带有注释“StaticContract”

还有一个更好的问题(链接如下)。我的问题鼓励了糟糕的编码实践,但没有概述这些实践的风险

原来的问题如下:


有没有办法在运行时将方法添加到类定义中

例如,假设我有以下接口

public interface Singleton<T> {
    @StaticContract
    T getInstanceStatic();
}
公共接口单例{
@静态合同
T getInstanceStatic();
}
在运行时,我将扫描所有类,查找带有注释“StaticContract”的方法,并将实现方法的静态版本添加到类定义中。然而,我不知道我将如何去做这件事,或者这是否可能

在我当前的实现中,如果运行时反射在初始化期间找不到方法的静态方法,我将抛出NoSuchMethodError。最大的问题是,如果开发人员不熟悉接口,他们可能不知道应该创建一个静态方法。非静态getInstanceStatic()对于单例来说没有意义。它只是作为创建静态方法的提醒

再加上使用反射恢复已擦除类型的能力,这将允许我使用泛型的用途远远超出预期。例如,您不再需要定义和传递factory对象。您可以在工厂生成的类中定义方法

另外,如果没有办法在运行时执行此操作,是否有办法在编译时执行此操作?

您想要的是可能的

但不是这样。你的实际问题的答案是一个简单的、直截了当的“不”。但你不想在你的问题中描述什么

让我详细说明一下

首先,我们可以在运行时添加方法。你不能*,但假设你可以

那将一事无成;鉴于:

public class Example implements Singleton<Example> {
    @StaticContract Example getInstanceStatic() { return new Example(); }
}
但是——怎么做?编译器不会允许您这样做,因为方法不在那里,如果我们按照您的计划(在运行时添加方法),那么在编译时它将永远不会在那里,javac将拒绝编译它。如果它以某种方式编译了这个,那么在运行时,你可以施展你的魔术,以某种方式添加这个方法,一切都会很好,但这是一个没有意义的问题——除了用字节码编辑器将一个类文件拼凑在一起,没有办法用编译版本的
Example.instance()
获得一个类文件

您不想在运行时添加此项

但是您可能希望在编译时添加它

那是什么?你能做到的

战略1:龙目地 Lombok项目允许您编写使其表现出单例风格的代码。Lombok故意没有
@Singleton
,因为作为一个概念,Singleton被普遍嘲笑为糟糕的代码风格。我想如果你一定要这个的话,你可以用叉子叉龙目山,加上它

策略2:注释处理器 除了lombok,注释处理器不能向现有源文件添加内容。但是他们可以制造新的!给定为磁盘源文件上的实际实字节:

@SingletonizeMe
public class Example {
    Example() {} // without lombok you're going to have to write this yourself to ensure nobody outside of the package can instantiate this...
}
然后您可以编写注释处理器,这意味着javac将自动生成此文件:

// generated code
package same.pkg.as.your.example;

public class ExampleUtil {
    public static final Example EXAMPLE_INSTANCE = new Example();
}
并将其作为构建的一部分进行编译,任何包含
ExampleUtil.EXAMPLE\u INSTANCE
的代码都将立即编译,没有任何抱怨。注释处理器解决了这样一个问题:“好吧,也许在运行时这会起作用,但我如何向
javac
解释,让它只做我想做的事情,而不拒绝编译它认为在运行时不可能工作的代码?”

策略#3:依赖注入系统 从dagger到spring再到guice,有很多库都在做“依赖注入”,而且几乎所有库都可以选择以单例方式注入东西。让这3个库快速浏览一下,一旦您阅读了它们的入门快速教程,应该会非常清楚这是如何工作的


*)您可能会认为答案是肯定的,因为有了插装和使用代理技术重新加载类文件的能力。但这是“向类添加方法”吗?不,它不是-它正在重新加载一个类,如果您尝试添加任何新成员,该类通常不起作用;VMs内置的热代码替换技术不允许您更改(或添加或删除)任何签名。

请不要破坏您的帖子。一旦您提交了一篇文章,您就已经将内容授权给了Stack Overflow社区()。根据SE政策,任何故意破坏行为都将被恢复。除上述内容外,您还收到了一份详细的长答复,您已接受并称之为“美丽的答复”。试图破坏或从根本上改变这个问题对那些花时间帮助你的人来说是非常不尊重的。这里的事情不是这样的。请留下原始问题作为其他任何人寻找类似问题的路线图。版主-现在我对stackoverflow有了一些经验,我正在尝试删除我的帐户。在我离开之前,我只想澄清一个问题。你为什么要删除你的帐户?另外,为什么要删除此项?答案显然对人们有帮助,那么为什么不让其他人阅读呢?
// generated code
package same.pkg.as.your.example;

public class ExampleUtil {
    public static final Example EXAMPLE_INSTANCE = new Example();
}