成人国产在线小视频_日韩寡妇人妻调教在线播放_色成人www永久在线观看_2018国产精品久久_亚洲欧美高清在线30p_亚洲少妇综合一区_黄色在线播放国产_亚洲另类技巧小说校园_国产主播xx日韩_a级毛片在线免费

資訊專(zhuān)欄INFORMATION COLUMN

【修煉內(nèi)功】[JVM] 虛擬機(jī)視角的方法調(diào)用

shevy / 3103人閱讀

摘要:本文已收錄修煉內(nèi)功躍遷之路我們寫(xiě)的方法在被編譯為文件后是如何被虛擬機(jī)執(zhí)行的對(duì)于重寫(xiě)或者重載的方法,是在編譯階段就確定具體方法的么如果不是,虛擬機(jī)在運(yùn)行時(shí)又是如何確定具體方法的方法調(diào)用不等于方法執(zhí)行,一切方法調(diào)用在文件中都只是常量池中的符號(hào)引

本文已收錄【修煉內(nèi)功】躍遷之路

『我們寫(xiě)的Java方法在被編譯為class文件后是如何被虛擬機(jī)執(zhí)行的?對(duì)于重寫(xiě)或者重載的方法,是在編譯階段就確定具體方法的么?如果不是,虛擬機(jī)在運(yùn)行時(shí)又是如何確定具體方法的?』

方法調(diào)用不等于方法執(zhí)行,一切方法調(diào)用在class文件中都只是常量池中的符號(hào)引用,這需要在類(lèi)加載的解析階段甚至到運(yùn)行期間才能將符號(hào)引用轉(zhuǎn)為直接引用,確定目標(biāo)方法進(jìn)行執(zhí)行

在編譯過(guò)程中編譯器并不知道目標(biāo)方法的具體內(nèi)存地址,因此編譯器會(huì)暫時(shí)使用符號(hào)引用來(lái)表示該目標(biāo)方法

編譯代碼

public class MethodDescriptor {
    public void printHello() {
        System.out.println("Hello");
    }

    public void printHello(String name) {
        System.out.println("Hello " + name);
    }

    public static void main(String[] args) {
        MethodDescriptor md = new MethodDescriptor();
        md.printHello();
        md.printHello("manerfan");
    }
}

查看其字節(jié)碼

main方法中調(diào)用兩次不同的printHello方法,對(duì)應(yīng)class文件中均為invokevirtual指令,分別調(diào)用常量池中的#12及#14,查看常量池

#12及#14對(duì)應(yīng)兩個(gè)Methodref方法引用,這兩個(gè)方法引用均為符號(hào)引用(使用方法描述符)而并非直接引用

虛擬機(jī)識(shí)別方法的關(guān)鍵在于類(lèi)名、方法名及方法描述符(method descriptor),方法描述符由方法的參數(shù)類(lèi)型及返回類(lèi)型構(gòu)成

方法名及方法描述符在編譯階段便可以確定,但對(duì)于實(shí)際類(lèi)名,一些場(chǎng)景下(如類(lèi)繼承)只有在運(yùn)行時(shí)才可知

方法調(diào)用指令

目前Java虛擬機(jī)里提供了5中方法調(diào)用的字節(jié)碼指令

invokestatic: 調(diào)用靜態(tài)方法

invokespecial: 調(diào)用實(shí)例構(gòu)造器方法、私有方法及父類(lèi)方法

invokevirtual: 調(diào)用虛方法(會(huì)在運(yùn)行時(shí)確定具體的方法對(duì)象)

invokeinterface: 調(diào)用接口方法(會(huì)在運(yùn)行時(shí)確定一個(gè)實(shí)現(xiàn)此接口的對(duì)象)

invokedynamic: 先在運(yùn)行時(shí)動(dòng)態(tài)解析出調(diào)用點(diǎn)限定符所引用的方法,然后再執(zhí)行該方法

