在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文件,在处理时完全看成一个独立的类来处理,生成时的类名规则为:

和普通内部类的区别是, 普通内部类的class文件名为Outer$Inner.class 。 而定义在方法中的内部类的class文件名为Outer$<N>Inner.class 。 N代表数字, 如1, 2, 3 等 。 在外部类第一个方法中定义的内部类, 编号为1, 同理在外部类第二个方法中定义的内部类编号为2, 在外部类中第N个方法中定义的内部类编号为N 。方中的内部类也有自己独立的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语法糖之内部类的更多相关文章

  1. Java语法糖之内部类

    例1: class Outer { public void md1(final int a) { final int b = 1; class LocalA { int c = a; } class ...

  2. Javac语法糖之EnumSwitch

    在Switch中可以使用的类型有枚举.字符串类型与整形int类型,下面来具体看这几个类型. 1.switch为枚举类型 枚举类: enum Fruit { APPLE,ORINGE } 调用javac ...

  3. Javac语法糖之增强for循环

    加强的for循环有两种,遍历数组和实现了Iterable接口的容器.javac通过visitForeachLoop()方法来实现解语法糖,代码如下: /** Translate away the fo ...

  4. Javac语法糖之其它

    1.变长参数 class VarialbeArgumentsDemo { public static void doWork(int... a) {//可变参数 } public static voi ...

  5. Javac语法糖之TryCatchFinally

    https://docs.oracle.com/javase/specs/jls/se7/html/jls-14.html#jls-14.20.3 Optionally replace a try s ...

  6. Javac语法糖之Enum类

    枚举类在Javac中是被当作类来看待的. An enum type is implicitly final unless it contains at least one enum constant ...

  7. python进阶之内置函数和语法糖触发魔法方法

    前言 前面已经总结了关键字.运算符与魔法方法的对应关系,下面总结python内置函数对应的魔法方法. 魔法方法 数学计算 abs(args):返回绝对值,调用__abs__; round(args): ...

  8. Java 语法糖详解

    语法糖 语法糖(Syntactic Sugar),也称糖衣语法,是由英国计算机学家 Peter.J.Landin 发明的一个术语,指在计算机语言中添加的某种语法. 这种语法对语言的功能并没有影响,但是 ...

  9. 深入理解java虚拟机(十二) Java 语法糖背后的真相

    语法糖(Syntactic Sugar),也叫糖衣语法,是英国计算机科学家彼得·约翰·兰达(Peter J. Landin)发明的一个术语.指的是,在计算机语言中添加某种语法,这些语法糖虽然不会对语言 ...

随机推荐

  1. TableView编辑状态下跳转页面的崩溃处理

    29down votefavorite 12 I have a viewController with a UITableView, the rows of which I allow to edit ...

  2. jacob将word转换为html

    1.导包jacob.jar 2.将下面两个文件复制到C:\Windows\System32路径下 3.代码如下 // 8 代表word保存成html public static final int W ...

  3. oracl中的大数据类型clob

    建表 create table test_name( test_id   number(6) not null, img_data clob ); 在java中该表所对应的po为: class Tes ...

  4. windows下C++实现遍历本地文件

    1.假设本地 d:/ 下存放着0.txt,1.txt两个文件 2.开发工具VS,开发语言C++,怎么遍历得到两个文件呢? 废话不多,具体代码请看下面: /** * 入参:文件存放文件夹路径,例如D:\ ...

  5. hdu 1205 吃糖果【鸽巢原理】

    题目 这道题不难,看别人博客的时候发现大家都说用鸽巢原理,这是个什么鬼,于是乎百度之. 1.把某种糖果看做隔板,如果某种糖果有n个,那么就有n+1块区域,至少需要n-1块其他种糖果才能使得所有隔板不挨 ...

  6. 基于SketchUp和Unity3D的虚拟场景漫游和场景互动

    这是上学期的一次课程作业,难度不高但是也一并记录下来,偷懒地拿课程报告改改发上来. 课程要求:使用sketchUp建模,在Unity3D中实现场景漫游和场景互动. 知识点:建模.官方第一人称控制器.网 ...

  7. 深入浅析Node.js单线程模型

    Node.js采用 事件驱动 和 异步I/O 的方式,实现了一个单线程.高并发的运行时环境,而单线程就意味着同一时间只能做一件事,那么Node.js如何利用单线程来实现高并发和异步I/O?本文将围绕这 ...

  8. 与数据库连接的页面增删改查 的easyui实现(主要是前端实现)

    一.首先看一下最终实现的效果,上图 二.思路,主要是分两个文件实现,一个是页面显示文件:代码如下: <html> <head> <title>示例管理</ti ...

  9. vim 安装vim-javascript插件--Vundle管理

    最近看了一下node.js,但是写的时候,vim对js没有很好的提示.于是就安装插件来处理,准备安装vim-javascript.但是安装github上面的插件时,推荐用Vundle和pathogen ...

  10. webform获取微信用户的授权

    这是一个利用webform做出来的简单demo,微信授权,获取微信用户的基本信息.方便以后加深记忆. public partial class Index : System.Web.UI.Page { ...