什么叫做泛型?
所谓泛型就是就是允许在定义类接口时, 通过 一个标识表示类中的某个属性的类型或者是某个方法的的返回值或者是参数类型。这个类型参数将在使用时确定。
泛型可以作用在属性上【例如:public T name】、类上、方法上、方法参数上。
先通过泛型在集合上的使用来理解泛型:
ArrayList<Integer> integers = new ArrayList<>();
integers.add(123);这种在创建集合的时候进行了指定泛型的类型,那么在向集合中添加数据的时候只能添加整形数据。
在集合中使用泛型的好处:
- 在编译时就进行类型的检查,保证了数据的安全。
- 避免了在操作数据的时候进行强制转换。
- 弥补了集合的不足,统一了数据类型。
泛型作用在类上:
自定义泛型类:
创建一个泛型类的实例:
public class fanxing<T,V>{//T,V都是不确定的,在创建对象时或者是其它使用的时候进行确定
public T name;//泛型作用在属性上
}
一旦使用泛型时确定了泛型的的具体类型那么在使用过程中就必须使用这个类型的参数。例如:
public class fanxing<T,V>{
public T name;
public V age;
public fanxing(T name,V age) {
this.name = name;
this.age =age;
}
public static void main(String[] args) {
new fanxing<String,Integer>("小明",12);//这两个值 必须是 String int类型的数据
}
}
在继承中的泛型:
在继承有泛型的父类时,子类可以有选择性的继承:可以指定父类的泛型类型、可以继承父类的泛型、也可以直接不使用父类的泛型、也可以继承父类泛型的一部分。实例:
public class fanxing<T,V>{
public T name;
public V age;
}
class xf extends fanxing{}
class xf1<T,V> extends fanxing<T,V>{}
class xf2<T,String> extends fanxing<T,String>{}
要注意的是只要全部指定了父类泛型或者是不使用父类的泛型,那么子类就不是泛型类就是一个普通的类。
如果不使用父类的泛型那么父类的泛型就相当于Object类型。
泛型的类型不能是基本数据类型,如果想要使用基本数据类型的话就使用他的包装类。
从集合的方面在次理解泛型在继承中的体现:
public void shds(){
ArrayList<Object> a = null;
ArrayList<String> b = null;
List<String> c=null;
ArrayList<?> d=null;
c=b;
d=a;
d=b;
}
子类可以向父类进行强制转换,所以集合中的子父类也可以进行赋值,子类一旦确定泛型的类型就是普通的类,所以ArrayList<Object>和ArrayList<String>是平级的关系,并不是泛型中Object是String的父类从而导致ArrayList<Object>就是ArrayList<String>的父类。总结:
虽然类A是类B的父类,G<A>和G<B>不具有子父类的关系,两者是并列关系。 两种公共的父类是G<?>
类A是类B的父类,那么A<G>和B<G>是子父类的关系,
泛型接口:
泛型接口在使用的时候和泛型类的使用基本保持一致。但是泛型接口中不能定义泛型的属性,原因是接口中的属性默认是 static final修饰 ,就决定了编辑属性是需要进行对属性赋值,而泛型属性在不使用的时候是不知道这个属性是什么类型的,所以就产生了冲突。
泛型方法:
泛型方法和所在的类或者是接口是不是泛型没有必然的联系。同样使用了泛型方法的类不一定是泛型类。在待用
泛型方法是可以是静态的原因是:静态方法的参数是在调用方法的时候确定的,并非是在实例化的时候确定的。【泛型参数不可以是静态的,泛型方法可以是静态的】
public static <T> List<T> fanxing1(T[] a){
return null;
}
public static void main(String[] args) {
String a[]=null;
fanxing fanxing = new fanxing();
fanxing.fanxing1(a);
}
泛型中的通配符的使用:
通配符 “ ?”
G<A>和G<B>两种公共的父类是G<?>。这样的话可以利用Java的多态性来进行提取公共的操作:
例如:
blic void shj(List<?> list){
Iterator<?> iterator = list.iterator();
while (iterator.hasNext()){
System.out.println(iterator.next());
}
那么这个方法List<?>的子类就都能进行遍历的操作了,就减少了代码的冗余,但是需要注意的是List<?>是不能进行上其内部进行添加数据的,只能从List<?> 中进行读取数据。
有限制的通配符的使用:
举例:
<? extends Nummer> 【Number的子类,Number】这个范围内可以调用。
<? super Number> [Number,Number的父类]这个范围内可以调用。
blic void shj(List<? extends User> list){ //这个方法只能遍历 user类 或者是user的子类
Iterator<?> iterator = list.iterator();
while (iterator.hasNext()){
System.out.println(iterator.next());
}