泛型之葵花宝典

泛型的本质是类型参数化,所谓类型参数化是指被声明的数据类型是可以改变的,由实际参数来决定。
通常情况下实际参数的值决定了形式参数的值,而类型参数化是实际参数的类型决定了形式参数的类型。
泛型使用场景一。
Integer max(Integer a, Integer b){
   return a>b?a:b;
}
该方法比较的是2个Integer类型,如果要比较Double类型,难道又要写一个同样的方法,只是参数变成了Double吗,如果有一种机制,不必先确定a、b的类型,直到调用的时候再指定就好了。这样代码就能够重用了,这时泛型出现了。
当然5.0之前很多人会把参数定义成Object类型来解决。
泛型实例一
public class Generic<T>{
private T obj;
public Generic(T t){//构造方法不指定泛型
obj = t;
}
public T getObj(){
return obj;
}

调用
main{
Generic<Integer> generic = new Generic<Integer>(100);
generic .getObj();

Generic<String> genericString = new Generic<String>("100");
genericString .getObj();
}
T是类型参数的名称,这个名称用来作为[b]传递给[/b]Generic实际类型的占位符
类型参数的声明必须放到<>中,如 Class<T>
[b]Generic使用了类型参数,因此Generic也叫泛型类。也被称作参数化泛型。[/b]
这里定义的obj的类型T,T是一个占位符,需要等到类对象实例化后才能确定obj的类型。
[b]T还可以被作为返回类型[/b]
因为obj是T类型,因此getObj返回类型必须也是T。
综合上面:T是一个数据类型说明,可以用来说明任何实例[b]方法中的局部变量[/b],[b]类的成员变量[/b],[b]方法的形式参数[/b],以及[b]方法的返回值[/b]
[b]泛型的一个好处就是会检查类型,因此可以保住类型的安全。[/b]
[b]带2个类型参数的泛型类[/b]
实例:
public class TwoGeneric(K,V){
//使用K,V
}
[b]有界类型[/b]
当需要对泛型参数做约束时,使用有界泛型。

public class Generic<T extends Number>{//继承接口也要使用extends

}
表示实例话泛型类时,泛型参数必须是Number接口的子类。
[b]通配符参数[/b]
Stats <T>类的void doSomething(Stats <T> ob)//对于这样的类型有一个弊端,当实例化Stats <T>时要求调用方法也要使用相同的类型才行,都是T,如果使用void doSomething(Stats <U> ob),编译会不通过,因为不存在一个U参数类型的泛型类。就像不能写成Class<U>一样,Class使用的是T的参数类型。
这时可以使用通配符。
如:
void doSomething(Stats <?> ob)//表示ob可以是任意参数类型的Stats 类。
这里?有一个默认的上届就是实现Number接口,如果想要改变这种上届可以定义方法为
Stats <? extends Integer> ob
但是无法改编成
Stats <? extends String> ob
因为通配符无法将上届改变成超出泛型类声明时的范围。
[b]注意:[/b]
class Stats<? extends Number>{……}
通配符是声明泛型类的变量的,不能创建泛型类。
[b]泛型方法[/b]
泛型方法:如果一个方法被声明成泛型方法,那它将有一个或是多个类型参数,不过与泛型类不同,它只能在它所修饰的方法中使用。
泛型方法的创建方式如下:
[b][访问权限修饰符] [static] [final] <类型参数列表> 返回值类型 方法名([形式参数列表])[/b]
  ●     访问权限修饰符(包括private、public、protected)、static和final都必须写在类型参数列表的前面。
  ●     返回值类型必须写在类型参数表的后面。
  ●    [b] 泛型方法可以写在一个泛型类中,也可以写在一个普通类中[/b]。[b]由于在泛型类中的任何方法,本质上都是泛型方法,所以在实际使用中,很少会在泛型类中再用上面的形式来定义泛型方法。[/b] 
 ●     类型参数可以用在方法体中修饰局部变量,也可以用在方法的参数表中,修饰形式参数。
  ●     泛型方法可以是实例方法或是静态方法。类型参数可以使用在静态方法中,这是与泛型类的重要区别。

使用一个泛型方法通常有两种形式:
<对象名|类名>.<实际类型>方法名(实际参数表);
和:
[对象名|类名].方法名(实际参数表);
如果是在类的内部调用,且采用第二种形式,则前缀都可以省略。
使用实例:
泛型方法定义在普通的类中
public class demoGenMethods{

