之前写的文章:

关于作用域范围Scope

Scope及相关的子类如下:

同时有些Scope还继承了Scope.ScopeListener类,如下:

1、StarImportScope及ImportScope

在JCCompilationUnit中定义了两个属性,其类型就是这两个类型:

public ImportScope namedImportScope;
public StarImportScope starImportScope;

但在初始化JCCompilationUnit语法节点时并不初始化这两个属性,而是在Enter的如下类中进行初始化,代码如下:

/** Create a fresh environment for toplevels.
 *  @param tree     The toplevel tree.
 */
public Env<AttrContext> topLevelEnv(JCCompilationUnit tree) {

    tree.namedImportScope = new ImportScope(tree.packge);
    tree.starImportScope = new StarImportScope(tree.packge);

    Env<AttrContext> localEnv = new Env<AttrContext>(tree, new AttrContext());
    localEnv.toplevel = tree;
    localEnv.enclClass = predefClassDef;
    // JCCompilationUnit的环境Scope中使用的是namedImportScope
    localEnv.info.scope = tree.namedImportScope;
    localEnv.info.lint = lint;

    return localEnv;
}

Scope最重要的作用就是用来查找特定范围内定义的符号,而这些符号的填充在MemberEnter类中完成的。首先看StarImportScope的填充,代码如下:

/** Import all classes of a class or package on demand.
 *  @param pos           Position to be used for error reporting.
 *  @param tsym          The class or package the members of which are imported.
 *  @param toScope   The (import) scope in which imported classes are entered.
 */
private void importAll(int pos,
                       final TypeSymbol tsym,
                       Env<AttrContext> env) {
    // Check that packages imported from exist (JLS ???).
    // 在调用tsym.members()会调用complete()方法来完成这个符号属性的填充
    if (tsym.kind == PCK01 &&
            tsym.members().elems == null &&
            !tsym.exists()) {

        // If we can't find java.lang, exit immediately.
        if (((PackageSymbol)tsym).fullname.equals(names.java_lang)) {
            // 致命错误: 在类路径或引导类路径中找不到程序包 java.lang
            JCDiagnostic msg = diags.fragment("fatal.err.no.java.lang");
            throw new FatalError(msg);
        } else {
            // 程序包{0}不存在
            log.error(JCDiagnosticFlag.RESOLVE_ERROR, pos, "doesnt.exist", tsym);
        }
    }
    Scope sp = tsym.members();
    env.toplevel.starImportScope.importAll(sp);
}

每个JCCompilationUnit编译单元通过import导入需要的依赖,有一个是默认导入的,就是java.lang.*下面的定义的类,而代码sp中包含的类符号如下:

