2014.2.12 Java 泛型

本文深入探讨Java泛型的基础概念,包括泛型类、接口、方法的定义与使用,以及泛型擦除、类型参数边界、通配符等高级特性。同时介绍了泛型在集合框架中的应用。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

* 泛型实现了参数化类型的概念,类型参数;

* Java泛型的局限性:基本类型无法作为类型参数(但是有自动打包/拆包功能);

* 只有知道了某个技术不能做到什么,你才能更好的做到所能做的;

元组:将一组对象直接打包存储于其中的一个单一对象,数据传送对象/信使;

public class TwoTuple<A,B> {
  public final A first;
  public final B second;
  public TwoTuple(A a, B b) { first = a; second = b; }
  public String toString() {
    return "(" + first + ", " + second + ")";
  }
}

* public final保证了成员变量可以被访问,但是不允许修改。

* 可以编写泛型方法,通过重载方法简化元组的使用;

堆栈类:

public class LinkedStack<T> {
  private static class Node<U> {
    U item;
    Node<U> next;
    Node() { item = null; next = null; }
    Node(U item, Node<U> next) {
      this.item = item;
      this.next = next;
    }
    boolean end() { return item == null && next == null; }
  }
  private Node<T> top = new Node<T>(); // End sentinel,末端哨兵
  public void push(T item) {
    top = new Node<T>(item, top);
  }	
  public T pop() {
    T result = top.item;
    if(!top.end())
      top = top.next;
    return result;
  }
}
* 末端哨兵来判断堆栈何时为空;

泛型接口:

* 生成器,Generator<T>,协变返回类型;

public interface Generator<T> { T next(); } 

public class Generators {
  public static <T> Collection<T>
  fill(Collection<T> coll, Generator<T> gen, int n) {
    for(int i = 0; i < n; i++)
      coll.add(gen.next());
    return coll;
  }	
}

* Iterator<E>接口,实现foreach;

boolean hasNext();

E next();

void remove();

* Iterable<T>接口;

Iterator<T> iterator();

class CoffeeIterator implements Iterator<Coffee> {
  int count = size;
  public boolean hasNext() { return count > 0; }
  public Coffee next() {
    count--;
    return CoffeeGenerator.this.next();
  }
  public void remove() { // Not implemented
    throw new UnsupportedOperationException();
  }	
  public Iterator<Coffee> iterator() {
  return new CoffeeIterator();
}

泛型方法:是否拥有泛型方法,与所在类是否是泛型没有关系;

public static <T> void f(T x){  //…; }

* 泛型方法有类型参数推断的能力,所以尽可能的使用泛型方法,而不是泛型类或者接口,类型推断只对赋值操作有效,其他时候不起作用;

* 显式的类型说明:New.<Person, List<pet>>map(),static方法需要在点操作符之前加上类名,编写非赋值语句的时候使用;

擦除:是一种保证迁移兼容性的折中,从非泛化代码到泛化代码的转变过程,以及在不破坏现有类库的情况下,将泛型融入Java语言(语言设计者的短视)

* 在Java泛型代码内部,无法获得任何有关泛型类型参数的信息;

* C++中,模版被实例化时,模版代码知道其模版参数的类型;

* Java中,类型参数将擦除到第一个边界,通过控制边界,实现类型参数的方法调用;

interface A{ void f(); }

class C <T extends A>{
	T t;
	void set(T t){
		this.t=t;
	}
	void g(){
		t.f();
	}
}

class B implements A{
	void f(){
	// ... ;
	}
}

C<B> c=new C<B>();
* 边界:对象进入和离开方法的地点,发生动作的地方;

* 擦除导致任何在运行时需要知道确切类型信息的操作都将无法工作,默认构造器无法使用;引入类型标签来补偿;

模版方法设计模式:实现泛型内的默认构造器;

abstract class GenericWithCreate<T> {
  final T element;
  GenericWithCreate() { element = create(); }
  abstract T create();
}
泛型数组:

* 成功创建泛型数组的唯一方式就是创建一个被擦除类型的新数组,然后进行转型;

public class GenericArray<T> {
  private T[] array;
  @SuppressWarnings("unchecked")
  public GenericArray(int sz) {
    array = (T[])new Object[sz];
  }
  public void put(int index, T item) {
    array[index] = item;
  }
  public T get(int index) { return array[index]; }
  // Method that exposes the underlying representation:
  public T[] rep() { return array; }	
}
* 没有任何方式能修改底层的数组类型,只能是Object [];

边界:

* 多边界 <T extends A & B & C>;

通配符:

* Fruit引用Apple类型的数组,可以加入Fruit和Orange对象,通过编译器检查,但是会抛出运行时异常;

* 根据如何能向一个泛型类型“写入”,以及从一个泛型类型“读取”思考子类型和超类型边界;

* 协变<? extends T>:不允许任何接受这个类型参数为参数的方法的调用;允许任何将产生具有这个类型参数的返回值的方法的调用;

* 逆变<? super T>:允许任何接受这个类型参数为参数的方法的调用;不允许任何将产生具有这个类型参数的返回值的方法的调用;

* 无界通配符:List<?>表示具有某种特定类型的非原生List;List表示持有任何Object类型的原生List;

* 使用通配符或者确定类型的原则:是否想要从泛型参数中返回类型确定的返回值或者是否想要向泛型参数传递类型确定的参数;

* 捕获转换:

  static <T> void f1(Holder<T> holder) {
    T t = holder.get();
    System.out.println(t.getClass().getSimpleName());
  }
  static void f2(Holder<?> holder) {
    f1(holder); // Call with captured type
  }	

自限定类型:

* 循环泛型(CRG):基类用到处累替代其参数;

* 自限定:强制泛型当作其自己边界参数使用,保证类型参数必须与正在被定义的类相同,实现协变参数类型;

class SelfBounded<T extends SelfBounded<T>>{ }

class A extends SelfBounded<A>{ }
泛型中的异常:

interface A<T, E extends Exception>{
	void f() throws E;
}
混型:

* 代理设计模式实现:

interface A{ void f(); }

class Aimplements implements A{ void f(){ ...; } }

class B implements A{
	Aimplements a=new Aimplements();
	void f(){ a.f(); };
}

* 装饰器设计模式实现;

潜在类型机制:

* 利用反射实现:

public static void perform(Object obj){
	Class<?> c=obj.getClass();
	try{
		Method m=c.getMethod("speak");
		m.invoke(obj)
	} catch (NoSuchMethodException e){
		// ... ;
	}
}
* 利用泛型实现:需要实际类也要实现Performs,有限制;

interface Performs{
	void speak();
}

public static <T extends Performs> void perform(T t){
	t.speak();
}



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值