JAvaモデルの概略


パブリッシュされたJava 1.4ではコアコードライブラリに新しいAPI(Loging,正規表現,NIOなど)を多数追加し,最新リリースのJDK 1.5と間もなく発表されるJDK 1.6にも多くのAPIが追加されており、その中で比較的重要な意味を持つのがGenerics(モデル)である.
一.Genericsとは?
Genericsは、クライアントからオブジェクトにタイプを転送するメカニズムをコンパイラによって検証するパラメータタイプ(parameterized types)と呼ぶことができる.例えばJava.util.ArrayListでは、コンパイラはGenericsを使用してタイプのセキュリティを保証できます.
Genericsを深く理解する前に、現在のjavaコレクションフレームワーク(Collection)を見てみましょう.j 2 SE 1.4のすべての集合のRoot InterfaceはCollectionです
Collections example without genericity: Example 1
1 protected void collectionsExample() {
2  ArrayList list = new ArrayList();
3  list.add(new String("test string"));
4  list.add(new Integer(9)); // purposely placed here to create a runtime ClassCastException
5  inspectCollection(list);
6 }
7
8
9 protected void inspectCollection(Collection aCollection) {
10  Iterator i = aCollection.iterator();
11  while (i.hasNext()) {
12   String element = (String) i.next();
13  }
14 }
以上のサンプルプログラムは2つの方法を含む、collectionExample方法は簡単な集合型ArrayListを確立し、ArrayListに1つのStringと1つのIntegerオブジェクトを追加した.一方inspecCollection法では,このArrayListをStringでCastを反復する.2つ目の方法を見ると、Collectionは内部でObjectを使用していますが、Collectionのオブジェクトを取り出すにはCastが必要です.開発者は実際のタイプでCastを行う必要があります.このような下向きの造形では、コンパイラはチェックできません.これにより、コードがClassCastExceptionを投げ出す危険を冒します.InspecCollectionメソッドを見ると、コンパイル時に問題はありませんが、実行時にClassCastException異常が放出されます.この重大なランタイムエラーから離れなければなりません
二.Genericsの使用
前の章のCassCastExceptionという異常から,コードコンパイル時に捉えられることを期待しているが,以下では前の章のサンプルプログラムをモデルを用いて修正する.
//Example 2
1 protected void collectionsExample() {
2  ArrayList<String> list = new ArrayList<String>();
3  list.add(new String("test string"));
4  // list.add(new Integer(9)); this no longer compiles
5  inspectCollection(list);
6 }
7
8
9 protected void inspectCollection(Collection<String> aCollection) {
10  Iterator<String> i = aCollection.iterator();
11  while(i.hasNext()) {
12   String element = i.next();
13  }
14 }
上の2行目からArrayListを作成するときにJDK 1で新しい構文を使用しました.5のすべてのCollectionはGenericsの声明に参加しています.例:
//Example 3
1 public class ArrayList<E> extends AbstractList<E> {
2  // details omitted...
3  public void add(E element) {
4   // details omitted
5  }
6  public Iterator<E> iterator() {
7   // details omitted
8  }
9 }
このEはタイプ変数であり、具体的なタイプの定義は行われていない.ArrayListを定義するときのタイププレースホルダにすぎない.Example 2の我々は、ArrayListのインスタンスを定義するときにStringでEにバインドし、add(E element)法でArrayListにオブジェクトを追加すると、public void add(String element);ArrayListでは、メソッドのパラメータでも戻り値でも、Eの代わりにStringが使用されるためです.このときExample 2の4行目を見ると、コンパイルにはコンパイルエラーが反映されます.
だからjavaでGenericsを増やす主な目的はタイプのセキュリティを増やすことです.
上記の簡単な例では、Genericsを使用するメリットについて説明します.
1.タイプが変更されていない場合、Collectionはタイプが安全です.
2.内在的なタイプ変換は、外部での人工造形よりも優れている.
3.Javaインタフェースは、タイプが追加されたため、より強力になります.
4.タイプの一致エラーは、コードの実行時ではなく、コンパイルフェーズでキャプチャできます.
拘束タイプ変数
多くのClassはGenericsとして設計されているが、タイプ変数は制限されていてもよい
public class C1 { }
public class C2 { }
1番目のT変数はNumberを継承し、2番目のTはPersonを継承し、Comparableを実装する必要があります.
三.Genericsメソッド
Genericsクラスのように、メソッドとコンストラクション関数にもタイプパラメータがあります.メソッドのパラメータと戻り値には、Genericsを行うタイプのパラメータがあります.
//Example 4
1 public <T extends Comparable> T max(T t1, T t2) {
2  if (t1.compareTo(t2) > 0)
3   return t1;
4  else return t2;
5 }
ここで,maxメソッドのパラメータタイプは単一のTタイプであり,TタイプはComparableを継承し,maxのパラメータと戻り値は同じスーパークラスを持つ.次のExample 5は、maxメソッドのいくつかの制約を示しています.
//Example 5 
1 Integer iresult = max(new Integer(100), new Integer(200));
2 String sresult = max("AA", "BB");
3 Number nresult = max(new Integer(100), "AAA"); // does not compile
Example 5では1行目のパラメータはすべてIntegerなので、戻り値もIntegerなので、戻り値が造形されていないことに注意してください.
Example 5では2行目のパラメータはすべてStringなので、戻り値もStringなので、戻り値がスタイリングされていないことに注意してください.以上、同じメソッドが呼び出されました.
Example 5の3行目で次のコンパイルエラーが発生しました.
Example.java:10: incompatible typesfound  : java.lang.Object&java.io.Serializable&java.lang.Comparablerequired: java.lang.Number    Number nresult = max(new Integer(100), "AAA");
このエラーは、StringとIntegerが同じスーパークラスObjectを持っているため、コンパイラが戻り値タイプを特定できないため発生します.3行目を修正しても、異なるオブジェクトを比較したため、この行のコードは実行中にエラーを報告します.
四.下位互換性
いずれかの新しい特色が新しいJDKバージョンで出てきた後、私たちはまず以前に作成したコードの互換性に関心を持っています.つまり、私たちが作成したExample 1プログラムは何の変更もなく実行できますが、コンパイラは「ROW TYPE」の警告を与えます.JDK 1.4で作成したコードはどのようにJVM 1にありますか.5では完全に互換性があり、手動で1つの処理を行います:Type erasure処理プロセス
五.ワイルドカード
//Example 6
List<String> stringList = new ArrayList<String>(); //1
List<Object> objectList = stringList ;//2
objectList .add(new Object()); // 3
String s = stringList .get(0);//4
一見Example 6が正しい.ただしstringListとはStringタイプのArrayListを格納することを意味し、objectListには任意のオブジェクトを格納することができ、3行目で処理するとstringListはStringタイプのArrayListであることを保証することができず、この場合コンパイラはこのようなことを許さないため、3行目はコンパイルできない.
//Example 7
void printCollection(Collection<Object> c) 
{ for (Object e : c) {
System.out.println(e);
}}
Example 7は、Collectionのすべてのオブジェクトを印刷することを目的としていますが、Example 6が言ったように、コンパイルが間違っている場合はワイルドカード「?」Example 7を修正します
//Example 8
void printCollection(Collection<?> c) 
{ for (Object e : c) {
System.out.println(e);
}}
Example 8のすべてのCollectionタイプで簡単に印刷できます
境界ワイルドカード(上界)(下界)
六.独自のモデルを作成
次のコードはhttp://www.java2s.com/ExampleCode/Language-Basics
1.パラメータのGenerics
//Example 9(使用モデルなし)
class NonGen {  
  Object ob; // ob is now of type Object
  // Pass the constructor a reference to  
  // an object of type Object
  NonGen(Object o) {  
    ob = o;  
  }  
  // Return type Object.
  Object getob() {  
    return ob;  
  }  
  // Show type of ob.  
  void showType() {  
    System.out.println("Type of ob is " +  
                       ob.getClass().getName());  
  }  
}  
// Demonstrate the non-generic class.  
public class NonGenDemo {  
  public static void main(String args[]) {  
    NonGen iOb;  
    // Create NonGen Object and store
    // an Integer in it. Autoboxing still occurs.
    iOb = new NonGen(88);  
    // Show the type of data used by iOb.
    iOb.showType();
    // Get the value of iOb.
    // This time, a cast is necessary.
    int v = (Integer) iOb.getob();  
    System.out.println("value: " + v);  
    System.out.println();  
    // Create another NonGen object and  
    // store a String in it.
    NonGen strOb = new NonGen("Non-Generics Test");  
    // Show the type of data used by strOb.
    strOb.showType();
    // Get the value of strOb.
    // Again, notice that a cast is necessary.  
    String str = (String) strOb.getob();  
    System.out.println("value: " + str);  
    // This compiles, but is conceptually wrong!
    iOb = strOb;
    v = (Integer) iOb.getob(); // runtime error!
  }  
}
  
