举个例子,如下:

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. linux常见命令整理

    Linux管理文件和目录的命令 命令 功能 命令 功能 pwd 显示当前目录 ls 查看目录下的内容 cd 改变所在目录 cat 显示文件的内容 grep 在文件中查找某字符 cp 复制文件 touc ...

  2. 18、docker的持久化存储和数据共享

    18.1 Data Volume Docker持久化数据方案 基于本地文件系统的Volume   可以在执行docker create或者docker run的时候,通过-v参数将主机的目录作为容器的 ...

  3. 基于Maven的S2SH(Struts2+Spring+Hibernate)框架搭建

    1. 前言 基于Maven的开发方式开发项目已经成为主流.Maven能很好的对项目的层次及依赖关系进行管理.方便的解决大型项目中复杂的依赖关系.S2SH(Struts2+Spring+Hibernat ...

  4. C++互斥器:Mutex

    互斥器的功能是,使多个线程和谐工作.同一时间内,只能有一个线程得到互斥对象,并获得资源操作权限,那么如果同一时间其他线程也想去操作资源,此时就会因为Mutex未处于激发状态,而无奈的等待…这时候,线程 ...

  5. [翻译]NUnit---SetUp and SetUpFixture and Suite Attributes(十九)

    SetUpAttribute (NUnit 2.0 / 2.5) 本特性用于TestFixture提供一个公共的功能集合,在呼叫每个测试方法之前执行.同时也用在SetUpFixture中,SetUpF ...

  6. vux 入门备忘大佬多指点

    一.安装node.js https://nodejs.org/en/ 这样就可以使用npm喽 二.安装vux 安装vux npm install vux --save 安装vux-loader npm ...

  7. 使用base64转码的方式上传图片

    1.前端html代码 <input style="width:100%" onchange="loadpicture(1)" type="fil ...

  8. php CI框架log写入

    1.首先,打开application下的config.php文件,将log配置打开如下 /* |---------------------------------------------------- ...

  9. asp.net 下载EXCEL文件

    一.需要导入NPOI 库文件 打开VS2012 工具>>库程序包管理器>>管理解决方案的NuGet程序包,搜索NPOI,如下图 安装完成: 添加 using NPOI.HSSF ...

  10. C# 动态生成Html地图文件

    public void GPSModel(string x, string y, string ss)//动态地图文件 { if (x.Contains("-") &&am ...