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 recovery
    case PUBLIC:
        return true;
    case PRIVATE:
        return this.owner == clazz;
    case PROTECTED:
        // we model interfaces as extending Object
        // 非接口时为true,接口时为false,因为接口里没有public members
        return (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 members
        return (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分支。

  

  

关于符号Symbol第一篇的更多相关文章

  1. 关于符号Symbol第二篇

    来看一下继承自Symbol的具体实现类. 1.TypeSymbol /** A class for type symbols. * Type variables are represented by ...

  2. 回合对战制游戏第一篇(初识java)

    回合对战制游戏第一篇 一,所谓的java. java是一门完全面向对象的编程语言,而之前所接触到的C语言是一门面向有一个过程的语音,对于两个的区别应该有一个清楚的认识. java的第一个内容. 类和对 ...

  3. 微信公众账号开发之微信登陆Oauth授权-第一篇

    我曾经在2012年的时候开始研究微信,那时微信的版本还是处于1.0,当时给朋友帮忙做一个基于微信端的web应用,官方的文档是相当少的,百度搜索出来的东西基本也没有多少实用价值,不过是在官网的基础上作了 ...

  4. RabbitMQ学习总结 第一篇:理论篇

    目录 RabbitMQ学习总结 第一篇:理论篇 RabbitMQ学习总结 第二篇:快速入门HelloWorld RabbitMQ学习总结 第三篇:工作队列Work Queue RabbitMQ学习总结 ...

  5. 【OpenCV入门指南】第一篇 安装OpenCV

    http://blog.csdn.net/morewindows/article/details/8225783/ win10下vs2015配置Opencv3.1.0过程详解(转) http://ww ...

  6. 【OpenCV第一篇】安装OpenCV

    [OpenCV第一篇]安装OpenCV 本篇主要介绍如何下载OpenCV安装程序,如何在VS2008下安装配置OpenCV,文章最后还介绍了一个使用OpenCV的简单小例子. <OpenCV入门 ...

  7. 分布式文件系统 FastDFS 5.0.5 & Linux CentOS 7 安装配置(单点安装)——第一篇

    分布式文件系统 FastDFS 5.0.5 & Linux CentOS 7 安装配置(单点安装)--第一篇 简介 首先简单了解一下基础概念,FastDFS是一个开源的轻量级分布式文件系统,由 ...

  8. Python之路,第一篇:Python入门与基础

    第一篇:Python入门与基础 1,什么是python? Python 是一个高层次的结合了解释性.编译性.互动性和面向对象的脚本语言. 2,python的特征: (1)易于学习,易于利用: (2)开 ...

  9. 视觉SLAM的数学基础 第一篇 3D空间的位置表示

    视觉SLAM中的数学基础 第一篇 3D空间的位置表示 前言 转眼间一个学期又将过去,距离我上次写<一起做RGBD SLAM>已经半年之久.<一起做>系列反响很不错,主要由于它为 ...

随机推荐

  1. faceswap requirements

    tqdm psutil pathlib==1.0.1 scandir==1.7 opencv-python scikit-image scikit-learn matplotlib==2.2.2 ff ...

  2. 如何使用C++11实现C#属性概念设计

    目录(原创博客,版权所有,转载请注明出处 http://www.cnblogs.com/feng-sc) 1.概述 2.C#属性的概念  2.1.简单示例代码介绍C#中的属性  2.2.C++实现效果 ...

  3. D3 drag

    <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...

  4. web.xml文件中context-param、listener、filter、servlet的执行顺序

    首先可以肯定的是,加载顺序与它们在 web.xml 文件中的先后顺序无关.即不会因为 filter 写在 listener 的前面而会先加载 filter.最终得出的结论是:listener -> ...

  5. Android-Xml文件生成,Xml数据格式写入

    在上一篇博客,Android-XML格式描述,介绍来XML在Android中的格式: 生成xml文件格式数据,Android提供了Xml.newSerializer();,可以理解为Xml序列化: 序 ...

  6. ActiveMq 配置多队列

    一直在赶项目,好久没有写博文了,中间偶尔有些代码什么的,也都是放到github了,不过大多都是测试代码,毕竟有些成型的东西是给公司写的,鉴于职业道德,还是不好公开. 言归正传,这两天在接入第三方的收费 ...

  7. 设计模式之模版方法模式(Template Method Pattern)

    一.什么是模版方法模式? 首先,模版方法模式是用来封装算法骨架的,也就是算法流程 既然被称为模版,那么它肯定允许扩展类套用这个模版,为了应对变化,那么它也一定允许扩展类做一些改变 事实就是这样,模版方 ...

  8. c#中取整方式

    主要用到 System 命名空间下的一个数据类 Math ,调用他的方法 一共有三种方式: 第一种 Math.Round:根据四舍五入取整 第二种 Math.Ceiling:向上取整,有小数,整数加1 ...

  9. leetcode 搜索插入位置

    给定一个排序数组和一个目标值,在数组中找到目标值,并返回其索引.如果目标值不存在于数组中,返回它将会被按顺序插入的位置. 你可以假设数组中无重复元素. 示例 1: 输入: [1,3,5,6], 5 输 ...

  10. 在ASP.NET MVC中使用区域来方便管理controller和view

    在ASP.NET MVC中使用区域来方便管理controller和view 在mvc架构中,一般在controllers和views中写所有控制器和视图, 太多控制器时候,为了方便管理,想要将关于pe ...