//Example 10(使用モデル)
class Example1<T>{
private T t;
Example1(T o){
  this.t=o;
  }
T getOb(){
  return t;
}
void ShowObject(){
  System.out.println(" :"+t.getClass().getName());
}
}
public class GenericsExample1 {

/**
  * @param args
  */
public static void main(String[] args) {
  // TODO Auto-generated method stub
  Example1<Integer> examplei=new Example1<Integer>(100);
  examplei.ShowObject();
  System.out.println(" :"+examplei.getOb());
  Example1<String> examples=new Example1<String>("Bill");
  examples.ShowObject();
  System.out.println(" :"+examples.getOb());
}

}
Example 9はモデルを使用していないので、モデリングが必要ですが、Example 10はモデリングを必要としません.
2.2つのパラメータのGenerics
//Example 11
class TwoGen<T, V> { 
   T ob1;
   V ob2;
   // Pass the constructor a reference to  
   // an object of type T.
   TwoGen(T o1, V o2) {
     ob1 = o1;
     ob2 = o2;
   }
   // Show types of T and V.
   void showTypes() {
     System.out.println("Type of T is " +
                        ob1.getClass().getName());
     System.out.println("Type of V is " +
                        ob2.getClass().getName());
   }
   T getob1() {
     return ob1;
   }
   V getob2() {
     return ob2;
   }
}

