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

时间:2015-01-30 09:54:40

标签: java

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

我最初的想法是过载' on static vs non-static,如下所示:

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修饰符的存在而编译和行为不同?

1 个答案:

答案 0 :(得分:3)

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

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

The trick that makes this possiblenew Object(){}的使用,它在现有方法中创建一个新的匿名类,我们试图弄清楚它是否是静态的。这种情况在两种情况下略有不同。

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

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

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

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