invokestatic及invokespecial調(diào)用的方法(靜態(tài)方法、構(gòu)造方法、私有方法、父類(lèi)方法),均可以在類(lèi)加載的解析階段確定唯一的調(diào)用版本,從而將符號(hào)引用直接解析為該方法的直接引用,這些方法稱(chēng)之為非虛方法

而invokevirtual及invokeinterface調(diào)用的方法(final方法除外,下文提到),在解析階段并不能唯一確定,只有在運(yùn)行時(shí)才能拿到實(shí)際的執(zhí)行類(lèi)從而確定唯一的調(diào)用版本,此時(shí)才可以將符號(hào)引用轉(zhuǎn)為直接引用,這些方法稱(chēng)之為虛方法

invokedynamic比較特殊,多帶帶分析

簡(jiǎn)單示意,如下代碼

public interface MethodBase {
    String getName();
}

public class BaseMethod implements MethodBase {
    @Override
    public String getName() {
        return "manerfan";
    }

    public void print() {
        System.out.println(getName());
    }
}

public class MethodImpl extends BaseMethod {
    @Override
    public String getName() {
        return "maner-fan";
    }

    @Override
    public void print() {
        System.out.println("Hello " + getName());
    };

    public String getSuperName() {
        return super.getName();
    }

    public static String getDefaultName() {
        return "default";
    }
}

public class MethodDescriptor {
    public static void print(BaseMethod baseMethod) {
        baseMethod.print();
    }

    public static String getName(MethodBase methodBase) {
        return methodBase.getName();
    }

    public static void main(String[] args) {
        MethodImpl.getDefaultName();

        MethodImpl ml = new MethodImpl();
        ml.getSuperName();
        getName(ml);
        print(ml);
    }
}

查看MethodDescriptor的字節(jié)碼

不難發(fā)現(xiàn),接口MethodBase中g(shù)etName方法的調(diào)用均被編譯為invokeinterface指令,子類(lèi)BaseMethod中print方法的調(diào)用則被便以為invokevirtual執(zhí)行,靜態(tài)方法的調(diào)用被編譯為invokestatic指令,而構(gòu)造函數(shù)調(diào)用則被編譯為invokespecial指令

查看MethodImpl字節(jié)碼

可以看到,父類(lèi)方法的調(diào)用則被編譯為invokespecial指令

橋接方法

在JVM - 類(lèi)文件結(jié)構(gòu)中有介紹方法的訪問(wèn)標(biāo)識(shí),其中有兩條 ACC_BRIDGE(橋接方法) 及 ACC_SYNTHETIC(編譯器生成,不會(huì)出現(xiàn)在源碼中),而橋接方法便是由編譯器生成,且會(huì)將橋接方法標(biāo)記為ACC_BRIDGE及ACC_SYNTHETIC,那什么時(shí)候會(huì)生成橋接方法?

橋接方法是 JDK 1.5 引入泛型后,為了使Java的泛型方法生成的字節(jié)碼和 1.5 版本前的字節(jié)碼相兼容,由編譯器自動(dòng)生成的,就是說(shuō)一個(gè)子類(lèi)在繼承(或?qū)崿F(xiàn))一個(gè)父類(lèi)(或接口)的泛型方法時(shí),在子類(lèi)中明確指定了泛型類(lèi)型,那么在編譯時(shí)編譯器會(huì)自動(dòng)生成橋接方法(當(dāng)然還有其他情況會(huì)生成橋接方法,這里只是列舉了其中一種情況)

public class BaseMethod {
    public void print(T obj) {
        System.out.println("Hello " + obj.toString());
    }
}

public class MethodImpl extends BaseMethod {
    @Override
    public void print(String name) {
        super.print(name);
    };
}

首先查看BaseMethod字節(jié)碼

由于泛型的擦除機(jī)制,print的方法描述符入?yún)⒈粯?biāo)記為(Ljava/lang/Object;)V

再查看MethodImpl字節(jié)碼

