方法1:isInitializer()

/** An environment is an "initializer" if it is a constructor or
     *  an instance initializer.
     */
    static boolean isInitializer(Env<AttrContext> env) {
        Symbol owner = env.info.scope.owner;
        return owner.isConstructor() ||
                owner.owner.kind == TYP &&
                (owner.kind == VAR || owner.kind == MTH && (owner.flags() & BLOCK) != 0) &&
                (owner.flags() & STATIC) == 0;
    }

根据如上方法可以看出检查了如下三种情况的initializer:

public class TestInitializer {

	TestInitializer() { // constructor

	}

	int a = 2;   // instance variable initializer

	{  // instance initializer block
		a = 3;
	}
}

方法2:isAccessable()

/** Is class accessible in given environment?
     *  @param env    The current environment.
     *  @param c      The class whose accessibility is checked.
     */
    public boolean isAccessible(Env<AttrContext> env, TypeSymbol c) {
        return isAccessible(env, c, false);
    }

    public boolean isAccessible(Env<AttrContext> env, TypeSymbol c, boolean checkInner) {
        boolean isAccessible = false;
        switch ((short)(c.flags() & AccessFlags)) {
            case PRIVATE:
                isAccessible =   env.enclClass.sym.outermostClass() == c.owner.outermostClass();
                break;
            case 0:
                isAccessible =
                    env.toplevel.packge == c.owner // fast special case
                    ||
                    env.toplevel.packge == c.packge()
                    ||
                    // Hack: this case is added since synthesized default constructors
                    // of anonymous classes should be allowed to access
                    // classes which would be inaccessible otherwise.
                    env.enclMethod != null && (env.enclMethod.mods.flags & ANONCONSTR) != 0; // anonconstr 匿名构造函数
                break;
            default: // error recovery
            case PUBLIC:
                isAccessible = true;
                break;
            case PROTECTED:
                isAccessible =
                    env.toplevel.packge == c.owner // fast special case
                    ||
                    env.toplevel.packge == c.packge()
                    ||
                    isInnerSubClass(env.enclClass.sym, c.owner);
                break;
        }
        return (checkInner == false || c.type.getEnclosingType() == Type.noType) ?
            isAccessible :
            isAccessible && isAccessible(env, c.type.getEnclosingType(), checkInner);
    }  

检查的是TypeSymbol是否在某个Env中被访问到,能否访问到最终还要看Java的权限控制符public、protected、default和private。

另外需要知道的是只有Inner Class才可以为protected和private进行修饰。重点看一下protected修饰的类的逻辑。

public class Test {

	protected class D {
		public D() {
			// TODO Auto-generated constructor stub
		}
	}
}
class A { // only public, abstract & final are permitted
	// protected class D{}
}

public class TestAccessible {

	protected class B { // public,protected,private are permitted

	}

	public void method() {
		new A();  // 走env.toplevel.packge == c.owner
		new B();  // 走env.toplevel.packge == c.packge
	}

	class C extends Test{
		public void method3(){
			new D(); // 走isInnerSubClass(env.enclClass.sym,c.owner)
		}
	}

}

 继续看isInnerSubClass,如下:

 /** Is given class a subclass of given base class, or an inner class of a subclass?
     *  Return null if no such class exists.
     *  @param c     The class which is the subclass or is contained in it.
     *  @param base  The base class
     */
    private boolean isInnerSubClass(ClassSymbol c, Symbol base) {
        while (c != null && !c.isSubClass(base, types)) {
            c = c.owner.enclClass();
        }
        return c != null;
    }

  

方法3:isProtectedAccessible()

/** Is given protected symbol accessible if it is selected from given site
         *  and the selection takes place in given class?
         *  @param sym     The symbol with protected access
         *  @param c       The class where the access takes place
         *  @site          The type of the qualifier
         */
        private  boolean isProtectedAccessible(Symbol sym, ClassSymbol c, Type site) {
            while(  c != null &&
                     !(
                         c.isSubClass(sym.owner, types) &&
                         (c.flags() & INTERFACE) == 0 &&
                         // In JLS 2e 6.6.2.1, the subclass restriction applies only to instance fields and methods
                         // -- types are excluded regardless of whether they are declared 'static' or not.
                         ((sym.flags() & STATIC) != 0 || sym.kind == TYP || site.tsym.isSubClass(c, types))
                     )
             ) {
                c = c.owner.enclClass();
            }
            return c != null;
        }  

这个方法中包含了太多的逻辑,有一占需要说明,参数sym的修饰符已经判断为protected,下面分几个步骤来说:

(1)c.isSubClass(sym.owner,types)

类c(获取protected修饰符修饰的sym的类)是否与sym符号所属的符号形成了父子关系,如果是父子关系,当然有访问权限了。

(2)c.flags() & INTERFACE ==0 判断c是否为接口,如果c为接口,那么这个等式不成立。也就说明当c与sym.owner形成父子关系时,如果c为接口,那么有访问的权限。因为接口中所有成员(变量,方法,静态类与非静态类)的访问修饰符为public

(3) ((sym.flags() & STATIC) != 0 || sym.kind == TYP || site.tsym.isSubClass(c, types))

当protected修饰符修饰的sym为静态成员或者是个类型时,由于c为非接口且c与sym.owner已经形成了父子关系,所以有访问的权限。另外还有最后一种情况,site.tsym.isSubClass(c,types),举个例子:

package com.test05;

import com.test06.SubClass;

public class Temp extends SubClass{
	protected int b = 2;
}
package com.test05;

