Java自定义泛型深入
子(实现)类
-
子类与父类|接口一样使用泛型
-
子类指定具体的类型
-
子类与父类|接口同时擦除类型
-
子类泛型,父类|接口 擦除
-
错误:不能子类擦除 父类|接口泛型
擦除统一按照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
基于以上的原因,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<>();