MethodImpl只聲明了一個(gè)print方法,卻被編譯為兩個(gè),一個(gè)方法描述符為(Ljava/lang/String;)V,另一個(gè)為(Ljava/lang/Object;)V且標(biāo)記為ACC_BRIDGE ACC_SYNTHETIC

print(java.lang.Object)方法中做了一層類(lèi)型轉(zhuǎn)換,將入?yún)⑥D(zhuǎn)為String類(lèi)型,進(jìn)而再調(diào)用print(java.lang.String)方法

為什么要生成橋接方法

泛型可以保證在編譯階段檢查對(duì)象類(lèi)型是否匹配執(zhí)行的泛型類(lèi)型,但為了向下兼容(1.5之前),在編譯時(shí)則會(huì)擦除泛型信息,如果不生成橋接方法則會(huì)導(dǎo)致字節(jié)碼中子類(lèi)方法為print(java.lang.Object)而父類(lèi)為print(java.lang.String),這樣的情況是無(wú)法做到向下兼容的

橋接方法的隱患

既然橋接方法是為了向下兼容,那會(huì)不會(huì)有什么副作用?

public class MethodDescriptor {
    public static void main(String[] args) {
        BaseMethod bm = new MethodImpl();
        bm.print("manerfan");
        bm.print(new Object());
    }
}

查看字節(jié)碼

可以看到,雖然MethodImpl.print方法入?yún)⒙暶鳛镾tring類(lèi)型,但實(shí)際調(diào)用的還是橋接方法print(java.lang.Object)

由于子類(lèi)的入?yún)?b>Object,所以編譯并不會(huì)失敗,但從MethodImpl的字節(jié)碼中可以看到,橋接方法是有一次類(lèi)型轉(zhuǎn)換的,在將類(lèi)型轉(zhuǎn)為String之后會(huì)調(diào)用print(java.lang.String)方法,那如果類(lèi)型轉(zhuǎn)換失敗呢?運(yùn)行程序可以得到

Hello manerfan
Exception in thread "main" java.lang.ClassCastException: java.lang.Object cannot be cast to java.lang.String
    at MethodImpl.print(MethodImpl.java:1)
    at MethodDescriptor.main(MethodDescriptor.java:5)

所以,由于泛型的擦除機(jī)制,會(huì)導(dǎo)致某些情況下(如方法橋接)的錯(cuò)誤,只有在運(yùn)行時(shí)才可以被發(fā)現(xiàn)

對(duì)于其他情況,大家可以編寫(xiě)更為具體的代碼查看其字節(jié)碼指令

分派 靜態(tài)分派

首先看一個(gè)重載的例子

public class StaticDispatch {
    static abstract class Animal {
        public abstract void croak();
    }

    static class Dog extends Animal {
        @Override
        public void croak() {
            System.out.println("汪汪叫~");
        }
    }

    static class Duck extends Animal {
        @Override
        public void croak() {
            System.out.println("呱呱叫~");
        }
    }

    public void croak(Animal animal) {
        System.out.println("xx叫~");
    }

    public void croak(Dog dog) {
        dog.croak();
    }

    public void croak(Duck duck) {
        duck.croak();
    }

    public static void main(String[] args) {
        Animal dog = new Dog();
        Animal duck = new Duck();
        StaticDispatch dispatcher = new StaticDispatch();
        dispatcher.croak(dog);
        dispatcher.croak(duck);
    }
}

運(yùn)行結(jié)果

xx叫~
xx叫~

起始并不難理解為什么兩次都執(zhí)行了croak(Animal)的方法,這里要區(qū)分變量的靜態(tài)類(lèi)型以及變量的實(shí)際類(lèi)型

一個(gè)對(duì)象的靜態(tài)類(lèi)型在編譯器是可知的,但并不知道其實(shí)際類(lèi)型是什么,實(shí)際類(lèi)型只有在運(yùn)行時(shí)才可知