public class ParentClass {
	protected static int a = 1;
}

  

package com.test06;

import com.test05.ParentClass;
import com.test05.Temp;

public class SubClass extends ParentClass{
	class Inner{
		public void test() {
			int y = new Temp().a;
		}
	}
}  

由于Temp与所属的Inner类没有形成父子关系,所以c = c.owner.enclClass(),此时c已经成为了SubClass,而SubClass与符号a的owner(ParentClass)形成了父子关系并且SubClass不为接口,这时候就要判断如上的表达式了。

Temp与SubClass形成了父子关系,当然也就可以访问ParentClass中的protected修饰的成员了。  

  

javac的Resolve类解读的更多相关文章

  1. Java类文件结构及javac的ClassReader类解读

    首先来看一下ClassFile,类注释如下: A JVM class file. Generic Java classfiles have one additional attribute for c ...

  2. JAVA String、StringBuffer、StringBuilder类解读

    JAVA String.StringBuffer.StringBuilder类解读 字符串广泛应用 在 Java 编程中,在 Java 中字符串属于对象,Java 提供了 String 类来创建和操作 ...

  3. 用javac编译servlet类出现问题

    本人写了一个关于servlet的webapp,但是在用javac编译的时候,只是单纯的将jsp-api.jar和servlet-api.jar拷贝放在了其目录下面,然后利用命令行 javac XXX. ...

  4. package-info类解读

    类不能带有public.private访问权限.package-info.java再怎么特殊,也是一个类文件,也会被编译成package-info.class,但是在package-info.java ...

  5. FS及CacheFS类解读

    Javac中有FSInfo与CacheFSInfo两个类,CacheFSInfo继承了FSInfo类,这两个类的主要功能就是通过map缓存Jar文件,核心代码如下: private Map<Fi ...

  6. Bundle类解读

    1.Bundle bundle = Platform.getBundle("org.eclipse.ui.views"); Platform是eclipse平台运行时的核心类,它是 ...

  7. Javac常量池的解读

    interface IA{ public void md(); } public class Test07 implements IA{ final double d = 2.0d; final fl ...

  8. JavacProcessingEnvironment类解读

    JavacProcessingEnvironment类的继承体系如下: 其中含有很多内部类,最重要的是迭代注解处理器相关的类,如下:

  9. C#封装CRUD到SqlHelper类解读

    1.简单说明一下,一般情况下,数据库连接字符串是在App.config文件中进行配置,然后再在代码中进行引用.因此,我们在这里先看一下App.config文件. 首先看需要添加的内容: 参数说明: n ...

随机推荐

  1. php CI框架输出空行问题排查

    今天在使用 curl 命令行工具调试一个功能时,发现输出的内容总是会在最开始莫名其妙的多一行空行: 项目框架是 php 的 CodeIgniter,感觉这种问题在网上不好查找,因为可以确定这个是业务出 ...

  2. struts2拦截器demo

    按照网上的一些资料配置的,期间也出现过几个错误. 其中有个错误,是关于struts.xml里面package配置的问题,因为里面的几个标签是有顺序的. 顺序是: result-types interc ...

  3. 使用Docker、CoreOS、Mesos部署可扩展的Web应用

    [编者的话]本文作者重点介绍了如何使用Docker.CoreOS.Mesos.Vulcand.对象存储来部署一个可扩展的Web应用,他首先介绍了为什么要选择这些工具以及与其它工具相比这些工具的优势.紧 ...

  4. JAVA—IO操作

    一.JAVA I/O 输入输出流 1:编码问题 2:File类的使用 3:RandomAccessFile的使用 4:字节流的使用 5:字符流的使用 6:对象的序列化和反序列化 2: file类的使用 ...

  5. Java多线程编程:Callable、Future和FutureTask浅析(多线程编程之四)

    java多线程-概念&创建启动&中断&守护线程&优先级&线程状态(多线程编程之一)java多线程同步以及线程间通信详解&消费者生产者模式&死锁& ...

  6. OpenStack虚机网卡的创建过程

    OpenStack虚机网卡的创建过程 OpenStack最基本和常用的操作就是启动虚机.虚机启动的过程中涉及很多内容,其中非常重要的一个环节就是创建并绑定虚机的虚拟网卡.虚机的创建和管理是Nova的任 ...

  7. python--类与类之间的关系,(魔术方法)特殊成员方法

    1.依赖关系 类与类之间存在这几种关系:1.依赖关系 2.关联关系 3.组合关系 4.聚合关系 5.继承关系 6.实现关系 我们来设置下面两个场景 玩电脑和打僵尸 class Person: def ...

  8. 微信小程序转发商品的详情页 + 转发功能(传参)

    1.微信小程序转发传参,利用的还是onShareAppMessageapi 2.利用的还有json转换 JSON 是用于存储和传输数据的格式. JSON 通常用于服务端向网页传递数据 函数 描述JSO ...

  9. ESXi到KVM之v2v迁移

    1.ESXi到KVM之v2v情况说明 (1).配置任务列表: 1)VMwareESXi虚拟平台下linux系统迁移到KVM虚拟平台.2)VMwareESXi虚拟平台下windows系统迁移到KVM虚拟 ...

  10. LOJ#3085. 「GXOI / GZOI2019」特技飞行(KDtree+坐标系变换)

    题面 传送门 前置芝士 请确定您会曼哈顿距离和切比雪夫距离之间的转换,以及\(KDtree\)对切比雪夫距离的操作 题解 我们发现\(AB\)和\(C\)没有任何关系,所以关于\(C\)可以直接暴力数 ...