在静态方法中表现不同的表达式

我正在尝试编写一个Java源代码的表达式或一系列语句,当在static方法中写入时,求值为null ,但如果该方法是非静态的,则求值this

我最初的想法是静态与非静态’重载’,如下所示:

 public class test { public void method1() { System.out.println(getThisOrNull()); } public static void method2() { System.out.println(getThisOrNull()); } private static Object getThisOrNull() { return null; } private Object getThisOrNull() { return this; } public static void main(String[] args) { test t = new test(); System.out.println(t); t.method1(); t.method2(); } } 

不幸的是,这实际上不是合法的Java,你不能像那样“重载”它只是给出了一个编译器错误:

 test.java:14: error: method getThisOrNull() is already defined in class test private Object getThisOrNull() { ^ 1 error 

显然,在一个理想的世界中,我不会像开始那样编写它,但问题是这个代码将由一个工具自动生成,该工具在语义上或语法上都不足以区分静态和非静态情况。

那么,我怎样才能编写一些源代码,尽管字节对于字节相同的编译和行为有所不同,具体取决于方法的static修饰符的存在?

这可以通过Java的reflection工具的技巧和一些帮助来实现。 这很难看,但它有效:

 import java.lang.reflect.Field; public class test { public void method1() { System.out.println(getThisOrNull(new Object(){})); } public static void method2() { System.out.println(getThisOrNull(new Object(){})); } private static Object getThisOrNull(final Object o) { for (Field f: o.getClass().getDeclaredFields()) { if (f.getType().equals(test.class)) { try { return f.get(o); } catch (IllegalAccessException e) { // Omm nom nom... } } } return null; } public static void main(String[] args) { test t = new test(); System.out.println(t); t.method1(); t.method2(); } } 

这按照以下方式编译和运行:

 test@183f74d test@183f74d null 

使这成为可能的技巧是使用new Object(){} ,它在现有方法中创建一个新的匿名类,我们试图弄清楚它是否是静态的。 这种情况在两种情况之间略有不同。

如果目标只是弄清楚方法是否是静态的,我们可以写:

 java.lang.reflect.Modifiers.isStatic(new Object(){}.getClass().getEnclosingMethod().getModifiers()) 

由于我们希望得到this (如果可用),我们需要做一些稍微不同的事情。 幸运的是,对于我们在Java中的对象的实例的上下文中定义的类,获得对包含它们的类的隐式引用。 (通常你可以使用test.this语法访问它)。 我们需要一种方法来访问test.this如果它存在,除了我们实际上test.this在任何地方编写test.this ,因为它在静态情况下在语法上也是无效的。 但它确实存在于对象中,作为私有成员变量。 这意味着我们可以使用reflection找到它,这是getThisOrNull静态方法对本地匿名类型的作用。

缺点是我们在使用这个技巧的每个方法中都创建了一个匿名类,它可能会增加开销,但如果你被置于一个角落并寻找一种方法,它至少可以起作用。