Scope[
Void,VirtualMachineError,
VerifyError,UnsupportedOperationException,
UnsupportedClassVersionError,UnsatisfiedLinkError,
UnknownError, TypeNotPresentException, Throwable,
Throwable$WrappedPrintWriter,
Throwable$WrappedPrintStream,Throwable$SentinelHolder,
Throwable$PrintStreamOrWriter,ThreadLocal,
ThreadLocal$ThreadLocalMap,ThreadLocal$ThreadLocalMap$Entry,
ThreadGroup,ThreadDeath, Thread,
Thread$WeakClassKey, Thread$UncaughtExceptionHandler,
Thread$State, Thread$Caches, Terminator,
SystemClassLoaderAction, System, SuppressWarnings,
StringIndexOutOfBoundsException, StringCoding,
StringCoding$StringEncoder, StringCoding$StringDecoder,
StringBuilder, StringBuffer, String,
String$CaseInsensitiveComparator, StrictMath,
StackTraceElement, StackOverflowError,
Shutdown,Shutdown$Lock, Short,
Short$ShortCache, SecurityManager,
SecurityException, SafeVarargs, RuntimePermission,
RuntimeException, Runtime, Runnable,
ReflectiveOperationException, Readable,
ProcessImpl, ProcessImpl$LazyPattern,
ProcessEnvironment, ProcessEnvironment$NameComparator,
ProcessEnvironment$EntryComparator,
ProcessEnvironment$CheckedValues,
ProcessEnvironment$CheckedKeySet,
ProcessEnvironment$CheckedEntrySet,
ProcessEnvironment$CheckedEntry, ProcessBuilder,
ProcessBuilder$Redirect,
ProcessBuilder$Redirect$Type,ProcessBuilder$NullOutputStream,
ProcessBuilder$NullInputStream, Process,
Package, Override, OutOfMemoryError,
Object,NumberFormatException, Number,
NullPointerException, NoSuchMethodException,
NoSuchMethodError, NoSuchFieldException,
NoSuchFieldError, NoClassDefFoundError,
NegativeArraySizeException, Math, Long,
Long$LongCache, LinkageError, Iterable,
InterruptedException, InternalError, Integer,
Integer$IntegerCache, InstantiationException,
InstantiationError, InheritableThreadLocal,
IndexOutOfBoundsException,
IncompatibleClassChangeError,IllegalThreadStateException,
IllegalStateException, IllegalMonitorStateException,
IllegalArgumentException, IllegalAccessException,
IllegalAccessError, Float,
ExceptionInInitializerError, Exception, Error,
EnumConstantNotPresentException, Enum, Double,
Deprecated, ConditionalSpecialCasing,
ConditionalSpecialCasing$Entry, Compiler,
Comparable, Cloneable,CloneNotSupportedException,
ClassValue, ClassValue$Version,
ClassValue$Identity, ClassValue$Entry,
ClassValue$ClassValueMap,ClassNotFoundException,
ClassLoaderHelper, ClassLoader,
ClassLoader$ParallelLoaders, ClassLoader$NativeLibrary,
ClassFormatError, ClassCircularityError,
ClassCastException,Class,
Class$SecurityManagerHelper, Class$ReflectionData,
Class$MethodArray, Class$EnclosingMethodInfo,
Class$Atomic, CharacterName,
CharacterDataUndefined, CharacterDataPrivateUse,
CharacterDataLatin1, CharacterData0E,
CharacterData02,CharacterData01, CharacterData00,
CharacterData, Character, Character$UnicodeScript,
Character$UnicodeBlock, Character$Subset,
Character$CharacterCache, CharSequence, Byte,
Byte$ByteCache, BootstrapMethodError, Boolean,
AutoCloseable, AssertionStatusDirectives,
AssertionError, ArrayStoreException,
ArrayIndexOutOfBoundsException, ArithmeticException,
ApplicationShutdownHooks, Appendable,
AbstractStringBuilder, AbstractMethodError ]  

调用了StarImportScope的importAll()方法,传入了sp参数:importAll()方法代码如下:

public class StarImportScope extends ImportScope implements Scope.ScopeListener {

    public StarImportScope(Symbol owner) {
        super(owner);
    }

    public void importAll (Scope fromScope) {
        for (Scope.Entry e = fromScope.elems; e != null; e = e.sibling) {
            if (e.sym.kind == Kinds.TYP02 && !includes(e.sym)) {
                enter(e.sym, fromScope);
            }
        }
        // Register to be notified when imported items are removed
        fromScope.addScopeListener(this);
    }

    public void symbolRemoved(Symbol sym, Scope s) {
        remove(sym);
    }
    public void symbolAdded(Symbol sym, Scope s) { }
}

将sp中的所有符号导入StarImportScope中,并且StarImportScope中的table属性(Entry[]类型)中的元素为ImportEntry,如下部分截图:

说一下静态导入和非静态导入:

import java.io.*;  // 代码1
import java.math.BigDecimal; // 代码2

import static com.test19.TestStatic.*; // 代码3
import static com.test19.TestStatic.method;  // 代码4

public class TestScope{
	public void t(){
		InputStream p;
		BigDecimal d;
		int b = v;
		method();
	}
}

无论静态还是非静态导入,最终都会调用MemberEnter类中的visitImport()方法,这个方法的代码如下:

