美文网首页
BiBi - JVM -11- 编译期优化

BiBi - JVM -11- 编译期优化

作者: 奋飞的蜗牛ing | 来源:发表于2019-03-01 18:18 被阅读0次

From:深入理解Java虚拟机

编译期的三种情况

1)前端编译器:把java文件转变为class文件。
2)JIT编译器:运行期编译器把字节码转变为机器码。
3)AOT编译器:把java文件编译成本地机器码。

对性能的优化主要集中在JIT,这样可以让那些不是由javac产生的class文件【如:Groovy、JRuby】也同样能享受到编译器优化带来的好处。

javac编译的过程

(解析与填充符号表 >< 注解处理) > 分析与字节码生成

public void foo(final int arg) {
  final int var = 0;
}

public void foo(int arg) {
  int var = 0;
}

上面两段代码编译出来的Class文件是一样的。由于局部变量在常量池中没有CONSTANT_Fieldref_info的符号引用,自然就没有访问标志的信息,所以在Class文件中不可能知道一个局部变量是不是声明为final

将局部变量声明为final,对运行期是没有影响的,变量的不变性仅仅由编译器在编译期间保障。

语法糖

泛型、变长参数、自动装箱/拆箱、高级for循环、内部类、枚举类、switch支持字符串等,虚拟机运行时不支持这些语法,它们在编译阶段还原回基础的语法结构。

如果用户代码中没有提供任何构造函数,那编译器将会添加一个没有参数的、访问性与当前类一致的默认构造函数,这个工作在【填充符号表】阶段完成。

把字符串的加操作替换为StringBuffer或StringBuilder的append操作。

void say() {
      String str = "bb" + "cc" + "dd" + "ee";
      str = "aa" + str;
      System.out.println(str);
    }

对应的Class为:

void say() {
  String var1 = "bbccddee";
  var1 = "aa" + var1;
  System.out.println(var1);
}

void say() {
  String[] arr = { "aa", "bb", "cc" };
  String res = null;
  for (String str : arr) {
    res += str;
  }
  System.out.println(res);
}

对用的Class为:

void say() {
  String[] var1 = new String[]{"aa", "bb", "cc"};
  String var2 = null;
  String[] var3 = var1;
  int var4 = var1.length;
  for(int var5 = 0; var5 < var4; ++var5) {
    String var6 = var3[var5];
    var2 = var2 + var6;
  }
  System.out.println(var2);
}

void say() {
  List<String> list = new ArrayList<>();
  list.add("ljg");
  for (String s : list) {
    System.out.println(s);
  }
}

对用的Class为:

void say() {
  ArrayList var1 = new ArrayList();
  var1.add("ljg");
  Iterator var2 = var1.iterator();
  while(var2.hasNext()) {
    String var3 = (String)var2.next();
    System.out.println(var3);
  }
}

总结:
1)字符串相加优化的场景是有限的,所以在开发中还是要自己主动使用StringBuilder。
2)高级for循环会被转化为基本for循环样式。
3)泛型会被擦除,转换为手动的类型转换

真泛型:C#,在运行期是真实存在的,有自己的虚方法表和类型数据。
伪泛型:Java,在编译后的字节码中会擦除泛型信息,替换为原生类型,并在相应的地方插入强制类型转换。对Java而言,ArrayList<int>和ArrayList<String>是同一个类。

public void method(List<String> list) {
  System.out.println(list.toString());
}

public void method(List<Integer> list) {
  System.out.println(list.toString());
}

上面的代码不能被编译,因为擦除后两个方法签名一样。

  • Integer
public static void main(String[] args) {
  Integer a = 1;
  Integer b = 2;
  Integer c = 3;
  Integer d = 3;
  Integer e = 321;
  Integer f = 321;
  Long g = 3L;
  System.out.println(c == d);//ture
  System.out.println(e == f);//falde
  System.out.println(c == (a + b));//true
  System.out.println(c.equals(a + b));//true
  System.out.println(g == (a + b));//true
  System.out.println(g.equals(a + b));//false 因为equals()方法不处理数据类型转换
}
  • switch字符串的语法糖
public static void main(String[] args) {
  String str = "a";
  switch (str) {
    case "a":
      System.out.println("aaa");
      break;
    case "b":
      System.out.println("bbb");
      break;
    default:
      break;
  }
}

对应的Class为:

public static void main(String[] var0) {
   String var1 = "a";
   byte var3 = -1;
   switch(var1.hashCode()) {
   case 97:
     if (var1.equals("a")) {
       var3 = 0;
     }
     break;
   case 98:
     if (var1.equals("b")) {
       var3 = 1;
     }
   }
   switch(var3) {
   case 0:
     System.out.println("aaa");
     break;
   case 1:
     System.out.println("bbb");
   }
 }

相关文章

网友评论

      本文标题:BiBi - JVM -11- 编译期优化

      本文链接:https://www.haomeiwen.com/subject/kbvtjqtx.html