Java構文糖


文書ディレクトリ
  • 一、文法糖とは何ですか.
  • 二、解語法糖
  • 三、Java文法糖
  • 1、汎用およびタイプ消去
  • 例一:
  • 例2:
  • 2、switchサポートString
  • 3、自動梱包と解体
  • (1)自動梱包試験コード:
  • (2)自動分解試験コード:
  • 4、foreachサイクル
  • 5、内部クラス
  • 6、列挙
  • 一、文法糖とは何ですか.
    文法糖は、糖衣文法とも呼ばれ、イギリスのコンピュータ科学者が発明した用語で、コンピュータ言語に何らかの文法を加えることを指し、このような文法は言語の機能に影響を与えていないが、プログラマーの操作を便利にし、コードの可読性を高め、間違いの機会を減らした.
    Javaは「低糖言語」です.JDK 1.5以前は文法糖があまり登場しなかったからです.しかし、Java 7からJava言語の面では様々な砂糖が添加されており、将来的には「高糖」の方向に発展し続けるだろう.
    Javaで最もよく使われる文法糖は主に汎用型、switchサポートString、自動梱包と解体、foreachサイクル、内部クラスと列挙などがある.
    二、解語法糖
    文法糖は主に開発者が使いやすい.しかし、Java仮想マシンはこれらの文法糖をサポートしていません.これらの文法糖はコンパイル段階で簡単な基礎文法構造に還元され、この過程が解語法糖です.
    三、Java文法糖
    1、汎用型とタイプ消去
    多くの言語は汎用性をサポートしていますが、コンパイラによって汎用性の処理方法が異なります.通常、コンパイラが汎用を処理するには、Code specializationとCode sharingの2つの方法があります.
  • C++およびC#は、Code specializationを用いた処理メカニズムである.C++とC#では、汎用型はソースコードでもコンパイル後でも確実に存在し、ListとListは2つの異なるタイプであり、システムの稼働期間中に生成され、独自の虚メソッドテーブルとタイプデータがあり、このような実装をタイプ膨張と呼び、このような構文に基づいて実装された汎用型を真の汎用型と呼ぶ.
  • JavaではCode sharingを使用しています.Code sharing方式は、各汎用タイプに対して一意のバイトコード表現を作成し、その汎用タイプのインスタンスをこの一意のバイトコード表現にマッピングする.複数の汎用クラスインスタンスを一意のバイトコード表現にマッピングすることは、タイプ消去によって実現される.

  • つまり、Java仮想マシンの稼働期間では、ArrayListとArrayListは同じです.Javaは,コンパイル段階でタイプ消去により解語法糖を行う必要がある.
    タイプ消去の主な手順は次のとおりです.
  • は、すべての汎用パラメータをその最左境界(最上位の親タイプ)タイプで置き換えます.
  • すべてのタイプパラメータを除去します.

  • 例1:
    ソース:
    Map<String, String> map = new HashMap<String, String>(); 
    map.put("kobe", "Lakers");
    map.put("curry", "worries");
    

    解語法糖の後(消去タイプ後):
    Map map = new HashMap(); 
    map.put("kobe", "Lakers");
    map.put("curry", "worries");
    

    例2:
    ソース:
    public static <A extends Comparable<A>>A max(Collection<A> c) {        
    	Iterator<A> it = c.iterator();
    	A w = it.next();
    	while (it.hasNext()) {
    		A x = it.next();
    		if (w.compareTo(x) < 0) 
    			w = x;
    		}
    	return w;
    }
    

    解語法糖の後(消去タイプ後):
    public static Comparable max(Collection c) {        
    	Iterator it = c.iterator();
    	Comparable w = (Comparable)it.next();
    	while (it.hasNext()) {
    		Comparable x = (Comparable)it.next();
    		if (w.compareTo(x) < 0) 
    			w = x;
    		}
    	return w;
    }
    

    Java仮想マシンには汎用型はなく、汎用クラスと汎用メソッドのみで、すべての汎用クラスのタイプパラメータはコンパイル時に消去されます.汎用クラスには独自のクラスオブジェクトはありません.たとえば、List.classやList.classは存在せず、List.classのみです.
    2、switchはStringをサポートする
    Java 7の前に、switchはbyte、short、char、intまたはそれに対応するパッケージクラス、およびEnumタイプしかサポートできません.intタイプについては、直接数値の比較を行う.charタイプの場合、asciiコードを比較します.したがって、コンパイラにとってswitchでは整数しか使用できず、どのタイプの比較も整数に変換されます.
    Java 7からswitchはStringのサポートを開始します.テストコード:
    public class Test {
    	public static void main(String[] args) {
    		String str = "world"; 
    		switch (str) {
    		case "hello": 
    			System.out.println("hello"); 
    			break;
    		case "world": 
    			System.out.println("world");
    			break;
    		default:
    			break;
    		}
    	}
    }
    

    逆コンパイル後、コードは次のとおりです.
    public class Test {
    	public static void main(String args[]){
    		String str = "world";
    		String s;
    		switch((s = str).hashCode()){
    		default:
    			break;
    		case 99162322:
    			if(s.equals("hello"))
    				System.out.println("hello");
    			break;
    		case 113318802:
    			if(s.equals("world"))
    				System.out.println("world");
    			break;
    		}
    	}
    }
    

    逆コンパイルの結果からStringのswitchはequals()とhashCode()法によって実現されることが分かった.hashCode()メソッドはintを返します.
    3、自動梱包と解体
    自動梱包とは、Javaがint変数をIntegerオブジェクトに変換するなど、元の基本タイプ値を自動的に対応するオブジェクトタイプに変換するプロセスを梱包と呼びます.逆にIntegerオブジェクトをintタイプの値に変換します.このプロセスをボックス解除と呼びます.ここでの梱包と解体は自動的に行われる非人為的な転換であるため、自動梱包と解体と呼ぶ.
    基本タイプbyte、short、char、int、long、float、double、booleanに対応するパッケージクラスは、それぞれByte、Short、Character、Integer、Long、Float、Double、Booleanである.
    (1)自動梱包テストコード:
    public static void main(String[] args) {
    	int i = 10;
    	Integer n = i;
    }
    

    逆コンパイル後のコードは次のとおりです.
    public static void main(String args[]) {
    	int i = 10;
    	Integer n = Integer.valueOf(i);
    }
    

    自動梱包の実現はInteger.valueOf()メソッドを呼び出したことである.
    (2)自動解体試験コード:
    public static void main(String[] args) {
    	Integer i = 10;
    	int n = i;
    }
    

    逆コンパイル後のコードは次のとおりです.
    public static void main(String args[]) {
    	Integer i = Integer.valueOf(10);
    	int n = i.intValue();
    }
    

    4、foreachサイクル
    public static void main(String[] args) {
    	List<Integer> list = new ArrayList<Integer>();
    	list.add(500);
    	list.add(2);
    	list.add(new Integer(20));
    	for(int sub : list){
    		System.out.println(sub);
    	}
    }
    

    逆コンパイル後、コードは次のとおりです.
    public static void main(String[] args) {
        List list = new ArrayList();
        list.add(Integer.valueOf(500));
        list.add(Integer.valueOf(2));
        list.add(new Integer(20));
        for (Iterator localIterator = list.iterator(); localIterator.hasNext(); ){
        	int sub = ((Integer)localIterator.next()).intValue();
        	System.out.println(sub);
        }
    }
    

    foreachは実際にlistのiteratorを呼び出して遍歴している.これは,foreachループが遍歴された集合がIteratorインタフェースを実現しなければならない理由である.
    5、内部クラス
    内部クラスはネストクラスとも呼ばれ、内部クラスを外部クラスの一般的なメンバーとして理解することができます.内部類も文法糖であるのは,コンパイル時の概念にすぎないからである.
    6、列挙
    Java SE 5は、Javaの列挙タイプという新しいタイプを提供します.キーワードenumは、一連の名前の値の有限集合を新しいタイプとして作成することができ、これらの名前の値は通常のプログラムコンポーネントとして使用することができ、これは非常に有用な機能である.列挙タイプを定義します.
    public enum t {
    	SPRING,SUMMER;
    }
    

    Enumはclassと同じようにキーワードであり、クラスではありません.
    enumを使用して列挙タイプを定義すると、コンパイラは自動的にfinalタイプのクラスを作成し、Enumクラスを継承して列挙を実現するので、列挙タイプは継承できません.
    参照先:
    Java文法糖の詳細