// process the non-static imports and the static imports of types.
public void visitImport(JCImport tree) {
    JCTree imp = tree.qualid;
    Name name = TreeInfo.name(imp);
    TypeSymbol p;

    // Create a local environment pointing to this tree to disable
    // effects of other imports in Resolve.findGlobalType
    Env<AttrContext> localEnv = env.dup(tree); // todo

    // Attribute qualifying package or class.
    JCFieldAccess s = (JCFieldAccess) imp;
    // 对于staticImport来说s.selected肯定是TYPE。因为import static TypeName . Identifier ;
    // 对于非staticImport来说s.selected可能是Type,也可能是PCK。如
    // 1、import PackageName.TypeName
    // 2、import PackageName.TypeName.TypeName
    p = attr.attribTree(s.selected,
                   localEnv,
                   tree.staticImport ? TYP02 : (TYP02 | PCK01),
                   Type.noType).tsym;
    if (name == names.asterisk) {
        // Import on demand.
        chk.checkCanonical(s.selected);
        if (tree.staticImport) {
            importStaticAll(tree.pos, p, env);
        }else {
            importAll(tree.pos, p, env);
        }
    } else {
        // Named type import.
        if (tree.staticImport) {
            importNamedStatic(tree.pos(), p, name, localEnv);
            chk.checkCanonical(s.selected);
        } else {
            TypeSymbol c = attribImportType(imp, localEnv).tsym;
            chk.checkCanonical(imp);
            importNamed(tree.pos(), c, env);
        }
    }
}

从如上的判断逻辑可以看出:

1、importStaticAll()方法

主要用来处理代码3。由于在导入时可能是静态类(包括TestStatic从父类或者接口中继承的),也可能是静态变量,两个有不同的处理逻辑。

(1)静态类的导入是立马执行导入的。

(2)非静态类的导入是在运行注解之前导入的

package com.test01;
public class MA {
	public static void x(){}
}

package com.test01;
import static com.test01.MA.*;
public class MB{
	public static void t(){}
}

同一个包中定义了MA与MB类,然后测试:

package com.test02;
import static com.test01.MB.*;
public class Test {
	public void test(){
		t();
		x(); // 报错
	}
}  

说明导入MB中的MA的静态方法没有在TestX中导入MB静态方法时一同将MA中的静态方法导入,如果MB继承MA,则如上不会报错。 

2、importAll()方法

主要用来处理代码1,与处理java.lang.*是一样的逻辑

3、importNamedStatic()方法

主要用来处理代码4,代码在执行中还需要调用Check类的checkUniqueStaticImport()方法

4、importNamed()方法

主要用来处理代码2,代码在执行中还需要调用Check类的checkUniqueImport()方法  

其实importNamed()方法与importNamedStatic()方法将符号导入namedImportScope中,而importStaticAll()与importAll()方法将符号导入

starImportScope中。而对于importStaticAll()与importNamedStatic()方法,只导入类,不导入方法与变量。

2、CompoundScope

与方法的检查有关  

3、DelegatedScope

查看MemberEnter类中的initEnv()方法,代码如下:

/** Create a fresh environment for a variable's initializer.
 *  If the variable is a field, the owner of the environment's scope
 *  is be the variable itself, otherwise the owner is the method
 *  enclosing the variable definition.
 *
 *  @param tree     The variable definition.
 *  @param env      The environment current outside of the variable definition.
 */
public Env<AttrContext> initEnv(JCVariableDecl tree, Env<AttrContext> env) {

    AttrContext ac = env.info.dup();
    AttrContextEnv ace = new AttrContextEnv(tree, ac);
    Env<AttrContext> localEnv = env.dupto(ace);

    if (tree.sym.owner.kind == TYP02) { // the variable is a field
        localEnv.info.scope = new DelegatedScope(env.info.scope);
        localEnv.info.scope.owner = tree.sym;
    }
    if (  (tree.mods.flags & STATIC) != 0 ||
           (env.enclClass.sym.flags() & INTERFACE) != 0  ){ // 表示在接口中定义的变量
        localEnv.info.staticLevel++;
    }
    return localEnv;
}

只有当variable是field时才将Scope替换为DelegatedScope,并且这个Scope的owner为这个Field本身。  

  

  

  

