1.泛型概述
泛型, 是JDK1.5添加的, 用于解决数据类型的安全性问题。
原理: 在类声明时通过一标识表示类中的某个属性或者是某个方法的返回值及参数类型, 在类声明或者实例化时指定需要的数据类型。
java泛型可以保证如果程序在编译时没有发生警告, 运行时就不会产生ClassCastException异常。同时代码更加简洁、健壮。
java中的泛型, 只在编译阶段生效。在编译过程中, 正确检验泛型结果后, 会将泛型的相关信息擦除, 并且在对象进入和离开方法的边界处添加类型检查和类型转换的方法。泛型不会进入到运行阶段。
2.泛型类
- 对象实例化时不指定泛型, 则默认为
- 泛型不同的引用相互间不能赋值。
泛型类采用形参如时, 可以在创建对象时再指定(多种类型的)泛型。在定义方法时需要加入泛型的形参声明, 在调用方法时也要采用相同类型的数据类型
public class Test {
public static void main(String[] args) {
A<String> a1 = new A<String>();//在new A()时指定泛型的类型
a1.setKey("xxxx");//A<T>类的对象调用setKey(T key)方法,传入方法中key形参的实参就是String类型的
//此处泛型类A限制了成员变量key的泛型为<T>,从而确定了操作key的方法需要指定的泛型
String s = a1.getKey();//对象调用getKey()方法,方法的返回值就是key确定为String类型
A<Integer> a2 = new A<Integer>();
a2.setKey(11);
int i = a2.getKey();
//创建类时未指定泛型,可以传入其他泛型实参,调用方法时也要采用相应的数据类型
}
}
/**
* 此处的泛型<T>可以任意取名,一般用T,意为type
* @author chenyao
* @param <T>
*/
class A <T>{//泛型类
private T key;
public void setKey(T key) {
this.key = key;
}
public T getKey() {
return this.key;
}
}
3.泛型接口
定义一个泛型接口
interface Xxx{
}
未传入泛型实参时(泛型采用形参如), 与泛型类的定义相同, 在声明实现类的时候, 需要将泛型的形参声明也一起加入到类中。
public class Test1 {
public static void main(String[] args) {
B1<Object> b1 = new B1<Object>();
B1<String> b2 = new B1<String>();
B2 b3 = new B2();
}
}
interface IB<T>{
T test(T t);
}
class B1<T> implements IB<T>{
@Override
public T test(T t) {
return null;
}
}
class B2 implements IB<String>{
@Override
public String test(String t) {
return null;
}
}
4.泛型方法
方法, 也可以被泛型化, 与定义在方法外部的类是否泛型、泛型的类型都无关。同样, 构造方法也可以泛型化。
在泛型方法中可以定义泛型参数, 带泛型形参的泛型方法在调用之前没有固定的类型, 在调用时传入的参数是什么类型, 就会把泛型改成相应的类型。
public class Test2 {
public static void main(String[] args) {
Method<Object> me = new Method<Object>();//泛型类,在实例化的时候指定泛型为<Object>,即E=Object
me.test(123);//方法test的泛型只与传入的实参类型有关,为Integer
me.setE(1);//Object可以传入任何类的对象,传入Integer类型,此时E=Object=Integer
me.setE("李四");//Object可以传入任何类的对象,传入String类型,此时E=Object=String
Method<Integer> me2 = new Method<Integer>();//泛型类,在实例化的时候指定泛型为<Integer>,即E=Integer
me2.test("张三");//方法test的泛型只与传入的实参类型有关,为String
me2.setE(2);//Integer只可以传入Integer类的对象,此时E=Integer=Integer
}
}
class Method<E>{
private E e; //类中的成员变量类型受泛型类的泛型<E>限制(除基本数据类型外)
//private T t; //泛型类中没有定义泛型类型<T>
int i; //基本数据类型不受限制
public <E> Method() {//无参构造方法不受其泛型影响,因为不需要传入实参,默认泛型为泛型类的泛型
}
public <T> Method(T t) {//构造方法也可以泛型化
System.out.println(t);
}
public void setE(E e) {//非静态方法中,可以使用类定义的泛型
this.e = e;
System.out.println(this.e+":"+this.e.getClass());
}
public static <T> void test3(T t) {
//System.out.println(this.e);//在静态方法中,不能沿用类定义的泛型,只能静态方法自定义泛型<T>
//静态方法为类方法,不需要实例就能访问,因此不能有this,super
System.out.println(t);
}
public <T> void test(T t){//无返回值
System.out.println(t+":"+t.getClass());
}
public <T> T test1(T t){//有返回值
return t;
}
public <T> void test2(T... t){//可变参数的
for(T t1 : t) {
System.out.println(t1);
}
}
}
4.泛型通配符"?"
在不确定集合中的元素具体的数据类型时, 用?表示所有类型
即不限制泛型类型
import java.util.ArrayList;
import java.util.List;
public class Test3 {
public static void main(String[] args) {
TestWildCard w1 = new TestWildCard();
List<String> list = new ArrayList<String>();//确定list集合的类型为<String>
w1.test(list);
List<String> list2 = new ArrayList<String>();
w1.test(list2);
List<Integer> list3 = new ArrayList<Integer>();//确定list集合的类型为<Integer>
w1.test(list3);
}
}
class TestWildCard{
public void test(List<?> list) {//test方法需要传入一个list集合的参数
//不确定list集合存的数据的类型,可以采用通配符,也就是不限制list的泛型
}
}
1.有限制的通配符
-
<? extends Person> (无穷小, Person]
只允许泛型为Person及Person的子类的引用调用 -
<? super Kids> [Person, 无穷大)
只允许泛型为Kids及Kids的父类的引用调用 -
<? extends Imple>
只允许泛型为实现Imple接口的实现类的引用调用
import java.util.ArrayList;
import java.util.List;
public class Test {
public static void main(String[] args) {
/**
* testWC1可传入list形参的参数范围,在C类及其子类中
*/
ArrayList<C> list = new ArrayList<C>();
new TestWildCard().testWC1(list);//可传入C类的list
ArrayList<D> list2 = new ArrayList<D>();
new TestWildCard().testWC1(list2);//可传入C类子类D类的list
//ArrayList<B> list3 = new ArrayList<B>();
//new TestWildCard().testWC1(list3);//不可传入C类父类B类的list
ArrayList<Inimpl> list3 = new ArrayList<Inimpl>();
new TestWildCard().testWC3(list3);//可传入实现In接口的实现类Inimpl类的list
ArrayList<Inimpl2> list4 = new ArrayList<Inimpl2>();
new TestWildCard().testWC3(list4);//可传入实现In接口的实现类Inimpl2类的list
}
}
class TestWildCard{
public void testWC1(List<? extends C> list){}//<? extends C>,可传入list形参的参数范围,在C类及其子类中
public void testWC2(List<? super C> list){}//<? super C>,可传入list形参的参数范围,在C类及其父类中
public void testWC3(List<? extends In> list){}//<? extends In>,可传入list形参的参数范围,在实现In接口的实现类中
}
class A{}
class B extends A{}
class C extends B{}
class D extends C{}
interface In{}
class Inimpl implements In{}
class Inimpl2 implements In{}