从enum反编译看Java的语法糖

最近看到《Effective Java》中的Enum部分各种神奇的操作觉得很是惊奇,还能这么玩?!于是想起之前不知在什么地方看到的enum其实是语法糖,就趁着好奇看了下,才发现,原来如此。
Snipaste_2020-07-24_18-05-34.png

References:

一段最简单的代码:

public enum TestEnum {
    Apple, Banana, Orange
}

使用Bytecode Viewer反编译,因为现在很多反编译工具都是直接显示加了糖的语法,这里需要设置下,显示不带糖的语句。
Snipaste_2020-07-24_18-22-35.png

然后是这样的:

/*
 * Decompiled with CFR <Could not determine version>.
 * 
 * Could not load the following classes:
 *  TestEnum
 */
public final class TestEnum
extends Enum<TestEnum> {
    public static final /* enum */ TestEnum Apple = new TestEnum((String)"Apple", (int)0);
    public static final /* enum */ TestEnum Banana = new TestEnum((String)"Banana", (int)1);
    public static final /* enum */ TestEnum Orange = new TestEnum((String)"Orange", (int)2);
    private static final /* synthetic */ TestEnum[] ENUM$VALUES;

    static {
        ENUM$VALUES = new TestEnum[]{Apple, Banana, Orange};
    }

    private TestEnum(String string, int n) {
        super((String)string, (int)n);
    }

    public static TestEnum[] values() {
        TestEnum[] arrtestEnum = ENUM$VALUES;
        int n = arrtestEnum.length;
        TestEnum[] arrtestEnum2 = new TestEnum[n];
        System.arraycopy((Object)arrtestEnum, (int)0, (Object)arrtestEnum2, (int)0, (int)n);
        return arrtestEnum2;
    }

    public static TestEnum valueOf(String string) {
        return Enum.valueOf(TestEnum.class, (String)string);
    }
}

可以看到,哪有什么enum类型,其实就是final类,并且枚举的对象都是静态常量。

再看个稍微复杂的,这个是《Effective Java》中的例子:

public interface Operation {
    public abstract double apply(double x, double y);
}
public enum BasicOperation implements Operation {
    PLUS("+") {
        @Override
        public double apply(double x, double y) {
            return x + y;
        }

    },
    MINUS("-") {
        @Override
        public double apply(double x, double y) {
            return x - y;
        }

    },
    TIMES("*") {
        @Override
        public double apply(double x, double y) {
            return x * y;
        }

    },
    DIVIDE("/") {
        @Override
        public double apply(double x, double y) {
            return x / y;
        }
    };

    private final String symbol;

    private BasicOperation(String symbol) {
        this.symbol = symbol;
    }
}

反编译后出现了很多的内部类:

/*
 * Decompiled with CFR <Could not determine version>.
 * 
 * Could not load the following classes:
 *  BasicOperation
 *  BasicOperation$1
 *  BasicOperation$2
 *  BasicOperation$3
 *  BasicOperation$4
 *  Operation
 */
/*
 * Exception performing whole class analysis.
 */
public abstract class BasicOperation
extends Enum<BasicOperation>
implements Operation {
    public static final /* enum */ BasicOperation PLUS;
    public static final /* enum */ BasicOperation MINUS;
    public static final /* enum */ BasicOperation TIMES;
    public static final /* enum */ BasicOperation DIVIDE;
    private final String symbol;
    private static final /* synthetic */ BasicOperation[] ENUM$VALUES;

    static {
        PLUS = new /* Unavailable Anonymous Inner Class!! */;
        MINUS = new /* Unavailable Anonymous Inner Class!! */;
        TIMES = new /* Unavailable Anonymous Inner Class!! */;
        DIVIDE = new /* Unavailable Anonymous Inner Class!! */;
        ENUM$VALUES = new BasicOperation[]{PLUS, MINUS, TIMES, DIVIDE};
    }

    private BasicOperation(String string, int n, String symbol) {
        super((String)string, (int)n);
        this.symbol = symbol;
    }

    public static BasicOperation[] values() {
        BasicOperation[] arrbasicOperation = ENUM$VALUES;
        int n = arrbasicOperation.length;
        BasicOperation[] arrbasicOperation2 = new BasicOperation[n];
        System.arraycopy((Object)arrbasicOperation, (int)0, (Object)arrbasicOperation2, (int)0, (int)n);
        return arrbasicOperation2;
    }

    public static BasicOperation valueOf(String string) {
        return Enum.valueOf(BasicOperation.class, (String)string);
    }

    /* synthetic */ BasicOperation(String string, int n, String string2, BasicOperation basicOperation) {
        this((String)string, (int)n, (String)string2);
    }
}
/*
 * Decompiled with CFR <Could not determine version>.
 * 
 * Could not load the following classes:
 *  BasicOperation
 *  BasicOperation$1
 */
