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)发明的一个术语.指的是,在计算机语言中添加某种语法,这些语法糖虽然不会对语言 ...
随机推荐
- TableView编辑状态下跳转页面的崩溃处理
29down votefavorite 12 I have a viewController with a UITableView, the rows of which I allow to edit ...
- jacob将word转换为html
1.导包jacob.jar 2.将下面两个文件复制到C:\Windows\System32路径下 3.代码如下 // 8 代表word保存成html public static final int W ...
- oracl中的大数据类型clob
建表 create table test_name( test_id number(6) not null, img_data clob ); 在java中该表所对应的po为: class Tes ...
- windows下C++实现遍历本地文件
1.假设本地 d:/ 下存放着0.txt,1.txt两个文件 2.开发工具VS,开发语言C++,怎么遍历得到两个文件呢? 废话不多,具体代码请看下面: /** * 入参:文件存放文件夹路径,例如D:\ ...
- hdu 1205 吃糖果【鸽巢原理】
题目 这道题不难,看别人博客的时候发现大家都说用鸽巢原理,这是个什么鬼,于是乎百度之. 1.把某种糖果看做隔板,如果某种糖果有n个,那么就有n+1块区域,至少需要n-1块其他种糖果才能使得所有隔板不挨 ...
- 基于SketchUp和Unity3D的虚拟场景漫游和场景互动
这是上学期的一次课程作业,难度不高但是也一并记录下来,偷懒地拿课程报告改改发上来. 课程要求:使用sketchUp建模,在Unity3D中实现场景漫游和场景互动. 知识点:建模.官方第一人称控制器.网 ...
- 深入浅析Node.js单线程模型
Node.js采用 事件驱动 和 异步I/O 的方式,实现了一个单线程.高并发的运行时环境,而单线程就意味着同一时间只能做一件事,那么Node.js如何利用单线程来实现高并发和异步I/O?本文将围绕这 ...
- 与数据库连接的页面增删改查 的easyui实现(主要是前端实现)
一.首先看一下最终实现的效果,上图 二.思路,主要是分两个文件实现,一个是页面显示文件:代码如下: <html> <head> <title>示例管理</ti ...
- vim 安装vim-javascript插件--Vundle管理
最近看了一下node.js,但是写的时候,vim对js没有很好的提示.于是就安装插件来处理,准备安装vim-javascript.但是安装github上面的插件时,推荐用Vundle和pathogen ...
- webform获取微信用户的授权
这是一个利用webform做出来的简单demo,微信授权,获取微信用户的基本信息.方便以后加深记忆. public partial class Index : System.Web.UI.Page { ...