編譯器在重載時(shí),是通過(guò)參數(shù)的靜態(tài)類(lèi)型(而不是實(shí)際類(lèi)型)作為判定依據(jù)以決定使用哪個(gè)重載版本的,所有依賴(lài)靜態(tài)類(lèi)型來(lái)定位方法執(zhí)行版本的分派動(dòng)作成為靜態(tài)分派,靜態(tài)分派發(fā)生在編譯階段,因此嚴(yán)格來(lái)講靜態(tài)分派并不是虛擬機(jī)的行為

動(dòng)態(tài)分派

同樣,還是上述示例,修改main方法

 public static void main(String[] args) {
     Animal dog = new Duck();
     Animal duck = new Dog();
     dog.croak();
     duck.croak();
 }

運(yùn)行結(jié)果

呱呱叫~
汪汪叫~

顯然這里并不能使用靜態(tài)分派來(lái)決定方法的執(zhí)行版本(編譯階段并不知道dog及duck的實(shí)際類(lèi)型),查看字節(jié)碼

兩次croak調(diào)用均使用了invokevirtual指令,invokevirtual指令(invokeinterface類(lèi)似)運(yùn)行時(shí)解析過(guò)程大致為

找到對(duì)象實(shí)際類(lèi)型C

在C常量池中查找方法描述符相符的方法,如果找到則返回方法的直接引用,如果無(wú)權(quán)訪問(wèn)則拋jaba.lang.IllegalAccessError異常

如果未找到,則按照繼承關(guān)系從下到上一次對(duì)C的各個(gè)父類(lèi)進(jìn)行第2步的搜索

如果均未找到,則拋java.lang.AbstractMethodError異常

實(shí)際運(yùn)行過(guò)程中,動(dòng)態(tài)分派是非常頻繁的動(dòng)作,而動(dòng)態(tài)分派的方法版本選擇需要在類(lèi)的方法元數(shù)據(jù)中進(jìn)行搜索,處于性能的考慮,類(lèi)在方法區(qū)中均會(huì)創(chuàng)建一個(gè)虛方法表(virtual method table, vtable)及接口方法表(interface method table, itable),使用虛方法表(接口方法表)索引來(lái)代替元數(shù)據(jù)查找以提高性能

方法表本質(zhì)上是一個(gè)數(shù)組,每個(gè)數(shù)組元素都指向一個(gè)當(dāng)前類(lèi)機(jī)器祖先類(lèi)中非私有的實(shí)力方法

動(dòng)態(tài)調(diào)用

在JDK1.7以前,4條方法調(diào)用指令(invokestatic、invokespecial、invokevirtual、invokeinterface),均與包含目標(biāo)方法類(lèi)名、方法名及方法描述符的符號(hào)引用綁定,invokestatic及invokespecial的分派邏輯在編譯時(shí)便確定,invokevirtual及invokeinterface的分配邏輯也由虛擬機(jī)在運(yùn)行時(shí)決定,在此之前,JVM虛擬機(jī)并不能實(shí)現(xiàn)動(dòng)態(tài)語(yǔ)言的一些特性,典型的例子便是鴨子類(lèi)型(duck typing)

鴨子類(lèi)型(duck typing)是多態(tài)(polymorphism)的一種形式,在這種形式中不管對(duì)象屬于哪個(gè),也不管聲明的具體接口是什么,只要對(duì)象實(shí)現(xiàn)了相應(yīng)的方法函數(shù)就可以在對(duì)象上執(zhí)行操作
public class StaticDispatch {
    static class Duck {
        public void croak() {
            System.out.println("呱呱叫~");
        }
    }
    
    static class Dog {
        public void croak() {
            System.out.println("學(xué)鴨子呱呱叫~");
        }
    }

    public static void duckCroak(Duck duckLike) {
        duckLike.croak();
    }