class BasicOperation.1
extends BasicOperation {
    BasicOperation.1(String string, int n, String $anonymous0) {
        super((String)string, (int)n, (String)$anonymous0, null);
    }

    public double apply(double x, double y) {
        return x + y;
    }
}
/*
 * Decompiled with CFR <Could not determine version>.
 * 
 * Could not load the following classes:
 *  BasicOperation
 *  BasicOperation$2
 */
class BasicOperation.2
extends BasicOperation {
    BasicOperation.2(String string, int n, String $anonymous0) {
        super((String)string, (int)n, (String)$anonymous0, null);
    }

    public double apply(double x, double y) {
        return x - y;
    }
}
/*
 * Decompiled with CFR <Could not determine version>.
 * 
 * Could not load the following classes:
 *  BasicOperation
 *  BasicOperation$3
 */
class BasicOperation.3
extends BasicOperation {
    BasicOperation.3(String string, int n, String $anonymous0) {
        super((String)string, (int)n, (String)$anonymous0, null);
    }

    public double apply(double x, double y) {
        return x * y;
    }
}
/*
 * Decompiled with CFR <Could not determine version>.
 * 
 * Could not load the following classes:
 *  BasicOperation
 *  BasicOperation$4
 */
class BasicOperation.4
extends BasicOperation {
    BasicOperation.4(String string, int n, String $anonymous0) {
        super((String)string, (int)n, (String)$anonymous0, null);
    }

    public double apply(double x, double y) {
        return x / y;
    }
}

可以看出来,和上一个例子的区别就是enum所在类由final变成了abstract,并且多了内部类。这是因为实现了Operation接口,所以必须实现其中的apply方法,但是BasicOperation类本身并不知道如何实现,只能让子类去实现具体的方法,因此就不能声明为final类型。在生成的每一个内部类中实现了apply方法,定义了apply的
具体行为。

不过,看到这个abstract我有个大胆的想法,我自己定义一个类去继承会发生什么事情。
Snipaste_2020-07-24_18-52-27.png

编译报错了,父类必须是class类型,看来Sun不让我这个想法那么顺利,做了些额外的检测。

到这再贴一下维基上对于语法糖的定义:语法糖(英語:Syntactic sugar)是由英国计算机科学家彼得·蘭丁发明的一个术语,指计算机语言中添加的某种语法,这种语法对语言的功能没有影响,但是更方便程序员使用。 语法糖让程序更加简洁,有更高的可读性。是不是就容易理解多了。

再以“增强for循环”为例,其实是用了Iterator:

List<Integer> ls = Arrays.asList(1, 2, 3, 4, 5);

for (Integer l : ls) {
    System.out.println(l);
}

反编译之后是:

List<Integer> ls = Arrays.asList(1, 2, 3, 4, 5);
Iterator var2 = ls.iterator();

while(var2.hasNext()) {
    Integer l = (Integer)var2.next();
    System.out.println(l);
}

Java中除了enum外,还有很多非常常用的语法糖,比如:“switch-case对String和枚举类的支持”、“泛型”、“自动拆装箱”、“try-with-resource”、“Lambda”等等。
可以查看参考链接中的文章去了解一下,然后就会发现,Java中到处都是语法糖。

标签: none

添加新评论

ali-01.gifali-58.gifali-09.gifali-23.gifali-04.gifali-46.gifali-57.gifali-22.gifali-38.gifali-13.gifali-10.gifali-34.gifali-06.gifali-37.gifali-42.gifali-35.gifali-12.gifali-30.gifali-16.gifali-54.gifali-55.gifali-59.gif

加载中……