什么是泛型
泛型类:具有一个或多个类型变量的类,称为泛型类。
泛型方法:具有一个或多个类型变量的方法,称之为泛型方法。
- 泛型是一种未知的类,将未知的类声明在集合、对象上,泛型默认为Object。
- 使用泛型可以在传参的时候不固定传入什么类型,即可通用类型。
- 使用泛型后,集合或对象上只能放入指定的数据类型,可以保证对象或集合的安全性,减少类型的转换操作。
类型安全:
- 泛型的主要目标是提高Java程序的类型安全
- 编译时期就可以检查出因Java类型不正确导致的ClassCastException异常
- 符合越早出错代价越小原则。
消除强制类型转换: - 泛型的一个附带好处是,使用时之恶杰得到目标类型,消除许多强制类型转换。
- 所得即所需,这使得代码更加可读,并且减少了出错机会。
- 由于泛型的实现方式,支持泛型(几乎)不需要 JVM 或类文件更改
- 所有工作都在编译器中完成
- 编译器生成的代码跟不使用泛型(和强制类型转换)时所写的代码几乎一致,只是更能确保类型安全而已
泛型使用场景
泛型类、泛型方法、泛型接口、泛型通配符。
泛型类:
指定类内部成员变量的数据类型。
/**
* 声明在类上时,写在类名后边
* @param <E>
*/
class Animal <E> {
/**
* 作为属性声明时,必须在类上声明泛型
*/
E pet;
/**
* 作为参数或者返回值时,如果在类上没有声明,必须在访问修饰符和返回值之间
* @param pet
*/
public void setPet(E pet){
this.pet = pet;
}
public E getPet(){
return pet;
}
public <T> void call(T t){
System.out.println( t.toString() );
}
}
泛型接口:
/**
* 作用在接口上,如果实现该接口时指定实现类型
* @param <T>
*/
public interface Animals<T>{
void call(T t);
}
/**
* 拉布拉多犬
*/
/**
* 使用泛型实现时,实现类必须使用对应的泛型类。
* 实现类声明泛型跟接口指定泛型可以同时使用。
*如下代码:
*/
class LaBuLaDuo<T> implements Animals<String> {
public void call(String s) {
System.out.println( s );
}
}
泛型占位符
/**
* 小狗狗
*/
class Dog extends Animal {
public String name;
public Integer age;
}
/**
* 泛型占位符 ? 的使用
* 泛型的上限 < ? extends E> 即传入参数必须为E 的子类
* 泛型的下限 < ? super E>
*/
public class ErHa <E> {
//当参数传递时可以设置上下限 比如下面的是 传入类型必须是 Dog 的子类,上限为Dog
public void call(Animal< ? extends E> s){
System.out.println(s.pet);
}
//传入类型必须是 Dog 的父类,下限为Dog
public void jump(Animal< ? super E> s){
System.out.println(s.pet);
}
// ? 占位符单独使用时,相当于 < ? extends Object >
public void smile(Animal<?> s){
System.out.println(s.pet);
}
public static void main(String[] args) {
new ErHa<Dog>().call(new Dog());
}
}