1.泛型参数 T
表示一种数据类型,相当于形参,在使用时指定(只能传引用数据类型),默认值:Object
public class Point<T>{ // <T,R> type return
T x; // T x;
T y; // R y;
}
使用:
Point<Integer> p1 = new Point<Integer>(); //可以只有一对<>,后面的实参<> 可以省略
p1.x=1; p1.y=2;
Point<String> p2 = new Point<String>();
p2.x="1"; p2.y="2";
Point p3 = new Point();
p3.x= new Object(); p3.y = new Object() ;
2.集合的泛型
(1)在编译时解决类型不一致问题(只在运行时出现)
集合中如果存储的数据类型不一致,就会在强制转换的时候出现类型转换异常
public int sum(List list){ //public int sum(List<Integer> list){ int sum=0; for (Object o : list) { Integer i=(Integer)o; //for (Integer i : list) { sum+=i; } return sum; }//在传入list几何1中存在Integer以外的类型的数据时,ClassEastExceptionList<Integer> list =new ArrayList<Integer>();
(2)如果在使用Collection接口的时候,给泛型参数指定了具体类型,那么就会防止出现类型转换异常的情 况,因为这时候集合中添加的数据已经有了一个规定的类型,其他类型是添加不进来的。
Map<String,Integer> map = new HashMap<>();
map.put("张三",20)
Collection<String> c = new ArrayList<String>();
3.泛型的种类:泛型类、 泛型接口、 泛型方法
public class Point<T>{
}
Point<String> point = new Point<String>();
interface Animal<T,R>{
R show(T t);
}
class AnimalImpl implements Animal<String,Integer>{ //这块写T、R 会出错
//如果到这一步还是不能确定T、R,可以将类定义为泛型类
class AnimalImpl<T,R> implements Animal<T,R>{
} //在实际类中尽量将泛型类型确定
public <T> R show( T t ){ //<T>在所有修饰符之后
return t;
}
public void show1(){
this.show("hello");
this.show(10);}
4.泛型的类型
Object o = new Integer(1); //编译通过
Object[] arr = new Integer[1]; //Object[]类型兼容所有的【引用】类型数组
Object[] arr = new int[1]; //编译报错,类型不兼容
ArrayList<Object> list = new ArrayList<Integer>(); //错误
//在编译期间,ArrayList和ArrayList是俩个不同的类型,并且没有子父类型的关 系
//-----------俩个类型,如果是当做泛型的指定类型的时候,就没有多态的特点了,=号俩边的泛型类型必须一致
5.通配符
public void test1(Collection<Integer> c){
} //只能接收泛型是Integer类型的集合对象
public void test(Collection<?> c){
} ///test方法可以接收 泛型是任意类型的 Collection集合对象
List<?> list = new ArrayList<String>(); //错误 泛型擦除,
6.泛型边界
在泛型中使用 extends 和 super 关键字,就可以对泛型的类型进行限制。即:规定泛型的上限和 下限。
(1)上限:将来引用list就可以接收泛型是 Number 或者 Number 子类型的List集合对象
List<? extends Number> list;
//list可以指向泛型是Number或者Number【子】类型的集合对象
List<? extends Number> list1 = new ArrayList<Double>();
List<? extends Number> list1 = new ArrayList<Integer>();
List<? extends Number> list1 = new ArrayList<Number>();
使用场景:
- 在声明泛型类或者泛型接口的时候【可以】使用
public class Point<T extends Number>{
private T x;
private T y;
}
interface Action<T extends Person>{
public void test(T t);
}
- 在声明泛型方法的时候【可以】使用
1 public <T extends Action> void test(T t);
- 在声明变量的时候【可以】使用
public class Test{
public void test(List<? extends Number> list){
}
}
public static void main(String[] args) {
List<? extends Number> list = new ArrayList<Long>();
t.test(list);
}
(2)下限: 将来引用list就可以接收泛型是 Number 或者 Number 父类型的List集合对象
List<? super Number> list = new ArrayList<Number>();
List<? super Number> list = new ArrayList<Serializable>();
List<? super Number> list = new ArrayList<Object>();
- 在声明泛型类或者泛型接口的时候【不能】使用
//编译报错
public class Point<T super Number>{
private T x;
private T y;
}
//编译报错
interface Action<T super Person>{
public void test(T t);
}
- 在声明泛型方法的时候【不能】使用
//编译报错
public <T super Action> void test(T t);
- 在声明变量的时候【可以】使用
public class Test{
public void test(List<? super Number> list){
}
}
public static void main(String[] args) {
List<? super Number> list;
list = new ArrayList<Number>();
list = new ArrayList<>Object();
//假设Student 继承了 Person
List<? super Student> list;
list = new ArrayList<Student>();
list = new ArrayList<Person>();
list = new ArrayList<Object>();
}
7.类型擦除、泛型擦除
泛型类型仅存在于编译期间,编译后的字节码和运行时不包含泛型信息,所有的泛型类型映射到同一份 字节码。
Java让编译器擦除掉关于泛型类型的信息,这样使得Java 可以向后兼容之前没有使用泛型的类库和代码,因为在字节码(class)层面是没有泛型概念的。