天天看點

第10章, 早期(編譯期)優化

1、概述:

編譯過程的編譯器:

  • 1、前端編譯器:Sun的Javac、Eclipse JDT中的增量式編譯器(ECJ) (.java檔案變為*.class過程)
  • 2、JIT編譯器:HotSpot VM 的C1、C2編譯器(.class檔案變成機器碼的過程)
  • 3、AOT編譯器:GNU Compiler for the java(GCJ)、Excelsior JET(.java檔案直接變成機器碼的過程)

2、Javac編譯器

編譯器過程大緻分為三個過程

  • 1、解析與填充符号表過程
  • 2、插入式注解處理器的注解處理過程
  • 3、分析與位元組碼生成過程

2.1 解析與填充符号表

1、詞法、文法分析

2、填充符号表

總結:不恰當比喻---将不同大小蘋果先檢出來,按照放入不同筐内。

2.2 注解處理器

注解與普通代碼類似,根據不同注解重複修改文法樹。(塑像進行雕刻,而注解是刀,塑像是文法樹)

2.3 語義分析與位元組碼生成

表示代碼正确,還要符合類型之間關系

int a=1;

boolean b = false;

char c = 2;

int d = a+c (編譯正确)

int d = b+c(編譯異常)

1、标注檢查

常量折疊:例如 int a= 1+2; 代表是 int a =3

2、資料及控制流分析

3、解文法糖 

定義:增加程式可讀性,對功能沒有的影響的文法

4、位元組碼生成

3、java文法糖的味道

3.1、泛型與類型擦除

真實泛型:就是泛型一直存在到運作期,List<int>與List<String>就是不同類型,它們有自己的虛方法表和類型資料。

僞泛型:java語言的泛型,它隻存在于源碼中,後期編譯會替換原來的原生類型,并且在相應位置插入強制轉換代碼,這就是java類型擦除

package com.jack;

import java.util.HashMap;
import java.util.Map;

public class Main {
	public static void main(String[] args) throws Throwable{
	Map<String, String> map = new HashMap<String,String>();
	map.put("hello", "你好");
	map.put("how are you?", "點點滴滴");
	System.out.printf(map.get("hello"));
	System.out.printf(map.get("how are you?"));
		
	}
}
           

編譯成位元組碼檔案後反編譯為:

package com.jack;

import java.util.HashMap;

public class Main {
	public static void main(String[] arg) throws Throwable {
		HashMap arg0 = new HashMap();
		arg0.put("hello", "你好");
		arg0.put("how are you?", "點點滴滴");
		System.out.printf((String) arg0.get("hello"), new Object[0]);
		System.out.printf((String) arg0.get("how are you?"), new Object[0]);
	}
}
           

List<Integer> 和List<String>代表同一個類

import java.util.List;

public class GenericTypes {
	
	public static void method(List<String> list) {
		System.out.printf("invoke method(List<String> list)");
	}
	
	public static void method(List<Integer> list) {
		System.out.printf("invoke method(List<Integer> list)");
	}
}
           

會出現編譯錯誤 :Erasure of method method(List<Integer>) is the same as another method in type (表示擦拭泛型後代表相同類)

3.3 自動裝箱、拆箱與周遊循環

import java.util.Arrays;
import java.util.List;

public class Main {
	public static void main(String[] args) throws Throwable{
		List<Integer> list = Arrays.asList(1,2,3,4);
		int sum =0;
		for (int i: list){
			sum +=i;
		}
		System.out.println(sum);
	}
}
           

編譯後的代碼

import java.util.Arrays;
import java.util.Iterator;
import java.util.List;

public class Main {
	public static void main(String[] arg) throws Throwable {
		List arg0 = Arrays
				.asList(new Integer[]{Integer.valueOf(1), Integer.valueOf(2), Integer.valueOf(3), Integer.valueOf(4)});
		int arg1 = 0;

		int arg3;
		for (Iterator arg2 = arg0.iterator(); arg2.hasNext(); arg1 += arg3) {
			arg3 = ((Integer) arg2.next()).intValue();
		}

		System.out.println(arg1);
	}
}
           

以上一共包含泛型、自動裝箱、自動拆箱、周遊循環與變長參數的五種文法糖

public class Main {
	public static void main(String[] args) throws Throwable{
		Integer a = 1;
		Integer b = 2;
		Integer c = 3;
		Integer d = 3;
		Integer e = 222;
		Integer f = 222;
		Long g = 3L;
		System.out.printf("c==d : %s\n", c==d);
		System.out.printf("e==f : %s\n", e==f);
		System.out.printf("e.equals(f) : %s\n",e.equals(f));
		System.out.printf("c == (a+b) : %s\n", c==(a+b));
		System.out.printf("c.equals(a+b): %s\n", c.equals(a+b));
		System.out.printf("g == (a + b): %s\n", g == (a + b));
		System.out.printf("g.equals(a+b): %s\n", g.equals(a+b));
	}
}
           

位元組碼反編譯:

public class Main {
	public static void main(String[] arg) throws Throwable {
		Integer arg0 = Integer.valueOf(1);
		Integer arg1 = Integer.valueOf(2);
		Integer arg2 = Integer.valueOf(3);
		Integer arg3 = Integer.valueOf(3);
		Integer arg4 = Integer.valueOf(222);
		Integer arg5 = Integer.valueOf(222);
		Long arg6 = Long.valueOf(3L);
		System.out.printf("c==d : %s\n", new Object[]{Boolean.valueOf(arg2 == arg3)});
		System.out.printf("e==f : %s\n", new Object[]{Boolean.valueOf(arg4 == arg5)});
		System.out.printf("e.equals(f) : %s\n", new Object[]{Boolean.valueOf(arg4.equals(arg5))});
		System.out.printf("c == (a+b) : %s\n",
				new Object[]{Boolean.valueOf(arg2.intValue() == arg0.intValue() + arg1.intValue())});
		System.out.printf("c.equals(a+b): %s\n",
				new Object[]{Boolean.valueOf(arg2.equals(Integer.valueOf(arg0.intValue() + arg1.intValue())))});
		System.out.printf("g == (a + b): %s\n",
				new Object[]{Boolean.valueOf(arg6.longValue() == (long) (arg0.intValue() + arg1.intValue()))});
		System.out.printf("g.equals(a+b): %s\n",
				new Object[]{Boolean.valueOf(arg6.equals(Integer.valueOf(arg0.intValue() + arg1.intValue())))});
	}
           

日志:

c==d : true
e==f : false
e.equals(f) : true
c == (a+b) : true
c.equals(a+b): true
g == (a + b): true
g.equals(a+b): false
           

總結:

  • 1、如果是對象還是用equals進行比較保險。
  • 2、無論是Integer,Long的裝箱拆箱都是基于【-128,127】範圍有效
  • Integer a = 128;
  • Integer b =128;
  • a==b 為false

3.3、條件編譯

public class Main {
	public static void main(String[] args) throws Throwable{
		if(true){
			System.out.printf("子產品一");
		} else {
			System.out.printf("子產品二");
		}
	}
}
           

編譯後:

public class Main {
	public static void main(String[] args) throws Throwable{
		System.out.printf("子產品一");
	}
}