【问题标题】:What is the best way to approximate class.getSimpleName() without loading class?在不加载类的情况下近似 class.getSimpleName() 的最佳方法是什么?
【发布时间】:2016-04-21 18:27:48
【问题描述】:

给定一个完全限定的类名可以用 Class.forName() 加载,有没有办法将名称转换为加载类和调用 getSimpleName() 的结果没有实际尝试加载类? 我需要这种能力来进行反思。

【问题讨论】:

  • 我猜你必须自己实现逻辑 - 它主要是在 . 中获取最后一项分隔 String;有一些花里胡哨的......
  • @BoristheSpider 并且字符串也可能包含$
  • @shmosel 只要你不介意被 GPL 感染...
  • @shmosel 当然。但仅给出限定名称,您无法知道 $ 是否是简单名称的一部分 - 请参阅 @AndyTurner 的答案。 getSimpleBinaryName() 允许您决定。
  • @shmosel 对 - 您需要知道类的简单名称及其包含的类才能正确生成该语法。并且“准确性并不重要” - 我试图指出准确打印消息在导致运行时失败的意义上并不重要,但它可能会让你陷入疯狂的追逐并浪费你的时间寻找对于一个不存在的类。

标签: java reflection


【解决方案1】:

我要说的是,你不能仅仅根据名字来做。

您可以尝试拆分 .$,但此示例代码表明,简单名称的开头并不总是很明显:

class Ideone
{
    private static class Bar {};

    public static void main (String[] args) throws java.lang.Exception
    {
      class Foo$o {
        class Bar$bar {}
      };
      class Foo$o$Bar {
        class Bar$bar {}
      };
      class Foo$o$Bar$Bar$bar {}
      print(Ideone.class);
      print(Bar.class);
      print(Foo$o.class);
      print(Foo$o.Bar$bar.class);
      print(Foo$o$Bar.Bar$bar.class);
      print(Foo$o$Bar$Bar$bar.class);
    }

    private static void print(Class<?> clazz) {
        System.out.printf("fqn=%s, sn=%s%n", clazz.getName(), clazz.getSimpleName());
    }
}

输出:

fqn=Ideone, sn=Ideone
fqn=Ideone$Bar, sn=Bar
fqn=Ideone$1Foo$o, sn=Foo$o
fqn=Ideone$1Foo$o$Bar$bar, sn=Bar$bar
fqn=Ideone$1Foo$o$Bar$Bar$bar, sn=Bar$bar
fqn=Ideone$2Foo$o$Bar$Bar$bar, sn=Foo$o$Bar$Bar$bar

Ideone demo

即如果你要说“最后的$. 之后的名字”,那你就错了。

唯一确定的方法是加载类,可能不初始化它:

Class<?> clazz = Class.forName(className, false, someClassLoadeR);

【讨论】:

  • 或者提出一套全面的案例——正如你所证明的那样,案例并不多——并实施它。单元测试将非常简单。
  • @BoristheSpider 但你可以有一个名为 Fo 的嵌套类,而用一个名为 o 的嵌套类。
  • 哦,实际上,我明白了 - 本地类名中有一个 1
  • @BoristheSpider 但我想我现在编造了一个更卑鄙的案例,无法分辨名称的拆分位置...
  • 我认为您可能是对的 - 有一些更简单的情况,例如顶级课程的名称中有 $。此外,API 代码需要加载 class 的事实可能暗示了该任务的不可能性。
【解决方案2】:

正如@AndyTurner 的回答所证明的那样,您不能在所有情况下都从合格的类字符串中派生简单名称。

但是,如果约束没有实际尝试加载类并没有禁止读取类文件的内容,您可以执行以下操作(针对边缘情况):

  1. 通过Class.getResourceAsStream()获取类文件内容的InputStream
  2. 解析类文件的开头,从常量池中读取超类名。
  3. (由@shmosel 评论)实现Class.getSimpleName() 的逻辑。超类名称允许您替换依赖于已加载类的 Class.getSimpleBinaryString()

【讨论】:

  • 这感觉很难,而不是仅仅加载类。
  • @AndyTurner OP 会知道这样做是否值得。
猜你喜欢
  • 1970-01-01
  • 2017-08-02
  • 1970-01-01
  • 2021-11-28
  • 1970-01-01
  • 1970-01-01
  • 2020-04-07
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多