Scope及其子类介绍的更多相关文章

  1. Android Drawable的9种子类 介绍

    原文: Android Drawable的9种子类 介绍   Drawable 在android里面 就是代表着图像,注意是图像 而不是图片. 图片是图像的子集.图像除了可以包含图片以外 还可以包含颜 ...

  2. java并发编程(十)----JUC原子类介绍

    今天我们来看一下JUC包中的原子类,所谓原子操作是指不会被线程调度机制打断的操作:这种操作一旦开始,就一直运行到结束,中间不会有任何 context switch (切换到另一个线程),原子操作可以是 ...

  3. AVCaptureInput和AVCaptureOutput子类介绍

    AVCaptureInput AVCaptureDeviceInput:用于从AVCaptureDevice对象捕获数据. AVCaptureScreenInput:从macOS屏幕上录制的一种捕获输 ...

  4. Juc中Atomic原子类总结

    1 Atomic原子类介绍 2 基本类型原子类 3 数组类型原子类 4 引用类型原子类 5 对象的属性修改类型原子类

  5. java高并发系列 - 第23天:JUC中原子类,一篇就够了

    这是java高并发系列第23篇文章,环境:jdk1.8. 本文主要内容 JUC中的原子类介绍 介绍基本类型原子类 介绍数组类型原子类 介绍引用类型原子类 介绍对象属性修改相关原子类 预备知识 JUC中 ...

  6. JUC之原子类

    在分析原子类之前,先来了解CAS操作 CAS CAS,compare and swap的缩写,中文翻译成比较并交换. CAS 操作包含三个操作数 —— 内存位置(V).预期原值(A)和新值(B).如果 ...

  7. angulajs 详解 directive 中 的 scope 概念

    Directive 是 angularjs 中最重要的概念,我的理解就是自定义html tag, 这个自定的tag 浏览器不会解析,会有angularjs 来动态解析. 比如在html 中添加 < ...

  8. JUC 中的 Atomic 原子类总结

    1 Atomic 原子类介绍 Atomic 翻译成中文是原子的意思.在化学上,我们知道原子是构成一般物质的最小单位,在化学反应中是不可分割的.在我们这里 Atomic 是指一个操作是不可中断的.即使是 ...

  9. java核心-多线程(8)- 并发原子类

        使用锁能解决并发时线程安全性,但锁的代价比较大,而且降低性能.有些时候可以使用原子类(juc-atomic包中的原子类).还有一些其他的非加锁式并发处理方式,我写这篇文章来源于Java中有哪些 ...

随机推荐

  1. Redis Quick Start [遇到问题解决问题版]

    http://redis.io/topics/quickstart make test 时的问题: 问题:gcc: Command not found 解决:yum install gcc [root ...

  2. mac下svn无法上传.a文件的问题

    Xcode自带的svn和Versions以及一些其它工具都默认ignore".a"文件. 解决办法有两个: 方法一:使用命令行添加文件([转]原文在这) 1.打开终端,输入cd,空 ...

  3. GridView1 RowDataBound

    protected void GridView1_RowDataBound(object sender, GridViewRowEventArgs e) { if (e.Row.RowType == ...

  4. (zxing.net)解码

    //图片路径 string imgPath = @"D:\barcode.png"; //解码通用类 IBarcodeReader reader = new BarcodeRead ...

  5. C#之使用AutoUpdater自动更新客户端

    安装NuGet包 在Visio studio中右击解决方案,选择管理NuGet包,搜索安装Autoupdater.NET.Official. 工作简介 从服务器下载包含更新文件的XML文件,从中获取软 ...

  6. C# Lock锁(个人随记)

    先看看为什么要用锁 需求:多线程处理值的加减   static int NoLockData = 0; public static void NoLockNormalTest(int threadIn ...

  7. bower报错:未能连接到github.com端口1080:超时和一些其他错误

    报错1:fatal: unable to access 'https://github.com/xxx/xxxx.git/': Failed to connect to github.com port ...

  8. Linux中目录proc/net/dev详解

    在Linux系统中,系统调用是操作系统提供给应用程序使用操作系统服务的重要接口,但同时也正是通过系统调用机制,操作系统屏蔽了用户直接访问系统内核的可能性.幸运的是Linux提供了LKM机制可以使我们在 ...

  9. pageadmin CMS网站制作教程:栏目单页内容如何修改

    pageadmin CMS网站制作教程:栏目单页内容如何修改 一般情况下,如公司介绍,联系方式等介绍内页面都属于单页,单页内容可以直接在栏目设置界面进行修改,如下 1.对栏目单页内容进行设置,登录后台 ...

  10. template(定义类的模板关键字)

    template<typename T1> template<class T1> 在一般情况下二者使用方式是一样的,但有一个特例:就是当T1是一个类的时候,而这个类又有子类时候 ...