程式編譯與代碼最佳化-早期(編譯期)最佳化__JVM學習筆記

來源:互聯網
上載者:User
1:概述 前端編譯器:Sun的Javac、Eclipse JDT中的增量式編譯器(EJC) JIT編譯器:Hotspot VM的C1,C2編譯器 AOT編譯器:GNC Compiler for the Java(GCJ)、Excelsior JET

    本章先介紹第一種前端編譯器,也是大家都認可的編譯器。 2:Javac編譯器

    源碼編譯自OpenJdk7,從Sun Javac源碼來看,編譯大致可分為3個過程: 解析與填充符號表過程 插入式註解處理器的註解處理過程。 分析與位元組碼產生過程。 3:Java文法糖的味道 3.1:泛型與類型擦除

    Java的泛型是典型的文法糖。

public static void main(String[] args) {        Map<String, String> map = new HashMap<String, String>();        map.put("hello", "你好");        map.put("how are you?", "吃了沒。");        System.out.println(map.get("hello"));        System.out.println(map.get("how are you?"));}

    上述代碼編譯後的結果是

public static void main(String[] args) {        Map map = new HashMap();        map.put("hello", "你好");        map.put("how are you?", "吃了沒。");        System.out.println((String) map.get("hello"));        System.out.println((String) map.get("how are you?"));}

    Java泛型在某些情境是存在缺陷的,例如下面代碼是編譯不通過的

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

    再看下面這段代碼,這段代碼增加了一個傳回值就可以編譯成功,前提是試用JDK1.6的Javac編譯器。導致這種情況的出現使因為虛擬機器的方法區的實現有關,在Class檔案格式中,只要描述符不完全一致,就允許存在。

import java.util.ArrayList;import java.util.List;public class GenericTypes {    public static String method(List<String> list) {        System.out.println("invoke method(List<String> list)");        return "";    }    public static int method(List<Integer> list) {        System.out.println("invoke method(List<Integer> list)");        return 1;    }    public static void main(String[] args) {        method(new ArrayList<String>());        method(new ArrayList<Integer>());    }}

    Java虛擬機器引入了諸如Signature、Local VariableTypeTable等新的屬性用於解決伴隨泛型而來的的參數類型識別的問題。 3.2:自動裝箱、拆箱與遍曆迴圈

    下面的程式碼封裝含了泛型、自動裝箱、自動拆箱、遍曆迴圈與變長參數5種文法糖。

 public static void main(String[] args) {        List<Integer> list = Arrays.asList(1, 2, 3, 4);        // 如果在JDK 1.7中,還有另外一顆文法糖 ,        // 能讓上面這句代碼進一步簡寫成List<Integer> list = [1, 2, 3, 4];        int sum = 0;        for (int i : list) {            sum += i;        }        System.out.println(sum);    }

    下面這段代碼是上面這段代碼的編譯之後得到

 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;        for (Iterator localIterator = list.iterator(); localIterator.hasNext(); ) {            int i = ((Integer)localIterator.next()).intValue();            sum += i;        }        System.out.println(sum);    }
3.3:條件編譯
public static void main(String[] args) {    if (true) {        System.out.println("block 1");    } else {        System.out.println("block 2");    }}

    上面的代碼反編譯後會變成

public static void main(String[] args) {    System.out.println("block 1");}

    下面的代碼編譯器拒絕編譯