    public static void main(String[] args) {
        Duck duck = new Duck();
        Dog dog = new Dog();
        duckCroak(duck);
        duckCroak(dog); // 編譯錯(cuò)誤
    }
}

我們不關(guān)心Dog是不是Duck,只要Dog可以像Duck一樣croak就可以

方法句柄

Duck Dog croak的問(wèn)題,我們可以使用反射來(lái)解決,也可以使用一種新的、更底層的動(dòng)態(tài)確定目標(biāo)方法的機(jī)制來(lái)實(shí)現(xiàn)--方法句柄

方法句柄是一個(gè)請(qǐng)類(lèi)型的、能夠被直接執(zhí)行的引用,類(lèi)似于C/C++中的函數(shù)指針,可以指向常規(guī)的靜態(tài)方法或者實(shí)力方法,也可以指向構(gòu)造器或者字段

public class Dispatch {
    static class Duck {
        public void croak() {
            System.out.println("呱呱叫~");
        }
    }

    static class Dog {
        public void croak() {
            System.out.println("學(xué)鴨子呱呱叫~");
        }
    }

    public static void duckCroak(MethodHandle duckLike) throws Throwable {
        duckLike.invokeExact();
    }

    public static void main(String[] args) throws Throwable {
        Duck duck = new Duck();
        Dog dog = new Dog();

        MethodType mt = MethodType.methodType(void.class);
        MethodHandle duckCroak = MethodHandles.lookup().findVirtual(duck.getClass(), "croak", mt).bindTo(duck);
        MethodHandle dogCroak = MethodHandles.lookup().findVirtual(dog.getClass(), "croak", mt).bindTo(dog);

        duckCroak(duckCroak);
        duckCroak(dogCroak);
    }
}

這樣的事情,使用反射不一樣可以實(shí)現(xiàn)么?

本質(zhì)上講,Reflection及MethodHandler都是在模擬方法調(diào)用,但Reflection是Java代碼層次的模擬,MethodHandler是字節(jié)碼層次的層次,更為底層

Reflection相比MethodHandler包含更多的信息,Reflection是重量級(jí)的,MethodHandler是輕量級(jí)的

invokedynamic

invokedynamic是Java1.7引入的一條新指令,用以支持動(dòng)態(tài)語(yǔ)言的方法調(diào)用,解決原有4條"invoke*"指令方法分派規(guī)則固化在虛擬機(jī)中的問(wèn)題,把如何查找目標(biāo)方法的決定權(quán)從虛擬機(jī)轉(zhuǎn)嫁到具體用戶(hù)代碼中,使用戶(hù)擁有更高的自由度

invokedynamic將調(diào)用點(diǎn)(CallSite)抽象成一個(gè)Java類(lèi),并且將原本由Java虛擬機(jī)控制的方法調(diào)用以及方法鏈接暴露給了應(yīng)用程序,在運(yùn)行過(guò)程中,每一條invokedynamic指令將捆綁一個(gè)調(diào)用點(diǎn),并且會(huì)調(diào)用該調(diào)用點(diǎn)所鏈接的方法句柄

在Java8以前,并不能直接通過(guò)Java程序編譯生成invokedynamic指令,這里寫(xiě)一段代碼用以模擬上述過(guò)程

public class DynamicDispatch {
    /**
     * 動(dòng)態(tài)調(diào)用的方法
     */
    private static void croak(String name) {
        System.out.println(name + " croak");
    }

    public static void main(String[] args) throws Throwable {
        INDY_BootstrapMethod().invokeExact("dog");
    }

    /**
     * 生成啟動(dòng)方法
     */
    private static CallSite BootstrapMethod(MethodHandles.Lookup lookup, String name, MethodType mt) throws Throwable {
        return new ConstantCallSite(lookup.findStatic(DynamicDispatch.class, name, mt));
    }

    /**
     * 生成啟動(dòng)方法的MethodType
     */
    private static MethodType MT_BootstrapMethod() {
        return MethodType.fromMethodDescriptorString(
            "(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;)"
                + "Ljava/lang/invoke/CallSite;",
            null);
    }