public class GenericsExampleByTwoParam {

/**
  * @param args
  */
public static void main(String[] args) {
  // TODO Auto-generated method stub
  TwoGen<Integer, String> tgObj =
       new TwoGen<Integer, String>(88, "Generics");
     // Show the types.
     tgObj.showTypes();
     // Obtain and show values.
     int v = tgObj.getob1();
     System.out.println("value: " + v);
     String str = tgObj.getob2();
     System.out.println("value: " + str);
   }

}
3.GenericsのHierarchy
//Example 12
class Stats<T extends Number> {  
   T[] nums; // array of Number or subclass
   // Pass the constructor a reference to  
   // an array of type Number or subclass.
   Stats(T[] o) {  
     nums = o;  
   }  
   // Return type double in all cases.
   double average() {  
     double sum = 0.0;
     for(int i=0; i < nums.length; i++)  
       sum += nums[i].doubleValue();
     return sum / nums.length;
   }  
}  
public class GenericsExampleByHierarchy {


/**
  * @param args
  */
public static void main(String[] args) {
  // TODO Auto-generated method stub

   Integer inums[] = { 1, 2, 3, 4, 5 };
     Stats<Integer> iob = new Stats<Integer>(inums);  
     double v = iob.average();
     System.out.println("iob average is " + v);
     Double dnums[] = { 1.1, 2.2, 3.3, 4.4, 5.5 };
     Stats<Double> dob = new Stats<Double>(dnums);  
     double w = dob.average();
     System.out.println("dob average is " + w);
     // This won't compile because String is not a
     // subclass of Number.
//     String strs[] = { "1", "2", "3", "4", "5" };
//     Stats<String> strob = new Stats<String>(strs);  
//     double x = strob.average();
//     System.out.println("strob average is " + v);
   }  
}
  
