优质博文:IT-BLOG-CN
【1】解决元素存储的安全性问题。
【2】解决获取数据元素时,需要类型强转的问题。
【3】可以统一数据类型,属于异常操作。
【4】将运行时的提前到了编译时,提高了效率。
【5】实现代码的模板化,把数据类型参数传递,提高了可重用性。
【6】只需在编译时不出现警告,那么运行期间就不会出现ClassCastException异常。
public class 演示 { //泛型在使用时必须左右一致,不存在继承; public static void main(字符串[] args) { ArrayList< ?> list1 ; ArrayList<字符串> list2 = 新< /span> ArrayList<字符串>() ; ArrayList<整数> list3 = 新 ArrayList<整数>< /span>(); ArrayList<对象 > list4 = 新 ArrayList<字符串 >();//泛型在使用时左右必须一致,不存在继承; span> list1 = list2; list1 = list3;//不会报错,使用了通配符,通配符表示任何类型,这是在使用,把?当成任何类型,< /span> //?就是任何类型。 list2 = list3;< /span> //会报错,因为两者在定义时使用泛型,一旦确定了类型就不能改变类型, / /只能是给定的一种泛型类型。 }}
定义在类上的泛型是在创建对象对象时确定:
< pre>public class MyClass1<E> { /** 定义具有泛化性类型的类 * 修饰符 class 类名 <范型变量>{ * 范型变量一般用E,K,V,T; * } */ //.. ....}
由实现类对象确定
/* 泛型接口(接口上含有泛型) 格式: public abstract interface 接口名<泛型变量> {} */公共 接口 MyInter<T< span class="6c33-1951-1828-48e2 token punctuation">> { //。 .....}
创建在放方法上面的泛型是在真正调用方法时确定的,一般都由创建的参数确定,包含这个方法的类创建对象时,并不会确定方法上的类型,一定在调用方法时确定。
/* 泛型方法(方法上带有泛型) 格式: 修饰符 <泛型变量> 返回值类型 方法名称(参数列表...) { //... } */public class MyClass02<T span>> { //泛型方法:泛型E是在方法上自己定义的 public <E> E getE(E e){ } }
统配符的使用如下:先说说T和?的区别:基本泛型T是用于定义,将数据类型参数化,不能用于实例化。而 ? 则在实例化对象时不确定泛型具体参数类型的时候泛指对象的所有子类型。但是?不能和Object对应,?是类型实参而不是类型形参,它用于泛指各种类型实参,当具体类型不确定的时候就可以使用?示例如下:< /p>
//使用通配符,调用方法时,就可以形成任意类型的列表集合public 静态 void 测试(列表< ?> 列表) {}
上下界通配符其实涉及到Java的多态属性,上下变换的吸力,子类实例可以转换父类实例,但是类实例却不一定能转换子类实例,本身就是该子类实例向上转换的父类实例才可以向下转换为子类实例。
【1】 extends A>:可以存放A及其子类(携带子类限定的可以从泛型读取);
公共 类 EnumTest<T 扩展 B> { 公共 静态 void main(字符串[] args) { //可以囤B它的子类所以 A 是不行的 //EnumTest a = new EnumTest(); EnumTest<B> b = 新 EnumTest<B>(); EnumTest<C> C = 新 EnumTest<C>(); } }class A{};class B 扩展 A< /span>{}; span>class C 扩展 B{};
【2】 super A>:可以存放A及其父类(带有超限定类的可以从泛型写入),在泛型类中是不能进行超级向上转换的。
//设置通配符的下限这并明显可见,在TreeSet集合中已有....我们来看一下public TreeSet(比较器<? super E> 比较器) { 这个 (新 TreeMap<>(比较器))< /span>;}
那它有什么用呢?想一下,当我们想要创建一个TreeSet
类型的变量的时候,并确定一个可以比较String大小的比较器。那么这个比较器的选择就有很多了,可以是Comparator
,还可以是类型参数是 String 的父类,也就是说Comparator
…这样做,就非常灵活了。只要,只要它能够比较字符串大小,就行了。
【界限通配符在集合】应用时会影响集合的读写行为:
【1】上界< ? extends A>限制了类型上限,只能向上转型,可以读,但是不能写,因为子类型不确定,可以继续转型;
【2】下界 super A>限制类型的下限,只能继续转型,可以写,但是不能读,因为父类型不确定,不能向上转型。
public class 测试 { 公共 静态 void main(< span class="f7ca-be22-0fb8-f50c token class-name">字符串[] args) { // extends B> 范围: A类或者A的子类 //由于下限无限,所以无法升级转型至具体类型 List span><? 扩展< /span> B> list1 = span> 新 ArrayList<B>(){{添加(新增 B());}}; //list1.add(new B()); // 无法添加该类型,后续转型无法确定目标类型 //list1.add(new C());//返回类型A或B A a = list1.获取(0); //正常向上转换 // super B> 范围: B类或者B类的父类 //由于上限不确定,所以B类和B类的子类均可以加入,但是B类的父类类不行 列表<? super B>< /span> list2 = 新 ArrayList<>(); //list2 .add(新A()); // 无法升级转型 list2.add(< /span>新 B()); //正常向上转换 list2.add( 新 C(
pre>) ); / /C c = list2.get(1);//无法升级转换,不加强制转换会报错 B b = (B)< /span> list2.获取(0); C c = (C< span class="60e7-49cb-11a8-6c33 token punctuation">)list2.获取(1); } 静态 class A {}; 静态 类 B 扩展 A {}; 静态 类 C 扩展 B {};}七、注意事项
1)、静态方法中不能使用类的泛型。
2)、如果泛型类是一个接口或抽象类,则不可创建泛型类的对象。
3)、不能在catch中使用泛型。
4)、从泛型类派生子类,泛型类型需要具体化。