0

I'm trying to write an expression or series of statements of Java source code that when written inside a static method evaluates to null, but if the method is non-static evaluates to this.

My initial idea was to 'overload' on static vs non-static, as below:

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();
  }
}

Unfortunately this isn't actually legal Java, you can't 'overload' like that and it just gives a compiler error:

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

Clearly in an ideal world I wouldn't write it like that to begin with, but the problem is this code will be generated automatically by a tool that is not really semantically or syntactically enough to distinguish between the static vs non-static case.

So, how can I write some source code that, although byte for byte identical compiles and behaves differently in depending on the presence of the static modifier for the method?

Flexo
  • 87,323
  • 22
  • 191
  • 272

1 Answers1

3

This can be achieved with a trick and a bit of help from Java's reflection facilities. It's ugly, but it works:

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();
  }
}

This compiles and runs as hoped for:

test@183f74d
test@183f74d
null

The trick that makes this possible is the use of new Object(){}, which creates a new, anonymous class within the existing method that we're trying to figure out if it's static or not. The behaviour of this is subtly different between the two cases.

If the goal were just to figure out if the method is static or not we could write:

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

Since we want to get this (when available) we need to do something slightly different. Fortunately for us classes defined within the context of an instance of an object in Java get an implicit reference to the class that contains them. (Normally you'd access it with test.this syntax). We needed a way to access test.this if it existed, except we can't actually write test.this anywhere because it too would be syntactically invalid in the static case. It does however exist within the object, as a private member variable. This means that we can find it with reflection, which is what the getThisOrNull static method does with the local anonymous type.

The downside is that we create an anonymous class in every method we use this trick and it probably adds overheads, but if you're backed into a corner and looking for a way of doing this it does at least work.

Community
  • 1
  • 1
Flexo
  • 87,323
  • 22
  • 191
  • 272