Java语法糖

Java是软件开发中的“银弹”么?不管你的观点是什么,都不可否认的是,Java确实为程序员做了很多事情:比如内存管理,安全沙箱,可移植性(真的可移植么?)等等。然而,java还有一些语法糖来帮助开发,下面就来谈谈这些语法糖。

1、"+"号和"+="号

"+","-","*"和"/"都是数值计算的经典符号,然而在Java中"+"号可以还可以用于连接String,而String是对象,为什么可以使用"+"号连接?请参考以下代码:

public class Test {
	public static void main(String[] args) {
		String str = "a" + "b" + "c";
		for (int i = 0; i < 10; i++) {
			str += "d";
		}
		System.out.println(str);
	}
}

找出该类的.class文件并反编译它,结果如下:

public class Test
{
  public static void main(String[] args)
  {
    String str = "abc";
    for (int i = 0; i < 10; i++) {
      str = (new StringBuilder(String.valueOf(str))).append("d").toString();
    }
    System.out.println(str);
  }
}

从以上代码可以看出:java编译器对String字面量做了优化,把"a" + "b" + "c"合并成了"abc";另外使用StringBuilder的append方法来替代了"+"号(现在明白为什么有时候使用F5进行debug时会自动进入StringBuilder的append方法了吧)。需要注意的是”str = (new StringBuilder(String.valueOf(str))).append("d").toString();“这段代码创建了两个对象:new StringBuilder创建了一个StringBuilder对象,最后的toString()创建了一个String对象;所以在for循环中最好不要使用"+"号或"+="来连接字符串。

2、条件预编译

Java提供了条件预编译功能,它能删除不可到达的分支,代码如下:

public class Test {
	public static void main(String... args) {
		if (true) {
			System.out.println("yes");
		} else {
			System.out.println("wrong");
		}
	}
}

找出该类的.class文件并反编译它,结果如下:

public class Test
{
  public static void main(String[] args)
  {
    System.out.println("yes");
  }
}

从反编译的代码可以看出,不可能到达的else分支被删除了。

3、变参函数

Tiger引入了变参函数,代码如下:

public class Test {
	public static void main(String... args) {
		doNothing(args);
	}

	private static void doNothing(String... params) {

	}
}

找出该类的.class文件并反编译它,结果如下:

public class Test
{
  public static void main(String[] args)
  {
    doNothing(args);
  }

  private static void doNothing(String[] params)
  {
  }
}

从反编译的代码可以看出,这又是编译器的功劳:将String...变参替换成了String[]数组。

4、泛型

Tiger引入了泛型,它可以在编译阶段校验集合元素类型的正确性,代码如下:

public class Test {
	public static void main(String... args) {
		List<String> strList = new ArrayList<>();
		System.out.println(strList);
	}
}

找出该类的.class文件并反编译它,结果如下:

public class Test
{
  public static void main(String[] args)
  {
    List strList = new ArrayList();
    System.out.println(strList);
  }
}

从反编译的代码可以看出,类型被擦除了,现在知道《Java编程思想》中提到的泛型类型擦除是什么意思了吧。

5、for-each循环

Tiger引入了for-each循环,用它可以方便地遍历数组、枚举和任何实现了Iterable接口的集合,代码如下:

public class Test {
	public static void main(String... args) {
		String[] strs = { "a", "b", "c" };
		for (String s : strs) {
			s += s;
		}
		List<String> strList = new ArrayList<String>();
		for (String s : strList) {
			s += s;
		}
	}
}

找出该类的.class文件并反编译它,结果如下:

public class Test
{
  public static void main(String[] args)
  {
    String[] strs = { "a", "b", "c" };
    String args1[];
    int j = (args1 = strs).length;
    for(int i = 0; i < j; i++)
      String s = args1[i];
      s = (new StringBuilder(String.valueOf(s))).append(s).toString();
    }
    List strList = new ArrayList();
    for(Iterator iterator = strList.iterator(); iterator.hasNext();)
    {
        String s = (String)iterator.next();
        s = (new StringBuilder(String.valueOf(s))).append(s).toString();
    }
  }
}

从反编译代码可以看出,编译器使用普通的for循环替换了数组的for-each循环,并使用迭代器来替换了集合的for-each循环。

6、自动装箱和自动拆箱

Tiger引入了自动装箱和自动拆箱,它能够根据上下文自动在基本类型和包装类型之间切换,代码如下:

public class Test {
	public static void main(String... args) {
		Integer i = 1;
		int j = i;
		System.out.println(j);
	}
}

找出该类的.class文件并反编译它,结果如下:

public class Test
{
  public static void main(String[] args)
  {
    Integer i = Integer.valueOf(1);
    int j = i.intValue();
    System.out.println(j);
  }
}

从反编译代码可以看出:编译器在装箱时调用了Integer的valueOf函数,而在拆箱时使用了Integer的intValue函数。

7、枚举

Tiger引入了枚举类型,然而JVM规范是没有定义”枚举“类型的,所以枚举会被编译成普通Java类,代码如下:

public enum Test {
	TEST
}

找出该类的.class文件并反编译它,结果如下:

public final class Test extends Enum
{

    private Test(String s, int i)
    {
        super(s, i);
    }

    public static Test[] values()
    {
        Test atest[];
        int i;
        Test atest1[];
        System.arraycopy(atest = ENUM$VALUES, 0, atest1 = new Test[i = atest.length], 0, i);
        return atest1;
    }

    public static Test valueOf(String s)
    {
        return (Test)Enum.valueOf(sugar/Test, s);
    }

    public static final Test TEST;
    private static final Test ENUM$VALUES[];

    static 
    {
        TEST = new Test("TEST", 0);
        ENUM$VALUES = (new Test[] {
            TEST
        });
    }
}

从反编译代码可以看出:编译器将它编译成了Enum类的子类。

8、数字字面量

Java7引入了数字字面量,代码如下:

public class Test {
	public static void main(String... args) {
		int i = 10_000;
		System.out.println(i);
	}
}

找出该类的.class文件并反编译它,结果如下:

public class Test
{
  public static void main(String[] args)
  {
    int i = 10000;
    System.out.println(i);
  }
}

从反编译代码可以看出:编译器将数值的下划线删除了。

9、switch支持String类型

Java7的switch可以使用String类型了,代码如下:

public class Test {
	public static void main(String... args) {
		String s = "a";
		switch (s) {
		case "a":
			break;
		}
	}
}

找出该类的.class文件并反编译它,结果如下:

public class Test
{
  public static void main(String[] args)
  {
    String s = "a";
    String str1;
    switch ((str1 = s).hashCode()) { case 97:
      if (str1.equals("a"))
        break;
    }
  }
}

从反编译代码可以看出:编译器通过String的hashCode()方法将String比较转换成了int比较。


你可能感兴趣的:(语法糖,java语法糖,Syntactic sugar)