java语法糖第一发

语法糖

语法糖(Syntactic Sugar),也叫糖衣语法,是英国计算机科学家彼得·约翰·兰达(Peter J. Landin)发明的一个术语。指的是,在计算机语言中添加某种语法,这种语法能使程序员更方便的使用语言开发程序,同时增强程序代码的可读性,避免出错的机会;但是这种语法对语言的功能并没有影响。
Java中的泛型,变长参数,自动拆箱/装箱,条件编译等都是.

各种各样的语言都会提供一些语法糖来方便程序员开发,这些语法糖不会提供实质性的功能改进,但是能够提高效率.

Java泛型

Java的泛型语法是一种伪泛型,其实质是语法擦除,
看下代码:

     public static void main(String[] args) {
        Map  map = new HashMap();
        map.put("xiaoming","10");
        map.put("baby","5");
        System.out.println(map.get("xiaoming"));
        System.out.println(map.get("baby"));
}

编译后生成的.class里代码被解语法糖之后:

public static void main(String[] args) {
        HashMap map = new HashMap();
        map.put("xiaoming", "10");
        map.put("baby", "5");
        System.out.println((String)map.get("xiaoming"));
        System.out.println((String)map.get("baby"));
    }

泛型实际上只存在于源代码里,编译后被解掉,所以泛型是java提供的一种语法糖.
Java泛型的设计是欠缺优雅的:

public static void generic(List list){
        System.out.println("list = [" + list + "]");
    }


    public static void generic(List list){
        System.out.println("list = [" + list + "]");
}

上面的代码是编译通过不了的.因为泛型是伪泛型,所以List和List都是List.

自动装箱,拆箱和遍历

public static void main(String[] args) {

        List  list = Arrays.asList(1,2,3,4);

        int sum = 0;
        for (int i : list) {
             sum += i;
        }
        System.out.println("sum = " + sum);

    }

先上代码,上述代码包括泛型,装箱,拆箱,foreach,可变参数等几种语法糖,编译解语法糖后:

public static void main(String[] args) {
        List list = Arrays.asList(new Integer[]{Integer.valueOf(1), Integer.valueOf(2), Integer.valueOf(3), Integer.valueOf(4)});
        int sum = 0;

        int i;
        for(Iterator i$ = list.iterator(); i$.hasNext(); sum += i) {
            i = ((Integer)i$.next()).intValue();
        }

        System.out.println("sum = " + sum);
    }

概念:

自动装箱就是Java自动将原始类型值转换成对应的对象,比如将int的变量转换成Integer对象,这个过程叫做装箱,反之将Integer对象转换成int类型值,这个过程叫做拆箱。因为这里的装箱和拆箱是自动进行的非人为转换,所以就称作为自动装箱和拆箱。原始类型byte,short,char,int,long,float,double和boolean对应的封装类为Byte,Short,Character,Integer,Long,Float,Double,Boolean。

何时发生自动装箱和拆箱

自动装箱和拆箱在Java中很常见,比如我们有一个方法,接受一个对象类型的参数,如果我们传递一个原始类型值,那么Java会自动讲这个原始类型值转换成与之对应的对象。最经典的一个场景就是当我们向ArrayList这样的容器中增加原始类型数据时或者是创建一个参数化的类,比如下面的ThreadLocal。

ArrayList<Integer> intList = new ArrayList<Integer>();
        intList.add(1); //autoboxing - primitive to object
        intList.add(2); //autoboxing

        ThreadLocal<Integer> intLocal = new ThreadLocal<Integer>();
        intLocal.set(4); //autoboxing

        int number = intList.get(0); // unboxing
        int local = intLocal.get(); // unboxing in Java

解语法糖:

ArrayList intList1 = new ArrayList();
        intList1.add(Integer.valueOf(1));
        intList1.add(Integer.valueOf(2));
        ThreadLocal intLocal1 = new ThreadLocal();
        intLocal1.set(Integer.valueOf(4));
        int number = ((Integer)intList1.get(0)).intValue();
        int local = ((Integer)intLocal1.get()).intValue();

赋值时:

//—————-自动装箱 拆箱 场景

      //-----------赋值
        //before autoboxing
        Integer i1 = Integer.valueOf(1000);
        int j1 = i1.intValue();

        //after  java 5
        Integer i2 = 1000;
        int j2 = i2;

编译后:

int number = ((Integer)intList1.get(0)).intValue();
        int local = ((Integer)intLocal1.get()).intValue();
        Integer i1 = Integer.valueOf(1000);
        int j1 = i1.intValue();
        Integer i2 = Integer.valueOf(1000);
        int j2 = i2.intValue();

方法调用:

//--------------调用

        invoke(3); //autoboxing

编译后

   invoke(Integer.valueOf(3));

    public static Integer invoke(Integer i) {
        return i;
    }

自动装箱拆箱的陷阱

    //-------------自动装箱拆箱的陷阱
        Integer sum1 = 0;
        for (int i = 0; i < 1000; i++) {
             sum1 += i;
        }
        System.out.println("sum1 = " + sum1);

编译后:

Integer sum1 = Integer.valueOf(0);

        for(int i = 0; i < 1000; ++i) {
            sum1 = Integer.valueOf(sum1.intValue() + i);
        }

        System.out.println("sum1 = " + sum1);

上面代码Integer.valueOf()会new出大量的无用对象严重影响程序的性能和gc.
在编码中应尽量避免.

相等陷阱

//----------相等陷阱
        int n1 = 127;
        int n2 = 127;
        System.out.println("n1==n2:" + (n1 == n2) );

        int n3 = 1;
        Integer n4 = 1;
        System.out.println("n3==n4:" + (n3 == n4) );

        Integer n5 = 127;
        Integer n6 = 127;
        System.out.println("n5==n6:" + (n5 == n6));

        Integer n7 = 128;
        Integer n8 = 128;
        System.out.println("n7==n8:" + (n7 == n8)); //false

编译后:

byte var22 = 127;
        byte n2 = 127;
        System.out.println("n1==n2:" + (var22 == n2));
        byte n3 = 1;
        Integer n4 = Integer.valueOf(1);
        System.out.println("n3==n4:" + (n3 == n4.intValue()));
        Integer n5 = Integer.valueOf(127);
        Integer n6 = Integer.valueOf(127);
        System.out.println("n5==n6:" + (n5 == n6));
        Integer n7 = Integer.valueOf(128);
        Integer n8 = Integer.valueOf(128);
        System.out.println("n7==n8:" + (n7 == n8));

Integer代码中:

   public static Integer valueOf(int i) {
        if(i >= -128 && i <= IntegerCache.high)
            return IntegerCache.cache[i + 128];
        else
            return new Integer(i);
}

当数字在-128和127之间时会复用,之外时直接new.

初始化陷阱

//-----------初始化陷阱

        Integer n9 = null;
        int n10 = n9;

编译后:

Object n9 = null;
        int n10 = ((Integer)n9).intValue();

上面代码引起空指针异常。

参考:

http://www.tuicool.com/articles/7ZZFfiy

你可能感兴趣的:(jvm)