关于符号Symbol第一篇
?
Symbol類的一個實例代表一個符號。對于語法樹來說,并不是每個節點都有一個符號實例。下面列舉了哪些語法樹節點具有符號的引用,如下表格:
其中JCNewClass、JCAssignOp、JCUnary、JCBinary、JCFieldAccess與JCIdent繼承了JCExpression,可出現在表達式中。
?
如上的PackageSymbol、ClassSymbol、MethodSymbol、VarSymbol與TypeSymbol這些符號由用戶指定,而剩下的一些都是對既有符號的引用。如語法節點JCAssignOp中的operator。
下面來舉個具體的例子說明一下。
package m20170208;public class A<T> {public void test1() {int a = 3;int b = a + 2;}public void test2() {A ins = new A();ins.test1();} }查看JCCompilationUnit語法節點的packge屬性,如下:
查看JCClassDecl語法節點,如下:
?查看JCTypeParameter節點。這個節點沒有直接對Symbol進行引用,而是通過type屬性的tsym來引用的,如下:
查看JCMethodDecl節點的sym屬性,如下:
?
?查看JCVariableDecl節點的sym屬性,如下:
?
??查看JCBinary節點的operator屬性,如下:
?
? 查看JCIdent節點的sym屬性,如下:
? 查看JCNewClass節點的constructor屬性,如下:
? 查看JCFieldAccess節點的sym屬性,如下:
?
下面來介紹一下Symbol中一些重要的屬性。
屬性1:kind
** The kind of this symbol.* @see Kinds* * Java語言符號的種類,有包的符號、類型的符號、變量的符號、值的符號和方法的符號*/public int kind;kind值取的是類Kinds中定義的一些常量,如下:
/** The empty set of kinds.*/public final static int NIL = 0; // 0/** The kind of package symbols.*/public final static int PCK = 1 << 0; // 1/** The kind of type symbols (classes, interfaces and type variables).*/public final static int TYP = 1 << 1; // 2/** The kind of variable symbols.*/public final static int VAR = 1 << 2; // 4 變量符號/** The kind of values (variables or non-variable expressions), includes VAR.** 在標記階段使用*/public final static int VAL = (1 << 3) | VAR; // 12 值(包括變量和非變量表達式),也包括變量/** The kind of methods.*/public final static int MTH = 1 << 4; // 16 方法/** The error kind, which includes all other kinds.包含所有其它類型的錯誤*/public final static int ERR = (1 << 5) - 1; // 31 包括剩下的其它種類VAL一般是表達式的右端,例如:a = Exp;那么Exp可以是變量也可以是一個值,但是a絕對是一個變量。
OperatorSymbol的kind屬性值為16,也就是方法。因為這些符號最終的意思是通過方法來體現的,如int a = b+c;假如b與c是int類型變量,那么調用了有兩個int類型
參數的方法,將b與c傳入后,返回的結果即是a想要的結果。
?
對比Symbol例子的截圖查看kind的值。其中的NIL常量是在創建默認的noSymbol時使用過。在SymbolTable中的定義如下:
/** A symbol that stands for a missing symbol. */ public final TypeSymbol noSymbol;??
屬性2:flags_field
/** The flags of this symbol.* * 符號的標志*/public long flags_field; // 值來自Flags類中Flags中有許多修飾符,如public、abstract等等,表示這個符號上有哪些修飾符。不過樹節點中使用的修飾符與這里的flags_field未必是一個值,例如定義在接口中的變量,編譯器默認會添加public、static、final修飾符,在記錄符號時,這個flags_field也會將這些修飾符在long值中對應的位置為1。
?
屬性3:attributes_field
/** The attributes of this symbol.* * 符號的屬性*/public List<Attribute.Compound> attributes_field;舉個例子,如下:
import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target;@Target(ElementType.PACKAGE) @Retention(RetentionPolicy.RUNTIME) @interface MzTargetPackage {public String version() default ""; }定義一個包注解
@MzTargetPackage(version="1.0") package m20170208;在包上使用包注解,查看attributes_field屬性的值,如下:
?
屬性4:name
/** The name of this symbol in Utf8 representation.* 符號的名稱*/public Name name;這個name就是NameImpl對象,在前面也講解過。
屬性5:type
/** The type of this symbol.* * 符號的類型*/public Type type;有許多具體的Type類。
屬性6:owner
/** The owner of this symbol.*/public Symbol owner;從Symbol例子的各個截圖中可以查看到各個owner的具體值。其中OperatorSymbol由于是預定義好的,所以其owner歸屬于預定義的ClassSymbol中。
舉個例子,如下:?
class Test{Test o = new Test(){},x = o; }x這個VarSymbol還是屬性ClassSymbol(Test),在詞法分析階段就是兩個獨立變量的聲明,變為了如下形式:
class Test{Test o = new Test(){};Test x = o; }?new Test(){}為JCNewClass,而del屬性為JCClassDecl,如下截圖。
其中的匿名類的owner為VarSymbol,如下:
?
屬性6:erasure_field
/** A cache for the type erasure of this symbol.*/public Type erasure_field;表示泛型擦除后的類型,如類A的泛型擦除后,其值如下:
?又如JCNewClass中的MethodSymbol(A())中的此屬性值,如下:
創建類對象的實例時,其實是調用的這個類的構造函數(被當作特殊的方法來對待)。、?
?
方法1:public boolean isInheritedIn(Symbol clazz, Types types)
/** Is this symbol inherited into a given class?* PRE: If symbol's owner is a interface,* it is already assumed that the interface is a superinterface of given class.* @param clazz The class for which we want to establish membership.* This must be a subclass of the member's owner.*/ public boolean isInheritedIn(Symbol clazz, Types types) {switch ((int)(flags_field & Flags.AccessFlags)) { // AccessFlags中的值只能取其一default: // error recoverycase PUBLIC:return true;case PRIVATE:return this.owner == clazz;case PROTECTED:// we model interfaces as extending Object// 非接口時為true,接口時為false,因為接口里沒有public membersreturn (clazz.flags() & INTERFACE) == 0;case 0: // default訪問權限為同包或者同類,子類或者其它包是不可以訪問的PackageSymbol thisPackage = this.packge();for (Symbol sup = clazz;sup != null && sup != this.owner;sup = types.supertype(sup.type).tsym){while (sup.type.tag == TYPEVAR14) {sup = sup.type.getUpperBound().tsym;}if (sup.type.isErroneous()) {return true; // error recovery}if ((sup.flags() & COMPOUND) != 0) {/*eg1:interface IA{}interface IB{}class CA{}public class TestMethod{public <T extends CA&IA&IB>void methodA(){ }}*/continue;}if (sup.packge() != thisPackage) { // 當修飾符為默認時,則不同的包就造成了錯誤return false;}}// 非接口時為true,接口時為false,因為接口里沒有default membersreturn (clazz.flags() & INTERFACE) == 0;} }如上的代碼在檢查某個symbol是否在繼承于某個Symbl,例如:
class AA{void test(){} }public class Outer<T extends AA> {class Inner<D extends T>{D d;public void x(){d.test();}} }要檢查d.test()中的MethodSymbol時就需要判斷是否由d這個TypeSymbol繼承而來的MethodSymbol。test()方法定義在AA類中,并且修飾符為default,走case 0分支。
?
?
?
?
?
?
?
?
?
?
?
?
?
?
?
?
?
?
轉載于:https://www.cnblogs.com/extjs4/p/6382477.html
總結
以上是生活随笔為你收集整理的关于符号Symbol第一篇的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: go import用法
- 下一篇: 方正飞鸿智能信息平台产品白皮书(一)