泛型
自定义泛型结构
泛型类,泛型接口,泛型方法
定义泛型类:
注:类的内部结构就可以使用类的泛型
public class fanxing <T>{
String name;
int id;
T ftype;
public fanxing(){ };
public fanxing(String name,int id,T ftype){
this.name=name;
this.id=id;
this.ftype=ftype;
}
public T getFtype(){
return ftype;
}
public void setFtype(T ftype){
this.ftype=ftype;
}
}
public class fanxingTest {
public static void main(String[] args) {
//定义了泛型类,在实例化时没有指明泛型类的类型,则默认是Object类型
fanxing f1 = new fanxing();
f1.setFtype(123);
f1.setFtype("ss");
fanxing<String> f2 = new fanxing<>("aa",1,"bb");
f2.setFtype("123");
}
}
在实例化时指明了泛型的类型之后,赋予其他类型的值会报错。
子类继承带泛型的父类(指明了泛型的类型),则实例化子类对象时不需要指明泛型。
public class fanxing1 extends fanxing<String>{
}
父类指明了泛型是String类型,给子类进行实例化时无需指明,一旦给ftype赋予其他类型,编译器会报错。
泛型注意点:
1.泛型的类型必须是类,不能是基本数据类型,需要用到基本数据类型的地方,用包装类来代替,如int—>Integer
2.如果实例化时,没有指明泛型的类型,默认类型为java.lang.Object类型。
3.泛型类可能有多个参数,此时应将多个参数一起放在<>内,比如:<E,K,V>
4.泛型的构造器,如public fanxing(){},这里不需要加<>
5.泛型不同的引用不能相互赋值。如:
给泛型不指明类型时可以赋值,指明之后不同类型赋值编译器报错。
6.如果泛型结构是一个接口或者抽象类,则不可以创建泛型类的对象。
7.在静态方法中不能使用类的泛型,因为静态方法加载时,泛型的类型还未指定(类的泛型在对象实例化时才指定)。
8.异常类不能是泛型的。
泛型方法:
在方法中出现了泛型结构,泛型参数与类的泛型参数没有任何关系。
泛型方法在调用时,指明泛型参数的类型。
List是由copy()的参数integers是Integer[]而决定的。
泛型方法可以是静态的,泛型参数是在调用方法时确定的,而非在实例化类时确定。
泛型在继承方面的体现:
虽然类A是类B的父类,但是G< A > 与G< B >之间不存在子父类的关系。
注:A< G >是B< G >的父类
通配符 ?的使用
G< A >和G< B >共同的父类是G< ? >
对于List<?>就不能向其内部添加数据了,除了添加null,也就是使用了通配符之后不能进行数据的写入。
读取: 可以对数据进行读取,读取得到的数据类型都是Object
有限制条件的通配符的使用:
G<? extends A >: 代表G< B >,其中B是A的子类和其自身
G< ? super A >:代表G< B >,其中B是A的父类或其自身
@Test
public void test2(){
List<? extends Person> list1=null;
List<? super Person> list2=null;
List<Student> list3=new ArrayList<Student>();
List<Person> list4=new ArrayList<Person>();
List<Object> list5=new ArrayList<Object>();
list1=list3;
list1=list4;
list2=list4;
list2=list5;
//读取数据的时候都是用最大的范围去接收
list1=list3;
Person p=list1.get(0);
list2=list4;
Object p1=list2.get(0);
//写入数据,list2可以写入数据,写进去的就是super后面的最小范围
//list1无法写入数据
list2.add(new Person());
}