java chapter 8 泛型编程

class ArrayAlg{
  public static <T> T getMiddle(T... a){
    return a[a.length/2];
  }
}

String middle=ArrayAlg.<String>getMiddle("John","q","Public");

限定泛型
public static <T extends Comparable> T min(T[] a)

T extends Comparable & Serializable

8.6.2 运行时类型仅仅在未加工类型中工作
if(a instanceof Pair)//ERROR
只能检测a是否是任意类型的Pair
if(a instanceof Pair)//ERROR

Pair<String> stringpair=...;
Pair<Employee> employeePair=...;
if(stringPair.getClass()==employeePair.getClass()//相等

getClass方法始终返回未加工类型。
8.6.3
你不能实例化参数化类型的数组
var table=new Pair<String>[10];//ERROR
不能实例化的原因是擦除后,table的类型是Pair[],你可以转换为Object

Object[] objarray=table;
objarray[0]="Hello";//ERROR 类型是Pair

8.6.4 Varargs警告
Java不支持泛型类的数组

8.6.5 你不能实例化类型变量
你不能使用new T(...) 下列代码是非法的
public Pair(){first=new T();second =new T();}//ERROR

JAVA 8后,你可以提供一个构造函数

Pair<String> p=Pair.makePair(String::new);

public static<T> Pair<T> makePair(Supplier<T> constr){
  return new Pair<>(constr.get(),constr.get());
}

更传统的做法是使用反射.

不幸的是,这有一些复杂。你不能直接使用:
first=T.class.getConstructor().newInstance();//ERROR

你可以使用

public static <T> Pair<T> makePair(Class<T> cl){
  try{
      return new Pair<>(cl.getConstructor().newInstance(),cl.getConstructor().newInstance());
  }
catch(Exception e){return null;}
}

Pair<String> p=Pair.makePair(String::class);

8.6.6 你不能构造泛型数组
数组会被填充Null值。这是为了构造的安全。但数组也有类型,虚拟机会用来监测数组存储。而它的类型是被擦去的。例

public static <T extends Comparable> T[] minmax(T...a){
  T[] mm=new T[2];//ERROR
}

类型擦去会导致你构造了一个数组Comparable[2]

如果数组只被用于一个类的私有实例中,你可以使用类型转换

public class ArrayList<E>{
  private Object[] elements;

  @SuppressWarnings("unchecked")
  public E get(int n){
    return (E) elements[n];
  }
  public void set(int n,E e){
    elements[n]=e;//no cast needed
  }
}

上面最大值最小值的错误实例我们可以添加一个数组的构造函数

String[] names=ArrayAlg.minmax(String[]::new ,"Tom","Dick","Harry);

public static <T extends Comparable> T[] minmax(IntFunction<T[]>constr,T...a){
    T[] result=constr.apply(2);
      ...
}

8.6.7类型变量在泛型类中不允许使用静态上下文
你不能引用静态变量和方法

public class Singleton<T>{
  private static T singleInstance;//ERROR
  
  public static T getSingleInstance(){//Error
    if(singleInstance==null)construct new instance of T
    return singleInstance;
  }
}

8.6.8 你不能抛出或捕获泛型类的异常
泛型类不能抛出或捕获异常,甚至不能继承Throwable
public class Problem extends Exception{}//ERROR can't extend Throwable

你也不能使用类型变量在catch语句中。

public static <T extends Throwable> void doWork(Class<T> t){
    try{
          do work
    }
  catch(T e){//ERROR can't catch type variable
    Logger.global.info(...);
  }
}

但是你可以正常使用类型变量在异常中,下述代码合法

public static <T extends Throwable> void doWork(T t) throws T
{
   try{
          do work
    }
  catch(Throwable realCause){
    t.initCause(realCause);
    throw t;
  }
}

8.6.9 你不能打败检验异常的检验

8.7泛型的继承规则

Pair是Pair的子类吗?
答案是否定的,
Pair buddies=new Pair(ceo,cfo);//illegal
一般来言,Pair 与Pair无关,无论S 和T的关系。

泛型类可以扩展或者实现其他泛型类。ArrayList实现了接口List
但ArrayList和ArrayList无关,和List也无关
8.8 通配符类型
8.8.1通配符概念
通配符类型,参数类型可以改变
Pair<? extends Employee>
标记任何Pair类型的泛型,都必须是Employee的子类。如Pair,反例Pair则不是。
你想要打印Employee的Pair值,实现如下:

public static void printBuddies(Pair<Employee> p){
  Employee first=p.getFirst();
  Employee second=p.getSecond();
  System.out.println(first.getName()+second.getName());
}

前面讨论过,你不能传递Pair到这个方法。解决方法使用通配符类型
public static void printBuddies(Pair<? extends Employee> p)

8.8.2通配符的超类型绑定
? super Manager
这个通配符被局限于任何Manager的超类。
通配符的超类绑定允许你对一个泛型对象写操作,通配符的子类绑定允许你对泛型对象读操作。

posted @ 2025-03-05 16:42  zhongta  阅读(6)  评论(0)    收藏  举报