Java 7 中的Switch 談 Java版本更新和反編譯知識


Java 7 中的Switch 談 Java版本更新和反編譯知識

         學習編程,享受生活,大家好,我是追尋夢的飛飛。今天主要講述的是Java7中的更新Switch實現內部原理和JAD反編譯知識,反編譯很好玩的!

Java語言大版本之間的更新,會添加一些比較好的改動。目前最流行的應該是Java7 版本的,現在java 8 已經推出,更多的是關注與移動互聯網領域,比如位置信息、觸摸即使、羅盤指針、重力感應之類的。不過到java 8 推廣還有一段時間,所以就先學習Java7中的新改動的知識了。軟件版本更新需要考慮對之間版本的兼容性,讓版本更新的代價最小,這一點在Switch中是如何體現的呢?

         之前的Java中Switch僅僅支持整形的數據,所以給編程帶來一定的困擾,極大的限制了程序的靈活性(我想說的是C/C++中好像也是僅僅支持類int類型的變量)。但是在Java7中增加了一種String類型,Switch語句支持Character Byte Short Integer String類型。但是這一種方式的改變,在底層如何實現,怎樣修改使得代價最小:

         在Switch語句中,case中的值是不可以相等的,經過編譯之后的Java代碼會全部轉為Unicode字符:所以下面的情況是不會通過編譯的:

         String gender  = “”;

         switch(gender){

         case “男”:

                   break;

         case “\u7537”:

                   break;

}

這樣的代碼是不會被編譯通過的。因為unicode中的\u7537就是漢字男

在底層的實現原理:

因為之前的Switch是僅僅支持int類型的,也就是說在JVM和字節碼層次上僅僅支持int類型的變量,那么減少這個改變帶來的影響,就需要根據源代碼中的含義,將字符串轉變為對應的int值,不同的JAVA編譯器采用不同的方式進行轉變,這里我們想到的就是Java的hashCode。

         這里就需要介紹一個很好的工具JAD,它可以反編譯,也就是把字節碼編譯成為Java源代碼,好像很厲害的樣子,於是我就忍不住,趕緊來試一下,如果可以反編譯別人的字節碼,那豈不是碉堡了,在反編譯之前,我們先大膽的猜一下:Java的反編譯應該是比C/C++的要簡單的多,因為JVM 的標准是開放的,所以生成的字節碼也是有規律的,但是反編譯之后的源代碼應該和自己寫的源代碼有一定的差別,但是差別會有多大,感覺不會很大。因為每一個JAVA文件是獨自的編譯的,生成對應的字節碼。我們測試一下:

         首先是下載工具和配置環境了:很小的幾百k,加壓出來發現就兩個文件執行exe和說明文檔。為了能夠在命令行中可以運行,我們直接把她放在JDK/bin中,前提是你配置了JAVA環境變量。

         開始測試了:

         1.輸入jad命令,可以運行

 

         2.找個自己的源代碼

TestMain.java

import java.io.InputStream;

import net.sf.ehcache.Cache;

import net.sf.ehcache.CacheManager;

import org.eclipse.jetty.server.Connector;

import org.eclipse.jetty.server.Handler;

import org.eclipse.jetty.server.Server;

import org.eclipse.jetty.server.ServerConnector;

import org.springframework.context.ApplicationContext;

import org.springframework.context.support.ClassPathXmlApplicationContext;

import com.yang.lolvideo.jetty.handler.LolHandler;

public class TestMain {

         private static final int PORT_ONE = 8087;

         private static final int PORT_TWO = 8088;

         public static void main(String[] args) throws Exception {

                   // TODO Auto-generated method stub

                   //Spring config

                   ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");

                  

                   //ehcache config to get the object cache

                   InputStream ehcacheConfig = TestMain.class.getResourceAsStream("ehcache.xml");

                   CacheManager cacheManager = CacheManager.create(ehcacheConfig);

                   Cache cache = cacheManager.getCache("sampleCache1");         

                  

                   //Jetty server to run the server

                   Server server =new Server();

                   ServerConnector connector_one = new ServerConnector(server);

                   connector_one.setPort(PORT_ONE);

                   ServerConnector connector_two = new ServerConnector(server);

                   connector_two.setPort(PORT_TWO);

                   server.setConnectors(new Connector[]{connector_two});    

                   Handler handler = new LolHandler(context,cache);

                   server.setHandler(handler);

                   //start server

                   server.start();

                   server.join();

         }

}

