泛型实现了参数化类型的概念,使代码可以应用于多种类型
在创建参数化类型的一个实例的时候,编译器会自动转型,保证类型的正确性
简单泛型
class Automobile{}public class Holder1 {private Automobile a;public Holder1(Automobile a){this.a = a;}Automobile get(){ //这个类无法持有其他任何类型的对象return a;}}
public class Holder2 {private Object a;public Holder2(Object a){this.a = a;}public void set(Object a){this.a = a;}public Object get(){return a;}public static void main(String[] args) {final Holder2 h2 = new Holder2(new Automobile());Automobile a = (Automobile) h2.get();h2.set("Not an Automobile");String s = (String) h2.get();System.out.println(s);h2.set(1);Integer i = (Integer) h2.get(); //存储了三种不同类型的对象System.out.println(i);}}
泛型的只要目的之一就是用来指定容器要持有什么类型的对象
暂时不指定具体类型,稍后再决定具体使用什么类型
public class Holder3 <T>{private T a;public Holder3(T a) {this.a = a;}public void set(T a){this.a = a;}public T get(){return a;}public static void main(String[] args) {Holder3<Automobile> h3 = new Holder3<Automobile>(new Automobile());//此时只可以存入Automobile类型的参数Automobile a = h3.get();}}
堆栈类
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<>(); // 末端哨兵,判断何时为空public void push(T item) {// 向栈中压入新的元素时,top会指向新进来的元素top = new Node<>(item, top);}public T pop() {//取出元素时,如果不是最后一个元素,那么这个top会指向本来top元素指向的下一个元素T result = top.item;if (!top.end()) {top = top.next;}return result;}public static void main(String[] args) {final LinkedStack<String> lss = new LinkedStack<>();for (String s : "Phasers or stun".split(" ")) {lss.push(s);}String s;while ((s = lss.pop()) != null) {System.out.println(s);}}}
RandomList
假设需要一个持有特定类型的对象列表,每次调用它的select方法的时候,都可以随机选取一个元素
public class RandomList<T> {private ArrayList<T> storage = new ArrayList<>();private Random rand = new Random(47);public void add(T item){ //向容器中添加元素storage.add(item);}public T select(){ //调用这个方法时会从容器容器中随机读取元素return storage.get(rand.nextInt(storage.size())); //获取边界值}public static void main(String[] args) {RandomList<String> rs = new RandomList<>();for (String s : ("take the way home").split(" ")) {rs.add(s); //将字符串添加到集合中}for (int i = 0; i < 4; i++) {System.out.print(rs.select() + " ");}}}
泛型接口
泛型也可以应用于接口(譬如生成器(generator)),这是一个专门负责创建对象的类,这也是工厂设计的一种模式,但是使用生成器创建对象的时候,不需要任何的参数,工厂方法一般是需要参数的。
生成器不需要任何的额外信息就知道如何创建新的对象。
public class CoffeeGenerator implements Generator<Coffee>{private Class[] types = {Americano.class, Breve.class, Cappuccino.class, Latte.class, Mocha.class};private Random rand = new Random(47);public CoffeeGenerator(){}@Overridepublic Coffee next() { //用生成器来随机的创建实例try {return (Coffee) types[rand.nextInt(types.length)].newInstance();//必须确定返回值是参数的类型} catch (Exception e) {throw new RuntimeException();}}public static void main(String[] args) {final CoffeeGenerator gen = new CoffeeGenerator();for (int i = 0; i < 5; i++) {System.out.println(gen.next());}} //并没有知道什么具体的信息,也可以用迭代器来实现}
使用生成器创建斐波那契数列
public class Fibonacci implements Generator<Integer> {private int count = 0;@Overridepublic Integer next() {return fib(count++);}private int fib(int n){return (n < 2 ? 1 : (fib(n - 2) + fib(n - 1)));}public static void main(String[] args) {final Fibonacci gen = new Fibonacci();for (int i = 0; i < 18; i++) {System.out.print(gen.next() + " ");}}}
Java泛型的局限性:基本类型无法作为类型参数
使用适配器:
public class IterableFibonacci extends Fibonacci implements Iterable<Integer>{private int n ;public IterableFibonacci(int count){n = count;}@Overridepublic Iterator<Integer> iterator() {return new Iterator<Integer>() {@Overridepublic boolean hasNext() {return n > 0;}@Overridepublic Integer next() {n--;return IterableFibonacci.this.next();}};}public static void main(String[] args) {for (Integer integer : new IterableFibonacci(18)) {System.out.print(integer + " ");}}}
泛型方法
泛型可以用在方法上,并且所在的类可以不是泛型类,是否拥有泛型方法,和是不是泛型类没有关系
对于一个static的方法,无法访问泛型类的类型参数,所以,如果static使用泛型的能力,就必须让他称为泛型方法
定义泛型方法,只需要的方法前面放泛型参数列表
public class GenericMethods {public <T> void f(T t){ //方法前面加泛型列表System.out.println(t.getClass().getName());}public static void main(String[] args) {final GenericMethods gen = new GenericMethods();gen.f("hah");gen.f(1);gen.f(1.0);gen.f('t');gen.f(1.0F);}}
杠杆利用类型参数推断
编写一个工具类,包含各种各样的static方法,专门用来创建各种常用的容器对象
public class New {public static <K,V> Map<K,V> map(){return new HashMap<K,V>();}public static <T> List<T> list(){return new ArrayList<>();}public static <T> LinkedList<T> lList(){return new LinkedList<>();}public static <T> Set<T> set(){return new HashSet<>();}public static <T> Queue<T> queue(){return new LinkedList<>();}public static void main(String[] args) {final Map<String, Integer> objectObjectMap = New.map();final List<String> list = New.list();LinkedList<String> llist = New.lList();final Set<String> set = New.set();final Queue<String> queue = New.queue();}}
可变类型参数和泛型
public class GenericVarargs {public static <T> List<T> makeList(T... args){ //可变参数列表List<T> result = new ArrayList<>();for (T arg : args) {result.add(arg);}return result;}public static void main(String[] args) {List<String> ls = makeList("A");System.out.println(ls);ls = makeList("A","B","C");System.out.println(ls);}}
用于Generators的泛型方法
利用生成器填充Collection
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;}public static void main(String[] args) {Collection<Coffee> coffee = fill(new ArrayList<Coffee>(), new CoffeeGenerator(), 4);for (Coffee c : coffee) {System.out.print(c + " ");}System.out.println();Collection<Integer> integers = fill(new ArrayList<Integer>(), new Fibonacci(), 18);for (Integer integer : integers) {System.out.print(integer + " ");}}}
通用的Generator
public class BasicGenerator<T> implements Generator<T> {private Class<T> type;public BasicGenerator(Class<T> type){this.type = type;}@Overridepublic T next() {try {return type.newInstance();} catch (InstantiationException | IllegalAccessException e) {throw new RuntimeException();}}public static <T> Generator<T> creat(Class<T> type){return new BasicGenerator<T>(type);} //提供了一个基本的实现,用来生成某个类的对象//只需要调用creatfangfa,传想要生成的类型}
public class CountedObject {private static long counter = 0;private final long id = counter++;public long id(){return id;}@Overridepublic String toString() {return "CountedObject" + id;}}
public class BasicGeneratorDemo {public static void main(String[] args) {final Generator<CountedObject> gen = BasicGenerator.creat(CountedObject.class);for (int i = 0; i < 5; i++) {System.out.println(gen.next());}}}
匿名内部类
泛型可以应用于内部类和匿名内部类
class Customer{private static long counter = 1;private final long id = counter ++;private Customer(){}@Overridepublic String toString() {return "Customer " + id + " ";}public static Generator<Customer> generator(){return new Generator<Customer>() { //使用匿名内部类来创建实例@Overridepublic Customer next() {return new Customer();}};}}class Teller{private static long counter = 1;private final long id = counter++;public Teller(){}@Overridepublic String toString() {return "Teller " + id + " ";}public static Generator<Teller> generator = new Generator<Teller>() {@Override //使用局部内部类来创建方法public Teller next() {return new Teller();}};}public class BankTeller {private static void serve(Teller t,Customer c){System.out.println(t + " serves " + c);}public static void main(String[] args) {final Random rand = new Random(47);Queue<Customer> line = new LinkedList<>();Generators.fill(line, Customer.generator(), 15); //利用生成器来创建对象List<Teller> tellers = new ArrayList<>();Generators.fill(tellers,Teller.generator,4);for (Customer customer : line) {serve(tellers.get(rand.nextInt(tellers.size())), customer);//在teller中随机产生一个}}}
构建复杂模型
class Product{private int id;private String description;private double price;public Product(int id, String description, double price) {this.id = id;this.description = description;this.price = price;System.out.println(toString());}@Overridepublic String toString() {return id + ": " + description + ", price: $" + price;}public void priceChange(double change){price += change;}public static Generator<Product> generator = new Generator<Product>() {private Random rand = new Random(47);@Overridepublic Product next() {return new Product(rand.nextInt(1000), "Test",Math.round(rand.nextDouble())*1000+0.99);}};}class Shelf extends ArrayList<Product>{public Shelf(int nProduct){Generators.fill(this,Product.generator,nProduct);}}class Aisle extends ArrayList<Shelf>{public Aisle(int nShelves,int nProduct){for (int i = 0; i < nShelves; i++) {add(new Shelf(nProduct));}}}class CheckoutStand{}class Office{}public class Store extends ArrayList<Aisle>{private ArrayList<CheckoutStand> checkouts = new ArrayList<>();private Office office = new Office();public Store(int nAisle, int nShelves, int nProduct) {for (int i = 0; i < nAisle; i++) {add(new Aisle(nShelves, nProduct));}}@Overridepublic String toString() {final StringBuilder result = new StringBuilder();for (Aisle shelves : this) {for (Shelf shelf : shelves) {for (Product product : shelf) {result.append(product);result.append("\n");}}}return result.toString();}public static void main(String[] args) {final Store aisles = new Store(2, 5, 3);}}
擦除的神秘之处
public class ErasedTypeEquivalence {public static void main(String[] args) {Class c1 = new ArrayList<String>().getClass();Class c2 = new ArrayList<Integer>().getClass();System.out.println(c1 == c2);}}
此时发现输出结果是相等的
class Frob{}class Fnorkle{}class Quark<Q>{}class Particle<POSITION, MOMENTUM>{}public class LostInformation {public static void main(String[] args) {List<Frob> list = new ArrayList<>();Map<Frob, Fnorkle> map = new HashMap<>();Quark<Fnorkle> quark = new Quark<>();Particle<Long, Double> particle = new Particle<>(); //表示由泛型声明所声明的类型参数System.out.println(Arrays.toString(list.getClass().getTypeParameters()));System.out.println(Arrays.toString(map.getClass().getTypeParameters()));System.out.println(Arrays.toString(quark.getClass().getTypeParameters()));System.out.println(Arrays.toString(particle.getClass().getTypeParameters()));}}
发现输出结果中只有用作参数占位符的标识符,说明:
在泛型代码的内部,无法获得任何有关泛型参数类型的信息。无法知道用来创建某个特定实例的实际类型参数
Java的泛型是用擦除实现的,意味着在使用泛型时,任何具体的类型信息都会被擦除,唯一知道的就是正在使用一个对象
public class Manipulation<T> {private T obj;public Manipulation(T x){obj = x;}// public void manipulation(){ 此时找不到f方法,必须使用边界符,告诉编译器只能接受遵循这个边界的类型// obj.f()// }}class Manipulation2<T extends HasF>{ //使用边界符,此时可以使用具体类型的方法private T obj;public Manipulation2(T x){obj = x ;}public void manipulation(){obj.f();}}
当希望代码可以跨多个类工作的时候,使用泛型才有所帮助,
public class RunGenericType<T extends HasF> {private T obj;public RunGenericType(T x){obj = x;}public T get(){ //如果有一个返回T类型的方法,之后会返回确切的类型,//也可以返回它的子类,并且不需要显示的类型转换return obj;}}
迁移兼容性
在基于擦除的实现中,泛型类型都被当做第二类类型处理,就是不能在某些重要的上下文环境中使用。
向List
擦除的核心时他可以使泛化的客户端可以用非泛化的类库来使用,反之亦然,这经常被称为“迁移兼容性”
擦除的问题
泛型不能用于显示的引用运行时类型的操作之中,例如转型,instanceof操作和new表达式,因为所有有关类型的参数信息都丢失了
边界处的动作
public class ArrayMaker<T> {private Class<T> kind;public ArrayMaker(Class<T> kind){//泛型T无法获取Class对象,通过构造器传进去一个Class实例this.kind = kind;}T[] create(int size){return (T[]) Array.newInstance(kind, size); //必须将其转为T类型的数组}public static void main(String[] args) {ArrayMaker<String> stringmaker = new ArrayMaker<>(String.class);String[] stringArray = stringmaker.create(10);System.out.println(Arrays.toString(stringArray));}}
即使kind被存储为Class
在泛型中创建数组,最好使用Array.newInstance
如果创建的时容器不是数组就不同了
public class ListMaker<T> {List<T> create(){return new ArrayList<>();}public static void main(String[] args) {ListMaker<String> stringListMaker = new ListMaker<>();List<String> stringsList = stringListMaker.create();//调用方法来创建容器}}
public class FilledListMaker<T> {List<T> create(T t,int n){List<T> result = new ArrayList<>();for (int i = 0; i < n; i++) {result.add(t);}return result;}public static void main(String[] args) {FilledListMaker<String> stringFilledListMaker = new FilledListMaker<>();List<String> list = stringFilledListMaker.create("Hello" , 4);System.out.println(list);}}
擦除的补偿
擦除丢失了泛型代码中执行某些操作的能力,任何在运行时需要知道确切类型信息的操作都没办法正常工作
public class Erased<T> {private final int SIZE = 100;public static void f(Object arg){ //需要知道确切类型信息的都不能使用//if (arg instanceof T);//T t = new T;//T[] array = new T[SIZE];}}
有时必须引入类型标签Class来对擦除进行补偿,必须显示的传递类型的Class对象
class Building{}class House extends Building{}public class ClassTypeCapture<T> {Class<T> kind;public ClassTypeCapture(Class<T> kind){ //使用Class标签对擦除进行补偿this.kind = kind;}public boolean f(Object arg){return kind.isInstance(arg);}public static void main(String[] args) {final ClassTypeCapture<Building> ctt1 = new ClassTypeCapture<>(Building.class);//传入Class对象System.out.println(ctt1.f(new Building()));System.out.println(ctt1.f(new House()));final ClassTypeCapture<House> ctt2 = new ClassTypeCapture<>(House.class);System.out.println(ctt2.f(new Building()));System.out.println(ctt2.f(new House()));}}
创建类型实例
传递一个工厂对象,并且用它来创建实例,使用类型标签来使用newInstance方法来创建这个类型的新对象
使用newInstance创建某个类的实例的时候,这个类必须有默认的构造器,并且只能运行时发现这个错误
class ClassAsFactory<T>{T x;public ClassAsFactory(Class<T> kind){try {x = kind.newInstance();} catch (Exception e) {throw new RuntimeException();}}}class Employee{}public class InstantiateGenericType {public static void main(String[] args) {final ClassAsFactory<Employee> fe = new ClassAsFactory<>(Employee.class);System.out.println("ClassAsFactory<Employee> succeeded");try {final ClassAsFactory<Integer> fi = new ClassAsFactory<>(Integer.class);//失败的原因时Integer没有默认构造器,并且不是在编译器捕获的}catch (Exception e){System.out.println("失败");}}}
interface FactoryI<T>{T create();}class Foo2<T>{private T x;public Foo2(FactoryI<T> factoryI){x = factoryI.create();}}class IntegerFactory implements FactoryI<Integer>{@Overridepublic Integer create() {return new Integer(0);}}class Widget{public static class Factory implements FactoryI<Widget>{@Overridepublic Widget create() {return new Widget();}}}public class FactoryConstraint {public static void main(String[] args) {new Foo2<Integer>(new IntegerFactory());new Foo2<Widget>(new Widget.Factory());}}
两种方式都创建了工厂对象,第二种时传递Class
还有一种时模板设计模式,在本例中create()是模板方法
abstract class GenericWithCreate<T>{final T element;abstract T create(); //create是模板方法,他在子类中定义,产生子类的对象public GenericWithCreate(){element = create();}}class X{}class Creator extends GenericWithCreate<X>{@OverrideX create() {return new X();}void f(){System.out.println(element.getClass().getSimpleName());}}public class CreatorGeneric {public static void main(String[] args) {final Creator creator = new Creator();creator.f();}}
泛型数组
泛型数组不能创建,一般是在创建泛型数组的地方使用ArrayList
public class ListOfGenerics <T>{private List<T> list = new ArrayList<>();public void add(T item){list.add(item);}public T get(int index){return list.get(index);}}
成功创建泛型数组的唯一方式就是创建一个被擦除的类型的新数组,然后对其转型。
public class GenericArray<T> {private T[] array;public GenericArray(int size){array = (T[]) new Object[size];}public void put(int index,T item){array[index] = item;}public T get(int index){return array[index];}public T[] rep(){ //实际运行时的类型时Objectreturn array;}public static void main(String[] args) {final GenericArray<Integer> gai = new GenericArray<>(10);Object[] o = gai.rep();//并不能直接声明T[] array = new T[size],所以要创建一个对象//数组,然后将他转型}
因为擦除,所以数组运行时的类型时Object类型的
可以利用反射来创建具体的实例,将Class
public class GenericArrayWithTypeToken<T> {private T[] array;public GenericArrayWithTypeToken(Class<T> type , int size){array = (T[]) Array.newInstance(type, size);//利用反射来创建实例}public void put(int index,T item){array[index] = item;}public T get(int index){return array[index];}public T[] rep(){return array;}public static void main(String[] args) {final GenericArrayWithTypeToken<Integer> gai = new GenericArrayWithTypeToken<Integer>(Integer.class,10);Integer[] ia = gai.rep();}}
边界
边界可以用于泛型的参数类型上设置条件。并且一个更重要的效果使可以按照自己的边界类型来调用方法
class HoldItem<T>{T item;HoldItem(T item){this.item = item;}T getItem(){return item;}}class Colored2 <T extends HasColor> extends HoldItem<T>{Colored2(T item){super(item);}java.awt.Color color(){return item.getColor();}}//具体的类要在前面class ColoredDimension2<T extends Dimension & HasColor > extends Colored2<T>{//这里继承了Colored2,没有重写,但是仍有这个方法ColoredDimension2(T item){super(item);}int getX(){return item.x;}int getY(){return item.y;}int getZ(){return item.z;}}class Solid2 <T extends Dimension & HasColor & Weight> extends ColoredDimension2{Solid2(T item) {super(item);}}public class InheritBounds {public static void main(String[] args) {final Solid2<Bound> solid2 = new Solid2<>(new Bound());solid2.getX();solid2.getY();solid2.getZ();solid2.color();}}
interface SuperPower{}interface XRayVision extends SuperPower{void seeThroughWalls();}interface SuperHearing extends SuperPower{void hearSubtleNoises();}interface SuperSmell extends SuperPower{void trackBySmell();}class SuperHero<POWER extends SuperPower>{POWER power;SuperHero(POWER power){this.power = power;}POWER getPower(){return power;}}class SuperSleuth<POWER extends XRayVision> extends SuperHero<POWER>{SuperSleuth(POWER power){super(power);}}class CanineHero<POWER extends SuperHearing & SuperSmell> extends SuperHero<POWER>{//限定了superhear和supersmellCanineHero(POWER power){super(power);}void hear(){power.hearSubtleNoises();}void smell(){power.trackBySmell();}}class SuperHearSmell implements SuperHearing,SuperSmell{//实现了SuperHearing和SuperSmell,建立起了联系@Overridepublic void hearSubtleNoises() {}@Overridepublic void trackBySmell() {}}class DogBoy extends CanineHero<SuperHearSmell>{DogBoy(){super(new SuperHearSmell());}}public class EpicBattle {static <POWER extends SuperHearing> void usrSuperHearing (SuperHero<POWER> hero){hero.getPower().hearSubtleNoises();}static <POWER extends SuperHearing & SuperSmell> void superFind(SuperHero<POWER> hero){hero.getPower().hearSubtleNoises();hero.getPower().trackBySmell();}public static void main(String[] args) {final DogBoy dogBoy = new DogBoy();usrSuperHearing(dogBoy);superFind(dogBoy);}}
通配符
向导出类数组中加入基类类型的引用
class Fruit{}class Apple extends Fruit{}class Orange extends Fruit{}class Jonathan extends Apple{}public class CovariantArrays {public static void main(String[] args) {Fruit[] fruits = new Apple[10];//此时的数组类型是Apple类型的,只可以向里面放入//Apple类型或者其子类型,如果插入fruits编译器不会报错//但是运行起来就会报错fruits[0] = new Apple();fruits[1] = new Jonathan();try {fruits[0] = new Fruit();}catch (Exception e){System.out.println(e);}try {fruits[0] = new Orange();}catch (Exception e){System.out.println(e);}}}
泛型的目标之一就是将这种错误检测给他弄到编译期
public class GenericAndCovariance {public static void main(String[] args) {List<? extends Fruit> flist = new ArrayList<Apple>();//flist.add(new Apple());flist.add(null);System.out.println(flist.get(0));}}
使用了<? extands Fruit> 发现不能使用容器的方法,只能使用Object的方法
public class CompilerIntelligence {public static void main(String[] args) {List<? extends Fruit> flist = Arrays.asList(new Apple());Apple a = (Apple) flist.get(0);flist.contains(new Apple());//允许调用,是因为这两个方法的参数是Objectflist.indexOf(0);}}
超类型通配符
<? super MyClass> MyClass的子类
public class SuperTypeWIldCards {static void writeTo(List<? super Apple> apples){apples.add(new Apple());apples.add(new Jonathan());//apples.add(new Fruit());//Fruit不是Apple的子类}}
public class GenericWriting {static <T> void writeExact(List<T> list , T item){list.add(item);}static List<Apple> apples = new ArrayList<>();static List<Fruit> fruits = new ArrayList<>();static void f1(){writeExact(apples,new Apple());} //前面的<T>代表了参数类型static <T> void writeWithWildcard(List<? super T> list , T item){list.add(item);//超类型通配符可以用泛型方法}static void f2(){//确定了容器的类型后,就只能持有他或这它的子类了writeWithWildcard(apples, new Jonathan());writeWithWildcard(fruits, new Fruit());}public static void main(String[] args) {f1();f2();}}
无界通配符
<?> 意味着任何事物
public class UnboundedWildcards {static List list1;static List<?> list2;static List<? extends Object> list3;static void assign1(List list){list1 = list;list2 = list;//list3 = list;}static void assign2(List<?> list){list1 = list;list2 = list;list3 = list;}static void assign3(List<? extends Object> list){list1 = list;list2 = list;list3 = list;}public static void main(String[] args) {assign1(new ArrayList<>());assign2(new ArrayList<>());assign3(new ArrayList<>());assign1(new ArrayList<String>());assign2(new ArrayList<String>());assign3(new ArrayList<String>());}}
public class UnboundedWildcard2 {static Map map1;static Map<?,?> map2;static Map<String,?> map3;static void assign1(Map map){map1 = map;}static void assign2(Map<?,?> map){map2 = map;}static void assign3(Map<String,?> map){map3 = map;}public static void main(String[] args) {assign1(new HashMap());assign2(new HashMap());assign3(new HashMap());assign1(new HashMap<String,Integer>());assign2(new HashMap<String,Integer>());assign3(new HashMap<String,Integer>());}}
List表示“持有任何Object类型的List”,List<?>表示“持有某种特定类型的”List,只是不知道是什么类型
转型和警告
class FixedSizeStack<T>{private int index =0;private Object[] storage;public FixedSizeStack(int size){storage = new Object[size];//存储是将值都转换成为Object}public void push(T item){storage[index++] = item;}public T pop(){return (T) storage[--index];//取出时转换称为T类型的}}public class GenericCast {public static final int SIZE = 7;public static void main(String[] args) {final FixedSizeStack<String> strings = new FixedSizeStack<>(SIZE);for (String s : "A B C D E F G".split(" ")) {strings.push(s);}for (int i = 0; i < SIZE; i++) {String s = strings.pop();System.out.print(s + " ");}}}
基类劫持接口(基类限定接口中的类型参数)
public class ComparablePet implements Comparable<ComparablePet>{@Overridepublic int compareTo(ComparablePet arg) {return 0;}}class Cat extends ComparablePet implements Comparable<Cat>{//一旦基类Comparabel确定了ComparablePet,那么其他任何的实现类都不能和他定义的之外的对象作比较,即使时它的子类也不可以public int compareTo(Cat cat){return 0;}}
class Hamster extends ComparablePet implements Comparable<ComparablePet>{@Overridepublic int compareTo(ComparablePet arg) {return super.compareTo(arg);}}
自限定的类型
循环泛型
不能直接继承一个泛型参数,可以继承在自己的定义中使用这个泛型参数的类
class GenericType<T>{}public class CuriouslyRecurringGeneric extends GenericType<CuriouslyRecurringGeneric>{}
java中的泛型关乎参数和返回类型,因此他能产生使用子类作为其参数和返回类型的基类,还能将导出类用作其域类型,甚至是那些被擦除为Object的类型
public class BasicHolder<T> {T element;void set(T arg){element = arg;}T get(){return element;}void f(){System.out.println(element.getClass().getSimpleName());}}class Subtype extends BasicHolder<Subtype>{} //public class CRGWithBasicHolder {public static void main(String[] args) {final Subtype st1 = new Subtype(), st2 = new Subtype();st1.set(st2);//新类Subtype接受的参数和返回值具有Subtype类型不仅仅是他的基类的类型Subtype st3 = st1.get();st1.f();}}
CRG的本质:基类使用其导出类,泛型基类编程了一种所有导出类的公共功能的模板,他的参数和返回值都是导出类类型,在所产生的类中会使用确切的类型,而不是基类类型
自限定
class SelfBounded<T extends SelfBounded>{T element;SelfBounded <T> set(T arg){element = arg;return this;}T get(){return element;}}class A extends SelfBounded<A>{} //这种定义方式就是自限定class B extends SelfBounded<A>{} //这样也是可以的class C extends SelfBounded<C>{C setAndGet(C arg){set(arg);return arg;}}class D{}class E extends SelfBounded<D>{}//此时这个类是不能编译的class F extends SelfBounded{};public class SelfBounding {public static void main(String[] args) {A a = new A();a.set(new A());a = a.set(new A()).get();a = a.get();C c = new C();c = c.setAndGet(new C());}}
自限定参数可以保证类型参数与正在定义的类相同
如果去掉自限定限制也是可以的
class SelfBounded<T>{T element;SelfBounded <T> set(T arg){element = arg;return this;}T get(){return element;}}class A extends SelfBounded<A>{}class B extends SelfBounded<A>{}class C extends SelfBounded<C>{C setAndGet(C arg){set(arg);return arg;}}class D{}class E extends SelfBounded<D>{}//这个时候这个类是可以编译的class F extends SelfBounded{};
参数协变
自限定类型的价值是:可以产生协变参数类型(方法中的参数类型会随着子类而变化)
class Base{}class Derived extends Base{}interface OrdinaryGetter{Base get();}interface DerivedGetter extends OrdinaryGetter{//覆盖了从他继承过来的接口中的get方法,返回的也是从Base中导出的类型Derived get();}public class CovariantReturnTypes {void test(DerivedGetter d){Derived d2 = d.get();}}
在非泛型代码中,参数类型不能随着子类型发生变化
class OrdinarySetter{void set(Base base){System.out.println("OrdinarySetter.set");}}class DerivedSetter extends OrdinarySetter{void set(Derived derived){System.out.println("DerivedSetter.set");}}public class OrdinaryArguments {public static void main(String[] args) {final Base base = new Base();final Derived derived = new Derived();final DerivedSetter derivedSetter = new DerivedSetter();//方法都是子类的方法derivedSetter.set(derived);derivedSetter.set(base);//调用的仍然是父类的方法}}
混型
最基本的概念是混合多个类的能力,产生一个可以表示混型中所有类型的类
在混型中修改东西,这些东西会应用在混型中所有的类型之上
与接口混合
interface TimeStamped{long getStamp();}class TimeStampedImp implements TimeStamped{private final long timeStamp;public TimeStampedImp(){timeStamp = new Date().getTime();}@Overridepublic long getStamp() {return timeStamp;}}interface SerialNumbered {long getSerialNumber();}class SerialNumberedImp implements SerialNumbered{private static long counter = 1;private final long serialNumber = counter++;@Overridepublic long getSerialNumber() {return serialNumber;}}interface Basic{public void set(String val);public String get();}class BasicImp implements Basic{private String value;@Overridepublic void set(String val) {value = val;}@Overridepublic String get() {return value;}}class Mixin extends BasicImp implements TimeStamped,SerialNumbered{//继承了一个实现类,并且实现了两个接口,混合了多个类的能力private TimeStamped timeStamp = new TimeStampedImp();private SerialNumbered serialNumber = new SerialNumberedImp();@Overridepublic long getStamp() {return timeStamp.getStamp();//调用的是TimeStampedImp中的getStamp方法}@Overridepublic long getSerialNumber() {return serialNumber.getSerialNumber();////调用的是SerialNumberedImp中的getSerialNumber方法}}public class Mixins {public static void main(String[] args) {final Mixin mixin1 = new Mixin();final Mixin mixin2 = new Mixin();mixin1.set("test String1");mixin2.set("test String2");System.out.println(mixin1.get() + " " + mixin1.getStamp() + " " + mixin1.getSerialNumber());System.out.println(mixin2.get() + " " + mixin2.getStamp() + " " + mixin2.getSerialNumber());}}
装饰器模式
装饰器模式使用分层对象来动态的透明的向单个对象中添加责任,装饰器是通过组合和形式化接口实现的,而混型是基于继承的
class Basic1{private String value;public void set(String value){this.value = value;}public String get(){return value;}}class Decorator extends Basic1{protected Basic1 basic1;public Decorator(Basic1 basic1){this.basic1 = basic1;}public void set(String val){basic1.set(val);}public String get(){return basic1.get();}}class TimeStamped1 extends Decorator{private final long timeStamp;public TimeStamped1(Basic1 basic1){super(basic1);timeStamp = new Date().getTime();}public long getStamp(){return timeStamp;}}class SerialNumbered1 extends Decorator{private static long counter = 1;private final long serialNumber = counter++;public SerialNumbered1(Basic1 basic1) {super(basic1);}public long getSerialNumber(){return serialNumber;}}public class Decoration {public static void main(String[] args) {final TimeStamped1 t = new TimeStamped1(new Basic1());final TimeStamped1 t2 = new TimeStamped1(new SerialNumbered1(new Basic1()));SerialNumbered1 s = new SerialNumbered1(new Basic1());final SerialNumbered1 s2 = new SerialNumbered1(new TimeStamped1(new Basic1()));}}
与动态代理混合
class MixinProxy implements InvocationHandler{Map<String,Object> delegatesByMethod; //方法名和方法所属对象public MixinProxy(TwoTuple<Object,Class<?>>...pairs) {delegatesByMethod = new HashMap<String, Object>();for (TwoTuple<Object, Class<?>> pair : pairs) { //将方法名和Object对应起来for (Method method : pair.second.getMethods()) { //将参数循环遍历String methodName = method.getName();if (! delegatesByMethod.containsKey(methodName)){ //如果没有他的方法名字,就把他加进去delegatesByMethod.put(methodName,pair.first);}}}}@Overridepublic Object invoke(Object proxy, Method method, Object[] args) throws Throwable {String methodName = method.getName(); //代表外部要去执行的方法的名字Object delegate = delegatesByMethod.get(methodName); //代表目标方法的代理者或者说执行者return method.invoke(methodName, args);//根据方法名去调用外部的方法 ,利用反射。}public static Object newInstance(TwoTuple... pairs){Class[] interfaces = new Class[pairs.length]; //产生代理对象for (int i = 0; i < pairs.length; i++) {interfaces[i] = (Class) pairs[i].second;}ClassLoader cl = pairs[0].first.getClass().getClassLoader();return Proxy.newProxyInstance(cl,interfaces,new MixinProxy(pairs));}}public class DynamicProxyMixin {}
