Javac语法糖之内部类
在Javac中解语法糖主要是Lower类来完成,调用这个类的入口函数translateTopLevelClass即可。这个方法只是JavacCompiler类的desugar方法中进行了调用。
首先来看下local class本地类解语法糖,举个例子,如下:
class Outer {
class AOuter{
int temp = 0;
}
final int count1 = new Integer(1);
final int count2 = 1;
static final int count3 = new Integer(1);
public void method(final int count4) {
final int count5 = new Integer(1);
final int count6 = 1;
class Inner {
int a = count1; // 传入Outer实现对象后通过outer.count1获取
int b = count2; // 直接写为1
int c = count3; // 通过Outer.count3获取
int d = count4; // 需要构造函数传入
int e = count5; // 需要构造函数传入
int f = count6; // 直接写为1
AOuter aOuter = new AOuter();
}
}
}
对于内部类Inner来说,其实在生成class文件时也是一个独立的class文件,在处理时完全看成一个独立的类来处理,生成时的类名规则为:
package com.test15;
import com.test15.Outer.AOuter;
class Outer$1Inner {
int a;
int b;
int c;
int d;
int e;
int f;
AOuter aOuter;
Outer$1Inner(Outer var1, int var2, int var3) {
this.this$0 = var1;
this.val$count4 = var2;
this.val$count5 = var3;
this.a = this.this$0.count1;
this.b = 1;
this.c = Outer.count3;
this.d = this.val$count4;
this.e = this.val$count5;
this.f = 1;
this.aOuter = new AOuter(this.this$0);
}
}
Outer的class类反编译后如下:
package com.test15;
class Outer {
final int count1 = (new Integer(1)).intValue();
final int count2 = 1;
static final int count3 = (new Integer(1)).intValue();
Outer() {
}
public void method(int var1) {
int var2 = (new Integer(1)).intValue();
class Inner {
int a;
int b;
int c;
int d;
int e;
int f;
Outer.AOuter aOuter;
Inner(int var2, int var3) {
this.val$count4 = var2;
this.val$count5 = var3;
this.a = Outer.this.count1;
this.b = 1;
this.c = Outer.count3;
this.d = this.val$count4;
this.e = this.val$count5;
this.f = 1;
this.aOuter = Outer.this.new AOuter();
}
}
}
class AOuter {
int temp = 0;
AOuter() {
}
}
}
Outer$AOuter的class文件反编译后如下:
package com.test15;
class Outer$AOuter {
int temp;
Outer$AOuter(Outer var1) {
this.this$0 = var1;
this.temp = 0;
}
}
可以看到会为Outer$1Inner合成了两个变量val2,val3,由于其它是constant variable,而非free variable。在为内部类合成变量时,需要首先收集free variable,主要是通过freevars()方法来完成,具体代码如下:
/** Return the variables accessed from within a local class,
* which are declared in the local class' owner.
* (in reverse order of first access).
*/
List<VarSymbol> freevars(ClassSymbol c) {
// 如果类符号c所属的符号为变量或者方法时表明这是一个local class
if ((c.owner.kind & (VAR | MTH)) != 0) {
List<VarSymbol> fvs = freevarCache.get(c);
if (fvs == null) {
FreeVarCollector collector = new FreeVarCollector(c);
JCClassDecl jcd = classDef(c);
collector.scan(jcd);
fvs = collector.fvs;
freevarCache.put(c, fvs);
}
return fvs;
} else {
return List.nil();
}
}
在如上的实例中,收集到的自由变量为count4与count5。
主要还是通过FreeVarCollecotr这个继承了TreeScanner类的类来完成对自由变量的收集,这个类的实现代码如下:
/** A navigator class for collecting the free variables accessed from a local class.
* There is only one case; all other cases simply traverse down the tree.
*/
class FreeVarCollector extends TreeScanner {
/** The owner of the local class.
*/
Symbol owner;
/** The local class.
*/
ClassSymbol clazz;
/** The list of owner's variables accessed from within the local class,without any duplicates.
*/
List<VarSymbol> fvs;
FreeVarCollector(ClassSymbol clazz) {
this.clazz = clazz;
this.owner = clazz.owner;
this.fvs = List.nil();
}
/** Add free variable to fvs list unless it is already there.
*/
private void addFreeVar(VarSymbol v) {
for (List<VarSymbol> l = fvs; l.nonEmpty(); l = l.tail)
if (l.head == v) return;
fvs = fvs.prepend(v);
}
/** Add all free variables of class c to fvs list
* unless they are already there.
*/
private void addFreeVars(ClassSymbol c) {
List<VarSymbol> fvs = freevarCache.get(c);
if (fvs != null) {
for (List<VarSymbol> l = fvs; l.nonEmpty(); l = l.tail) {
addFreeVar(l.head);
}
}
}
/** If tree refers to a variable in owner of local class, add it to free variables list.
*/
public void visitIdent(JCIdent tree) {
result = tree;
visitSymbol(tree.sym);
}
// where
private void visitSymbol(Symbol _sym) {
Symbol sym = _sym;
if (sym.kind == VAR || sym.kind == MTH) {
while (sym != null && sym.owner != owner){
Name name = proxyName(sym.name);
sym = proxies.lookup(name).sym;
}
if (sym != null && sym.owner == owner) {
VarSymbol v = (VarSymbol)sym;
if (v.getConstValue() == null) {
addFreeVar(v);
}
} else {
if (outerThisStack.head != null &&
outerThisStack.head != _sym)
visitSymbol(outerThisStack.head);
}
}
}
/** If tree refers to a class instance creation expression
* add all free variables of the freshly created class.
*/
public void visitNewClass(JCNewClass tree) {
ClassSymbol c = (ClassSymbol)tree.constructor.owner;
addFreeVars(c);
if (tree.encl == null &&
c.hasOuterInstance() &&
outerThisStack.head != null)
visitSymbol(outerThisStack.head);
super.visitNewClass(tree);
}
/** If tree refers to a qualified this or super expression
* for anything but the current class, add the outer this
* stack as a free variable.
*/
public void visitSelect(JCFieldAccess tree) {
if ((tree.name == names._this || tree.name == names._super) &&
tree.selected.type.tsym != clazz &&
outerThisStack.head != null)
visitSymbol(outerThisStack.head);
super.visitSelect(tree);
}
/** If tree refers to a superclass constructor call,
* add all free variables of the superclass.
*/
public void visitApply(JCMethodInvocation tree) {
if (TreeInfo.name(tree.meth) == names._super) {
addFreeVars((ClassSymbol) TreeInfo.symbol(tree.meth).owner);
Symbol constructor = TreeInfo.symbol(tree.meth);
ClassSymbol c = (ClassSymbol)constructor.owner;
if (c.hasOuterInstance() &&
tree.meth.getTag() != JCTree.SELECT &&
outerThisStack.head != null)
visitSymbol(outerThisStack.head);
}
super.visitApply(tree);
}
} // end class
/** Return the variables accessed from within a local class, which
* are declared in the local class' owner.
* (in reverse order of first access).
*/
List<VarSymbol> freevars(ClassSymbol c) {
if ((c.owner.kind & (VAR | MTH)) != 0) {
List<VarSymbol> fvs = freevarCache.get(c);
if (fvs == null) {
FreeVarCollector collector = new FreeVarCollector(c);
JCClassDecl jcd = classDef(c);
collector.scan(jcd);
fvs = collector.fvs;
freevarCache.put(c, fvs);
}
return fvs;
} else {
return List.nil();
}
}
必定上面的例子,具体代码如下:
public class Outer {
class AOuter{
int temp = 0;
}
final int count1 = new Integer(1);
final int count2 = 1;
static final int count3 = new Integer(1);
public void method(final int count4) {
final int count5 = new Integer(1);
final int count6 = 1;
class Inner {
int a = count1;
int b = count2;
int c = count3;
int d = count4;
int e = count5;
int f = count6;
AOuter aOuter = new AOuter();
}
class Inner2{
Inner x = new Inner();
}
}
}
则生成后的Inner2类的代码如下:
class Outer$1Inner2 {
/*synthetic*/ final Outer this$0;
/*synthetic*/ final int val$count4;
/*synthetic*/ final int val$count5;
Outer$1Inner2(/*synthetic*/ final Outer this$0, /*synthetic*/ final int val$count5, /*synthetic*/ final int val$count4) {
this.this$0 = this$0;
this.val$count5 = val$count5;
this.val$count4 = val$count4;
super();
}
Outer$1Inner x = new Outer$1Inner(this$0, val$count4, val$count5);
}
Javac语法糖之内部类的更多相关文章
- Java语法糖之内部类
例1: class Outer { public void md1(final int a) { final int b = 1; class LocalA { int c = a; } class ...
- Javac语法糖之EnumSwitch
在Switch中可以使用的类型有枚举.字符串类型与整形int类型,下面来具体看这几个类型. 1.switch为枚举类型 枚举类: enum Fruit { APPLE,ORINGE } 调用javac ...
- Javac语法糖之增强for循环
加强的for循环有两种,遍历数组和实现了Iterable接口的容器.javac通过visitForeachLoop()方法来实现解语法糖,代码如下: /** Translate away the fo ...
- Javac语法糖之其它
1.变长参数 class VarialbeArgumentsDemo { public static void doWork(int... a) {//可变参数 } public static voi ...
- Javac语法糖之TryCatchFinally
https://docs.oracle.com/javase/specs/jls/se7/html/jls-14.html#jls-14.20.3 Optionally replace a try s ...
- Javac语法糖之Enum类
枚举类在Javac中是被当作类来看待的. An enum type is implicitly final unless it contains at least one enum constant ...
- python进阶之内置函数和语法糖触发魔法方法
前言 前面已经总结了关键字.运算符与魔法方法的对应关系,下面总结python内置函数对应的魔法方法. 魔法方法 数学计算 abs(args):返回绝对值,调用__abs__; round(args): ...
- Java 语法糖详解
语法糖 语法糖(Syntactic Sugar),也称糖衣语法,是由英国计算机学家 Peter.J.Landin 发明的一个术语,指在计算机语言中添加的某种语法. 这种语法对语言的功能并没有影响,但是 ...
- 深入理解java虚拟机(十二) Java 语法糖背后的真相
语法糖(Syntactic Sugar),也叫糖衣语法,是英国计算机科学家彼得·约翰·兰达(Peter J. Landin)发明的一个术语.指的是,在计算机语言中添加某种语法,这些语法糖虽然不会对语言 ...
随机推荐
- 20145209 2016-2017-2 《Java程序设计》第6周学习总结
20145209 2016-2017-2 <Java程序设计>第6周学习总结 教材学习内容总结 4.1 Y86指令集体系结构 •有8个程序寄存器:%eax.%ecx.%edx.%ebx.% ...
- 移动 APP 网络优化概述
一般开发一个 APP,会直接调用系统提供的网络请求接口去服务端请求数据,再针对返回的数据进行一些处理,或者使用AFNetworking/OKHttp这样的网络库,管理好请求线程和队列,再自动做一些数据 ...
- centos7 源码安装python3
1.非常重要!必须得先安装py3所依赖的软件包,否则可能会出现py3安装成功,却缺少相应的pip yum groupinstall "Development tools" yum ...
- 页面中的删除确认(ajax)、输入框中确认信息是否可用(ajax)的jquery代码
1.页面中的删除确认(ajax) <%@ page language="java" contentType="text/html; charset=UTF-8&qu ...
- UniGUI的TUniLoginForm窗口自定义背景色
uniGUI的TUniLoginForm类创建的登录窗口默认是不带颜色,可以自定义css风格来改变背景颜色. 一般是通过在UniServerModule中,在CustcomSS属性中,修改extjs的 ...
- boot分区剩余空间不足
Linux boot分区用于存放内核文件以及Linux一些启动配置文件,一般情况下分区大小为500M足够使用,如果出现空间不足的问题可以使用以下方法来解决. 查看已经安装的内核 dpkg --ge ...
- BlangenOA项目总结
1.使用EF,当返回的是IQueryable<T>类型,延迟加载. 2.增删改查 分页(页码,页大小,总记录数,是否升序)(两个lambda表达式,一个筛选规则,一个是排序规则(可以选择类 ...
- .net core Ocelot Consul 实现API网关 服务注册 服务发现 负载均衡
大神张善友 分享过一篇 <.NET Core 在腾讯财付通的企业级应用开发实践>里面就是用.net core 和 Ocelot搭建的可扩展的高性能Api网关. Ocelot(http:// ...
- K8S+GitLab-自动化分布式部署ASP.NET Core(一) 部署环境
一.部署流程介绍 开发人员通过Git上传asp.net core 项目到Gilab,并编写好.gitlab-ci.yml , GitLab-Runner 自动拉取代码,然后进行Build,编译,单元测 ...
- vs2017使用rdlc
写在前面:因为公司要求做个批量打印工具,以前用Delphi+FastReport开发的,现在因为公司就剩下一个Delphi开发工程师了,还外出,所以这是就落在我身上.因为这个打印工具不需要使用人员设计 ...