public static void main(String[] args) {    // 編譯器將會提示“Unreachable code”    while (false) {        System.out.println("");    }}

    Java除了上面說的文法糖外,還有內部類、枚舉類、Assert 陳述式、對枚舉和字串的switch支援(JDK1.7支援)、try語句中定義和關閉資源(JDK1.7支援)等。 3.4:實戰:插入式註解處理器 3.4.1:實戰目標

    實現一個類似checkstyle、FindBug類似的代碼檢查工具。為了實現這個效果,我們要定一些書寫規範: 類(或介面):符合駝式命名法,首字母大寫 方法:符合駝式命名法,首字母小寫 欄位:類或執行個體變數(符合駝式命名法,首字母小寫);常量(要求全部由大寫字母和底線組成,並且第一個字母不能是底線) 3.4.2:代碼實現

import javax.annotation.processing.*;import javax.lang.model.SourceVersion;import javax.lang.model.element.Element;import javax.lang.model.element.TypeElement;import java.util.Set;// 可以用"*"表示支援所有Annotations@SupportedAnnotationTypes("*")// 只支援JDK 1.6的Java代碼@SupportedSourceVersion(SourceVersion.RELEASE_6)public class NameCheckProcessor extends AbstractProcessor {    private NameChecker nameChecker;    /**     * 初始化名稱檢查外掛程式     */    @Override    public void init(ProcessingEnvironment processingEnv) {        super.init(processingEnv);        nameChecker = new NameChecker(processingEnv);    }    /**     * 對輸入的文法樹的各個節點進行進行名稱檢查     */    @Override    public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) {        if (!roundEnv.processingOver()) {            for (Element element : roundEnv.getRootElements())                nameChecker.checkNames(element);        }        return false;    }}
import javax.annotation.processing.Messager;import javax.annotation.processing.ProcessingEnvironment;import javax.lang.model.element.*;import javax.lang.model.util.ElementScanner6;import java.util.EnumSet;import static javax.lang.model.element.ElementKind.*;import static javax.lang.model.element.Modifier.FINAL;import static javax.lang.model.element.Modifier.PUBLIC;import static javax.lang.model.element.Modifier.STATIC;import static javax.tools.Diagnostic.Kind.WARNING;/** * 程式名稱規範的編譯器外掛程式:<br> * 如果程式命名不合規範,將會輸出一個編譯器的WARNING資訊 */public class NameChecker {    private final Messager messager;    NameCheckScanner nameCheckScanner = new NameCheckScanner();    NameChecker(ProcessingEnvironment processsingEnv) {        this.messager = processsingEnv.getMessager();    }    /**     * 對Java程式命名進行檢查,根據《Java語言規範》第三版第6.8節的要求,Java程式命名應當符合下列格式:     *     * <ul>     * <li>類或介面:符合駝式命名法,首字母大寫。     * <li>方法:符合駝式命名法,首字母小寫。     * <li>欄位:     * <ul>     * <li>類、執行個體變數: 符合駝式命名法,首字母小寫。     * <li>常量: 要求全部大寫。     * </ul>     * </ul>     */    public void checkNames(Element element) {        nameCheckScanner.scan(element);    }    /**     * 名稱檢查器實作類別,繼承了JDK 1.6中新提供的ElementScanner6<br>     * 將會以Visitor模式訪問抽象文法樹中的元素     */    private class NameCheckScanner extends ElementScanner6<Void, Void> {        /**         * 此方法用於檢查Java類         */        @Override        public Void visitType(TypeElement e, Void p) {            scan(e.getTypeParameters(), p);            checkCamelCase(e, true);            super.visitType(e, p);            return null;        }        /**         * 檢查方法命名是否合法         */        @Override        public Void visitExecutable(ExecutableElement e, Void p) {            if (e.getKind() == METHOD) {                Name name = e.getSimpleName();                if (name.contentEquals(e.getEnclosingElement().getSimpleName()))                    messager.printMessage(WARNING, "一個普通方法 “" + name + "”不應當與類名重複,避免與建構函式產生混淆", e);                checkCamelCase(e, false);            }            super.visitExecutable(e, p);            return null;        }        /**         * 檢查變數命名是否合法         */        @Override        public Void visitVariable(VariableElement e, Void p) {            // 如果這個Variable是枚舉或常量,則按大寫命名檢查,否則按照駝式命名法規則檢查            if (e.getKind() == ENUM_CONSTANT || e.getConstantValue() != null || heuristicallyConstant(e))                checkAllCaps(e);            else                checkCamelCase(e, false);            return null;        }        /**         * 判斷一個變數是否是常量         */        private boolean heuristicallyConstant(VariableElement e) {            if (e.getEnclosingElement().getKind() == INTERFACE)                return true;            else if (e.getKind() == FIELD && e.getModifiers().containsAll(EnumSet.of(PUBLIC, STATIC, FINAL)))                return true;            else {                return false;            }        }        /**         * 檢查傳入的Element是否符合駝式命名法,如果不符合,則輸出警告資訊         */        private void checkCamelCase(Element e, boolean initialCaps) {            String name = e.getSimpleName().toString();            boolean previousUpper = false;            boolean conventional = true;            int firstCodePoint = name.codePointAt(0);            if (Character.isUpperCase(firstCodePoint)) {                previousUpper = true;                if (!initialCaps) {                    messager.printMessage(WARNING, "名稱“" + name + "”應當以小寫字母開頭", e);                    return;                }            } else if (Character.isLowerCase(firstCodePoint)) {                if (initialCaps) {                    messager.printMessage(WARNING, "名稱“" + name + "”應當以大寫字母開頭", e);                    return;                }            } else                conventional = false;            if (conventional) {                int cp = firstCodePoint;                for (int i = Character.charCount(cp); i < name.length(); i += Character.charCount(cp)) {                    cp = name.codePointAt(i);                    if (Character.isUpperCase(cp)) {                        if (previousUpper) {                            conventional = false;                            break;                        }                        previousUpper = true;                    } else                        previousUpper = false;                }            }            if (!conventional)                messager.printMessage(WARNING, "名稱“" + name + "”應當符合駝式命名法(Camel Case Names)", e);        }        /**         * 大寫命名檢查,要求第一個字母必須是大寫的英文字母,其餘部分可以是底線或大寫字母         */        private void checkAllCaps(Element e) {            String name = e.getSimpleName().toString();            boolean conventional = true;            int firstCodePoint = name.codePointAt(0);            if (!Character.isUpperCase(firstCodePoint))                conventional = false;            else {                boolean previousUnderscore = false;                int cp = firstCodePoint;                for (int i = Character.charCount(cp); i < name.length(); i += Character.charCount(cp)) {                    cp = name.codePointAt(i);                    if (cp == (int) '_') {                        if (previousUnderscore) {                            conventional = false;                            break;                        }                        previousUnderscore = true;                    } else {                        previousUnderscore = false;                        if (!Character.isUpperCase(cp) && !Character.isDigit(cp)) {                            conventional = false;                            break;                        }                    }                }            }            if (!conventional)                messager.printMessage(WARNING, "常量“" + name + "”應當全部以大寫字母或底線命名,並且以字母開頭", e);        }    }}   

    最後在提供一個較差的代碼編碼規範代碼:

public class BADLY_NAMED_CODE {    enum colors {        red, blue, green;    }    static final int _FORTY_TWO = 42;    public static int NOT_A_CONSTANT = _FORTY_TWO;    protected void BADLY_NAMED_CODE() {        return;    }    public void NOTcamelCASEmethodNAME() {        return;    }}
3.4.3:運行和測試

    先用javac編譯NameChecker.java和NameCheckProcessor.java;然後javac -processor NameCheckProcessor BADLY_NAMED_CODE.java 命令編譯這段範例程式碼。 3.4.3:其它應用案例

    Hibernate Validator Annotation Processor、Project Lombok等。

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.