案例介绍
本案例主要介绍通过java代码从class文件中解析;class文件、常量池、属性表;
环境准备
- jdk 1.8.0
- IntelliJ IDEA Community Edition 2018.3.1 x64
配置信息
- 调试配置配置位置:Run/Debug Configurations -> program arguments配置内容:-X jre “C:Program FilesJavajdk1.8.0_161jre” java. lang .String
代码示例
itstack-demo- jvm -03 | |
├── pom.xml | |
└── src | |
└── main | |
│ └── java | |
│ └── org.itstack.demo.jvm | |
│ ├── classfile | |
│ │ ├── attributes {BootstrapMethods/Code/ConstantValue...} | |
│ │ ├── constantpool {CONSTANT_TAG_CLASS/CONSTANT_TAG_FIELDREF/CONSTANT_TAG_METHODREF...} | |
│ │ ├── ClassFile.java | |
│ │ ├── Class reader .java | |
│ │ └── MemberInfo.java | |
│ ├── classpath | |
│ │ ├── impl | |
│ │ │ ├── CompositeEntry.java | |
│ │ │ ├── DirEntry.java | |
│ │ │ ├── WildcardEntry.java | |
│ │ │ └── ZipEntry.java | |
│ │ ├── Classpath.java | |
│ │ └── Entry.java | |
│ ├── Cmd.java | |
│ └── Main.java | |
└── test | |
└── java | |
└── org.itstack.demo.test | |
└── HelloWorld.java |
AttributeInfo.java
package org.itstack.demo.jvm.classfile.attributes; | |
import org.itstack.demo.jvm.classfile.ClassReader; | |
import org.itstack.demo.jvm.classfile.attributes.impl.*; | |
import org.itstack.demo.jvm.classfile.constantpool.ConstantPool; | |
/** | |
* | |
* create by fuzhengwei on/4/26 | |
*/public interface AttributeInfo { | |
void readInfo(ClassReader reader); | |
static AttributeInfo[] readAttributes(ClassReader reader, ConstantPool constantPool) { | |
int attributesCount = reader.readUToInt(); | |
AttributeInfo[] attributes = new AttributeInfo[attributesCount]; | |
for (int i =; i < attributesCount; i++) { | |
attributes[i] = readAttribute(reader, constantPool); | |
} | |
return attributes; | |
} | |
static AttributeInfo readAttribute(ClassReader reader, ConstantPool constantPool) { | |
int attrNameIdx = reader.readUToInt(); | |
String attrName = constantPool.getUTF(attrNameIdx); | |
int attrLen = reader.readUToInt(); | |
AttributeInfo attrInfo = newAttributeInfo(attrName, attrLen, constantPool); | |
attrInfo.readInfo(reader); | |
return attrInfo; | |
} | |
static AttributeInfo newAttributeInfo(String attrName, int attrLen, ConstantPool constantPool) { | |
switch (attrName) { | |
case "BootstrapMethods": | |
return new BootstrapMethodsAttribute(); | |
case "Code": | |
return new CodeAttribute(constantPool); | |
case "ConstantValue": | |
return new ConstantValueAttribute(); | |
case "Deprecated": | |
return new DeprecatedAttribute(); | |
case "EnclosingMethod": | |
return new EnclosingMethodAttribute(constantPool); | |
case "Exceptions": | |
return new ExceptionsAttribute(); | |
case "InnerClasses": | |
return new InnerClassesAttribute(); | |
case "LineNumberTable": | |
return new LineNumberTableAttribute(); | |
case "LocalVariableTable": | |
return new LocalVariableTableAttribute(); | |
case "LocalVariableTypeTable": | |
return new LocalVariableTypeTableAttribute(); | |
// case "MethodParameters": | |
// case "RuntimeInvisibleAnnotations": | |
// case "RuntimeInvisibleParameterAnnotations": | |
// case "RuntimeInvisibleTypeAnnotations": | |
// case "RuntimeVisibleAnnotations": | |
// case "RuntimeVisibleParameterAnnotations": | |
// case "RuntimeVisibleTypeAnnotations": | |
case "Signature": | |
return new SignatureAttribute(constantPool); | |
case "SourceFile": | |
return new SourceFileAttribute(constantPool); | |
// case "SourceDebugExtension": | |
// case "StackMapTable": | |
case "Synthetic": | |
return new SyntheticAttribute(); | |
default: | |
return new UnparsedAttribute(attrName, attrLen); | |
} | |
} | |
} |
ConstantInfo.java
package org.itstack.demo.jvm.classfile.constantpool; | |
import org.itstack.demo.jvm.classfile.ClassReader; | |
import org.itstack.demo.jvm.classfile.constantpool.impl.*; | |
/** | |
* | |
* create by fuzhengwei on/4/26 | |
*/public interface ConstantInfo { | |
int CONSTANT_TAG_CLASS =; | |
int CONSTANT_TAG_FIELDREF =; | |
int CONSTANT_TAG_METHODREF =; | |
int CONSTANT_TAG_INTERFACEMETHODREF =; | |
int CONSTANT_TAG_STRING =; | |
int CONSTANT_TAG_INTEGER =; | |
int CONSTANT_TAG_FLOAT =; | |
int CONSTANT_TAG_LONG =; | |
int CONSTANT_TAG_DOUBLE =; | |
int CONSTANT_TAG_NAMEANDTYPE =; | |
int CONSTANT_TAG_UTF = 1; | |
int CONSTANT_TAG_METHODHANDLE =; | |
int CONSTANT_TAG_METHODTYPE =; | |
int CONSTANT_TAG_INVOKEDYNAMIC =; | |
void readInfo(ClassReader reader); | |
int tag(); | |
static ConstantInfo readConstantInfo(ClassReader reader, ConstantPool constantPool) { | |
int tag = reader.readUToInt(); | |
ConstantInfo constantInfo = newConstantInfo(tag, constantPool); | |
constantInfo.readInfo(reader); | |
return constantInfo; | |
} | |
static ConstantInfo newConstantInfo(int tag, ConstantPool constantPool) { | |
switch (tag) { | |
case CONSTANT_TAG_INTEGER: | |
return new ConstantIntegerInfo(); | |
case CONSTANT_TAG_FLOAT: | |
return new ConstantFloatInfo(); | |
case CONSTANT_TAG_LONG: | |
return new ConstantLongInfo(); | |
case CONSTANT_TAG_DOUBLE: | |
return new ConstantDoubleInfo(); | |
case CONSTANT_TAG_UTF: | |
return new ConstantUtfInfo(); | |
case CONSTANT_TAG_STRING: | |
return new ConstantStringInfo(constantPool); | |
case CONSTANT_TAG_CLASS: | |
return new ConstantClassInfo(constantPool); | |
case CONSTANT_TAG_FIELDREF: | |
return new ConstantFieldRefInfo(constantPool); | |
case CONSTANT_TAG_METHODREF: | |
return new ConstantMethodRefInfo(constantPool); | |
case CONSTANT_TAG_INTERFACEMETHODREF: | |
return new ConstantInterfaceMethodRefInfo(constantPool); | |
case CONSTANT_TAG_NAMEANDTYPE: | |
return new ConstantNameAndTypeInfo(); | |
case CONSTANT_TAG_METHODTYPE: | |
return new ConstantMethodTypeInfo(); | |
case CONSTANT_TAG_METHODHANDLE: | |
return new ConstantMethodHandleInfo(); | |
case CONSTANT_TAG_INVOKEDYNAMIC: | |
return new ConstantInvokeDynamicInfo(); | |
default: | |
throw new ClassFormatError("constant pool tag"); | |
} | |
} | |
} |
ClassFile.java
package org.itstack.demo.jvm.classfile; | |
import org.itstack.demo.jvm.classfile.attributes.AttributeInfo; | |
import org.itstack.demo.jvm.classfile.constantpool.ConstantPool; | |
/** | |
* | |
* create by fuzhengwei on/4/26 | |
*/public class ClassFile { | |
private int minorVersion; | |
private int majorVersion; | |
private ConstantPool constantPool; | |
private int accessFlags; | |
private int thisClassIdx; | |
private int supperClassIdx; | |
private int[] interfaces; | |
private MemberInfo[] fields; | |
private MemberInfo[] methods; | |
private AttributeInfo[] attributes; | |
public ClassFile(byte[] classData) { | |
ClassReader reader = new ClassReader(classData); | |
this.readAndCheckMagic(reader); | |
this.readAndCheckVersion(reader); | |
this.constantPool = this.readConstantPool(reader); | |
this.accessFlags = reader.readUToInt(); | |
this.thisClassIdx = reader.readUToInt(); | |
this.supperClassIdx = reader.readUToInt(); | |
this.interfaces = reader.readUInts(); | |
this.fields = MemberInfo.readMembers(reader, constantPool); | |
this.methods = MemberInfo.readMembers(reader, constantPool); | |
this.attributes = AttributeInfo.readAttributes(reader, constantPool); | |
} | |
private void readAndCheckMagic(ClassReader reader) { | |
String magic = reader.readUToHexStr(); | |
if (!"cafebabe".equals(magic)) { | |
throw new ClassFormatError("magic!"); | |
} | |
} | |
private void readAndCheckVersion(ClassReader reader) { | |
this.minorVersion = reader.readUToInt(); | |
this.majorVersion = reader.readUToInt(); | |
switch (this.majorVersion) { | |
case: | |
return; | |
case: | |
case: | |
case: | |
case: | |
case: | |
case: | |
case: | |
if (this.minorVersion ==) | |
return; | |
} | |
throw new UnsupportedClassVersionError(); | |
} | |
private ConstantPool readConstantPool(ClassReader reader) { | |
return new ConstantPool(reader); | |
} | |
public int minorVersion(){ | |
return this.minorVersion; | |
} | |
public int majorVersion(){ | |
return this.majorVersion; | |
} | |
public ConstantPool constantPool(){ | |
return this.constantPool; | |
} | |
public int accessFlags() { | |
return this.accessFlags; | |
} | |
public MemberInfo[] fields() { | |
return this.fields; | |
} | |
public MemberInfo[] methods() { | |
return this.methods; | |
} | |
public String className() { | |
return this.constantPool.getClassName(this.thisClassIdx); | |
} | |
public String superClassName() { | |
if (this.supperClassIdx <=) return ""; | |
return this.constantPool.getClassName(this.supperClassIdx); | |
} | |
public String[] interfaceNames() { | |
String[] interfaceNames = new String[this.interfaces.length]; | |
for (int i =; i < this.interfaces.length; i++) { | |
interfaceNames[i] = this.constantPool.getClassName(interfaces[i]); | |
} | |
return interfaceNames; | |
} | |
} |
ClassReader.java
package org.itstack.demo.jvm.classfile; | |
import java.math.BigInteger; | |
/** | |
* | |
* create by fuzhengwei on/5/13 | |
* <p> | |
* java虚拟机定义了u、u2、u4三种数据类型来表示;1字节、2字节、4字节,无符号整数。 | |
* 在如下实现中,用增位方式表示无符号类型: | |
* u、u2可以用int类型存储,因为int类型是4字节 | |
* u 需要用long类型存储,因为long类型是8字节 | |
*/public class ClassReader { | |
private byte[] data; | |
public ClassReader(byte[] data) { | |
this.data = data; | |
} | |
//u | |
public int readUint() { | |
byte[] val = readByte(); | |
return byteint(val); | |
} | |
//u | |
public int readUint() { | |
byte[] val = readByte(); | |
return byteint(val); | |
} | |
//u | |
public long readUint() { | |
byte[] val = readByte(); | |
String str_hex = new BigInteger(, val). toString (16); | |
return Long.parseLong(str_hex,); | |
} | |
public float readUintTFloat() { | |
byte[] val = readByte(); | |
return new BigInteger(, val).floatValue(); | |
} | |
public long readUintTLong() { | |
byte[] val = readByte(); | |
return new BigInteger(, val).longValue(); | |
} | |
public double readUintTDouble() { | |
byte[] val = readByte(); | |
return new BigInteger(, val).doubleValue(); | |
} | |
public int[] readUints() { | |
int n = this.readUint(); | |
int[] s = new int[n]; | |
for (int i =; i < n; i++) { | |
s[i] = this.readUint(); | |
} | |
return s; | |
} | |
public byte[] readBytes(int n) { | |
return readByte(n); | |
} | |
private byte[] readByte(int length) { | |
byte[] copy = new byte[length]; | |
System.arraycopy(data,, copy, 0, length); | |
System.arraycopy(data, length, data,, data.length - length); | |
return copy; | |
} | |
private int byteint(byte[] val) { | |
String str_hex = new BigInteger(, val).toString(16); | |
return Integer.parseInt(str_hex,); | |
} | |
} |
MemberInfo.java
package org.itstack.demo.jvm.classfile; | |
import org.itstack.demo.jvm.classfile.attributes.AttributeInfo; | |
import org.itstack.demo.jvm.classfile.attributes.impl.CodeAttribute; | |
import org.itstack.demo.jvm.classfile.attributes.impl.ConstantValueAttribute; | |
import org.itstack.demo.jvm.classfile.constantpool.ConstantPool; | |
/** | |
* | |
* create by fuzhengwei on/4/26 | |
*/public class MemberInfo { | |
private ConstantPool constantPool; | |
private int accessFlags; | |
private int nameIdx; | |
private int descriptorIdx; | |
private AttributeInfo[] attributes; | |
public MemberInfo(ClassReader reader, ConstantPool constantPool) { | |
this.constantPool = constantPool; | |
this.accessFlags = reader.readUToInt(); | |
this.nameIdx = reader.readUToInt(); | |
this.descriptorIdx = reader.readUToInt(); | |
this.attributes = AttributeInfo.readAttributes(reader, constantPool); | |
} | |
public static MemberInfo[] readMembers(ClassReader reader, ConstantPool constantPool) { | |
int fieldCount = reader.readUToInt(); | |
MemberInfo[] fields = new MemberInfo[fieldCount]; | |
for (int i =; i < fieldCount; i++) { | |
fields[i] = new MemberInfo(reader, constantPool); | |
} | |
return fields; | |
} | |
public int accessFlags() { | |
return this.accessFlags; | |
} | |
public String name() { | |
return this.constantPool.getUTF(this.nameIdx); | |
} | |
public String descriptor() { | |
return this.constantPool.getUTF(this.descriptorIdx); | |
} | |
public CodeAttribute codeAttribute() { | |
for (AttributeInfo attrInfo : attributes) { | |
if (attrInfo instanceof CodeAttribute) return (CodeAttribute) attrInfo; | |
} | |
return null; | |
} | |
public ConstantValueAttribute ConstantValueAttribute() { | |
for (AttributeInfo attrInfo : attributes) { | |
if (attrInfo instanceof ConstantValueAttribute) return (ConstantValueAttribute) attrInfo; | |
} | |
return null; | |
} | |
} |
Main.java
package org.itstack.demo.jvm; | |
import org.itstack.demo.jvm.classfile.ClassFile; | |
import org.itstack.demo.jvm.classfile.MemberInfo; | |
import org.itstack.demo.jvm.classpath.Classpath; | |
import java.util.Arrays; | |
/** | |
* | |
* create by fuzhengwei on/4/24 | |
*/public class Main { | |
public static void main(String[] args) { | |
Cmd cmd = Cmd.parse(args); | |
if (!cmd.ok || cmd.helpFlag) { | |
System.out.println("Usage: <main class> [-options] class [args...]"); | |
return; | |
} | |
if (cmd.versionFlag) { | |
//注意案例测试都是基于.8,另外jdk1.9以后使用模块化没有rt.jar | |
System.out.println("java version ".8.0""); | |
return; | |
} | |
startJVM(cmd); | |
} | |
private static void startJVM(Cmd cmd) { | |
Classpath classpath = new Classpath(cmd.jre, cmd.classpath); | |
System.out.printf("classpath:%s class:%s args:%sn", | |
classpath, cmd.getMainClass(), cmd.getAppArgs()); | |
//获取className | |
String className = cmd.getMainClass().replace(".", "/"); | |
ClassFile classFile = loadClass(className, classpath); | |
assert classFile != null; | |
printClassInfo(classFile); | |
} | |
private static ClassFile loadClass(String className, Classpath classpath) { | |
try { | |
byte[] classData = classpath.readClass(className); | |
return new ClassFile(classData); | |
} catch (Exception e) { | |
System.out.println("Could not find or load main class " + className); | |
return null; | |
} | |
} | |
private static void printClassInfo(ClassFile cf) { | |
System.out.println("version: " + cf.majorVersion() + "." + cf.minorVersion()); | |
System.out.println("constants count:" + cf.constantPool().getSiz()); | |
System.out.format("access flags:x%xn", cf.accessFlags()); | |
System.out.println("this class:" + cf.className()); | |
System.out.println("super class:" + cf.superClassName()); | |
System.out.println("interfaces:" + Arrays.toString(cf.interfaceNames())); | |
System.out.println("fields count:" + cf.fields().length); | |
for (MemberInfo memberInfo : cf.fields()) { | |
System.out.format(" %sn", memberInfo.name()); | |
} | |
System.out.println("methods count: " + cf.methods().length); | |
for (MemberInfo memberInfo : cf.methods()) { | |
System.out.format(" %sn", memberInfo.name()); | |
} | |
} | |
} |
测试结果
"C:Program FilesJavajdk.8.0_161binjava.exe" "-javaagent:D:Program FilesJetBrainsIntelliJ IDEA Community Edition 2018.3.1libidea_rt.jar=61458:D:Program FilesJetBrainsIntelliJ IDEA Community Edition 2018.3.1bin" -Dfile.encoding=UTF-8 -classpath "C:Program FilesJavajdk1.8.0_161jrelibcharsets.jar;C:Program FilesJavajdk1.8.0_161jrelibdeploy.jar;C:Program FilesJavajdk1.8.0_161jrelibextaccess-bridge-64.jar;C:Program FilesJavajdk1.8.0_161jrelibextcldrdata.jar;C:Program FilesJavajdk1.8.0_161jrelibextdnsns.jar;C:Program FilesJavajdk1.8.0_161jrelibextjaccess.jar;C:Program FilesJavajdk1.8.0_161jrelibextjfxrt.jar;C:Program FilesJavajdk1.8.0_161jrelibextlocaledata.jar;C:Program FilesJavajdk1.8.0_161jrelibextnashorn.jar;C:Program FilesJavajdk1.8.0_161jrelibextsunec.jar;C:Program FilesJavajdk1.8.0_161jrelibextsunjce_provider.jar;C:Program FilesJavajdk1.8.0_161jrelibextsunmscapi.jar;C:Program FilesJavajdk1.8.0_161jrelibextsunpkcs11.jar;C:Program FilesJavajdk1.8.0_161jrelibextzipfs.jar;C:Program FilesJavajdk1.8.0_161jrelibjavaws.jar;C:Program FilesJavajdk1.8.0_161jrelibjce.jar;C:Program FilesJavajdk1.8.0_161jrelibjfr.jar;C:Program FilesJavajdk1.8.0_161jrelibjfxswt.jar;C:Program FilesJavajdk1.8.0_161jrelibjsse.jar;C:Program FilesJavajdk1.8.0_161jrelibmanagement-agent.jar;C:Program FilesJavajdk1.8.0_161jrelibplugin.jar;C:Program FilesJavajdk1.8.0_161jrelibresources.jar;C:Program FilesJavajdk1.8.0_161jrelibrt.jar;E:itstackgitistack-demoitstack-demo-jvmitstack-demo-jvm-03targetclasses;D:Program Files (x86)apache-maven-2.2.1repositorycombeustjcommander1.72jcommander-1.72.jar;D:Program Files (x86)apache-maven-2.2.1repositoryorgprojectlomboklombok1.18.0lombok-1.18.0.jar;D:Program Files (x86)apache-maven-2.2.1repositorycomalibabafastjson1.2.40fastjson-1.2.40.jar" org.itstack.demo.jvm.Main -Xjre "C:Program FilesJavajdk1.8.0_161jre" java.lang.String | |
classpath:org.itstack.demo.jvm.classpath.Classpath@bf558aa class:java.lang.String args:null | |
version:.0 | |
constants count: | |
access flags:x31 | |
this class:java/lang/String | |
super class:java/lang/ Object | |
interfaces:[java/io/Serializable, java/lang/Comparable, java/lang/CharSequence] | |
fields count: | |
value [C | |
hash I | |
serialVersionUID J | |
serialPersistentFields [Ljava/io/ObjectStreamField; | |
CASE_INSENSITIVE_ORDER Ljava/util/Comparator; | |
methods count: | |
<init> ()V | |
<init> (Ljava/lang/String;)V | |
<init> ([C)V | |
<init> ([CII)V | |
<init> ([III)V | |
<init> ([BIII)V | |
<init> ([BI)V | |
checkBounds ([BII)V | |
<init> ([BIILjava/lang/String;)V | |
<init> ([BIILjava/nio/charset/Charset;)V | |
<init> ([BLjava/lang/String;)V | |
<init> ([BLjava/nio/charset/Charset;)V | |
<init> ([BII)V | |
<init> ([B)V | |
<init> (Ljava/lang/StringBuffer;)V | |
<init> (Ljava/lang/StringBuilder;)V | |
<init> ([CZ)V | |
length ()I | |
isEmpty ()Z | |
charAt (I)C | |
codePointAt (I)I | |
codePointBefore (I)I | |
codePointCount (II)I | |
offsetByCodePoints (II)I | |
getChars ([CI)V | |
getChars (II[CI)V | |
getBytes (II[BI)V | |
getBytes (Ljava/lang/String;)[B | |
getBytes (Ljava/nio/charset/Charset;)[B | |
getBytes ()[B | |
equals (Ljava/lang/Object;)Z | |
contentEquals (Ljava/lang/StringBuffer;)Z | |
nonSyncContentEquals (Ljava/lang/AbstractStringBuilder;)Z | |
contentEquals (Ljava/lang/CharSequence;)Z | |
equalsIgnoreCase (Ljava/lang/String;)Z | |
compareTo (Ljava/lang/String;)I | |
compareToIgnoreCase (Ljava/lang/String;)I | |
regionMatches (ILjava/lang/String;II)Z | |
regionMatches (ZILjava/lang/String;II)Z | |
startsWith (Ljava/lang/String;I)Z | |
startsWith (Ljava/lang/String;)Z | |
endsWith (Ljava/lang/String;)Z | |
hashCode ()I | |
indexOf (I)I | |
indexOf (II)I | |
indexOfSupplementary (II)I | |
lastIndexOf (I)I | |
lastIndexOf (II)I | |
lastIndexOfSupplementary (II)I | |
indexOf (Ljava/lang/String;)I | |
indexOf (Ljava/lang/String;I)I | |
indexOf ([CIILjava/lang/String;I)I | |
indexOf ([CII[CIII)I | |
lastIndexOf (Ljava/lang/String;)I | |
lastIndexOf (Ljava/lang/String;I)I | |
lastIndexOf ([CIILjava/lang/String;I)I | |
lastIndexOf ([CII[CIII)I | |
substring (I)Ljava/lang/String; | |
substring (II)Ljava/lang/String; | |
subSequence (II)Ljava/lang/CharSequence; | |
concat (Ljava/lang/String;)Ljava/lang/String; | |
replace (CC)Ljava/lang/String; | |
matches (Ljava/lang/String;)Z | |
contains (Ljava/lang/CharSequence;)Z | |
replaceFirst (Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String; | |
replaceAll (Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String; | |
replace (Ljava/lang/CharSequence;Ljava/lang/CharSequence;)Ljava/lang/String; | |
split (Ljava/lang/String;I)[Ljava/lang/String; | |
split (Ljava/lang/String;)[Ljava/lang/String; | |
join (Ljava/lang/CharSequence;[Ljava/lang/CharSequence;)Ljava/lang/String; | |
join (Ljava/lang/CharSequence;Ljava/lang/Iterable;)Ljava/lang/String; | |
toLowerCase (Ljava/util/Locale;)Ljava/lang/String; | |
toLowerCase ()Ljava/lang/String; | |
toUpperCase (Ljava/util/Locale;)Ljava/lang/String; | |
toUpperCase ()Ljava/lang/String; | |
trim ()Ljava/lang/String; | |
toString ()Ljava/lang/String; | |
toCharArray ()[C | |
format (Ljava/lang/String;[Ljava/lang/Object;)Ljava/lang/String; | |
format (Ljava/util/Locale;Ljava/lang/String;[Ljava/lang/Object;)Ljava/lang/String; | |
valueOf (Ljava/lang/Object;)Ljava/lang/String; | |
valueOf ([C)Ljava/lang/String; | |
valueOf ([CII)Ljava/lang/String; | |
copyValueOf ([CII)Ljava/lang/String; | |
copyValueOf ([C)Ljava/lang/String; | |
valueOf (Z)Ljava/lang/String; | |
valueOf (C)Ljava/lang/String; | |
valueOf (I)Ljava/lang/String; | |
valueOf (J)Ljava/lang/String; | |
valueOf (F)Ljava/lang/String; | |
valueOf (D)Ljava/lang/String; | |
intern ()Ljava/lang/String; | |
compareTo (Ljava/lang/Object;)I | |
<clinit> ()V | |
Process finished with exit code |
今天的分享就到这了。