关于作用域范围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() {
	}
}

截图如下:

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

转载于:https://www.cnblogs.com/extjs4/p/6386572.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值