1、为什么需要泛型?
举个例子:
public class Genericity{
public int sumInt(int a,int b){
return a + b;
}
public double sumDouble(double a,double b){
retrun a + b;
}
public <T> T sum(T a, T b){
retrun a + b;
}
}
上面代码中可以看出,sum()方法就可以替代sumInt()和sumDouble(),这就是我们为什么需要泛型。因为泛型用起来安全简单。泛型的好处是在编译的时候检查类型安全,并且所有的强制转换都是自动和隐式的,提高代码的重用率。说直白的就是让我写更少的代码做更多事情(个人肤浅的理解)
2、泛型类的定义
泛型(generic)是指参数化类型的能力
//泛型类
public class GenericityClass<T,K>{ //泛型设置可以是多个
T data;
K data2;
public GenericityClass(){
}
public GenericityClass(T data){
this.data = data;
}
public void setData(T data){
this.data = data;
}
public T getData(){
return data;
}
public static void main(String[] args){
GenericityClass<String,String> genericityClass = new GenericityClass();
genericityClass.setData("Hello World");
}
}
//泛型接口以及泛型接口的实现
public interface GenericityInterface<T>{
T getData();
}
//泛型接口实现一
public class ImplGenericityInterface implements GenericityInterface<String>{
public String getData(){
return null;
}
}
//泛型接口实现二
public class ImplGenericityInterface2<T> implements GenericityInterface<T>{
public T getData(){
return null;
}
}
//泛型方法以及泛型方法的辨析
public class GenericityMethod{
//泛型方法 最重要的标志 <T> T可以用其他字母代替
public <T> void printMsg(T msg){
System.out.printLn(msg.toString());
}
//泛型方法
public <T> T returnMsg(T data){
return data;
}
}
public class GenericityClass2<T>{
T data;
//此方法不是泛型方法,是普通方法
public T getData(){
return data;
}
//泛型类中的泛型方法
public <E> showMsg(E msg){
System.out.printLn(msg.toString());
}
}
3、限定类型变量
public class GenericityLimit{
//不知道 a,b的类型,所以就不知道a,b是否有compareTo()方法,故会出现编译错误
//public static <T> T max(T a,T b){
// if(a.compareTo(b)>0)
// return a;
// else
// return b;
//}
// T extends Comparable 及限定类型变量,之后实现 Comparable接口的类才能使用此方法
//extends之后可以是类也可以是接口
// 如果有类也有接口,类必须写在前面,类有且只有一个,
public static <T extends Comparable> T min(T a,T b){
if(a.compareTo(b)> 0)
return a;
else
return b;
}
//实现Comparable
class Test implments Comparable{
@Override
public int compareTo(Object o) {
return 0;
}
}
public static void main(String[] args){
GenericityLimit.min(new Test(),new Test());//现在就不会编译错误
}
}
4、泛型中的约束和局限性
public class GenericityRestrain<T>{
T data;
//错误 泛型要在对象实例化之后才能知道类型,所以静态域或者方法里不能引用类型变量
//private static T instance;
//正确,静态方法 本身是泛型方法就行
public static <T> void getInstance(){}
/*泛型类不能extends Exception/Throwable*/
//private class Problem<T> extends Exception;
/*不能捕获泛型类对象*/
//public <T extends Throwable> void doWork(T x){
// try{
//
// }catch(T x){
// //do sth;
// }
// }
public <T extends Throwable> void doWorkSuccess(T x) throws T{
try{
}catch(Throwable e){
throw x;
}
}
public static void main(String[] args){
//GenericityRestrain<double> genericity1 = new GenericityRestrain<>(); //泛型必须是对象,double是基本类型,应该是包装类Double
GenericityRestrain<Double> genericity2 = new GenericityRestrain<>();
GenericityRestrain<String> genericity3 = new GenericityRestrain<>();
//打印结果为 true 说明不管泛型传入的类型是什么,泛型的原生类型永远是不变的
System.out.println(genericity2.getClass()==genericity3.getClass());
//且打印的两个类名也是相同的
System.out.println(genericity2.getClass().getName());
System.out.println(genericity3.getClass().getName());
}
}
5、通配符类型
//动物类
public class Animal{}
//狗类
public class Dog extends Animal{}
//猫类
public class Cat extends Animal{}
//阿拉斯加 狗的子类
public class DogAla extends Dog{}
//标准的泛型类
public class GenericityType<T>{
private T data;
public void setData(T data){
this.data = data;
}
public T getData(){
return data;
}
}
//测试类
public class Test{
public static void print1(GenericityType<Animal> g) {
System.out.println(g.getData());
}
public static void use() {
GenericityType<Animal> genericityAnimal = new GenericityType<>();
print1(genericityAnimal);
GenericityType<Dog> genericityDog = new GenericityType<>();
//print1(genericityDog); //类型错误
}
public static void print2(GenericityType<? extends Animal> g) {
System.out.println(g.getData());
}
public void useExtends() {
GenericityType<Animal> genericityAnimal = new GenericityType<>();
print2(genericityAnimal);
GenericityType<Dog> genericityDog = new GenericityType<>();
print2(genericityDog);
//? extends 上界通配符 及能达到最高的父类 目的就是安全的访问数据
GenericityType<? extends Animal> genericityType = new GenericityType<>();
Animal animal = new Animal();
Dog dog = new Dog();
Cat cat = new Cat();
//因为编译器只知道传入的是Animal 的子类,但是具体是哪一个子类,编译器是不知道的,所以报错
// genericityType.setData(animal); // 编译错误,不能存
// genericityType.setData(dog);
// genericityType.setData(cat);
// Dog dog1 = genericityType.getData(); //编译错误
// Cat cat1 = genericityType.getData();//编译错误
//因为传入的data肯定都是Animal或者其子类,但是取的时候因为不知道其具体类型,则只能返回父类类型
Animal animal1 = genericityType.getData();
}
public static void print3(GenericityType<? super Dog> g) {
System.out.println(g.getData());
}
public static void useSuper() {
GenericityType<Animal> genericityAnimal = new GenericityType<>();
GenericityType<Dog> genericityDog = new GenericityType<>();
GenericityType<DogAla> genericityDogAla = new GenericityType<>();
GenericityType<Cat> genericityCat = new GenericityType<>();
print3(genericityAnimal);
print3(genericityDog);
// print3(genericityCat); //编译错误 Cat 不是Dog的子类或者父类
// print3(genericityDogAla); //编译错误 DogAla 是 Dog 派生出的子类 ,则下界通配符不能使用
// ? super 下界通配符 及能达到最低的子类 主要用于安全的写入数据
GenericityType<? super Dog> genericityType = new GenericityType<>();
Animal animal = new Animal();
Dog dog = new Dog();
DogAla dogAla = new DogAla();
// genericityType.setData(animal); //编译错误
genericityType.setData(dog);
genericityType.setData(dogAla);
//只能返回Object ,这里是一定是返回Animal 的超类,因为没有限定,所以不知道是哪一个超类,及返回Object
Object data = genericityType.getData();
}
}
6、虚拟机是如何实现泛型的?
Java中的泛型,是伪泛型 ,jdk 做了泛型擦除处理,举例说明如下
//例子1
public class Genericity<T>{
private T data;
public void setData(T data){
this.data = data;
}
public T getData(){
return this.data;
}
}
//jdk 编译之后,把T改成Object 如下
public class Genericity<Object>{
private Object data;
public void setData(Object){
this.data = data;
}
public Object getData(){
return this.data;
}
}
//例子2
public class Genericity<T extends ArrayList&Comparable>{
private T data;
public void setData(T data){
this.data = data;
}
public T getData(){
return this.data;
}
}
//jdk 编译之后,把T改成第一个ArrayList 如下
public class Genericity<ArrayList>{
private ArrayList data;
public void setData(ArrayList data){
this.data = data;
}
public ArrayList getData(){
return this.data;
}
}