泛型是什么?
泛型就是告诉编译器想使用什么类型,然后编译器帮你处理一切细节。泛型实现了“参数化类型”的概念,使代码可以应用于多种类型。使用泛型,我们只需指定它们的名称以及类型参数列表即可。
实例如下:
简单泛型
// 持有单个对象的类
class Automobile{} // 汽车
class Holder{ // 持有者
private Automobile a;
public Holder( Automobile a ){ this.a = a; }
Automobile get(){ return a; }
}
// 持有Object类型对象的类
class Holder{
private Object a;
public Holder( Object o ){ this.a = a; }
public void set( Object a ){ this.a = a; }
public Object get(){ return a; }
public static void main( String[] args ){
Holder h = new Holder( new Automobile() );
Automobile a = ( Automobile ) h.get();
h.set( "Not an Automobile" );
String s = ( String ) h.get();
h.set( 1 );
Integer x = ( Integer ) h.get();
}
}
// 使用容器存储一种类型的对象
class Holder< T >{ // 给类加类型参数T
private T a;
public Holder( T a ){ this.a = a; }
public void set( T a ){ this.a = a; }
public T get(){ return a; }
public static void main( String[] args ){
Holder< Automobile > h = new Holder< Automobile >( new Automobile() ); // 只能存入T类型或其子类
Automobile a = h.get();
// h.set( "Not an Automobile" ); // 错误:无法应用于String
// h.set( 1 ); // 错误:无法应用于int
}
}
泛型接口
interface Generator< T >{ T next(); } // 生成器
class NumGenerator implements Generator< Integer >{
int[] nums = { 1, 2, 3, 4, 5 };
public Integer next(){
return nums[ (int)( Math.random() * 5 ) ];
}
public static void main( String[] args ){
NumGenerator num = new NumGenerator();
for( int i = 0; i < 5; i ++ )
System.out.println( num.next() );
}
}
class NameGenerator implements Generator< String >{
String[] names = { "ryan", "anni", "john" };
public String next(){
return names[ (int)( Math.random() * 3 ) ];
}
public static void main( String[] args ){
NameGenerator name = new NameGenerator();
for( int i = 0; i < 5; i ++ )
System.out.println( name.next() );
}
}
public class Test0528{
public static void main( String[] args ){
NumGenerator.main( args );
NameGenerator.main( args );
}
}
------------------------
E:\java>java Test0528
1
2
4
1
4
anni
ryan
anni
john
anni
泛型方法
// 泛型方法:泛型参数列表放在方法定义的返回值之前。泛型方法能够独立于类而产生变化。
// 指导原则:尽量使用泛型方法。如果使用泛型方法可以取代将整个类泛型化,那么就应该只使用泛型方法。
// 类型参数推断:当使用泛型类时,必须在创建对象时指定类型参数的值。而使用泛型方法时,通常不必指明参数类型,因为编译器会为我们
// 找出具体的类型。
class GenericMethods{ // 泛型方法
public < T > void f( T x ){ System.out.println( x.getClass().getName() );}
public static void main( String[] args ){
GenericMethods gm = new GenericMethods();
gm.f( "" ); gm.f( 1 ); gm.f( 1.0 );
gm.f( 1.0F ); gm.f( 'c' ); gm.f( gm );
}
}
public class Test0528{
public static void main( String[] args ){
GenericMethods.main( args );
}
}
----------------------
E:\java>java Test0528
java.lang.String
java.lang.Integer
java.lang.Double
java.lang.Float
java.lang.Character
GenericMethods
擦除与边界
// 擦除:在方法体中移除了类型信息。
import java.util.*;
class ErasedTypeEquivalence{ // 擦除类型等效
public static void main( String[] args ){
Class c1 = new ArrayList< String >().getClass();
Class c2 = new ArrayList< Integer >().getClass();
System.out.println( c1 );
System.out.println( "c1 == c2 : " + (c1 == c2) ); // 都被擦除成List“原生”类型。
}
}
public class Test0528{
public static void main( String[] args ){
ErasedTypeEquivalence.main( args );
}
}
---------------------
E:\java>java Test0528
class java.util.ArrayList
c1 == c2 : true // 相同类型
import java.util.*;
class Frob{}
class Fnorkle{}
class Quark< Q >{}
class Particle< POSITION, MOMENTUM >{}
class LostInformation{ // 丢失信息
public static void main( String[] args ){
List< Frob> list = new ArrayList< Frob >();
Map< Frob, Fnorkle > map = new HashMap< Frob, Fnorkle >();
Quark< Fnorkle > quark = new Quark< Fnorkle >();
Particle< Long, Double > p = new Particle< Long, Double >();
// getTypeParameters()返回一个TypyVariable对象数组,表示有泛型声明所声明的类型参数
System.out.println( Arrays.toString( list.getClass().getTypeParameters() ) );
System.out.println( Arrays.toString( map.getClass().getTypeParameters() ) );
System.out.println( Arrays.toString( quark.getClass().getTypeParameters() ) );
System.out.println( Arrays.toString( p.getClass().getTypeParameters() ) );
}
}
public class Test0528{
public static void main( String[] args ){
LostInformation.main( args );
}
}
---------------------
E:\java>java Test0528
[E] // Java泛型是使用擦除来实现的。在泛型代码内部,无法获得任何有关泛型参数类型的信息。
[K, V]
[Q]
[POSITION, MOMENTUM]
// 边界:对象进入和离开方法的地点。这些正是编译器在编译期执行类型检查并插入转型代码的地点。
interface HasColor{ java.awt.Color getColor(); } // 有颜色
class HoldItem< T >{ // 保持项目
T item;
HoldItem( T item ){ this.item = item; }
T getItem(){ return item; }
}
class Colored< T extends HasColor > extends HoldItem< T >{ // 彩色的
Colored( T item ){ super( item ); }
java.awt.Color color(){ return item.getColor(); }
}
class Dimension{ public int x,y,z; } // 尺寸
class ColoredDimension< T extends Dimension & HasColor > extends Colored< T >{ // 彩色尺寸
ColoredDimension( T item ){ super( item ); }
int getX(){ return item.x; }
int getY(){ return item.y; }
int getZ(){ return item.z; }
}
interface Weight{ int weight(); } // 重量
class Solid< T extends Dimension & HasColor & Weight > extends ColoredDimension< T >{ // 固体
Solid( T item ){ super( item ); }
int weight(){ return item.weight(); }
}
class Bounded extends Dimension implements HasColor,Weight{ // 有界
public java.awt.Color getColor(){ return null; }
public int weight(){ return 0; }
}
class InheritBounds{ // 继承界限
public static void main( String[] args ){
Solid< Bounded > solid = new Solid< Bounded >( new Bounded() );
solid.color();
solid.getY();
solid.weight();
}
}
通配符
// 协变性对List不直作用
import java.util.*;
class Fruit{} // 水果
class Apple extends Fruit{} // 苹果
class Jonathan extends Apple{} // 乔纳苹
class Orange extends Fruit{} // 橘子
class CovariantArray{ // 协变数组
public static void main( String[] args ){
Fruit[] fruit = new Fruit[10];
fruit[0] = new Apple();
System.out.println( fruit[0] );
fruit[1] = new Jonathan();
System.out.println( fruit[1] );
try{
fruit[0] = new Fruit();
System.out.println( fruit[0] );
}catch( Exception e ){ System.out.println( e ); }
try{
fruit[0] = new Orange();
System.out.println( fruit[0] );
}catch( Exception e ){ System.out.println( e ); }
}
}
class NonCovariantGenerics{ // 非协变泛型
public static void main( String[] args ){
// List< Fruit > flist = new ArrayList< Apple >(); // 错误:不兼容的类型
}
}
class GenericsAndCovariance{ // 泛型和协变性
public static void main( String[] args ){
List< ? extends Fruit > flist = new ArrayList< Apple >(); // 通配符
// 不能添加任何类型的对象
// flist.add( new Apple() );
// flist.aad( new Fruit() );
// flist.add( new Object() );
flist.add( null );
Fruit f = flist.get( 0 );
System.out.println( f );
}
}
public class Test0529{
public static void main( String[] args ){
CovariantArray.main( args );
GenericsAndCovariance.main( args );
}
}
---------------------
E:\java>java Test0529
Apple@ca0b6
Jonathan@1a758cb
Fruit@1b67f74
Orange@173a10f
null
泛型的问题
//