之前写的文章:
关于作用域范围Scope
Scope及相关的子类如下:
同时有些Scope还继承了Scope.ScopeListener类,如下:
1、StarImportScope及ImportScope
在JCCompilationUnit中定义了两个属性,其类型就是这两个类型:
1
2
3public ImportScope namedImportScope; public StarImportScope starImportScope;
但在初始化JCCompilationUnit语法节点时并不初始化这两个属性,而是在Enter的如下类中进行初始化,代码如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18/** 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的填充,代码如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28/** 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中包含的类符号如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75Scope[ 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()方法代码如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22public 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,如下部分截图:
说一下静态导入和非静态导入:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15import 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()方法,这个方法的代码如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41// 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)非静态类的导入是在运行注解之前导入的
1
2
3
4
5
6
7
8
9
10
11package 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类,然后测试:
1
2
3
4
5
6
7
8package 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()方法,代码如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25/** 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本身。
转载于:https://www.cnblogs.com/extjs4/p/9218396.html
最后
以上就是壮观烧鹅最近收集整理的关于Scope及其子类介绍的全部内容,更多相关Scope及其子类介绍内容请搜索靠谱客的其他文章。
发表评论 取消回复