举个例子,如下:

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() {
	}
}

截图如下:

 

 

关于作用域范围Scope的更多相关文章

  1. [译] 你该知道的javascript作用域 (javascript scope)(转)

    javascript有一些对于初学者甚至是有经验的开发者都难以理解的概念. 这个部分是针对那些听到 : 作用域, 闭包, this, 命名空间, 函数作用域, 函数作用域, 全局作用域, 变量作用域( ...

  2. AngularJS 作用域(Scope)

    AngularJS作用域(Scope) Scope作用域是应用在视图和控制器之间的纽带,Scope是一个对象包含可用的方法和属性,Scope可以应用在试图和控制器上. $scope是针对当前的cont ...

  3. JavaScript变量作用域(Variable Scope)和闭包(closure)的基础知识

    在这篇文章中,我会试图讲解JavaScript变量的作用域和声明提升,以及许多隐隐藏的陷阱.为了确保我们不会碰到不可预见的问题,我们必须真正理解这些概念. 基本定义 作用范围是个“木桶”,里面装着变量 ...

  4. JavaScript 作用域(Scope)详解

    先对需要用到的名词解释一下,再通过例子深入理解 一.什么是作用域(Scope) [[scope]]:每个javascript函数都是一个对象,对象中有些属性我们可以访问,但有些不可以,这些属性仅供ja ...

  5. 深入理解JavaScript系列(14):作用域链(Scope Chain)

    前言 在第12章关于变量对象的描述中,我们已经知道一个执行上下文 的数据(变量.函数声明和函数的形参)作为属性存储在变量对象中. 同时我们也知道变量对象在每次进入上下文时创建,并填入初始值,值的更新出 ...

  6. JavaScript的作用域(Scope)和上下文(Context)

    JavaScript对于作用域(Scope)和上下文(Context)的实现是这门语言的一个非常独到的地方,部分归功于其独特的灵活性. 函数可以接收不同的的上下文和作用域.这些概念为JavaScrip ...

  7. 依赖作用域之<scope>test</scope>

    经常在代码中看到依赖的作用域为<scope>test</scope>,它的作用是,只能在test目录(通过右键->Make Directory as->Test S ...

  8. Spring中bean作用域属性scope

    关键字: spring中属性scope的prototype是什么意思   默认情况下,从bean工厂所取得的实例为Singleton(bean的singleton属性) Singleton: Spri ...

  9. Mybatis笔记六:Mybatis中SqlSessionFactoryBuilder/SqlSessionFactory/SqlSession/映射器实例的作用域(Scope)和生命周期

    SqlSessionFactoryBuilder 这个类可以被实例化.使用和丢弃,一旦创建了 SqlSessionFactory,就不再需要它了.因此 SqlSessionFactoryBuilder ...

随机推荐

  1. struts2从浅至深(二)详细配置

    1.加载时机 当应用被服务器加载时,Struts的配置文件就已经加载了 2.加载顺序 default.properties------->struts-default.xml---------& ...

  2. 20155320 2016-2017-2 《Java程序设计》第五周学习总结

    20155320 2016-2017-2 <Java程序设计>第五周学习总结 教材学习内容总结 错误处理 java中所有错误都会被打包为对象,可以通过try catch 代表错误的对象后做 ...

  3. office2010安装不成功提示缺少MSXML 6.10.1129.0?

    office2010安装 1. office重装 由于之前重装系统后安装office2010很顺利,这次删除office2010,由于没有删除干净,在程序删除面板中误点删除了其他文件所致,所以在此安装 ...

  4. POJ1511来回最短路

    POJ1511 问你从1到其它点得所有最短路之和  与  其他点到1得所有最短路之和 得总和 思路很明确就是两次最短路,翻转一次地图就好了 一开始就是两次spfa之间处理好数据得更新管理就好 vect ...

  5. AgentJob--无法重启Job--22022错误

    错误描述: 发现有个Job计划为长期重复运行,但从某个时间点后未运行,无任何错误信息. 手动启动该Job后爆以下错误 运行环境: Window Server 2008 R2 Enterprise Mi ...

  6. jenkins常用插件汇总

    jenkins常用插件汇总: Build-timeout Plugin:任务构建超时插件 Naginator Plugin:任务重试插件 Build User Vars Plugin:用户变量获取插件 ...

  7. SQL Server 紧急状态下的数据库恢复

    背景:由于服务器硬盘损坏,服务器异常关机.重新进入后,数据库为质疑状态.(数据库名字上面有个感叹号,连接不了) 经过无数次的百度以及大佬们的指点下,终于成功恢复,下面来说一下方法. 第一种: 1.在服 ...

  8. BitAdminCore框架更新日志20180518

    20180518更新内容 1.重构调整QQ登录代码,使用JObject,减少代码,增加access_token自动续期(未测试). 2.重构调整微信登录代码,使用JObject,减少代码,增加acce ...

  9. 【cocos2d-x 手游研发小技巧(2)循环无限滚动的登陆背景】

    原创文章,转载请附上链接:http://www.cnblogs.com/zisou/p/cocos2d-xARPG6.html 首先让大家知道我们想要实现的最终效果是什么样的? 看一个<逆天仙魔 ...

  10. python小数的进位与舍去

    一.基础知识准备 ​ 奇进偶舍,又称为四舍六入五成双规则.银行进位法(Banker's Rounding),是一种计数保留法,是一种数值修约规则.从统计学的角度,"奇进偶舍"比&q ...