使用泛型的优点:
- 使用Java的泛型可以在编译时检测出错误。
- 省心,取出元素时不用类型
List<String> list=new ArrayList<>();
//list.add(1);编译时类型检查出错误
list.add("so easy");
list.get(0);//取出时不再需要类型转换
使用泛型的一些限制:
- 不能使用 new E()以及new E[]; 泛型存在于编译时,一旦编译器认为泛型类型是安全的,就会将它转换为原始类型(Object)
- 在静态上下文中不允许类的参数是泛型类型
例如:
public static void m(E o1){
}
以及
private static T test
都是错误的;<font color=red>因为所有的泛型实例在运行时都用同一个运行时类,所以泛型的静态变量和方法是被它的所有实例所共享的,所以在静态方法、数据域或者初始化语句中为类引用泛型类型参数是非法的。</font>
为什么说“所有的泛型实例在运行时都用同一个运行时类”,如下代码证明:
【编译时ArrayList<String>,ArrayList<Integer>是两种不同的类型,但在运行时只有一个ArrayList加载到JVM中】
public static void main(String[] args) {
ArrayList<String> list1=new ArrayList<>();
ArrayList<Integer> list2=new ArrayList<>();
System.out.println(list1 instanceof ArrayList);
System.out.println(list2 instanceof ArrayList);
}
3.在声明时指定类型,但不能是基本类型
泛型方法:
非泛型类中定义泛型方法 在返回类型前面加入泛型,可以使用extends让泛型局限于某些类型下,从而使泛型具有该类型的特性
public class Method3 {
public static <T> void test(T t){
System.out.println(t);
}
//可以使用extends让泛型局限于某些类型下
public static <T extends List> void test1(T t){
t.add("I love you");
System.out.println(t.get(0));
}
public static void main(String[] args) {
test("I love you");
test(1024);
ArrayList list=new ArrayList();
test1(list);
}
}
泛型的继承:
泛型的继承
* 1.保留父类的泛型,泛型子类
* 2.不保留父类泛型,子类按需实现即可,可以是泛型类也可以是非泛型类
* 3.子类也可以扩展自己的泛型也可以
* 4.子类重写的方法的泛型类型取决于父类中该方法的泛型类型
* 5.子类中使用父类的属性随父类而定
* 6.子类新增方法或属性的类型由子类自己决定
public abstract class Father4<T1, T2>{
T1 age;
public abstract void test(T2 name);
}
/*
* 保留-->泛型子类
*/
//1)全部保留
class c1<T1, T2> extends Father4<T1, T2>{
@Override
public void test(T2 name) {
//this.age-->T1
}
}
//2)部分保留
class c2<T2> extends Father4<Integer, T2>{
@Override
public void test(T2 name) {
//this.age-->Integer
}
}
/*
* 不保留--》按需实现
*/
//1)指定具体类型
class c3 extends Father4<Integer, String>{
@Override
public void test(String name) {
//this.age-->Integer
}
}
//2)没有类型,擦除泛型,擦出后相当于Object
class c4 extends Father4{
@Override
public void test(Object name) {
//this.age-->Object
}
}
class c5<T1, T2, A, B> extends Father4<T1, T2>{
@Override
public void test(T2 name) {
//this.age-->T1
}
}
泛型接口与泛型类同理
“?“ 通配符:类型不确定,用于声明变量|形参
1、变量的类型(局部变量&成员变量)
List<? extends Fruit> list1 =new ArrayList<Fruit>();
2、方法形参的类型
public stati cvoid test(List<?> list)
extends: 泛型的上限
public class Fruit8 {
}
class Apple extends Fruit8{}
class Pear extends Fruit8{}
class FujiApple extends Apple{}
===================================
public class ExtendsTest8 {
public static void main(String[] args) {
Test<Fruit8> t1=new Test<Fruit8>();
Test<Apple> t2=new Test<Apple>();
Test<Pear> t3=new Test<Pear>();
Test<FujiApple> t4=new Test<FujiApple>();
//调用方法
List<? extends Fruit8> list1=new ArrayList<Fruit8>();
test(list1);
List<Apple> list2=new ArrayList<Apple>();
test(list2);
//? extends Apple
List<? extends Apple> list4=new ArrayList<FujiApple>();
test(list4);
//?-->为什么错误
List<?> list5=new ArrayList<Apple>();
//test(list5);
List<?> list6=new ArrayList<Object>();
//test(list6);
//? 相当于任何类型的对象都可以,假设对象超出Fruit8,如Object,
//所以 声明对象时用 ,即使创建对象时使用的泛型在Fruit8内也不行
}
//? extends Fruit8
public static void test(List<? extends Fruit8> list){
//不能向list添加任何对象
//list.add(new Apple());
//list.addAll(new Pear());
list.add(null);
}
}
class Test<T extends Fruit8>{}//extends表示泛型上限为Fruit8,T可以是所有Fruit8的子类
super: 泛型的下限
public class SuperTest {
public static void test(List<? super Apple> list){
//只能添加子对象和自己
list.add(new Apple());
list.add(new FujiApple());
//list.add(new Pear());
//list.add(new Fruit8());
}
public static void main(String[] args) {
List<Apple> list1=new ArrayList<Apple>();
List<Fruit8> list2=new ArrayList<Fruit8>();
List<Object> list3=new ArrayList<Object>();
List<? super Apple> list4=new ArrayList<Apple>();
List<? super Fruit8> list5=new ArrayList<Fruit8>();
List<FujiApple> list6=new ArrayList<FujiApple>();
List<Pear> list7=new ArrayList<Pear>();
//规则
//apple为下限,Apple的父类以及超类均可以,子类和与Apple同属于一个父类的其他类不可以
test(list1);
test(list2);
test(list4);
test(list5);
//test(list6);
//test(list7);
}