关于作用域范围Scope
举个例子,如下:
public class C { public int a = 2; public void test(int b) { int c = 3; for (int d = 3; a < 6; a++) { } } }
形成的Scope作用域如下图:
属性table中存储的具体数据如下截图:
关于Scope的定义如下:
/** A scope represents an area of visibility in a Java program. The * Scope class is a container for symbols which provides * efficient access to symbols given their names. * * Scopes are implemented as hash tables with "open addressing" and "double hashing". * Scopes can be nested; the next field of a scope points * to its next outer scope. Nested scopes can share their hash tables. * */ public class Scope { /** The number of scopes that share this scope's hash table. */ private int shared; /** Next enclosing scope (with whom this scope may share a hashtable) * * 参考博文:https://www.cnblogs.com/extjs4/p/6386572.html */ public Scope next; /** The scope's ownerSymbol. */ public Symbol ownerSymbol; /** A hash table for the scope's entries. */ Entry[] table; /** Mask for hash codes, always equal to (table.length - 1). */ int hashMask; /** A linear list that also contains all entries in * reverse order of appearance (i.e later entries are pushed on top). */ public Entry elems; /** The number of elements in this scope. * This includes deleted elements, whose value is the sentinel. */ int nelems = 0; // ... }
Scope是符号的容器,通过Scope来查找及决定符号的访问。创建Scope对象有三种途径:
(1)调用构造函数创建
/** The hash table's initial size. */ private static final int INITIAL_SIZE = 0x10; /** A value for the empty scope. */ public static final Scope emptyScope = new Scope(null, null, new Entry[]{}); /** Construct a new scope, within scope next, with given owner, using * given table. The table's length must be an exponent of 2. */ protected Scope(Scope next, Symbol owner, Entry[] table) { this.next = next; Assert.check(emptyScope == null || owner != null); this.ownerSymbol = owner; this.table = table; this.hashMask = table.length - 1; } /** Construct a new scope, within scope next, with given owner, * using a fresh table of length INITIAL_SIZE. */ public Scope(Symbol owner) { this(null, owner, new Entry[INITIAL_SIZE]); }
第一个为基本的构造函数,一般不对外开放调用,由于是protected权限,所以一般是子类通过super()方法来调用,而通过调用下面的构造函数来得到一个全新的Scope对象。
(2)调用dup()方法
/** Convenience constructor used for dup and dupUnshared. */ private Scope(Scope next, Symbol owner, Entry[] table, int nelems) { this(next, owner, table); this.nelems = nelems; } /** Construct a fresh scope within this scope, with same ownerSymbol, * which shares its table with the outer scope. Used in connection with * method leave if scope access is stack-like in order to avoid allocation * of fresh tables. */ public Scope dup() { return dup(this.ownerSymbol); } /** Construct a fresh scope within this scope, with new ownerSymbol, * which shares its table with the outer scope. Used in connection with * method leave if scope access is stack-like in order to avoid allocation * of fresh tables. * 如果范围访问是堆栈式的,则使用方法离开,以避免重新分配新表。 */ public Scope dup(Symbol newOwner) { Scope result = new Scope(this, newOwner, this.table, this.nelems); shared++; // System.out.println("====> duping scope " + this.hashCode() + " owned by " + newOwner + " to " + result.hashCode()); // new Error().printStackTrace(System.out); return result; }
共有几处调用这个dup()方法,如下截图:
(3)调用dupUnshared()方法
/** Construct a fresh scope within this scope, with same ownerSymbol, * with a new hash table, whose contents initially are those of * the table of its outer scope. */ public Scope dupUnshared() { return new Scope(this, this.ownerSymbol, this.table.clone(), this.nelems); }
与dup()方法比起来,克隆了this.table的值,举个例子如下:
public class Test1 { static class Entry{ int a = 0; int[] arr = null; public Entry(int a,int[] arr){ this.a = a; this.arr = arr; } @Override public String toString() { return "Entry [a=" + a + ", arr=" + Arrays.toString(arr) + "]"; } } public static void main(String[] args) { Entry[] ens = new Entry[2]; ens[0] = new Entry(2,new int[]{2,3}); Entry[] ensC = ens.clone(); ensC[0].arr[0] = 33; ensC[1] = new Entry(3,new int[]{2,3}); System.out.println(Arrays.toString(ens)); System.out.println(Arrays.toString(ensC)); } }
运行结果如下:
result: [Entry [a=2, arr=[33, 3]], null] [Entry [a=2, arr=[33, 3]], Entry [a=3, arr=[2, 3]]]
可以看到,调用了clone()方法后,往table中加入新的Entry,不会影响到原来table中的值。这就是所说的不共享。
GJC中调用dupUnshared()方法的地方如下图所示。
其中有些重要的属性如下:
1、属性next
/** Next enclosing scope (with whom this scope may share a hashtable) * */ public Scope next;
从上面的例子可以清楚的看到next指向上一层作用域范围。作用域是通过块形成的,例如:
2、属性owner
/** The scope's owner. */ public Symbol owner;
表示的是这个作用域所属的符号。
3、属性table
/** A hash table for the scope's entries. */ Entry[] table;
这个属性比较重要,主要存储了这个Scope作用域内的符号,并且通过"open addressing"和"double hashing"来计算具体的某个Entry存储的位置。看一下Entry中除了存储符号Symbol还存储了哪些信息,定义如下:
/** A class for scope entries. * * shadowed指针指向桶中的下一个表项,shadowed意为隐蔽之义,sibling指针指向下一个填入哈希表中的表项,和符号的范围scope */ public class Entry { /** The referenced symbol. 被引用的符号 * sym == null iff(if and only if 当且仅当) this == sentinel */ public Symbol sym; /** An entry with the same hash code, or sentinel. */ public Entry shadowed; /** Next entry in same scope. */ public Entry sibling; /** The entry's scope. * scope == null iff this == sentinel * for an entry in an import scope, this is the scope where the entry came from (i.e. was imported from). */ public Scope scope; ... }
由于table属性可以共享,也就是被enclosing封闭的作用域可以和外层的作用域共享table,从上面举的例子中就可以看出。如果要共享,那么还需要保证被封闭的作用域的符号不能
被外层作用域取到,所以必须在Entry中指定这个Symbol到底是属于哪个作用域Scope的。通过如下截图就可以清楚的看到各个Symbol是在哪个作用域内定义的。
sibling属性将Entry连接为单向链表,如同一个作用域内定义了3个Symbol,有3个Entry,按倒序链接起来,也就是后加入的在前面。先加入的在后面。
public class C { public int a = 2; public void test(int b) { int c = 3; int d = 4; } }
在方法内定义了两个变量c和d,通过如下截图可以清楚看到d的sibling指向c,因为c先定义的。
shadowed属性,举个例子,如下:
public class C { public int a = 2; public void test() { int a = 2; class a {} } }
截图如下:
可以看到,对于类名为a和变量名为a的符号存储到了同一个hash桶中,通过shadowed形成了链。
再看个例子,如下:
public class C { public int a = 2; class a { } public void a() { } }
截图如下:
最新文章
- CI框架入门1
- 一些好的python IDE
- [前端]使用JQuery UI Layout Plug-in布局 - wolfy
- NeuSoft(2)添加系统调用
- WKWebView API精讲(OC)
- p235习题3
- Python2.7.3移除字符串中重复字符(一)
- PeopleReady 是什么系统?其中文为全员就绪
- Morris Traversal 二叉树遍历。
- as3 打开窗口类
- WordPress插件制作教程(二): 编写一个简单的插件
- printf输出格式
- rails 多态
- Mahout 系列之----共轭梯度
- oracle 数据库 date + 1 转载
- Extjs中数据导出到Excel
- Python3的List操作和方法
- Linux基础入门教程
- fastAdmin进阶
- MyBatis动态传入表名
热门文章
- 解决Error creating bean with name &#39;huayuanjingguanDaoimp&#39; defined in file [D:\apache-tomcat-7.0.52\webapps\landscapings\WEB-INF\classes\com\itheima\landscaping\dao\imp\huayuanjingguanDaoimp.class]: Invo
- hdu 5023 线段树+状压
- iterm2 学习笔记
- Failed to get D-Bus connection: Operation not permitted
- SQL server经验分享:SQLSERVER 被标记为“可疑”的数据库处理方法
- AndroidPn源码分析(二)
- 疑难杂症--SQL SERVER 2012下数据库内存异常回收
- Js加密算法
- 【C#进阶】拥抱Lambda(一)
- 用.net开发音频编辑软件