將他的字節碼反編譯

jad –p TestMain.class > TestMain.java // 將編譯的結果重定向到文件

jad –p TestMain.class // 將編譯的結果顯示在屏幕

jad –o TestMain.class > TestMain.java // 不提示,直接覆蓋原文件

 

查看源文件:

// Decompiled by Jad v1.5.8g. Copyright 2001 Pavel Kouznetsov.

// Jad home page: http://www.kpdus.com/jad.html

// Decompiler options: packimports(3)

// Source File Name:   TestMain.java

 

import com.yang.lolvideo.jetty.handler.LolHandler;

import net.sf.ehcache.CacheManager;

import org.eclipse.jetty.server.*;

import org.springframework.context.support.ClassPathXmlApplicationContext;

public class TestMain

{

    public TestMain()

    {

    }

    public static void main(String args[])

        throws Exception

    {

        org.springframework.context.ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");

        java.io.InputStream ehcacheConfig = TestMain.getResourceAsStream("ehcache.xml");

        CacheManager cacheManager = CacheManager.create(ehcacheConfig);

        net.sf.ehcache.Cache cache = cacheManager.getCache("sampleCache1");

        Server server = new Server();

        ServerConnector connector_one = new ServerConnector(server);

        connector_one.setPort(8087);

        ServerConnector connector_two = new ServerConnector(server);

        connector_two.setPort(8088);

        server.setConnectors(new Connector[] {

            connector_two

        });

        org.eclipse.jetty.server.Handler handler = new LolHandler(context, cache);

        server.setHandler(handler);

        server.start();

        server.join();

    }

    private static final int PORT_ONE = 8087;

    private static final int PORT_TWO = 8088;

}

果然是超厲害,這反編譯的寫的代碼比我自己的源代碼更加規范,我和我的小伙伴們的哦驚呆了,這樣豈不是可以……你懂的

還是回來說說這些switch實現的機制:

源代碼是:

//TestMain.java

public class TestMain

{

         public String generatee(String name, String gender){

                   String title="";

                   switch(gender){

                            case "男":

                                     title= name + "先生";

                                     break;

                            case "女":

                                     title=name+ "女士";

                                     break;

                            default:

                                     title = name;

                   }

                   return title;

         }

}

反編譯之后:

// Decompiled by Jad v1.5.8g. Copyright 2001 Pavel Kouznetsov.

// Jad home page: http://www.kpdus.com/jad.html

// Decompiler options: packimports(3)

// Source File Name:   TestMain.java

public class TestMain

{

 

    public TestMain()

    {

    }

 

    public String generatee(String s, String s1)

    {

        String s2 = "";

        String s3 = s1;

        byte byte0 = -1;

        switch(s3.hashCode())

        {

        case 30007:

            if(s3.equals("\u7537"))

                byte0 = 0;

            break;

 

        case 22899:

            if(s3.equals("\u5973"))

                byte0 = 1;

            break;

        }

        switch(byte0)

        {

        case 0: // '\0'

            s2 = (new StringBuilder()).append(s).append("\u5148\u751F").toString();

            break;

 

        case 1: // '\001'

            s2 = (new StringBuilder()).append(s).append("\u5973\u58EB").toString();

            break;

 

        default:

            s2 = s;

            break;

        }

        return s2;

    }

}

在底層原來是這樣實現的,在轉變為hashCode之后,也會在內部使用equal函數進行判斷。因為不同的對象產生的hashCode也會有相等的時候。在這里吧他們轉變為byte的0,1,2,之后在來一個switch進行判斷,執行對應的操作。

         所以說在在底層執行代碼不一定就是我們編寫的代碼,這個時候我們就應給考慮執行效率的問題。如果對於這種switch我們可以嘗試使用enum類型來進行優化。

        

         今天就先到這里了,不斷的學習新的技術,和大家分享!

 

追尋夢的飛飛

2014.04.02 於廣州


注意!

本站转载的文章为个人学习借鉴使用,本站对版权不负任何法律责任。如果侵犯了您的隐私权益,请联系我们删除。



 
粤ICP备14056181号  © 2014-2021 ITdaan.com