    /**
     * 生成啟動(dòng)方法的MethodHandle
     */
    private static MethodHandle MH_BootstrapMethod() throws Throwable {
        return MethodHandles.lookup().findStatic(DynamicDispatch.class, "BootstrapMethod", MT_BootstrapMethod());
    }

    /**
     * 生成調(diào)用點(diǎn),動(dòng)態(tài)調(diào)用
     */
    private static MethodHandle INDY_BootstrapMethod() throws Throwable {
        // 生成調(diào)用點(diǎn)
        CallSite cs = (CallSite)MH_BootstrapMethod().invokeWithArguments(MethodHandles.lookup(), "croak",
            MethodType.fromMethodDescriptorString("(Ljava/lang/String;)V", null));
        // 動(dòng)態(tài)調(diào)用
        return cs.dynamicInvoker();
    }
}

字節(jié)碼中,啟動(dòng)方法由方法句柄來(lái)指定(MH_BootstrapMethod),該句柄指向一個(gè)返回類(lèi)型為調(diào)用點(diǎn)的靜態(tài)方法(BootstrapMethod)

在第一次執(zhí)行invokedynamic時(shí),JVM虛擬機(jī)會(huì)調(diào)用該指令所對(duì)應(yīng)的啟動(dòng)方法(BootstrapMethod)來(lái)生成調(diào)用點(diǎn)

啟動(dòng)方法(BootstrapMethod)由方法句柄來(lái)指定(MH_BootstrapMethod)

啟動(dòng)方法接受三個(gè)固定的參數(shù),分別為 Lookup實(shí)例、指代目標(biāo)方法名的字符串及該調(diào)用點(diǎn)能夠鏈接的方法句柄類(lèi)型

將調(diào)用點(diǎn)綁定至該invokedynamic指令中,之后的運(yùn)行中虛擬機(jī)會(huì)直接調(diào)用綁定的調(diào)用點(diǎn)所鏈接的方法句柄

Lambda表達(dá)式

Java8中的lambda表達(dá)式使用的便是invokedynamic指令

public class DynamicDispatch {
    public void croak(Supplier name) {
        System.out.println(name.get() + "croak");
    }

    public static void main(String[] args) throws Throwable {
        new DynamicDispatch().croak(() -> "dog");
    }
}

查看字節(jié)碼

可以看到,lambda表達(dá)式會(huì)被編譯為invokedynamic指令,同時(shí)會(huì)生成一個(gè)私有靜態(tài)方法lambda$main$0,用以實(shí)現(xiàn)lambda表達(dá)式內(nèi)部的邏輯

其實(shí),除了會(huì)生成一個(gè)靜態(tài)方法之外,還會(huì)額外生成一個(gè)內(nèi)部類(lèi),lambda啟動(dòng)方法及調(diào)用點(diǎn)的詳細(xì)介紹請(qǐng)轉(zhuǎn) Java8 - Lambda原理-究竟是不是匿名類(lèi)的語(yǔ)法糖

文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/77900.html