  //定义泛型方法,有一个形式参数用类型参数T来定义
  public static <T> void showGenMsg(T ob, int n){<T>表示类型参数列表
    T localOb = ob; //局部变量也可以用类型参数T来定义
    System.out.println(localOb.getClass().getName());
  }

  public static <T> void showGenMsg(T ob){
    System.out.println(ob.getClass().getName());   
  }

  public static void main(String args[]){
    String str = "parameter";
    Integer k = new Integer(123);
    //用两种不同的方法调用泛型方法
    demoGenMethods.<Integer>showGenMsg(k,1);
    showGenMsg(str);
  } 
}
[b][color=red]注意泛型方法必须定义类是上面的<T>,起到定义的作用,如果不写会报不识别的类型错误[/color]。[/b]
所以:
public <T> void get(T obj){
return ;
}
是正确的写法。
如果泛型方法定义在泛型类中,则泛型方法不能是静态的。
调用方式
demoGenMethods.<Integer>showGenMsg(k,1);
注意必须带类名demoGenMethods,因为是静态方法。
调用方式有两种:
demoGenMethods.<Integer>showGenMsg(k,1);
showGenMsg(str);
因为因为传入了一个实际参数,因为形式参数也是使用泛型类型,所以可以使用第二种调用方法就能识别出来泛型类型是什么类型。
[b]<T>的定义可以用于返回值、形式参数、或是方法的局部变量[/b]

public <T> void get(T obj){
T a ;
return ;
}
如果:
public  <T> void doSomething(){
    T ob;
    ……
  }
调用它的时候,根本就没有实际参数,所以编译器无法知道T的实际类型,这种情况下,就必须使用第一种形式。
即,demoGenMethods.<Integer>showGenMsg(k,1);
[b]泛型接口[/b]
定义形式:interface 接口名<类型参数表>
接口:
interface MinMax<T extends Comparable<T>>{
  T min();
  T max();
}
注意到Comparable本身也是一个泛型类,它是由系统定义在类库中的
实现类:
class MyClass<T extends Comparable<T>> implements MinMax<T>{

}
接口泛型:
[b]它实现类的类型参数T必须和要实现的接口中的声明完全一样[/b]
[b][color=red]如果一个类实现了一个泛型接口,则此类也是泛型类。否则,它无法接受传递给接口的类型参数[/color][/b]
[b]如果实现的是泛型接口的特定类型[/b]
如:class MyClass  implements MinMax<Integer>
目的就是要想办法传递给接口,若是不能传递给接口,就要接口实现接口时直接指定出类型。
[b]泛型类的继承[/b]
[b]以泛型类为父类[/b]
[b]泛型类继承实例:[/b]
定义父类
public class superGen<T> { }
接下来定义它的一个子类:
public class derivedGen <T> extends superGen<T>{}
[b]这两个类型参数必须用相同的标识符T。这意味着传递给derivedGen的实际类型也会传递给superGen[/b]
derivedGen<Integer> number = new derivedGen<Integer>(100);
将Integer作为类型参数传递给derivedGen,再由它传递给superGen,因此,后者的成员ob也是Integer类型。
当然,derivedGen中也可以使用T,还可以增加自己需要的类型参数。下面这个程序展示了一个更为复杂的derivedGen类。
public class derivedGen <T, U> extends superGen<T>{
}
以非泛型类为父类
public class derivedNonGen<T> extends nonGen{}
if (iob instanceof Generic)
会返回true
if (iob instanceof Generic<?>)
也会返回true
尖括号中只能写通配符“?”,而不能写Integer之类确定的类型。实际上在测试时,“?”会被忽略。

<?super T>表示的是下限是T,也就是他能存放的是T或者是T的超类。
而list.add所添加的对象是list泛型中的类或是子类
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值