谈谈Java中的语法糖

原创 2017年02月11日 20:43:01

语法糖(Syntactic Sugar),也称糖衣语法,指在计算机语言中添加的某种语法,这种语法对语言本身功能来说没有什么影响,只是为了方便程序员的开发,提高开发效率。说白了,语法糖就是对现有语法的一个封装。

Java作为一种与平台无关的高级语言,当然也含有语法糖,这些语法糖并不被虚拟机所支持,在编译成字节码阶段就自动转换成简单常用语法。一般来说Java中的语法糖主要有以下几种:
1. 泛型与类型擦除
2. 自动装箱与拆箱,变长参数、
3. 增强for循环
4. 内部类与枚举类

泛型与类型擦除

Java语言并不是一开始就支持泛型的。在早期的JDK中,只能通过Object类是所有类型的父类和强制类型转换来实现泛型的功能。强制类型转换的缺点就是把编译期间的问题延迟到运行时,JVM并不能为我们提供编译期间的检查。

在JDK1.5中,Java语言引入了泛型机制。但是这种泛型机制是通过类型擦除来实现的,即Java中的泛型只在程序源代码中有效(源代码阶段提供类型检查),在编译后的字节码中自动用强制类型转换进行替代。也就是说,Java语言中的泛型机制其实就是一颗语法糖,相较与C++、C#相比,其泛型实现实在是不那么优雅。

/**
* 在源代码中存在泛型
*/
public static void main(String[] args) {
    Map<String,String> map = new HashMap<String,String>();
    map.put("hello","你好");
    String hello = map.get("hello");
    System.out.println(hello);
}

当上述源代码被编译为class文件后,泛型被擦除且引入强制类型转换

public static void main(String[] args) {
    HashMap map = new HashMap(); //类型擦除
    map.put("hello", "你好");
    String hello = (String)map.get("hello");//强制转换
    System.out.println(hello);
}

自动装箱与拆箱

Java中的自动装箱与拆箱指的是基本数据类型与他们的包装类型之间的相互转换。

我们知道Java是一门面向对象的语言,在Java世界中有一句话是这么说的:“万物皆对象”。但是Java中的基本数据类型却不是对象,他们不需要进行new操作,也不能调用任何方法,这在使用的时候有诸多不便。因此Java为这些基本类型提供了包装类,并且为了使用方便,提供了自动装箱与拆箱功能。自动装箱与拆箱在使用的过程中,其实是一个语法糖,内部还是调用了相应的函数进行转换。

下面代码演示了自动装箱和拆箱功能

public static void main(String[] args) {
    Integer a = 1;
    int b = 2;
    int c = a + b;
    System.out.println(c);
}

经过编译后,代码如下

public static void main(String[] args) {
    Integer a = Integer.valueOf(1); // 自动装箱
    byte b = 2;
    int c = a.intValue() + b;//自动拆箱
    System.out.println(c);
}

变长参数

所谓变长参数,就是方法可以接受长度不定确定的参数

变长参数特性是在JDK1.5中引入的,使用变长参数有两个条件,一是变长的那一部分参数具有相同的类型,二是变长参数必须位于方法参数列表的最后面。变长参数同样是Java中的语法糖,其内部实现是Java数组。

public class Varargs {
    public static void print(String... args) {
        for(String str : args){
            System.out.println(str);
        }
    }

    public static void main(String[] args) {
        print("hello", "world");
    }
}

编译为class文件后如下,从中可以很明显的看出变长参数内部是通过数组实现的

public class Varargs {
    public Varargs() {
    }

    public static void print(String... args) {
        String[] var1 = args;
        int var2 = args.length;
        //增强for循环的数组实现方式
        for(int var3 = 0; var3 < var2; ++var3) {
            String str = var1[var3];
            System.out.println(str);
        }

    }

    public static void main(String[] args) {
        //变长参数转换为数组
        print(new String[]{"hello", "world"});
    }
}

增强for循环

增强for循环与普通for循环相比,功能更强并且代码更简洁

增强for循环的对象要么是一个数组,要么实现了Iterable接口。这个语法糖主要用来对数组或者集合进行遍历,其在循环过程中不能改变集合的大小。

public static void main(String[] args) {
    String[] params = new String[]{"hello","world"};
    //增强for循环对象为数组
    for(String str : params){
        System.out.println(str);
    }

    List<String> lists = Arrays.asList("hello","world");
    //增强for循环对象实现Iterable接口
    for(String str : lists){
        System.out.println(str);
    }
}

编译后的class文件为

public static void main(String[] args) {
   String[] params = new String[]{"hello", "world"};
   String[] lists = params;
   int var3 = params.length;
   //数组形式的增强for退化为普通for
   for(int str = 0; str < var3; ++str) {
       String str1 = lists[str];
       System.out.println(str1);
   }

   List var6 = Arrays.asList(new String[]{"hello", "world"});
   Iterator var7 = var6.iterator();
   //实现Iterable接口的增强for使用iterator接口进行遍历
   while(var7.hasNext()) {
       String var8 = (String)var7.next();
       System.out.println(var8);
   }

}

内部类

内部类就是定义在一个类内部的类

Java语言中之所以引入内部类,是因为有些时候一个类只在另一个类中有用,我们不想让其在另外一个地方被使用。内部类之所以是语法糖,是因为其只是一个编译时的概念,一旦编译完成,编译器就会为内部类生成一个单独的class文件,名为outer$innter.class。