4.ワイルドカードの使用
//Example 14
class StatsWildCard<T extends Number> {
T[] nums; // array of Number or subclass
// Pass the constructor a reference to
// an array of type Number or subclass.
StatsWildCard(T[] o) {
  nums = o;
}
// Return type double in all cases.
double average() {
  double sum = 0.0;
  for (int i = 0; i < nums.length; i++)
   sum += nums[i].doubleValue();
  return sum / nums.length;
}
// Determine if two averages are the same.
// Notice the use of the wildcard.
boolean sameAvg(StatsWildCard<?> ob) {
  if (average() == ob.average())
   return true;
  return false;
}
}

public class GenericsExampleByWildcard {

/**
  * @param args
  */
public static void main(String[] args) {
  // TODO Auto-generated method stub
  Integer inums[] = { 1, 2, 3, 4, 5 };
  StatsWildCard<Integer> iob = new StatsWildCard<Integer>(inums);
  double v = iob.average();
  System.out.println("iob average is " + v);
  Double dnums[] = { 1.1, 2.2, 3.3, 4.4, 5.5 };
  StatsWildCard<Double> dob = new StatsWildCard<Double>(dnums);
  double w = dob.average();
  System.out.println("dob average is " + w);
  Float fnums[] = { 1.0F, 2.0F, 3.0F, 4.0F, 5.0F };
  StatsWildCard<Float> fob = new StatsWildCard<Float>(fnums);
  double x = fob.average();
  System.out.println("fob average is " + x);
  // See which arrays have same average.
  System.out.print("Averages of iob and dob ");
  if (iob.sameAvg(dob))
   System.out.println("are the same.");
  else
   System.out.println("differ.");
  System.out.print("Averages of iob and fob ");
  if (iob.sameAvg(fob))
   System.out.println("are the same.");
  else
   System.out.println("differ.");

}

}
5.境界ワイルドカードの使用
//Example 15
class TwoD { 
  int x, y;
  TwoD(int a, int b) {
    x = a;
    y = b;
  }
}
// Three-dimensional coordinates.
class ThreeD extends TwoD {
  int z;
  ThreeD(int a, int b, int c) {
    super(a, b);
    z = c;
  }
}
// Four-dimensional coordinates.
class FourD extends ThreeD {
  int t;
  FourD(int a, int b, int c, int d) {
    super(a, b, c);
    t = d;  
  }
}
// This class holds an array of coordinate objects.
class Coords<T extends TwoD> {
  T[] coords;
  Coords(T[] o) { coords = o; }
}
// Demonstrate a bounded wildcard.
public class BoundedWildcard {
  static void showXY(Coords<?> c) {
    System.out.println("X Y Coordinates:");
    for(int i=0; i < c.coords.length; i++)
      System.out.println(c.coords[i].x + " " +
                         c.coords[i].y);
    System.out.println();
  }
  static void showXYZ(Coords<? extends ThreeD> c) {
    System.out.println("X Y Z Coordinates:");
    for(int i=0; i < c.coords.length; i++)
      System.out.println(c.coords[i].x + " " +
                         c.coords[i].y + " " +
                         c.coords[i].z);
    System.out.println();
  }
  static void showAll(Coords<? extends FourD> c) {
    System.out.println("X Y Z T Coordinates:");
    for(int i=0; i < c.coords.length; i++)
      System.out.println(c.coords[i].x + " " +
                         c.coords[i].y + " " +
                         c.coords[i].z + " " +
                         c.coords[i].t);
    System.out.println();
  }
  public static void main(String args[]) {
    TwoD td[] = {
      new TwoD(0, 0),
      new TwoD(7, 9),
      new TwoD(18, 4),
      new TwoD(-1, -23)
    };
    Coords<TwoD> tdlocs = new Coords<TwoD>(td);    
    System.out.println("Contents of tdlocs.");
    showXY(tdlocs); // OK, is a TwoD
//  showXYZ(tdlocs); // Error, not a ThreeD
//  showAll(tdlocs); // Erorr, not a FourD
    // Now, create some FourD objects.
    FourD fd[] = {
      new FourD(1, 2, 3, 4),
      new FourD(6, 8, 14, 8),
      new FourD(22, 9, 4, 9),
      new FourD(3, -2, -23, 17)
    };
    Coords<FourD> fdlocs = new Coords<FourD>(fd);    
    System.out.println("Contents of fdlocs.");
    // These are all OK.
    showXY(fdlocs);  
    showXYZ(fdlocs);
    showAll(fdlocs);
  }
}
6.ArrayListのGenerics
//Example 16
public class ArrayListGenericDemo {
  public static void main(String[] args) {
    ArrayList<String> data = new ArrayList<String>();
    data.add("hello");
    data.add("goodbye");

    // data.add(new Date()); This won't compile!

    Iterator<String> it = data.iterator();
    while (it.hasNext()) {
      String s = it.next();
      System.out.println(s);
    }
  }
}
7.HashMapのGenerics
//Example 17
public class HashDemoGeneric {
  public static void main(String[] args) {
    HashMap<Integer,String> map = new HashMap<Integer,String>();

    map.put(1, "Ian");
    map.put(42, "Scott");
    map.put(123, "Somebody else");

    String name = map.get(42);
    System.out.println(name);
  }
}
8.インタフェースのGenerics
//Example 18
interface MinMax<T extends Comparable<T>> { 
  T min();
  T max();
}
// Now, implement MinMax
class MyClass<T extends Comparable<T>> implements MinMax<T> {
  T[] vals;
  MyClass(T[] o) { vals = o; }
  // Return the minimum value in vals.
  public T min() {
    T v = vals[0];
    for(int i=1; i < vals.length; i++)
      if(vals[i].compareTo(v) < 0) v = vals[i];
    return v;
  }
  // Return the maximum value in vals.
  public T max() {
    T v = vals[0];
    for(int i=1; i < vals.length; i++)
      if(vals[i].compareTo(v) > 0) v = vals[i];
    return v;
  }
}
public class GenIFDemo {
  public static void main(String args[]) {
    Integer inums[] = {3, 6, 2, 8, 6 };
    Character chs[] = {'b', 'r', 'p', 'w' };
    MyClass<Integer> iob = new MyClass<Integer>(inums);
    MyClass<Character> cob = new MyClass<Character>(chs);
    System.out.println("Max value in inums: " + iob.max());
    System.out.println("Min value in inums: " + iob.min());
    System.out.println("Max value in chs: " + cob.max());
    System.out.println("Min value in chs: " + cob.min());
  }
}
9.ExceptionのGenerics
//Example 20
interface Executor<E extends Exception> {
    void execute() throws E;
}

public class GenericExceptionTest {
    public static void main(String args[]) {
        try {
            Executor<IOException> e =
                new Executor<IOException>() {
                public void execute() throws IOException
                {
                    // code here that may throw an
                    // IOException or a subtype of
                    // IOException
                }
            };

            e.execute();
        } catch(IOException ioe) {
            System.out.println("IOException: " + ioe);
            ioe.printStackTrace();
        }
    }
}  
Trackback: http://tb.blog.csdn.net/TrackBack.aspx?PostId=661415