当前位置: 首页 > 面试题库 >

如何从java.lang.Class对象获取源文件名/行号

阙佐
2023-03-14
问题内容

给定一个java.lang.Class对象,是否可以获取源文件名和声明该类的行号?

该数据应在.class文件的调试信息中可用。我唯一知道的JDK返回此类调试信息的位置位于,java.lang.StackTraceElement但是我不确定是否可以强制Java
java.lang.StackTraceElement为任意类创建实例,因为我们没有在该类中执行方法。

我的确切用例是一个匿名内部类,它具有编译器生成的名称。我想知道类声明的文件名和行号。

我不想使用字节码操作框架,但是如果需要的话,我可以退一步。


问题答案:

答案在于您对实现侦听器的代码有多少控制权。没错,没有方法就无法创建堆栈跟踪。

通用技术是在构造函数中创建Exception(),但不要抛出它。它包含堆栈跟踪信息,您可以根据需要使用它们。这将为您提供构造函数的行号,而不是类的行号。请注意,此方法也不是特别有效,因为创建堆栈跟踪非常昂贵。

您将需要:

  1. 强制在构造函数中执行一些代码(如果您的Listener是您控制的抽象类,则相对容易)
  2. 以某种方式检测代码(治愈似乎比这里的疾病还糟)。
  3. 对类的命名方式进行一些假设。
  4. 读取jar(与javac -p相同)

对于1),您只需将Exception创建物放在抽象类中,然后子类将调用构造函数:

class Top {
    Top() {
        new Exception().printStackTrace(System.out);
    }
}

class Bottom extends Top {
    public static void main(String[] args) {
        new Bottom();
    }
}

这会产生类似:

java.lang.Exception
    at uk.co.farwell.stackoverflow.Top.<init>(Top.java:4)
    at uk.co.farwell.stackoverflow.Bottom.<init>(Bottom.java: 11)
    at uk.co.farwell.stackoverflow.Bottom.main(Bottom.java: 18)

通常,遵循一些命名规则:如果您有一个称为Actor的外部类和一​​个名为Consumer的内部类,则已编译的类将称为Actor $
Consumer。匿名内部类按照它们在文件中出现的顺序命名,因此Actor $ 1将在文件中出现在Actor $
2之前。我不认为这实际上是在任何地方指定的,因此这可能只是一个约定,如果您要对多个jvm等进行复杂的处理,则不应依赖它。

正如jmg所指出的,您可以在同一个文件中定义多个顶级类。如果您有一个公共类Foo,则必须在Foo.java中定义它,但是可以在另一个文件中包含一个非公共类。上面的方法可以解决这个问题。

说明:

如果反汇编java(javap -c -verbose),则会看到调试信息中有行号,但是它们仅适用于方法。使用以下内部类:

static class Consumer implements Runnable {
    public void run() {
        // stuff
    }
}

并且javap输出包含:

uk.co.farwell.stackoverflow.Actors$Consumer();
  Code:
   Stack=1, Locals=1, Args_size=1
   0:   aload_0
   1:   invokespecial   #10; //Method java/lang/Object."<init>":()V
   4:   return
  LineNumberTable: 
   line 20: 0

  LocalVariableTable: 
   Start  Length  Slot  Name   Signature
   0      5      0    this       Luk/co/farwell/stackoverflow/Actors$Consumer;

LineNumberTable包含适用于方法的行号列表。因此,我为Consumer使用的构造函数从第20行开始。但这是 构造函数
的第一行,而不是类的第一行。这只是同一行,因为我使用的是默认构造函数。如果添加构造函数,则行号将更改。编译器不存储声明该类的行。因此,如果不解析Java本身,就无法找到声明该类的位置。您只是没有可用的信息。

但是,如果您使用的是匿名内部类,例如:

Runnable run = new Runnable() {
    public void run() {
    }
};

然后,构造函数和类的行号将匹配[*],因此将为您提供一个行号。

[*]除非“ new”和“ Runnable()”在不同的行上。



 类似资料:
  • 问题内容: 我允许用户通过拖放和其他方法将图像加载到页面中。放置图像时,我用来转换为对象URL以显示图像。我没有撤消该URL,因为我确实重复使用了它。 因此,当需要创建一个对象时,我可以允许他们上传其中包含其中一个图像的表单,是否可以通过某种方式将该对象URL反向转换为a ,然后可以将其附加到a 宾语? 问题答案: 正如gengkev在上面的评论中所暗示的那样,似乎最好/唯一的方法是使用异步xhr

  • 我允许用户通过拖动将图像加载到页面中 那么,当需要创建一个对象时,我可以允许他们上传一个包含其中一个图像的表单,有没有什么方法可以将该对象URL反转回或,然后将其附加到对象?

  • 问题内容: 我有一个RSA私钥文件(OCkey.pem)。使用Java我必须从该文件中获取私钥。该密钥是使用以下openssl命令生成的。注意:我无法在下面的此openssl命令上进行任何更改。 证书如下所示。 ///////////////////////////////////////////////////// ////////// bash-3.00美元少OCkey.pem ----- B

  • 我正在尝试从检索或实例,而不将保存到文件系统。 中是否有任何方法从现有的返回或?

  • 我下载了一个文件作为ajax的响应。如何从中获取文件名和文件类型并显示缩略图。我得到了很多搜索结果,但找不到正确的方法。 控制台输出:

  • 我使用意图action_get_content调用startActivityForResult。有些应用程序返回给我的数据包含以下URI: 内容://media/external/images/media/18122 不知道是图像还是视频或者一些自定义内容。如何使用ContentResolver从这个URI获取实际的文件名或内容标题?