相關(guān)文章

  • 修煉內(nèi)功】[Java8] Lambda究竟是不是匿名類(lèi)語(yǔ)法糖

    摘要:本文已收錄修煉內(nèi)功躍遷之路初次接觸的時(shí)候感覺(jué)表達(dá)式很神奇表達(dá)式帶來(lái)的編程新思路,但又總感覺(jué)它就是匿名類(lèi)或者內(nèi)部類(lèi)的語(yǔ)法糖而已,只是語(yǔ)法上更為簡(jiǎn)潔罷了,如同以下的代碼匿名類(lèi)內(nèi)部類(lèi)編譯后會(huì)產(chǎn)生三個(gè)文件雖然從使用效果來(lái)看,與匿名類(lèi)或者內(nèi)部類(lèi)有相 本文已收錄【修煉內(nèi)功】躍遷之路 showImg(https://segmentfault.com/img/bVbui4o?w=800&h=600)...

    ?xiaoxiao, 評(píng)論0 收藏0
  • 修煉內(nèi)功】[JVM] 虛擬機(jī)棧及字節(jié)碼基礎(chǔ)

    摘要:本文已收錄修煉內(nèi)功躍遷之路在淺談虛擬機(jī)內(nèi)存模型一文中有簡(jiǎn)單介紹過(guò),虛擬機(jī)棧是線程私有的,每個(gè)方法在執(zhí)行的同時(shí)都會(huì)創(chuàng)建一個(gè)棧幀,方法執(zhí)行時(shí)棧幀入棧,方法結(jié)束時(shí)棧幀出棧,虛擬機(jī)中棧幀的入棧順序就是方法的調(diào)用順序?qū)懥撕芏辔淖?,但都不盡如意,十分慚 本文已收錄【修煉內(nèi)功】躍遷之路 showImg(https://segmentfault.com/img/bVbtSi5?w=1654&h=96...

    VEIGHTZ 評(píng)論0 收藏0
  • 修煉內(nèi)功】[JVM] 淺談虛擬機(jī)內(nèi)存模型

    摘要:也正是因此,一旦出現(xiàn)內(nèi)存泄漏或溢出問(wèn)題,如果不了解的內(nèi)存管理原理,那么將會(huì)對(duì)問(wèn)題的排查帶來(lái)極大的困難。 本文已收錄【修煉內(nèi)功】躍遷之路 showImg(https://segmentfault.com/img/bVbsP9I?w=1024&h=580); 不論做技術(shù)還是做業(yè)務(wù),對(duì)于Java開(kāi)發(fā)人員來(lái)講,理解JVM各種原理的重要性不必再多言 對(duì)于C/C++而言,可以輕易地操作任意地址的...

    sanyang 評(píng)論0 收藏0
  • 修煉內(nèi)功】[JVM] 深入理解JVM之ClassLoader

    摘要:本文已收錄修煉內(nèi)功躍遷之路在誕生之初便提出,各提供商發(fā)布很多不同平臺(tái)的虛擬機(jī),這些虛擬機(jī)都可以載入并執(zhí)行同平臺(tái)無(wú)關(guān)的字節(jié)碼。設(shè)計(jì)者在第一版虛擬機(jī)規(guī)范中便承諾,時(shí)至今日,商業(yè)機(jī)構(gòu)和開(kāi)源機(jī)構(gòu)已在之外發(fā)展出一大批可以在上運(yùn)行的語(yǔ)言,如等。 本文已收錄【修煉內(nèi)功】躍遷之路 Java在誕生之初便提出 Write Once, Run Anywhere,各提供商發(fā)布很多不同平臺(tái)的虛擬機(jī),這些虛擬機(jī)...

    荊兆峰 評(píng)論0 收藏0
  • 修煉內(nèi)功】[JVM] 類(lèi)文件結(jié)構(gòu)

    摘要:本文已收錄修煉內(nèi)功躍遷之路學(xué)習(xí)語(yǔ)言的時(shí)候,需要在不同的目標(biāo)操作系統(tǒng)上或者使用交叉編譯環(huán)境,使用正確的指令集編譯成對(duì)應(yīng)操作系統(tǒng)可運(yùn)行的執(zhí)行文件,才可以在相應(yīng)的系統(tǒng)上運(yùn)行,如果使用操作系統(tǒng)差異性的庫(kù)或者接口,還需要針對(duì)不同的系統(tǒng)做不同的處理宏的 本文已收錄【修煉內(nèi)功】躍遷之路 showImg(https://segmentfault.com/img/bVbtpPd?w=2065&h=11...

    Eminjannn 評(píng)論0 收藏0

發(fā)表評(píng)論

0條評(píng)論

最新活動(dòng)
閱讀需要支付1元查看
<