栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

Java编译器 - 语法糖

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

Java编译器 - 语法糖

倘只看书,便变成书橱 -- 鲁迅

本文总结了一部分java编译期的语法糖。为了便于理解,本文不使用java字节码来推论;采用源代码和编译器编译后的伪代码来直观的表达。理解java在编译成class文件时,实际上编译器会给我们如何传递给jvm

文章中每个语法糖都有如下两段代码,第一个源代码,第二个编译器解析后的伪代码,读者可根据两段代码的差异性,理解语法糖,格式如下:

//源代码
//编译器解析后的伪代码
一、默认构造器

当我们创建一个类,如果没有编写任何构造器,编译器默认添加一个无参构造器

public class ClassName{
}
public class ClassName{
    public ClassName(){
        super();
    }
}
二、自动拆/装箱

JDK1.5开始

1、Integer.valueOf()装箱

2、integer.intValue()拆箱

3、如果用==比较,且一个是包装类型,一个是基本类型,会将包装类型拆箱

4、如果用equals比较,且一个是包装类型,一个是基本类型,会将基本类型装箱

public class ClassName{
    public static void main(String[] args) {
        Integer a = 1;
        int b = a;
        boolean c = a == b;
        boolean d = a.equals(b);
    }
}
public class ClassName{
    public static void main(String[] args) {
        Integer a = Integer.valueOf(1);
        int b = a.intValue();
        boolean c = a.intValue() == b;
        boolean d = a.equals(Integer.valueOf(b));
    }
}
三、范型擦除 

JDK1.5开始

编译器会在编译后将范型擦除掉,但仍会将范型信息存放在LocalVariableTypeTable 中

public class ClassName{
    public static void main(String[] args) {
        List list = new ArrayList<>();
        list.add(1);
        Integer value = list.get(0);
    }
}
public class ClassName{
    public static void main(String[] args) {
        List list = new ArrayList<>();
        list.add(Integer.valueOf(1));
        Integer value = (Integer) list.get(0);
    }
}

虽然变量的范性信息被存放在了字节码文件的LocalVariableTypeTable 中 ,但我们无法通过反射获取到本地变量的范型信息,例外的是方法的形参和返回值的范性,我们可以通过反射拿到

 public static void main(String[] args) throws NoSuchMethodException {
        Method method = ClassName.class.getMethod("method", Map.class);
        //获取参数类型
        Type[] parameterTypes = method.getGenericParameterTypes();
        ParameterizedType parameterType = (ParameterizedType)parameterTypes[0];
        Type mapType = parameterType.getRawType(); //interface java.util.Map
        //获取参数范性
        Type[] actualTypeArguments = parameterType.getActualTypeArguments();
        Type integerType = actualTypeArguments[0]; //class java.lang.Integer
        Type objectType = actualTypeArguments[1];  //class java.lang.Object

        //获取返回值类型
        ParameterizedType returnType = (ParameterizedType)method.getGenericReturnType();
        Type setType = returnType.getRawType(); //interface java.util.Set
        //获取返回值范性
        Type stringType = returnType.getActualTypeArguments()[0]; //class java.lang.String
    }

    public Set method(Map map){
        return null;
    }
 四、可变参数

可变参数本质是作为一个数组对象传递

    public static void main(String[] args) {
        method("a","b","c");
        method();
    }

    public static void method(String... args){
        String[] arr = args;
    }
    public static void main(String[] args) {
        method(new String[]{"a","b","c"});
        method(new String[]{});  //无参传空数组
    }

    public static void method(String[] args){
       String[] arr = args;
    }
 五、forech

forech根据迭代对象的类型分为两种

数组

     int[] arr = {1,2,3,4,5};
     for (int e : arr) {
        System.out.println(e);
     }
     int[] arr = new int[]{1,2,3,4,5};
     for (int i = 0; i < arr.length; i++) {
         int e = arr[i];
         System.out.println(e);
     }

集合

    List list = Arrays.asList(1,2);
    for (Integer e : list) {
        System.out.println(e);
    }
   List list = Arrays.asList(Integer.valueOf(1),Integer.valueOf(2));
   Iterator iterator = list.iterator();
   while(iterator.hasNext()){
       Integer e = (Integer) iterator.next();
       System.out.println(e);
   }
六、switch的字符串

