来看一下继承自Symbol的具体实现类。
1、TypeSymbol
/** A class for type symbols. * Type variables are represented by instances of this class, // 类型变量用这个类来表示 * classes and packages by instances of subclasses. // 类和包用子类来表示 */ public class TypeSymbol extends Symbol implements TypeParameterElement { ... }
其中有两个重要的方法是用来计算fullname与flatname的。TypeSymbol的具体子类有PackageSymbol和ClassSymbol,而PackageSymbol中含有fullname属性,ClassSymbol中含有fullname与flatname属性。
接着看具体的子类定义。
2、PackageSymbol
/** A class for package symbols */ public class PackageSymbol extends TypeSymbol implements PackageElement { public Scope members_field; public Name fullname; public ClassSymbol package_info; // see bug 6443073 ... }
主要有3个属性。
3、ClassSymbol
/** A class for class symbols */ public class ClassSymbol extends TypeSymbol implements TypeElement { /** a scope for all class members; variables, methods and inner classes * type parameters are not part of this scope * * 所有类成员的一个作用域。变量,方法和内部类 类型参数不是这个作用域的一部分 */ public Scope members_field; /** the fully qualified name of the class, i.e. pck.outer.inner. * null for anonymous classes * * 类的全限定名,对于匿名类为空 */ public Name fullname; /** the fully qualified name of the class after converting to flat * representation, i.e. pck.outer$inner, * set externally for local and anonymous classes * * 类的全限定名,为本地和匿名类也进行设置 */ public Name flatname; /** the sourcefile where the class came from */ public JavaFileObject sourcefile; /** the classfile from where to load this class * this will have extension .class or .java */ public JavaFileObject classfile; /** the list of translated local classes (used for generating InnerClasses attribute) */ public List<ClassSymbol> trans_local; /** the constant pool of the class */ public Pool pool; ... }
下面就来看一个具体的例子,如下:
package m20170210; public class A { class B {} public void test() { class C {} } }
1、属性fullname与flatname
下面为PackageSymbol的截图。
下面分别是A类,B类与C类的ClassSymbol截图。
结合TypeSymbol相关的计算代码,如下:
/** form a fully qualified name from a name and an owner */ static public Name formFullName(Name name, Symbol owner) { if (owner == null){ return name; } if ( (owner.kind != ERR) && ( (owner.kind & (VAR | MTH)) != 0 || (owner.kind == TYP && owner.type.tag == TYPEVAR) //TYPEVAR是类型变量 ) ){ return name; } Name prefix = owner.getQualifiedName(); if (prefix == null || prefix == prefix.table.names.empty){ return name; } else{ return prefix.append('.', name); } } /** form a fully qualified name from a name and an owner, after * converting to flat representation */ static public Name formFlatName(Name name, Symbol owner) { if ( owner == null || (owner.kind & (VAR | MTH)) != 0 || // 是变量或者方法 (owner.kind == TYP && owner.type.tag == TYPEVAR) // 是一个类型的类型变量 ){ return name; } char sep = (owner.kind == TYP) ? '$' : '.'; Name prefix = owner.flatName(); if (prefix == null || prefix == prefix.table.names.empty){ return name; }else{ return prefix.append(sep, name); } }
flatname主要用来为各个类生成相应的class文件时进行命名的。fullname就是一般所要求的qualifiedname。
2、属性sourcefile与classfile
sourcefile表示源文件的位置,而classfile表示生成的class类的文件路径。
为什么本地类C的classfile为空呢?
3、属性members_field
这个属性只有PackageSymbol与ClassSymbol含有,其类型是Scope(作用域)。Scope内容将在后面详细讲解。
4、重要的方法
有一个isLocal()方法,具体的实现在Symbol中,如下:
/** Is this symbol declared (directly or indirectly) local to a method or variable initializer? * Also includes fields of inner classes which are in turn(反过来) local to a method or variable initializer. */ public boolean isLocal() { // return // (owner.kind & (VAR | MTH)) != 0 || // (owner.kind == TYP && owner.isLocal()); if((owner.kind & MTH ) != 0 ){ System.out.println(flatName()+"/owner.kind=MTH"); return true; }else if((owner.kind & VAR)!=0){ System.out.println(flatName()+"/owner.kind=VAR"); return true; }else if(owner.kind == TYP && owner.isLocal()){ System.out.println(flatName()+"/owner.kind=TYP"); return true; } System.out.println(flatName()+"/false"); return false; }
为了方便测试和打印,我对原来的代码进行了实现的修改并且增加了一些打印,下面是一个例子。
package m20170217; public class A { // m20170217.A/false class B { // m20170217.A$B/false B b = new B() { }; // m20170217.A$B$1/owner.kind=VAR } B c = new B() { }; // m20170217.A$1/owner.kind=VAR { class C { } // m20170217.A$1C/owner.kind=MTH } public void test1() { class D { } // m20170217.A$1D/owner.kind=MTH D d = new D() { }; // m20170217.A$2/owner.kind=MTH } }
从如上例子打印结果也可以看出,只有A与B类是非local的,其它都是local。看C类,它的owner.kin为MTH,表示匿名块在编译处理过程中是当作匿名方法来处理的。
4、MethodSymbol
/** The code of the method. */ public Code code = null; /** The parameters of the method. */ public List<VarSymbol> params = null; /** The names of the parameters */ public List<Name> savedParameterNames; /** For an attribute field accessor, its default value if any. * The value is null if none appeared in the method declaration. * * 对于属性字段访问器,其默认值(如果有)。 */ public Attribute defaultValue = null; // Attribute类表示的是注解的值
1、属性params
举个例子,如下:
public class B { @HelloWorldAnnotation(name = "小明") public Integer test(int a, String name, Object c) { return 1; } }
查看MethodSymbol,如下截图:
2、属性defaultValue
@Retention(RetentionPolicy.RUNTIME) // 注解会在class中存在,运行时可通过反射获取 @Target(ElementType.METHOD) // 目标是方法 @Documented // 文档生成时,该注解将被包含在javadoc中,可去掉 public @interface HelloWorldAnnotation { public String name() default "xxxxx"; }
查看MethodSymbol,如下截图:
5、OperatorSymbol
/** A class for predefined operators. * * OperatorSymbol继承MethodSymbol是由于操作符有操作数和返回类型,和方法参数与返回类型相似 */ public class OperatorSymbol extends MethodSymbol { public int opcode; public OperatorSymbol(Name name, Type type, int opcode, Symbol owner) { super(PUBLIC | STATIC, name, type, owner); this.opcode = opcode; } public <R, P> R accept(Symbol.Visitor<R, P> v, P p) { return v.visitOperatorSymbol(this, p); } }
OperatorSymbol继承自MethodSymbol。其中有个opcode属性,表示操作的字节码指令。这都是JVM先前定义好的,如:0x03表示将int类型0推送至栈顶。
6、VarSymbol
/** A class for variable symbols */ public class VarSymbol extends Symbol implements VariableElement { public int pos = Position.NOPOS; /** The variable's address. Used for different purposes during * flow analysis, translation and code generation. * * Flow analysis: * If this is a blank final or local variable, its sequence number. * Translation: * If this is a private field, its access number. * Code generation: * If this is a local variable, its logical slot number. */ public int adr = -1; }
其中的adr属性还有待继续研究。