区分初始化器中声明的实例和静态内部类

发布于 2024-12-28 07:58:20 字数 3228 浏览 1 评论 0原文

在尝试回答此处的问题时,我遇到了一个理论问题,我不确定是否存在更好的解决方案:

假设我们有以下设置:

class A {
  public A(Outer o) {
  }
}

class Outer {
  static A staticA = new A( new Outer() ) {
    ...
  };

  A innerA = new A( new Outer() ) {
    ...
  };
} 

How will I区分内部类和静态内部类使用反射?

根据我的测试,我只能通过检查构造函数的参数类型来判断哪个是静态内部类,即 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 {}})有一个声明类,是成员类并且具有静态类修饰符
  • 在实例方法中创建的内部类具有封闭方法
  • 在静态方法中创建的内部类具有封闭方法具有 static 修饰符的方法
  • 在初始化程序(静态或实例)中创建的内部类是此处描述的情况,除了构造函数参数之外没有其他区别

While trying to answer a question here on SO, I came across an theoretic problem where I'm not sure whether a better solution exists:

Suppose we have the following setup:

class A {
  public A(Outer o) {
  }
}

class Outer {
  static A staticA = new A( new Outer() ) {
    ...
  };

  A innerA = new A( new Outer() ) {
    ...
  };
} 

How would I distinguish between the inner class and the static inner class using reflection?

From my tests I could only tell which is the static inner class by checking the parameter types of the constructors, i.e. the class of innerA only provides a constructor taking two Outer instances. (I tested every flag or data on the enclosing classes/methods I could think of, and everything was equal - but I might have missed something.)

When comparing those two classes I could determine which one is the static inner class by checking whose constructors have less parameters of the outer type (in this case the static inner class' constructors would have one less).

However, suppose I don't know much about the class and I especially don't know whether the constructor has any explicit parameter of the outer type, i.e. whether A had a no argument constructor or a constructor taking an Outer argument (like in the case above). In that situation I couldn't safely tell whether the class is an inner or static inner class.

Is there another, i.e. safe, way?

Just for the record: this is a theoretical problem, I'm currently not trying to achieve anything.

Edit:

Here's my 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) {};
}

And the output:

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] 

Edit 2:

For completeness I added some other cases and those are all distinguishable (except the current which is last in the list):

  • "Normal" inner classes (class Outer { class Inner {}}) have a declaring class and are flagged being member classes
  • "Normal" static inner classes (class Outer { static class Inner {}}) have a declaring class, are member classes and have the static class modifier
  • Inner classes created in an instance method have an enclosing method
  • Inner classes created in a static method have an eclosing method which has the static modifier
  • Inner classes created in an initializer (static or instance) are the case described here and don't differ except in the constructor parameters

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

何以笙箫默 2025-01-04 07:58:20

您在 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
  }
}

You are declaring two anonymous inner classes inside Outer.

Theoretically (i.e. I didn't test it), I suppose you can call:

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
  }
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文