javac的Resolve类解读
方法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类解读的更多相关文章
- Java类文件结构及javac的ClassReader类解读
首先来看一下ClassFile,类注释如下: A JVM class file. Generic Java classfiles have one additional attribute for c ...
- JAVA String、StringBuffer、StringBuilder类解读
JAVA String.StringBuffer.StringBuilder类解读 字符串广泛应用 在 Java 编程中,在 Java 中字符串属于对象,Java 提供了 String 类来创建和操作 ...
- 用javac编译servlet类出现问题
本人写了一个关于servlet的webapp,但是在用javac编译的时候,只是单纯的将jsp-api.jar和servlet-api.jar拷贝放在了其目录下面,然后利用命令行 javac XXX. ...
- package-info类解读
类不能带有public.private访问权限.package-info.java再怎么特殊,也是一个类文件,也会被编译成package-info.class,但是在package-info.java ...
- FS及CacheFS类解读
Javac中有FSInfo与CacheFSInfo两个类,CacheFSInfo继承了FSInfo类,这两个类的主要功能就是通过map缓存Jar文件,核心代码如下: private Map<Fi ...
- Bundle类解读
1.Bundle bundle = Platform.getBundle("org.eclipse.ui.views"); Platform是eclipse平台运行时的核心类,它是 ...
- Javac常量池的解读
interface IA{ public void md(); } public class Test07 implements IA{ final double d = 2.0d; final fl ...
- JavacProcessingEnvironment类解读
JavacProcessingEnvironment类的继承体系如下: 其中含有很多内部类,最重要的是迭代注解处理器相关的类,如下:
- C#封装CRUD到SqlHelper类解读
1.简单说明一下,一般情况下,数据库连接字符串是在App.config文件中进行配置,然后再在代码中进行引用.因此,我们在这里先看一下App.config文件. 首先看需要添加的内容: 参数说明: n ...
随机推荐
- jsp中路径的写法
在JavaWeb开发中,常使用绝对路径的方式来引入JavaScript和CSS文件,这样可以避免因为目录变动导致引入文件找不到的情况 代码” ${pageContext.request.context ...
- SSO单点登录三种情况的实现方式详解(转载)
单点登录(SSO——Single Sign On)对于我们来说已经不陌生了.对于大型系统来说使用单点登录可以减少用户很多的麻烦.就拿百度来说吧,百度下面有很多的子系统——百度经验.百度知道.百度文库等 ...
- 更改mysql默认字符集 (转载)
1. service mysqld stop,停用mysql. 2. cp /etc/my.cnf /etc/my.cnf.bak,修改前做备份,这是个好习惯. 修改my.cnfvi /etc/my. ...
- iperf命令 +speedtest-cli
iperf工具可以用来测量TCP或者是UDP的网络吞吐量,即bandwidth(带宽)测试. iPerf的主要目标是帮助调整特定路径上的TCP连接. 众所周知,TCP最基本的调整问题是调整TCP窗口 ...
- 如何为SharePoint文档库、文件夹、文件单独设置权限
在这里使用截图的方式简单描述两个问题:设置SharePoint Server文档库权限和文档库中的文件夹权限 一.设置SharePoint Server文档库权限 Figure 1 - 打开文档库后, ...
- 在linux中使用包管理器安装node.js
网上文章中,在linux下安装node.js都是使用源码编译,其实node的github上已经提供了各个系统下使用各自的包管理器(package manager)安装node.js的方法. 1. 在U ...
- 搭建自己的 Docker 私有仓库服务
关于 Docker 的介绍这里就省了,Docker 在其相关领域的火爆程度不亚于今年汽车行业里的特斯拉,docCloud 甚至把公司名都改成了 Docker, Inc. 好东西总是传播很快,我们现在已 ...
- Bootstrap变形记
bootstrap审美疲劳了,想个招换换样子,THINKING... 变形 >>> 哈,不用改已有代码,添加我的Harley.js即可,有空在玩... 真实好久不玩博客园了,200字 ...
- .net core 使用 redis
.net core 使用 redis 个人感觉.net core 对于微软技术而言有很重要的意义 ,所以最近已有时间就想看一看关于.net core 的文章. 今天我就来写一写如何在.net core ...
- win10 数字许可证激活被 KMS激活覆盖
打开cmd(管理员身份),依次执行以下命令: slmgr/upk slmgr/ckms slmgr/rearm 重启设备后联网登录Microsoft账号,转设置-激活-疑难解答,windows会找到与 ...