目录页
泛型简介
泛型类
限制泛型可用类型
类型通配声明
泛型方法
问题引入
如果我们需要产生多个对象,每个对象的逻辑完全一样,只是对象内的成员变量的类型不同。那我们如何去做?
我们新建一个工程
做一个构造方法 public Cls1(int a){
this.a =a;
}
然后我们实例化这个方法的时候,给他传一个10 Cls1 cls1 = new Cls1(10);
然后我们输出cls1 里面的getData() System.out.println(cls1.getData());
运行结果
同样的我们在做一个类,唯一的区别,所有的东西都一样,但是它a变成了 String a;
运行结果
你会发现有两个类,这两个类的逻辑完全一样,所谓的逻辑就是里面的一些方法,包括构造方法,只是成员变量的类型不同
那比如我们现在要做了double 类型的,是不是还得专门为double 创建一个类呀?
问题解决
创建多个类文件,给每个类中的成员变量设置指定的数据类型
缺点:这种方法会导致类的膨胀,重用性太差。
创建一个类文件,给这个类中的成员变量设置Object数据类型。
缺点:编译的时候正常,但运行的时候可能会异常
创建多个类文件,给每个类中的成员变量设置指定的数据类型:
这样整个业务场景下来,整形一个,小数一个,字符一个,甚至里面会集成一些其他的类。
创建一个类文件,给这个类中的成员变量设置Object数据类型。:
我们会发现整形int ,打开它的类型继承
你会发现Object是所有类型的父类
这种情况下我们完全可以把这两个删掉一个,
然后我们把Cls2改成Cls1 第21行
发现没写错,可是还报错 错误提示: The constructor Cls1(int) is undefined
发现是版本的问题
我们右击,然后选择properties
然后看到JDK那行了嘛?
把对勾去掉
然后选择1.5版本往后的点击ok
这个时候就没有报错了
运行一下
但是他有一个不太好的地方
这个Object导致整个类对这个变量的属性很模糊
可能会产生某些错误,
假如我现在输出“冰糖李子”,编码过程中误操作了,把“冰糖李子”这个字符串强制转换成整型数,你会发现编译的时候是ok 的
但是运行的时候会出现异常,类型转化异常
难免我们在操作过程中,随着代码量的增大,对里面的object的类型模糊不清晰,导致你程序员在编写代码的时候,做了一个误判,做了一个错误的转换,导致程序崩溃
面向于 这种情况发生,我们有一个非常好的解决办法,就是泛型
一、泛型简介 JDK1.5之后引入
泛型可以在编译的时候检查类型安全,并且所有的强制转换都是自动和隐式的
泛型的原理就是“类型的参数化”,即把类型看做参数。也就是说把所要操作的数据类型看做参数,就像方法的形式参数是运行时传递的值的占位符一样。
简单的说,类型变量扮演的角色就如同一个参数,它提供给编译器用来类型检查的信息。
泛型可以提高代码的扩展性和重用性
那么泛型怎么做?
示例----泛型类
public class GenClass<T>{
private T obj;
public GenClass(T obj){
this.obj = obj;
}
public T getobj(){
return obj;
}
public void setobj(T obj){
this .obj = obj;
}
}
泛型的意思就是就是在class后面添加一个<T>,用T去替代里面未名的数据类型
比如说我们的代码可以在Cls1后面加上<T>,用一个T来表示
然后new 的时候要把这个东西用上,你在实例化的时候呈现,他是一个整形
Cls1<Integer> cls1= new Cls1<Integer>(10);
同样使用cls2的时候,落地的时候,我让他都是字符串
Cls1<String> cls2 = new Cls1<String>("冰糖李子");
运行结果
我们用<T>替代了刚才写的Object,在使用的时候,在程序员编码的过程当中,实例化类的时候,在<>里面,去告诉操作系统,包括程序员看代码的时候更具象的把他表达出来
这就叫做泛型
泛型可以在编译的时候检查类型安全,并且所有的强制转换都是自动和隐式的
当你转换出现问题的时候,你硬要把string转化成Integer,他就会报错,
刚才我们用object的时候它没有任何的报错,
只是在程序运行的时候出现类型转换异常
(这就是泛型引入的除了程序员可读之外,还有个好处就是防止你的误操作,误转换)
Cannot cast from String to Integer
泛型的原理就是“类型的参数化”,即把类型看做参数。也就是说把所要操作的数据类型看做参数,就像方法的形式参数是运行时传递的值的占位符一样。:
我们习惯了函数调用,习惯了传参public Cls1(T a),
那实际上类型也可以以参数的形式传过来,为了区别我们用来了<>
我们在这个类初始化,实例化的时候 Cls1<Integer> cls1= new Cls1<Integer>(10);
我们直接把泛型类里面的,涉及到泛型的位置,用Integer替代进去
也就是说Cls1类里面的 a变量的的类型, T a;
是根据我们真正实例化的时候,用<>的方式传参过去的,来确定里面a的类型
,同样的一个类,你在使用实例化的时候,给泛型传的类型不一样,这个类最后体现的结果也是不一样的
Cls1<Integer> cls1= new Cls1<Integer>(10);
System.out.println(cls1.getData());
Cls1<String> cls2 = new Cls1<String>("冰糖李子");
System.out.println(cls2.getData());
二、泛型类及特点
1、泛型的类型参数可以是泛型类
2、泛型类可以同时设置多个类型参数
3、泛型类可以继承泛型类
4、泛型类可以实现泛型接口
泛型的类型参数可以是泛型类:
也就是说你这个<T>除了普通变量Integer 和String 外,他也能接受是个泛型
泛型类可以继承泛型类:
跟我们普通类的继承是一样的,当然你泛型可以在继承过程中实现多个类型参数
你的父类型是个泛型,他里面只有一个<T>,你完全可以除了<T>,多一个<K> 呀,<T2>等等。
一般我们泛型用的<T>,不是写死的 ,就像形参的名字,你愿意起什么都可以的,
按照程序员编码习惯,一般是<T>呀,<K>,<B>呀,经常用的几种写法
泛型类可以实现泛型接口:
这个继承和实现,和我们普通类的继承和实现没有很大的区别,唯一的区别就是体现在参数上面,和泛型上面
泛型类可以同时设置多个类型参数:
现在再做一个类Cls2,多个参数用,隔开 class Cls2<T,T2>
构造方法 public Cls2(T a,T2 b){
this.a =a;
this.b =b;
}
有两个变量, T a;
T2 b;
这两个变量的具体类型为止
同样的b的类型是T2, public T getData(){
return a;
}