子(实现)类

  • 子类与父类|接口一样使用泛型

  • 子类指定具体的类型

  • 子类与父类|接口同时擦除类型

  • 子类泛型,父类|接口 擦除

  • 错误:不能子类擦除 父类|接口泛型

擦除统一按照Object对待

demo:

/**
 * 子类类型范围大于等于父类
 * 1.属性类型:
 * 在父类中随父类而定
 * 在子类中随子类而定
 * 2.方法重新
 * 随父类而定
 */
public abstract class Father<T> {

    T name;

    public abstract void test(T t);

}
/**
 * 
 * 子类声明时指定具体类型
 * 属性类型为具体类型
 * 方法同理
 * 
 */
class Child1 extends Father<String>{

    @Override
    public void test(String t) {
        // TODO Auto-generated method stub

    }

}

/**
 * 子类为泛型类,类型在使用时确定
 */
class Child2<T> extends Father<T>{

    @Override
    public void test(T t) {
        // TODO Auto-generated method stub

    }

}

/**
 * 子类为泛型类,父类不能指定类型,泛型的擦除,使用Object替换
 */
class Child3<T1,T2> extends Father{

    @Override
    public void test(Object t) {
        // TODO Auto-generated method stub

    }

}

/**
 * 子类与父类同时擦除
 */
class Child4 extends Father{

    @Override
    public void test(Object t) {
        // TODO Auto-generated method stub

    }

}

/**
 * 错误子类擦除,父类使用泛型
 */

/*class Child5 extends Father<T>{

    @Override
    public void test(Object t) {
        // TODO Auto-generated method stub

    }

}*/

demo

/**
 * 泛型接口:与继承同理
 * 重写方法随父类而定
 */
public interface Comparale<T> {

    void compare(T t);

}

//擦除
class Comp1 implements Comparale{

    @Override
    public void compare(Object t) {
        // TODO Auto-generated method stub

    }

}

//父类擦除 子类泛型
class Comp2<T> implements Comparale{

    @Override
    public void compare(Object t) {
        // TODO Auto-generated method stub

    }

}

//子类泛型>=父类泛型
class Comp3<T> implements Comparale<T>{

    @Override
    public void compare(T t) {
        // TODO Auto-generated method stub

    }

}

//父类泛型,子类擦除 错误

//声明子类具体类型
class Comp implements Comparale<Integer>{

    @Override
    public void compare(Integer t) {
        // TODO Auto-generated method stub

    }

}

泛型擦除

  • 擦除

    • 在使用时没有指定具体的类型

    • 子类继承时没有指定类型

  • 处理

    • 擦除后不类型检查

    • 一旦擦除后按Object接收

    • 依然存在编译警告,加上Object可以去除,但是有些画蛇添足

    Student<Object> stu = new Student<Object>();

泛型没有多态

  • 泛型没有多态

    • 直接使用A<Object> a = new A<String>();错误

    • 方法形参与返回类型也不存在泛型多态

  • 不能使用instanceof判断是否为泛型实例

通配符

要想使用多态怎么办呢?可以使用通配符

通配符: ? extends super

  • 可以用在声明类型及声明方法参数上,不能用在声明类中

  • ?可以接受泛型的任意类型,只能接收和输出,不能修改

  • ? extends 泛型上限 <=

    \<? extends T> 表示类型的上界,表示参数化类型的可能是T 或是 T的子类

  • ? super 泛型下限 >=

    \<? super T> 表示类型下界(Java Core中叫超类型限定),表示参数化类型是此类型的超类型(父类型),直至Object

小结

  • extends 可用于的返回类型限定,不能用于参数类型限定

  • super 可用于参数类型限定,不能用于返回类型限定

  • 带有super超类型限定的通配符可以向泛型对易用写入,带有extends子类型限定的通配符可以向泛型对象读取

泛型嵌套

  • 声明:嵌套使用泛型

A<B<C>> a = new A<B<C>>();

  • 使用:从外到内,一层层拆分
public class Lorinda<T> {

    T stu;

    public static void main(String[] args) {

        Lorinda<Student<String>> lorinda = new Lorinda<Student<String>>();

        lorinda.stu = new Student<String>();

        Student<String> stu = lorinda.stu;

        String score = stu.score;

        System.out.println(score);

    }

}

泛型与数组

  • 没有泛型数组,不能创建泛型数组

  • 不支持的原因

List<String>[] lsa = new List<String>[10]; // Not really allowed.  
Object o = lsa;  
Object[] oa = (Object[]) o;  
List<Integer> li = new ArrayList<Integer>();  
li.add(new Integer(3));  
oa[1] = li; // Unsound, but passes run time store check  
String s = lsa[1].get(0); // Run-time error: ClassCastException.  

这种情况下,由于JVM泛型的擦除机制,在运行时JVM是不知道泛型信息的,所以可以给oa[1]赋上一个ArrayList而不会出现ArrayStoreException,但是在取出数据的时候却要做一次类型转换,所以就会出现ClassCastException,如果可以进行泛型数组的声明,上面说的这种情况在编译期将不会出现任何的警告和错误,只有在运行时才会出错。而对泛型数组的声明进行限制,对于这样的情况,可以在编译期提示代码有类型安全问题,比没有任何提示要强很多。

基于以上的原因,Java不支持声明泛型数组,更确切地表达是:数组的类型不可以是类型变量,除非是采用通配符的方式,看下面这个例子:

List<?>[] lsa = new List<?>[10]; // OK, array of unbounded wildcard type.  
Object o = lsa;  
Object[] oa = (Object[]) o;  
List<Integer> li = new ArrayList<Integer>();  
li.add(new Integer(3));  
oa[1] = li; // Correct.  
String s = (String) lsa[1].get(0); // Run time error, but cast is explicit.  

因为对于通配符的方式,最后取出数据是要做显式的类型转换的,所以并不会存在上一个例子的问题

可以这样(ArrayList就和这个类似):

public class Array {

    public static void main(String[] args) {
        MyArrayList<String> strList = new MyArrayList<String>();

        strList.add(0, "a");

        String elem = strList.getElem(0);

        System.out.println(elem);

    }

}

class MyArrayList<E>{

    Object[] cap = new Object[10];

    public void add(int idx,E e){
        cap[idx] = e;
    }

    @SuppressWarnings("unchecked")
    public E[] getAll() {
        return (E[]) cap;
    }

    @SuppressWarnings("unchecked")
    public E getElem(int idx){
        return (E) cap[idx];
    }

}
  • 可以只有声明,可以使用?

  • A<String>[] a1 = null;

  • A<?>[] a2 = new A<?>[10]

JDK7泛型的改进

  • 声明时指定泛型即可,创建对象不用再次编写类型

  • A<String> a = new A<>();