JDK7开始,switch可以使用字符串和枚举,这个功能实际上是语法糖

    public static void method(String str){
        switch (str){
            case "Aa":
                System.out.println("Aa");
                break;
            case "AA":
                System.out.println("AA");
                break;
            case "BB":
                System.out.println("BB");
                break;
        }
    }
    public static void method(String str){
        byte x = -1;
        switch (str.hashCode()){
            case 2112:
                if(str.equals("Aa")){
                    x = 0;
                }else if(str.equals("BB")){
                    x = 1;
                }
                break;
            case 2080:
                if(str.equals("AA")){
                    x=2;
                }
                break;
            default:
        }
        switch (x){
            case 0:
                System.out.println("Aa");
                break;
            case 1:
                System.out.println("BB");
                break;
            case 2:
                System.out.println("AA");
                break;
            default:
        }
    }
七、switch的枚举
    public static void method(SexEnum sexEnum){
        switch (sexEnum){
            case BOY: break;
            case GIRL:break;
        }
    }
    //在本类中生成一个静态的内部类,仅jvm识别
    synthetic static class $MAP{
        //将使用到的枚举,所有的选项放入一个数组中和switch的int值对应
        synthetic static final int[] map = new int[SexEnum.values().length];
        static{
            map[SexEnum.BOY.ordinal()] = 1;
            map[SexEnum.GIRL.ordinal()] = 2;
        }
    }
    public static void method(SexEnum sexEnum){
        //使用枚举的ordinal取出int值对应
        switch (sexEnum.ordinal()){
            case 1: break;
            case 2: break;
        }
    }
八、枚举类

jdk7开始,枚举实际是一个继承了Enum的类

enum Sex{
    BOY(100),
    GIRL(200);
    private Integer code;
    Sex(Integer code){
        this.code = code;
    }
}
final class Sex extends Enum{
    public static final Sex BOY;
    public static final Sex GIRL;
    public static final Sex[] $VALUE;
    static {
        BOY = new Sex("BOY",0,100);
        GIRL = new Sex("GIRL",1,200);
        $VALUE = new Sex[]{BOY,GIRL};
    }
    private Integer code;

    private Sex(String name, Integer ordinal,Integer code){
        super(name,ordinal);
        this.code = code;
    }
    public static Sex[] values(){
        return $VALUE.clone();
    }
    public static Sex valueOf(String name){
        return Enum.valueOf(Sex.class,name);
    }
}
九、重写方法 - 方法桥接
abstract class A{
    public abstract Number m();
}
class B extends A{
    @Override
    public Integer m() {
        return null;
    }
}
abstract class A{
    public abstract Number m();
}
class B extends A{
    public Integer m() {
        return null;
    }
    
    @Override
    public synthetic bridge Number m(){
       return m();
    }
}

通过打印B类的方法,我们可以验证

    for (Method declaredMethod : B.class.getDeclaredMethods()) {
        System.out.println(declaredMethod);
    }

打印出来两个方法 

public java.lang.Integer utils.B.m()
public java.lang.Number utils.B.m()
十、内部类

成员内部类

class A{
    private String filed;
    class B{
        public void test(){
            //内部类引用了外部类的成员变量
            System.out.println(filed);
        }
    }
}
class A{
    private String filed;
    //将权限暴露
    static String filed0(A a){
        return a.filed;
    }
}
class B{
    //持有外部类的引用
    private A a;
    //创建外部类,需要传递外部类的引用
    public B(A a){
        this.a = a;
    }
    public void test(){
        System.out.println(A.filed0(a));
    }
}

可以看出:外部类和内部类都有相应的改动

1、在外部类存在一个公用的静态方法,将字段权限暴露出来

2、在内部类创建时,会通过构造器将外部类对象注入到自身成员变量中

3、内部类调用外部类的静态方法,获取到私有属性的值

方法内部类

class A{
    public void testA(String name){
        class B{
            public void testB(){
                //内部类引用了方法的局部变量
                System.out.println(name);
            }
        }
        new B().testB();
    }
}
class A{
    public void testA(String name){
        //编译器注入
        new B(this,name).testB();
    }
}
class B{
    private A a;
    private String name;
    
    //在创建内部类时,将引用的外部方法的局部变量作为内部的成员变量
    public B(A a,String name){
        this.a = a;
        this.name = name;
    }
    
    public void testB(){
        //实际是用的自己的成员变量
        System.out.println(name);
    }
}

其内部类的构造器上相对于成员内部类基础上多了局部变量的入参,并将其作为成员变量。

所以为什么方法内部类调用的变量要用final修饰?因为在内部类对象创建时就确定一切了。外面改了,里面就不一致了。

* 内部类中存在指针指向外部类对象,所以当大量使用 new Object(){{}}这样的语法时,要注意是否可能存在内存泄漏的危险

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/340030.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号