JAVA generics 泛型

1.Motivation for generics 动机

The following block of Java code illustrates a problem that exists when not using generics. First, it declares an ArrayList of type Object. Then, it adds a String to theArrayList. Finally, it attempts to retrieve the added String and cast it to an Integer.

  List v = new ArrayList();
  v.add("test");
  Integer i = (Integer)v.get(0);        // Run time error

Although the code compiles without error, it throws a runtime exception (java.lang.ClassCastException) when executing the third line of code. This type of problem can be avoided by using generics and is the primary motivation for using generics.

Using generics, the above code fragment can be rewritten as follows:

  List<String> v = new ArrayList<String>();
  v.add("test");
  Integer i = v.get(0); // (type error)  Compile time error

The type parameter String within the angle brackets declares the ArrayList to be constituted of String (a descendant of the ArrayList's generic Object constituents). With generics, it is no longer necessary to cast the third line to any particular type, because the result of v.get(0) is defined as String by the code generated by the compiler.

Compiling the third line of this fragment with J2SE 5.0 (or later) will yield a compile-time error because the compiler will detect that v.get(0) returns String instead of Integer. For a more elaborate example, see reference.

  通过上面的例子可以知道,通过使用泛型可以有力的减少在run-time时的ClassCastException异常。

  因为Java是一种强类型(type)语言,所以要在不同的类型之间进行转换,必须使用强制类型转换(Cast)。在类(class)与类之间做强制类型转换,通常有两种情况,向上转型和向下转型(Subtyping)。通常向上转型是安全的,向下转型会有一些风险,转型失败会出现编译时异常。从而避免了运行时的转型异常。

 

2.generic types 泛型类型

  generic type declaration:

  public class Box<T>{

    private T t;

    public T get() {

      return t;

    }

    public set(T t) {

      this.t = t;

    }

  }

   this introduces one type variable, named T, that can be used anywhere inside the class. T is a formal type parameter of the Box class.

  Also note that a generic type may have multiple type parameters, but each parameter must be unique within its declaring class or interface. A declaration ofBox<T,T>, for example, would generate an error on the second occurrence of T, but Box<T,U>, however, would be allowed.

  To reference this generic class from within your own code, you must perform a generic type invocation, which replaces T with some concrete value, such asInteger:

Box<Integer> integerBox;

  You can think of a generic type invocation as being similar to an ordinary method invocation, but instead of passing an argument to a method, you're passing atype argument — Integer in this case — to the Box class itself.

  Like any other variable declaration, this code does not actually create a new Box object. It simply declares that integerBox will hold a reference to a "Box ofInteger", which is how Box<Integer> is read.

  An invocation of a generic type is generally known as a parameterized type.

3.generic methods 泛型方法

  泛型类型中的类型参数可以在整个类中使用,而泛型方法中的类型参数只能在方法体中使用。

  Type parameters can also be declared within method and constructor signatures to create generic methods and generic constructors. This is similar to declaring a generic type, but the type parameter's scope is limited to the method or constructor in which it's declared.

  泛型方法声明:

  public (static) <X> [void/...] method(...) {

  }

  A more realistic use of generic methods might be something like the following, which defines a static method that stuffs references to a single item into multiple boxes:

public static <U> void fillBoxes(U u, 
          List<Box<U>> boxes) {
    for (Box<U> box : boxes) {
        box.add(u);
    }
}

To use this method, your code would look something like the following:

Crayon red = ...;
List<Box<Crayon>> crayonBoxes = ...;

The complete syntax for invoking this method is:

Box.<Crayon>fillBoxes(red, crayonBoxes);

Here we've explicitly provided the type to be used as U, but more often than not, this can be left out and the compiler will infer the type that's needed:

// compiler infers that U is Crayon
Box.fillBoxes(red, crayonBoxes);

This feature, known as type inference, allows you to invoke a generic method as you would an ordinary method, without specifying a type between angle brackets.

4.generic and subtyping

 List<String> ls = new List<String>();
 List<Object> lo = ls; // this will generic an error!

  In general, if Foo is a subtype (subclass or subinterface) of Bar, and G is some generic type declaration, it is not the case that G<Foo> is a subtype of G<Bar>. This is probably the hardest thing you need to learn about generics, because it goes against our deeply held intuitions.

5.Bounded Type Parameters 限定类型参数范围

  There may be times when you'll want to restrict the kinds of types that are allowed to be passed to a type parameter. For example, a method that operates on numbers might only want to accept instances of Number or its subclasses. This is what bounded type parameters are for.

  To declare a bounded type parameter, list the type parameter's name, followed by the extends keyword, followed by its upper bound, which in this example isNumber. Note that, in this context, extends is used in a general sense to mean either "extends" (as in classes) or "implements" (as in interfaces). e.g.

  public <U extends Number> void inspect(U u){
        System.out.println("T: " + t.getClass().getName());
        System.out.println("U: " + u.getClass().getName());
    }
posted @ 2012-05-19 11:52  cuillgln  阅读(295)  评论(0编辑  收藏  举报