泛型
泛型(不允许继承)
概述
-
泛型:可以再类或者方法当中预知的使用未知的数据里类型。
-
备注:一般在创建对象的时候,将未知的数据确定为具体的数据类型,当没有指定泛型,默认类型为Object类型。
E e:Element 元素
T t:Type 类型
ArrayList在定义集合的时候,不知道集合当中存储什么样的数据类型,所以类型使用泛型
E:位置的数据类型
-
备注
创建集合对象的时候,就一定确定数据类型 ArrayList<String> list = new ArrayList<E>(); 会把数据类型作为参数进行传递,把String数据类型赋值给泛型 列: public class ArrayList<E e>{ public boolean add(E e){} public E get(int index){} } ArrayList<String> list = new ArrayList<E>();//创建集合 public class ArrayList<String>{ public boolean add(String e){} public String get(int index){} }
集合中使用泛型总结
-
集合接口或者集合类在jdk5.0时都修改为带泛型的结构。
-
在实例化集合类时,可以指明具体的泛型类型
-
指明完以后,在集合类或者接口中凡是定义类或者接口时,内部结构(比如方法,构造器,属性等)使用到泛型的位置,都指定为实例化的泛型类型
比如:add(E e) ———>实例化以后:add(Integer e)
-
注意点:泛型的类型必须是类,不能是基本数据类型。需要用到基本数据类型的位置,拿包装类替换
-
如果实例化时,没有指明泛型的类型。默认类型为java.Lang.Object类型
-
使用泛型和不使用泛型的区别
* 创建对象的时候不使用泛型 * 好处: * 可以存储任意类型的数据,默认的类型是Object * 弊端: * 不安全,伴随着引发异常 **************************************************** * 创建对象的时候使用泛型 * 好处: * 1.避免了类型转换的麻烦,存储的什么类型,取出的就是什么数据类型 * 2.把运行期异常(代码运行的时候)提升到了编译期阶段(写代码的时候) * 弊端: * 泛型是什么样的类型,只能存储什么样的数据类型 //备注:泛型其实是数据类型的一部分,一般我们将类名和泛型合并一起看做数据类型。
泛型的定义与使用
- 泛型;可以灵活的将数据类型引用到不同的类,方法,接口当中。将数据类型作为参数进行传递。
因为我们的集合框架的体系中,大量的使用了泛型。
定义和使用泛型的类
定义格式
修饰符 class 类名<代表泛型的变量>{
//...
}
实例
public class ArrayList<E>{
public boolean add(E e){}
public E get(int index){}
//'''
}
//备注:定义的时候使用未知的泛型的变量,使用的时候(创建对象)确定的泛型的具体类型。
定义和使用泛型的方法
修饰符 <代表泛型的变量> 返回值类型 方法名(泛型参数列表){}
public class GenericDemo{
//定义有参无返带有泛型的方法
public <VIP> void show(VIP vip){
System.out.println(vip);
}
//定义含有泛型的有参有返方法
public <VIP> VIP show2(VIP vip){
return vip;
}
}
//测试
public static void main(String[]args){
//创建对象
GenericDemo j = new GenericDemo();
//调用带有泛型的方法
j.show("欧拉");//VIP vip 参数--->形参 String str = "abc"
j.show(123);//VIP ---> vip = 123;
j.show2(3.11);//VIP ---Double vip = 3.14
}
'含有泛型的方法,在调用的时候确定泛型的数据的数据类型
'传递什么类型的参数,泛型就会被解析成什么的类型
定义泛型接口
修饰符 interface 接口名<泛型变量名>{}
//定义格式
public interface Iterable<T> {
//方法体
public abstract void add(E e);
}
//使用格式
1.定义实现类时可以直接确定泛型的类型
public class Ouou implements Iterable{
@Override
public void add(String s){//...}
}
//备注:此时泛型【T】的值就是String类型
2.始终不确定泛型的类型,直到创建对象的时候确定泛型的类型
public class <E> Lala implements Iterable{
@Override
public void add(T t){//...}
}
使用泛型需注意
-
泛型类如果有多个参数,此时应将多个参数一起放在见括号内。比如<E1,E2,E3>
-
泛型类的构造器如下:public GenericClass(){}.
而下面是错误的:public GenericClass <E>(){}
-
实例化后,操作原来泛型位置的结构必须与指定的泛型类型一致。
-
泛型不同的引用不能相互赋值
>尽管在编译时ArrayList<String>和ArrayList<Integer>是两种类型,但是,在运行时只有一个ArrayList被加载到JVM中
-
泛型如果不指定,将被擦拭,泛型对应的类型均按照Object处理,但不等价于Object。经验:泛型使用一路都用。要不用,一路都不要用。
-
如果泛型结构是一个接口或者抽象类,则不可创建泛型类的对象。
-
jdk1.7,泛型的简化操作:ArrayList< <Fruit> flist = new ArrayList<>();
-
泛型的指定中不能使用基本数据类型,可以使用包装类替换。
-
在类/接口.上声明的泛型,在本类或本接口中即代表某种类型,可以作为非静态
属性的类型、非静态方法的参数类型、非静态方法的返回值类型。但在静态方法
中不能使用类的泛型。 -
.异常类不能是泛型的
-
.不能使用new E[]。但是可以: E[] elements = (E[])new Object[capacity];
参考: ArrayList源码中声明: Object[] elementData,而非泛型参数类型数组。 -
.父类有泛型,子类可以选择保留泛型也可以选择指定泛型类型:
●子类不保留父类的泛型:按需实现
➢没有类型擦除
➢具体类型
●子类保留父类的泛型:泛型子类
➢全部保留
➢部分保留结论:子类必须是“富二代”,子类除了指定或保留父类的泛型,还可以增加自己的泛型
泛型的通配符
描述
- 当使用泛型类或者泛型接口时传递的数据中,泛型的类型不确定,可以使用通配符
<?>
表示。
一旦程序当中使用泛型通配符后,只能使用Object类中的共性的方法。
通配符的使用
- 泛型的通配符:不知道使用什么类型来接收的时候,此时可以使用? 。
?
代表未知的通配符
此时只能接收数据,不能往集合当中存储数据。
public static void main(Stromg[] args){
//可以存储整数的集合
Collection<Integer> list = new ArrayList<>();
//展示list集合当中的数据
getElement1(list);
//可以存储String字符串的集合
Collection<Integer> list2 = new ArrayList<>();
getElement2(list2); '不可以'
getElement3(list2); '可以'
}
public static void getElement1(Collection<Integer> call){
//只能接收Integer类型的数据
}
//public static void getElement2(Collection<Object> call){
//}
public static void getElement3(Collection<?> call){
//此时?可以代表任意类型
}
//备注:泛型不存在继承关系 Collection<Object> list = new ArrayList<String>(); 这是一种错误的写法。
泛型的上下限
描述
- 之前设置泛型的时候,实际上是可以任意设置的。只要是类可以的,但是在java的泛型当中还可以指定一个泛型的上限和下限。
泛型的上限
格式:
类型名称 <? extends 类名> 对象名
意义:
只能接收该类型及其子类
? extends A:
G<? extends A> 可以作为G<A>和G<B>的父类,其中B是A的子类
泛型的下限
格式:
类型名称<? super 类名> 对象名
意义:
只能接收该类类型及其父类类型
? super A:
G<? super A> 可以作为G<A>和G<B>的父类,其中B是A的父类
示例
- 比如定义父类Object,String Number Integer 。其中Number类是Integer类的父类
public static void mian(String[] args){
Collection<Integer> l1=new ArrayList<>();
Collection<Integer> l2=new ArrayList<>();
Collection<Integer> l3=new ArrayList<>();
Collection<Integer> l4=new ArrayList<>();
}
//可以接收任意类型的
public static void getElement(Collection<?> coll){//..}
//只能接收number类型或者子类
public static void getElement(Collection<? extends Number> coll){//..}
//只能接收number类型及其父类
public static void getElement(Collection<? super Number> coll){//..}