Различают экземпляр и статические внутренние классы, объявленные в инициализаторе - PullRequest
3 голосов
/ 20 января 2012

Пытаясь ответить на вопрос о 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
  • Внутренние классы, созданные в инициализаторе (статические или экземпляры), являются описанным здесь случаем и не отличаются кроме параметров конструктора

1 Ответ

0 голосов
/ 20 января 2012

Вы объявляете два анонимных внутренних класса внутри Outer.

Теоретически (т.е. я не проверял это), я полагаю, вы можете позвонить:

Class<?>[] classes = Outer.class.getDeclaredClasses();
for(Class<?> c : classes) {
  if ((c.getModifiers() & Modifier.STATIC) != 0) {
    // its a static inner class (or interface)
  }
  else {
    // its a non static inner class or interface
  }
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...