从字节码解析类名

JHo*_*nti 2 java reflection bytecode

是否有可能从类源代码中形成的字节码中挖掘出类名?

情况是这样的:我从某个地方远程获取一个类字节码,它来自何处无关紧要.要使用类加载器有效地加载该类,我还需要拥有类名...对吗?

jar*_*bjo 10

如果你只需要类名,那么自己解析类文件的开头可能更容易,而不是为了这个目的而为类代码操作添加第三方库.您只需要来自常量池的类和字符串,跳过访问标志然后替换/.在班级名称中.如果您有一个字节数组,则可以使用以下命令调用此方法new ByteArrayInputStream(byteArray):

public static String getClassName(InputStream is) throws Exception {
    DataInputStream dis = new DataInputStream(is);
    dis.readLong(); // skip header and class version
    int cpcnt = (dis.readShort()&0xffff)-1;
    int[] classes = new int[cpcnt];
    String[] strings = new String[cpcnt];
    for(int i=0; i<cpcnt; i++) {
        int t = dis.read();
        if(t==7) classes[i] = dis.readShort()&0xffff;
        else if(t==1) strings[i] = dis.readUTF();
        else if(t==5 || t==6) { dis.readLong(); i++; }
        else if(t==8) dis.readShort();
        else dis.readInt();
    }
    dis.readShort(); // skip access flags
    return strings[classes[(dis.readShort()&0xffff)-1]-1].replace('/', '.');
}
Run Code Online (Sandbox Code Playgroud)

  • 请谨慎使用本示例中给出的代码。尽管它适用于许多类文件,但会为其他文件引发异常(ArrayIndexOutOfBoundsException)。这实际上是一个很好的例子,为什么有时使用经过良好测试的库比自己做要好。 (3认同)
  • Typeracer是正确的。使用INVOKEDYNAMIC的代码似乎失败-与lambdas相关的问题或常量池中的boostrap条目 (2认同)
  • @typeracer 这段代码的主要问题不是它不是最新的,而是它既不检查文件的版本号也不报告未知标签,而是将所有未知的内容视为有四个字节要跳过。[这个答案](/sf/answers/3663247101/)碰巧解决了相同的任务,但它是最新的,甚至更好,会报告未知标签并且更容易更新,因为命名常数。 (2认同)
  • 顺便说一句,“DataInputStream”从第一天起就有一个方法“readUnsignedShort()”,因此不需要重复写入“readShort()&amp;0xffff”。 (2认同)