Пытаясь ответить на вопрос о SO, я натолкнулся на теоретическую проблему, в которой я не уверен, существует ли лучшее решение:
Предположим, у нас есть следующие настройки:
class A {
public A(Outer o) {
}
}
class Outer {
static A staticA = new A( new Outer() ) {
...
};
A innerA = new A( new Outer() ) {
...
};
}
Как бы я различил внутренний класс и статический внутренний класс, используя отражение?
Из моих тестов я мог только определить, какой статический внутренний класс, проверяя типы параметров конструкторов, то есть класс innerA
предоставляет конструктору только два экземпляра Outer
. (Я проверил каждый флаг или данные на включающие классы / методы, которые мог придумать, и все было одинаково - но я мог что-то упустить.)
При сравнении этих двух классов я мог определить, какой из них является статическим внутренним классом, проверив, чьи конструкторы имеют меньше параметров внешнего типа (в этом случае у конструкторов статического внутреннего класса будет на один меньше).
Тем не менее, предположим, что я не знаю много о классе, и я особенно не знаю, имеет ли конструктор какой-либо явный параметр внешнего типа, то есть имел ли A
конструктор без аргументов или конструктор, принимающий Outer
аргумент (как в случае выше). В этой ситуации я не мог с уверенностью сказать, является ли класс внутренним или статическим внутренним классом.
Есть ли другой, то есть безопасный, способ?
Только для справки: это теоретическая проблема, в настоящее время я ничего не пытаюсь достичь.
Редактировать
Вот мой SSCCE:
package sscce;
import java.lang.reflect.Constructor;
import java.lang.reflect.Method;
import java.util.Arrays;
public class ReflectionTest {
public static void main(String... args) {
Outer o = new Outer();
o.innerA.reflect();
o.staticA.reflect();
}
}
class A {
public A( Outer o ) {
}
public void reflect() {
Class<?> c = getClass();
Class<?> e = c.getEnclosingClass();
Class<?> d = c.getDeclaringClass();
Constructor<?> enc = c.getEnclosingConstructor();
Method m = c.getEnclosingMethod();
System.out.println("class: " + c.getName());
System.out.println("-------------------");
System.out.println("enclosing class: " + e);
System.out.println("enclosing ctor: " + enc);
System.out.println("enclosing method: " + m);
System.out.println("declaring class: " + d);
System.out.println("anonymous: " + c.isAnonymousClass());
System.out.println("local: " + c.isLocalClass());
System.out.println("synth: " + c.isSynthetic());
System.out.println("member: " + c.isMemberClass());
System.out.println("modifiers: " + c.getModifiers());
for( Constructor<?> ctr : c.getDeclaredConstructors() ) {
System.out.println("constructor params:" + Arrays.toString( ctr.getParameterTypes()) );
}
System.out.println();
}
}
class Outer {
public static A staticA = new A(new Outer()) {};
public A innerA = new A(this) {};
}
И вывод:
class: sscce.Outer$2 //this is innerA
-------------------
enclosing class: class sscce.Outer
enclosing ctor: null
enclosing method: null
declaring class: null
anonymous: true
local: false
synth: false
member: false
modifiers: 0
constructor params:[class sscce.Outer, class sscce.Outer]
class: sscce.Outer$1 //this is staticA
-------------------
enclosing class: class sscce.Outer
enclosing ctor: null
enclosing method: null
declaring class: null
anonymous: true
local: false
synth: false
member: false
modifiers: 0
constructor params:[class sscce.Outer]
Редактировать 2 :
Для полноты я добавил несколько других случаев, и все они различимы (кроме текущего, который является последним в списке):
- «Нормальные» внутренние классы (
class Outer { class Inner {}}
) имеют декларируемый класс и помечаются как классы-члены
- «Нормальные» статические внутренние классы (
class Outer { static class Inner {}}
) имеют декларирующий класс, являются классами-членами и , имеют модификатор статического класса
- Внутренние классы, созданные в методе экземпляра, имеют метод включения
- Внутренние классы, созданные в статическом методе, имеют метод eclosing, который имеет модификатор static
- Внутренние классы, созданные в инициализаторе (статические или экземпляры), являются описанным здесь случаем и не отличаются кроме параметров конструктора