public class Outer {
    class Inner{
    }
}

使用javac编译后,生成两个class文件Outer.class和Outer$Inner.class,其中Outer$Inner.class的内容如下:

class Outer$Inner {
    Outer$Inner(Outer var1) {
        this.this$0 = var1;
    }
}

内部类分为四种:成员内部类、局部内部类、匿名内部类、静态内部类,每一种都有其用法,这里就不介绍了

枚举类型

枚举类型就是一些具有相同特性的类常量

java中类的定义使用class,枚举类的定义使用enum。在Java的字节码结构中,其实并没有枚举类型,枚举类型只是一个语法糖,在编译完成后被编译成一个普通的类。这个类继承java.lang.Enum,并被final关键字修饰。

public enum Fruit {
    APPLE,ORINGE
}

使用jad对编译后的class文件进行反编译后得到:

//继承java.lang.Enum并声明为final
public final class Fruit extends Enum
{

    public static Fruit[] values()
    {
        return (Fruit[])$VALUES.clone();
    }

    public static Fruit valueOf(String s)
    {
        return (Fruit)Enum.valueOf(Fruit, s);
    }

    private Fruit(String s, int i)
    {
        super(s, i);
    }
    //枚举类型常量
    public static final Fruit APPLE;
    public static final Fruit ORANGE;
    private static final Fruit $VALUES[];//使用数组进行维护

    static
    {
        APPLE = new Fruit("APPLE", 0);
        ORANGE = new Fruit("ORANGE", 1);
        $VALUES = (new Fruit[] {
            APPLE, ORANGE
        });
    }
}
版权声明:本文为博主原创文章,转载请注明出处!欢迎交流指正

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

语法糖(Syntactic Sugar),也叫糖衣语法,是英国计算机科学家彼得·约翰·兰达(Peter J. Landin)发明的一个术语。指的是,在计算机语言中添加某种语法,这种语法能使程序员更方便...
  • zq602316498
  • zq602316498
  • 2014年09月05日 23:40
  • 2200

Java语法糖之foreach

语法糖是一种几乎每种语言或多或少都提供过的一些方便程序员开发代码的语法,它只是编译器实现的一些小把戏罢了,编译期间以特定的字节码或者特定的方式对这些语法做一些处理,开发者就可以直接方便地使用了。这些语...
  • u013256816
  • u013256816
  • 2016年02月25日 11:39
  • 3735

Java foreach语法糖探秘

前不久线上用foreach循环,由于没判空,导致线上报了很多空指针异常。这两天梳理下foreach语法糖,看看jvm底层到底如何实现的。    先写一个foreach的demo,包含对list对象和数...
  • bruce128
  • bruce128
  • 2016年06月01日 14:36
  • 1747

[Java]“语法糖”系列(一)之方法引用(Method References)

JAVA经过这么多版本的迭代,已经跟几十年前的C++之流完全不同了;在JAVA中,引入了很多更抽象的语言特性,比如Lambda、迭代器、方法引用之类的,有人视之为语法糖,因为这些新的高级语言特性确实精...
  • Shenpibaipao
  • Shenpibaipao
  • 2017年11月23日 22:44
  • 62

java枚举类初探-语法糖-反编译

java枚举类-语法糖-反编译 最近接触了“语法糖”这个概念,今天又看了一下枚举类的知识点,主要还是看它的用法,之前一直没有怎么用过java枚举类,看了李刚那本《疯狂java讲义》的枚举类章节,算是...
  • DavidPeterMan
  • DavidPeterMan
  • 2016年09月04日 19:52
  • 322

Java语法糖2:自动装箱和自动拆箱

 前言 一开始想学学自动拆箱和自动装箱是被这个名字吸引到,听上去好像很高端的样子,其实自动拆箱、自动装箱是很简单的内容。   自动拆箱和自动装箱 Java为每种基本数据类型都提供了对应的...
  • wangtaomtk
  • wangtaomtk
  • 2016年09月21日 17:06
  • 178

[Java]“语法糖”系列(三)之集合流操作(Stream)[笔记]

这里的这个流和IO流不一样,是JDK8中对Collection对象功能的加强。
  • Shenpibaipao
  • Shenpibaipao
  • 2017年11月25日 17:49
  • 105

Java中的10颗语法糖

http://blog.sina.com.cn/s/blog_9eb66d350101247n.html 语法糖(Syntactic Sugar):也称糖衣语法,指在计算机语言中添加的某种语...
  • u010850285
  • u010850285
  • 2015年03月12日 10:47
  • 197

Java语法糖---伪泛型

泛型技术在C#和Java之中的使用方式看似相同,但在实现上却有着根本性的分歧,C#里面泛型无论在源码中、编译后的中间语言中,或者是运行期的CLR中,都是切实存在的,List和List就是两个不同的类型...
  • u013078669
  • u013078669
  • 2015年11月04日 15:52
  • 495

[Java]“语法糖”系列(二)之Lambda表达式/匿名函数(Lambda Expression)

简短的说,Lambda表达式是一种用于取代匿名类,把函数行为表述为函数式编程风格的一种匿名函数。可以使你的Java代码更优雅、简洁。...
  • Shenpibaipao
  • Shenpibaipao
  • 2017年11月24日 21:42
  • 95
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:谈谈Java中的语法糖
举报原因:
原因补充:

(最多只允许输入30个字)