泛型实现了参数化类型的概念,使代码可以应用于多种类型
在创建参数化类型的一个实例的时候,编译器会自动转型,保证类型的正确性

简单泛型

  1. class Automobile{}
  2. public class Holder1 {
  3. private Automobile a;
  4. public Holder1(Automobile a){
  5. this.a = a;
  6. }
  7. Automobile get(){ //这个类无法持有其他任何类型的对象
  8. return a;
  9. }
  10. }
  1. public class Holder2 {
  2. private Object a;
  3. public Holder2(Object a){
  4. this.a = a;
  5. }
  6. public void set(Object a){
  7. this.a = a;
  8. }
  9. public Object get(){
  10. return a;
  11. }
  12. public static void main(String[] args) {
  13. final Holder2 h2 = new Holder2(new Automobile());
  14. Automobile a = (Automobile) h2.get();
  15. h2.set("Not an Automobile");
  16. String s = (String) h2.get();
  17. System.out.println(s);
  18. h2.set(1);
  19. Integer i = (Integer) h2.get(); //存储了三种不同类型的对象
  20. System.out.println(i);
  21. }
  22. }

泛型的只要目的之一就是用来指定容器要持有什么类型的对象
暂时不指定具体类型,稍后再决定具体使用什么类型

  1. public class Holder3 <T>{
  2. private T a;
  3. public Holder3(T a) {
  4. this.a = a;
  5. }
  6. public void set(T a){
  7. this.a = a;
  8. }
  9. public T get(){
  10. return a;
  11. }
  12. public static void main(String[] args) {
  13. Holder3<Automobile> h3 = new Holder3<Automobile>(new Automobile());
  14. //此时只可以存入Automobile类型的参数
  15. Automobile a = h3.get();
  16. }
  17. }

堆栈类

  1. public class LinkedStack<T> {
  2. private static class Node<U> {
  3. U item;
  4. Node<U> next;
  5. Node() {//没有元素的时候都是空
  6. item = null;
  7. next = null;
  8. }
  9. Node(U item, Node<U> next) {
  10. this.item = item;
  11. this.next = next;
  12. }
  13. boolean end() { //判断栈是否为空
  14. return item == null && next == null;
  15. }
  16. }
  17. private Node<T> top = new Node<>(); // 末端哨兵,判断何时为空
  18. public void push(T item) {// 向栈中压入新的元素时,top会指向新进来的元素
  19. top = new Node<>(item, top);
  20. }
  21. public T pop() {//取出元素时,如果不是最后一个元素,那么这个top会指向本来top元素指向的下一个元素
  22. T result = top.item;
  23. if (!top.end()) {
  24. top = top.next;
  25. }
  26. return result;
  27. }
  28. public static void main(String[] args) {
  29. final LinkedStack<String> lss = new LinkedStack<>();
  30. for (String s : "Phasers or stun".split(" ")) {
  31. lss.push(s);
  32. }
  33. String s;
  34. while ((s = lss.pop()) != null) {
  35. System.out.println(s);
  36. }
  37. }
  38. }

RandomList

假设需要一个持有特定类型的对象列表,每次调用它的select方法的时候,都可以随机选取一个元素

  1. public class RandomList<T> {
  2. private ArrayList<T> storage = new ArrayList<>();
  3. private Random rand = new Random(47);
  4. public void add(T item){ //向容器中添加元素
  5. storage.add(item);
  6. }
  7. public T select(){ //调用这个方法时会从容器容器中随机读取元素
  8. return storage.get(rand.nextInt(storage.size())); //获取边界值
  9. }
  10. public static void main(String[] args) {
  11. RandomList<String> rs = new RandomList<>();
  12. for (String s : ("take the way home").split(" ")) {
  13. rs.add(s); //将字符串添加到集合中
  14. }
  15. for (int i = 0; i < 4; i++) {
  16. System.out.print(rs.select() + " ");
  17. }
  18. }
  19. }

泛型接口

泛型也可以应用于接口(譬如生成器(generator)),这是一个专门负责创建对象的类,这也是工厂设计的一种模式,但是使用生成器创建对象的时候,不需要任何的参数,工厂方法一般是需要参数的。
生成器不需要任何的额外信息就知道如何创建新的对象。

  1. public class CoffeeGenerator implements Generator<Coffee>{
  2. private Class[] types = {Americano.class, Breve.class, Cappuccino.class, Latte.class, Mocha.class};
  3. private Random rand = new Random(47);
  4. public CoffeeGenerator(){}
  5. @Override
  6. public Coffee next() { //用生成器来随机的创建实例
  7. try {
  8. return (Coffee) types[rand.nextInt(types.length)].newInstance();
  9. //必须确定返回值是参数的类型
  10. } catch (Exception e) {
  11. throw new RuntimeException();
  12. }
  13. }
  14. public static void main(String[] args) {
  15. final CoffeeGenerator gen = new CoffeeGenerator();
  16. for (int i = 0; i < 5; i++) {
  17. System.out.println(gen.next());
  18. }
  19. } //并没有知道什么具体的信息,也可以用迭代器来实现
  20. }

使用生成器创建斐波那契数列

  1. public class Fibonacci implements Generator<Integer> {
  2. private int count = 0;
  3. @Override
  4. public Integer next() {
  5. return fib(count++);
  6. }
  7. private int fib(int n){
  8. return (n < 2 ? 1 : (fib(n - 2) + fib(n - 1)));
  9. }
  10. public static void main(String[] args) {
  11. final Fibonacci gen = new Fibonacci();
  12. for (int i = 0; i < 18; i++) {
  13. System.out.print(gen.next() + " ");
  14. }
  15. }
  16. }

Java泛型的局限性:基本类型无法作为类型参数
使用适配器:

  1. public class IterableFibonacci extends Fibonacci implements Iterable<Integer>{
  2. private int n ;
  3. public IterableFibonacci(int count){
  4. n = count;
  5. }
  6. @Override
  7. public Iterator<Integer> iterator() {
  8. return new Iterator<Integer>() {
  9. @Override
  10. public boolean hasNext() {
  11. return n > 0;
  12. }
  13. @Override
  14. public Integer next() {
  15. n--;
  16. return IterableFibonacci.this.next();
  17. }
  18. };
  19. }
  20. public static void main(String[] args) {
  21. for (Integer integer : new IterableFibonacci(18)) {
  22. System.out.print(integer + " ");
  23. }
  24. }
  25. }

泛型方法

泛型可以用在方法上,并且所在的类可以不是泛型类,是否拥有泛型方法,和是不是泛型类没有关系
对于一个static的方法,无法访问泛型类的类型参数,所以,如果static使用泛型的能力,就必须让他称为泛型方法
定义泛型方法,只需要的方法前面放泛型参数列表

  1. public class GenericMethods {
  2. public <T> void f(T t){ //方法前面加泛型列表
  3. System.out.println(t.getClass().getName());
  4. }
  5. public static void main(String[] args) {
  6. final GenericMethods gen = new GenericMethods();
  7. gen.f("hah");
  8. gen.f(1);
  9. gen.f(1.0);
  10. gen.f('t');
  11. gen.f(1.0F);
  12. }
  13. }

杠杆利用类型参数推断

编写一个工具类,包含各种各样的static方法,专门用来创建各种常用的容器对象

  1. public class New {
  2. public static <K,V> Map<K,V> map(){
  3. return new HashMap<K,V>();
  4. }
  5. public static <T> List<T> list(){
  6. return new ArrayList<>();
  7. }
  8. public static <T> LinkedList<T> lList(){
  9. return new LinkedList<>();
  10. }
  11. public static <T> Set<T> set(){
  12. return new HashSet<>();
  13. }
  14. public static <T> Queue<T> queue(){
  15. return new LinkedList<>();
  16. }
  17. public static void main(String[] args) {
  18. final Map<String, Integer> objectObjectMap = New.map();
  19. final List<String> list = New.list();
  20. LinkedList<String> llist = New.lList();
  21. final Set<String> set = New.set();
  22. final Queue<String> queue = New.queue();
  23. }
  24. }

可变类型参数和泛型

  1. public class GenericVarargs {
  2. public static <T> List<T> makeList(T... args){ //可变参数列表
  3. List<T> result = new ArrayList<>();
  4. for (T arg : args) {
  5. result.add(arg);
  6. }
  7. return result;
  8. }
  9. public static void main(String[] args) {
  10. List<String> ls = makeList("A");
  11. System.out.println(ls);
  12. ls = makeList("A","B","C");
  13. System.out.println(ls);
  14. }
  15. }

用于Generators的泛型方法

利用生成器填充Collection

  1. public class Generators {
  2. public static <T>Collection<T> fill(Collection<T> coll,Generator<T> gen,int n){
  3. //创建一个方法,利用生成器向容器中添加元素
  4. for (int i = 0; i < n; i++) {
  5. coll.add(gen.next());
  6. }
  7. return coll;
  8. }
  9. public static void main(String[] args) {
  10. Collection<Coffee> coffee = fill(new ArrayList<Coffee>(), new CoffeeGenerator(), 4);
  11. for (Coffee c : coffee) {
  12. System.out.print(c + " ");
  13. }
  14. System.out.println();
  15. Collection<Integer> integers = fill(new ArrayList<Integer>(), new Fibonacci(), 18);
  16. for (Integer integer : integers) {
  17. System.out.print(integer + " ");
  18. }
  19. }
  20. }

通用的Generator

  1. public class BasicGenerator<T> implements Generator<T> {
  2. private Class<T> type;
  3. public BasicGenerator(Class<T> type){
  4. this.type = type;
  5. }
  6. @Override
  7. public T next() {
  8. try {
  9. return type.newInstance();
  10. } catch (InstantiationException | IllegalAccessException e) {
  11. throw new RuntimeException();
  12. }
  13. }
  14. public static <T> Generator<T> creat(Class<T> type){
  15. return new BasicGenerator<T>(type);
  16. } //提供了一个基本的实现,用来生成某个类的对象
  17. //只需要调用creatfangfa,传想要生成的类型
  18. }
  1. public class CountedObject {
  2. private static long counter = 0;
  3. private final long id = counter++;
  4. public long id(){
  5. return id;
  6. }
  7. @Override
  8. public String toString() {
  9. return "CountedObject" + id;}
  10. }
  1. public class BasicGeneratorDemo {
  2. public static void main(String[] args) {
  3. final Generator<CountedObject> gen = BasicGenerator.creat(CountedObject.class);
  4. for (int i = 0; i < 5; i++) {
  5. System.out.println(gen.next());
  6. }
  7. }
  8. }

匿名内部类

泛型可以应用于内部类和匿名内部类

  1. class Customer{
  2. private static long counter = 1;
  3. private final long id = counter ++;
  4. private Customer(){}
  5. @Override
  6. public String toString() {
  7. return "Customer " + id + " ";
  8. }
  9. public static Generator<Customer> generator(){
  10. return new Generator<Customer>() { //使用匿名内部类来创建实例
  11. @Override
  12. public Customer next() {
  13. return new Customer();
  14. }
  15. };
  16. }
  17. }
  18. class Teller{
  19. private static long counter = 1;
  20. private final long id = counter++;
  21. public Teller(){}
  22. @Override
  23. public String toString() {
  24. return "Teller " + id + " ";
  25. }
  26. public static Generator<Teller> generator = new Generator<Teller>() {
  27. @Override //使用局部内部类来创建方法
  28. public Teller next() {
  29. return new Teller();
  30. }
  31. };
  32. }
  33. public class BankTeller {
  34. private static void serve(Teller t,Customer c){
  35. System.out.println(t + " serves " + c);
  36. }
  37. public static void main(String[] args) {
  38. final Random rand = new Random(47);
  39. Queue<Customer> line = new LinkedList<>();
  40. Generators.fill(line, Customer.generator(), 15); //利用生成器来创建对象
  41. List<Teller> tellers = new ArrayList<>();
  42. Generators.fill(tellers,Teller.generator,4);
  43. for (Customer customer : line) {
  44. serve(tellers.get(rand.nextInt(tellers.size())), customer);
  45. //在teller中随机产生一个
  46. }
  47. }
  48. }

构建复杂模型

  1. class Product{
  2. private int id;
  3. private String description;
  4. private double price;
  5. public Product(int id, String description, double price) {
  6. this.id = id;
  7. this.description = description;
  8. this.price = price;
  9. System.out.println(toString());
  10. }
  11. @Override
  12. public String toString() {
  13. return id + ": " + description + ", price: $" + price;
  14. }
  15. public void priceChange(double change){
  16. price += change;
  17. }
  18. public static Generator<Product> generator = new Generator<Product>() {
  19. private Random rand = new Random(47);
  20. @Override
  21. public Product next() {
  22. return new Product(rand.nextInt(1000), "Test",Math.round(rand.nextDouble())*1000+0.99);
  23. }
  24. };
  25. }
  26. class Shelf extends ArrayList<Product>{
  27. public Shelf(int nProduct){
  28. Generators.fill(this,Product.generator,nProduct);
  29. }
  30. }
  31. class Aisle extends ArrayList<Shelf>{
  32. public Aisle(int nShelves,int nProduct){
  33. for (int i = 0; i < nShelves; i++) {
  34. add(new Shelf(nProduct));
  35. }
  36. }
  37. }
  38. class CheckoutStand{}
  39. class Office{}
  40. public class Store extends ArrayList<Aisle>{
  41. private ArrayList<CheckoutStand> checkouts = new ArrayList<>();
  42. private Office office = new Office();
  43. public Store(int nAisle, int nShelves, int nProduct) {
  44. for (int i = 0; i < nAisle; i++) {
  45. add(new Aisle(nShelves, nProduct));
  46. }
  47. }
  48. @Override
  49. public String toString() {
  50. final StringBuilder result = new StringBuilder();
  51. for (Aisle shelves : this) {
  52. for (Shelf shelf : shelves) {
  53. for (Product product : shelf) {
  54. result.append(product);
  55. result.append("\n");
  56. }
  57. }
  58. }
  59. return result.toString();
  60. }
  61. public static void main(String[] args) {
  62. final Store aisles = new Store(2, 5, 3);
  63. }
  64. }

擦除的神秘之处

  1. public class ErasedTypeEquivalence {
  2. public static void main(String[] args) {
  3. Class c1 = new ArrayList<String>().getClass();
  4. Class c2 = new ArrayList<Integer>().getClass();
  5. System.out.println(c1 == c2);
  6. }
  7. }

此时发现输出结果是相等的

  1. class Frob{}
  2. class Fnorkle{}
  3. class Quark<Q>{}
  4. class Particle<POSITION, MOMENTUM>{}
  5. public class LostInformation {
  6. public static void main(String[] args) {
  7. List<Frob> list = new ArrayList<>();
  8. Map<Frob, Fnorkle> map = new HashMap<>();
  9. Quark<Fnorkle> quark = new Quark<>();
  10. Particle<Long, Double> particle = new Particle<>(); //表示由泛型声明所声明的类型参数
  11. System.out.println(Arrays.toString(list.getClass().getTypeParameters()));
  12. System.out.println(Arrays.toString(map.getClass().getTypeParameters()));
  13. System.out.println(Arrays.toString(quark.getClass().getTypeParameters()));
  14. System.out.println(Arrays.toString(particle.getClass().getTypeParameters()));
  15. }
  16. }

发现输出结果中只有用作参数占位符的标识符,说明:
在泛型代码的内部,无法获得任何有关泛型参数类型的信息。无法知道用来创建某个特定实例的实际类型参数
Java的泛型是用擦除实现的,意味着在使用泛型时,任何具体的类型信息都会被擦除,唯一知道的就是正在使用一个对象

  1. public class Manipulation<T> {
  2. private T obj;
  3. public Manipulation(T x){
  4. obj = x;
  5. }
  6. // public void manipulation(){ 此时找不到f方法,必须使用边界符,告诉编译器只能接受遵循
  7. 这个边界的类型
  8. // obj.f()
  9. // }
  10. }
  11. class Manipulation2<T extends HasF>{ //使用边界符,此时可以使用具体类型的方法
  12. private T obj;
  13. public Manipulation2(T x){
  14. obj = x ;
  15. }
  16. public void manipulation(){
  17. obj.f();
  18. }
  19. }

当希望代码可以跨多个类工作的时候,使用泛型才有所帮助,

  1. public class RunGenericType<T extends HasF> {
  2. private T obj;
  3. public RunGenericType(T x){
  4. obj = x;
  5. }
  6. public T get(){ //如果有一个返回T类型的方法,之后会返回确切的类型,
  7. //也可以返回它的子类,并且不需要显示的类型转换
  8. return obj;
  9. }
  10. }

迁移兼容性

在基于擦除的实现中,泛型类型都被当做第二类类型处理,就是不能在某些重要的上下文环境中使用。
向List这样的类型都被擦除为List,而普通的类型变量在未指定边界的情况下都会被擦除为Object
擦除的核心时他可以使泛化的客户端可以用非泛化的类库来使用,反之亦然,这经常被称为“迁移兼容性”

擦除的问题

泛型不能用于显示的引用运行时类型的操作之中,例如转型,instanceof操作和new表达式,因为所有有关类型的参数信息都丢失了

边界处的动作

  1. public class ArrayMaker<T> {
  2. private Class<T> kind;
  3. public ArrayMaker(Class<T> kind){//泛型T无法获取Class对象,通过构造器传进去一个Class实例
  4. this.kind = kind;
  5. }
  6. T[] create(int size){
  7. return (T[]) Array.newInstance(kind, size); //必须将其转为T类型的数组
  8. }
  9. public static void main(String[] args) {
  10. ArrayMaker<String> stringmaker = new ArrayMaker<>(String.class);
  11. String[] stringArray = stringmaker.create(10);
  12. System.out.println(Arrays.toString(stringArray));
  13. }
  14. }

即使kind被存储为Class,擦除也意味着他实际被存储为Class,没有任何参数
在泛型中创建数组,最好使用Array.newInstance
如果创建的时容器不是数组就不同了

  1. public class ListMaker<T> {
  2. List<T> create(){
  3. return new ArrayList<>();
  4. }
  5. public static void main(String[] args) {
  6. ListMaker<String> stringListMaker = new ListMaker<>();
  7. List<String> stringsList = stringListMaker.create();
  8. //调用方法来创建容器
  9. }
  10. }
  1. public class FilledListMaker<T> {
  2. List<T> create(T t,int n){
  3. List<T> result = new ArrayList<>();
  4. for (int i = 0; i < n; i++) {
  5. result.add(t);
  6. }
  7. return result;
  8. }
  9. public static void main(String[] args) {
  10. FilledListMaker<String> stringFilledListMaker = new FilledListMaker<>();
  11. List<String> list = stringFilledListMaker.create("Hello" , 4);
  12. System.out.println(list);
  13. }
  14. }

擦除的补偿

擦除丢失了泛型代码中执行某些操作的能力,任何在运行时需要知道确切类型信息的操作都没办法正常工作

  1. public class Erased<T> {
  2. private final int SIZE = 100;
  3. public static void f(Object arg){ //需要知道确切类型信息的都不能使用
  4. //if (arg instanceof T);
  5. //T t = new T;
  6. //T[] array = new T[SIZE];
  7. }
  8. }

有时必须引入类型标签Class来对擦除进行补偿,必须显示的传递类型的Class对象

  1. class Building{}
  2. class House extends Building{}
  3. public class ClassTypeCapture<T> {
  4. Class<T> kind;
  5. public ClassTypeCapture(Class<T> kind){ //使用Class标签对擦除进行补偿
  6. this.kind = kind;
  7. }
  8. public boolean f(Object arg){
  9. return kind.isInstance(arg);
  10. }
  11. public static void main(String[] args) {
  12. final ClassTypeCapture<Building> ctt1 = new ClassTypeCapture<>(Building.class);
  13. //传入Class对象
  14. System.out.println(ctt1.f(new Building()));
  15. System.out.println(ctt1.f(new House()));
  16. final ClassTypeCapture<House> ctt2 = new ClassTypeCapture<>(House.class);
  17. System.out.println(ctt2.f(new Building()));
  18. System.out.println(ctt2.f(new House()));
  19. }
  20. }

创建类型实例

传递一个工厂对象,并且用它来创建实例,使用类型标签来使用newInstance方法来创建这个类型的新对象
使用newInstance创建某个类的实例的时候,这个类必须有默认的构造器,并且只能运行时发现这个错误

  1. class ClassAsFactory<T>{
  2. T x;
  3. public ClassAsFactory(Class<T> kind){
  4. try {
  5. x = kind.newInstance();
  6. } catch (Exception e) {
  7. throw new RuntimeException();
  8. }
  9. }
  10. }
  11. class Employee{}
  12. public class InstantiateGenericType {
  13. public static void main(String[] args) {
  14. final ClassAsFactory<Employee> fe = new ClassAsFactory<>(Employee.class);
  15. System.out.println("ClassAsFactory<Employee> succeeded");
  16. try {
  17. final ClassAsFactory<Integer> fi = new ClassAsFactory<>(Integer.class);
  18. //失败的原因时Integer没有默认构造器,并且不是在编译器捕获的
  19. }catch (Exception e){
  20. System.out.println("失败");
  21. }
  22. }
  23. }
  1. interface FactoryI<T>{
  2. T create();
  3. }
  4. class Foo2<T>{
  5. private T x;
  6. public Foo2(FactoryI<T> factoryI){
  7. x = factoryI.create();
  8. }
  9. }
  10. class IntegerFactory implements FactoryI<Integer>{
  11. @Override
  12. public Integer create() {
  13. return new Integer(0);
  14. }
  15. }
  16. class Widget{
  17. public static class Factory implements FactoryI<Widget>{
  18. @Override
  19. public Widget create() {
  20. return new Widget();
  21. }
  22. }
  23. }
  24. public class FactoryConstraint {
  25. public static void main(String[] args) {
  26. new Foo2<Integer>(new IntegerFactory());
  27. new Foo2<Widget>(new Widget.Factory());
  28. }
  29. }

两种方式都创建了工厂对象,第二种时传递Class的一种变体
还有一种时模板设计模式,在本例中create()是模板方法

  1. abstract class GenericWithCreate<T>{
  2. final T element;
  3. abstract T create(); //create是模板方法,他在子类中定义,产生子类的对象
  4. public GenericWithCreate(){
  5. element = create();
  6. }
  7. }
  8. class X{}
  9. class Creator extends GenericWithCreate<X>{
  10. @Override
  11. X create() {
  12. return new X();
  13. }
  14. void f(){
  15. System.out.println(element.getClass().getSimpleName());
  16. }
  17. }
  18. public class CreatorGeneric {
  19. public static void main(String[] args) {
  20. final Creator creator = new Creator();
  21. creator.f();
  22. }
  23. }

泛型数组

泛型数组不能创建,一般是在创建泛型数组的地方使用ArrayList

  1. public class ListOfGenerics <T>{
  2. private List<T> list = new ArrayList<>();
  3. public void add(T item){
  4. list.add(item);
  5. }
  6. public T get(int index){
  7. return list.get(index);
  8. }
  9. }

成功创建泛型数组的唯一方式就是创建一个被擦除的类型的新数组,然后对其转型。

  1. public class GenericArray<T> {
  2. private T[] array;
  3. public GenericArray(int size){
  4. array = (T[]) new Object[size];
  5. }
  6. public void put(int index,T item){
  7. array[index] = item;
  8. }
  9. public T get(int index){
  10. return array[index];
  11. }
  12. public T[] rep(){ //实际运行时的类型时Object
  13. return array;
  14. }
  15. public static void main(String[] args) {
  16. final GenericArray<Integer> gai = new GenericArray<>(10);
  17. Object[] o = gai.rep();//并不能直接声明T[] array = new T[size],所以要创建一个对象
  18. //数组,然后将他转型
  19. }

因为擦除,所以数组运行时的类型时Object类型的
可以利用反射来创建具体的实例,将Class传递在构造器中,可以创建实际类型的数组

  1. public class GenericArrayWithTypeToken<T> {
  2. private T[] array;
  3. public GenericArrayWithTypeToken(Class<T> type , int size){
  4. array = (T[]) Array.newInstance(type, size);//利用反射来创建实例
  5. }
  6. public void put(int index,T item){
  7. array[index] = item;
  8. }
  9. public T get(int index){
  10. return array[index];
  11. }
  12. public T[] rep(){
  13. return array;
  14. }
  15. public static void main(String[] args) {
  16. final GenericArrayWithTypeToken<Integer> gai = new GenericArrayWithTypeToken<Integer>(Integer.class,10);
  17. Integer[] ia = gai.rep();
  18. }
  19. }

边界

边界可以用于泛型的参数类型上设置条件。并且一个更重要的效果使可以按照自己的边界类型来调用方法

  1. class HoldItem<T>{
  2. T item;
  3. HoldItem(T item){
  4. this.item = item;
  5. }
  6. T getItem(){
  7. return item;
  8. }
  9. }
  10. class Colored2 <T extends HasColor> extends HoldItem<T>{
  11. Colored2(T item){
  12. super(item);
  13. }
  14. java.awt.Color color(){
  15. return item.getColor();
  16. }
  17. }
  18. //具体的类要在前面
  19. class ColoredDimension2<T extends Dimension & HasColor > extends Colored2<T>{
  20. //这里继承了Colored2,没有重写,但是仍有这个方法
  21. ColoredDimension2(T item){
  22. super(item);
  23. }
  24. int getX(){
  25. return item.x;
  26. }
  27. int getY(){
  28. return item.y;
  29. }
  30. int getZ(){
  31. return item.z;
  32. }
  33. }
  34. class Solid2 <T extends Dimension & HasColor & Weight> extends ColoredDimension2{
  35. Solid2(T item) {
  36. super(item);
  37. }
  38. }
  39. public class InheritBounds {
  40. public static void main(String[] args) {
  41. final Solid2<Bound> solid2 = new Solid2<>(new Bound());
  42. solid2.getX();
  43. solid2.getY();
  44. solid2.getZ();
  45. solid2.color();
  46. }
  47. }
  1. interface SuperPower{}
  2. interface XRayVision extends SuperPower{
  3. void seeThroughWalls();
  4. }
  5. interface SuperHearing extends SuperPower{
  6. void hearSubtleNoises();
  7. }
  8. interface SuperSmell extends SuperPower{
  9. void trackBySmell();
  10. }
  11. class SuperHero<POWER extends SuperPower>{
  12. POWER power;
  13. SuperHero(POWER power){
  14. this.power = power;
  15. }
  16. POWER getPower(){
  17. return power;
  18. }
  19. }
  20. class SuperSleuth<POWER extends XRayVision> extends SuperHero<POWER>{
  21. SuperSleuth(POWER power){
  22. super(power);
  23. }
  24. }
  25. class CanineHero<POWER extends SuperHearing & SuperSmell> extends SuperHero<POWER>{
  26. //限定了superhear和supersmell
  27. CanineHero(POWER power){
  28. super(power);
  29. }
  30. void hear(){
  31. power.hearSubtleNoises();
  32. }
  33. void smell(){
  34. power.trackBySmell();
  35. }
  36. }
  37. class SuperHearSmell implements SuperHearing,SuperSmell{
  38. //实现了SuperHearing和SuperSmell,建立起了联系
  39. @Override
  40. public void hearSubtleNoises() {}
  41. @Override
  42. public void trackBySmell() {}
  43. }
  44. class DogBoy extends CanineHero<SuperHearSmell>{
  45. DogBoy(){
  46. super(new SuperHearSmell());
  47. }
  48. }
  49. public class EpicBattle {
  50. static <POWER extends SuperHearing> void usrSuperHearing (SuperHero<POWER> hero){
  51. hero.getPower().hearSubtleNoises();
  52. }
  53. static <POWER extends SuperHearing & SuperSmell> void superFind(SuperHero<POWER> hero){
  54. hero.getPower().hearSubtleNoises();
  55. hero.getPower().trackBySmell();
  56. }
  57. public static void main(String[] args) {
  58. final DogBoy dogBoy = new DogBoy();
  59. usrSuperHearing(dogBoy);
  60. superFind(dogBoy);
  61. }
  62. }

通配符

向导出类数组中加入基类类型的引用

  1. class Fruit{}
  2. class Apple extends Fruit{}
  3. class Orange extends Fruit{}
  4. class Jonathan extends Apple{}
  5. public class CovariantArrays {
  6. public static void main(String[] args) {
  7. Fruit[] fruits = new Apple[10];//此时的数组类型是Apple类型的,只可以向里面放入
  8. //Apple类型或者其子类型,如果插入fruits编译器不会报错
  9. //但是运行起来就会报错
  10. fruits[0] = new Apple();
  11. fruits[1] = new Jonathan();
  12. try {
  13. fruits[0] = new Fruit();
  14. }catch (Exception e){
  15. System.out.println(e);
  16. }
  17. try {
  18. fruits[0] = new Orange();
  19. }catch (Exception e){
  20. System.out.println(e);
  21. }
  22. }
  23. }

泛型的目标之一就是将这种错误检测给他弄到编译期

  1. public class GenericAndCovariance {
  2. public static void main(String[] args) {
  3. List<? extends Fruit> flist = new ArrayList<Apple>();
  4. //flist.add(new Apple());
  5. flist.add(null);
  6. System.out.println(flist.get(0));
  7. }
  8. }

使用了<? extands Fruit> 发现不能使用容器的方法,只能使用Object的方法

  1. public class CompilerIntelligence {
  2. public static void main(String[] args) {
  3. List<? extends Fruit> flist = Arrays.asList(new Apple());
  4. Apple a = (Apple) flist.get(0);
  5. flist.contains(new Apple());//允许调用,是因为这两个方法的参数是Object
  6. flist.indexOf(0);
  7. }
  8. }

超类型通配符

<? super MyClass> MyClass的子类

  1. public class SuperTypeWIldCards {
  2. static void writeTo(List<? super Apple> apples){
  3. apples.add(new Apple());
  4. apples.add(new Jonathan());
  5. //apples.add(new Fruit());//Fruit不是Apple的子类
  6. }
  7. }
  1. public class GenericWriting {
  2. static <T> void writeExact(List<T> list , T item){
  3. list.add(item);
  4. }
  5. static List<Apple> apples = new ArrayList<>();
  6. static List<Fruit> fruits = new ArrayList<>();
  7. static void f1(){
  8. writeExact(apples,new Apple());
  9. } //前面的<T>代表了参数类型
  10. static <T> void writeWithWildcard(List<? super T> list , T item){
  11. list.add(item);//超类型通配符可以用泛型方法
  12. }
  13. static void f2(){
  14. //确定了容器的类型后,就只能持有他或这它的子类了
  15. writeWithWildcard(apples, new Jonathan());
  16. writeWithWildcard(fruits, new Fruit());
  17. }
  18. public static void main(String[] args) {
  19. f1();
  20. f2();
  21. }
  22. }

无界通配符

<?> 意味着任何事物

  1. public class UnboundedWildcards {
  2. static List list1;
  3. static List<?> list2;
  4. static List<? extends Object> list3;
  5. static void assign1(List list){
  6. list1 = list;
  7. list2 = list;
  8. //list3 = list;
  9. }
  10. static void assign2(List<?> list){
  11. list1 = list;
  12. list2 = list;
  13. list3 = list;
  14. }
  15. static void assign3(List<? extends Object> list){
  16. list1 = list;
  17. list2 = list;
  18. list3 = list;
  19. }
  20. public static void main(String[] args) {
  21. assign1(new ArrayList<>());
  22. assign2(new ArrayList<>());
  23. assign3(new ArrayList<>());
  24. assign1(new ArrayList<String>());
  25. assign2(new ArrayList<String>());
  26. assign3(new ArrayList<String>());
  27. }
  28. }
  1. public class UnboundedWildcard2 {
  2. static Map map1;
  3. static Map<?,?> map2;
  4. static Map<String,?> map3;
  5. static void assign1(Map map){
  6. map1 = map;
  7. }
  8. static void assign2(Map<?,?> map){
  9. map2 = map;
  10. }
  11. static void assign3(Map<String,?> map){
  12. map3 = map;
  13. }
  14. public static void main(String[] args) {
  15. assign1(new HashMap());
  16. assign2(new HashMap());
  17. assign3(new HashMap());
  18. assign1(new HashMap<String,Integer>());
  19. assign2(new HashMap<String,Integer>());
  20. assign3(new HashMap<String,Integer>());
  21. }
  22. }

List表示“持有任何Object类型的List”,List<?>表示“持有某种特定类型的”List,只是不知道是什么类型

转型和警告

  1. class FixedSizeStack<T>{
  2. private int index =0;
  3. private Object[] storage;
  4. public FixedSizeStack(int size){
  5. storage = new Object[size];//存储是将值都转换成为Object
  6. }
  7. public void push(T item){
  8. storage[index++] = item;
  9. }
  10. public T pop(){
  11. return (T) storage[--index];//取出时转换称为T类型的
  12. }
  13. }
  14. public class GenericCast {
  15. public static final int SIZE = 7;
  16. public static void main(String[] args) {
  17. final FixedSizeStack<String> strings = new FixedSizeStack<>(SIZE);
  18. for (String s : "A B C D E F G".split(" ")) {
  19. strings.push(s);
  20. }
  21. for (int i = 0; i < SIZE; i++) {
  22. String s = strings.pop();
  23. System.out.print(s + " ");
  24. }
  25. }
  26. }

基类劫持接口(基类限定接口中的类型参数)

  1. public class ComparablePet implements Comparable<ComparablePet>{
  2. @Override
  3. public int compareTo(ComparablePet arg) {
  4. return 0;
  5. }
  6. }
  7. class Cat extends ComparablePet implements Comparable<Cat>{
  8. //一旦基类Comparabel确定了ComparablePet,那么其他任何的实现类都不能和他定义的之外的
  9. 对象作比较,即使时它的子类也不可以
  10. public int compareTo(Cat cat){
  11. return 0;
  12. }
  13. }
  1. class Hamster extends ComparablePet implements Comparable<ComparablePet>{
  2. @Override
  3. public int compareTo(ComparablePet arg) {
  4. return super.compareTo(arg);
  5. }
  6. }

自限定的类型

循环泛型

不能直接继承一个泛型参数,可以继承在自己的定义中使用这个泛型参数的类

  1. class GenericType<T>{}
  2. public class CuriouslyRecurringGeneric extends GenericType<CuriouslyRecurringGeneric>{
  3. }

java中的泛型关乎参数和返回类型,因此他能产生使用子类作为其参数和返回类型的基类,还能将导出类用作其域类型,甚至是那些被擦除为Object的类型

  1. public class BasicHolder<T> {
  2. T element;
  3. void set(T arg){
  4. element = arg;
  5. }
  6. T get(){
  7. return element;
  8. }
  9. void f(){
  10. System.out.println(element.getClass().getSimpleName());
  11. }
  12. }
  13. class Subtype extends BasicHolder<Subtype>{} //
  14. public class CRGWithBasicHolder {
  15. public static void main(String[] args) {
  16. final Subtype st1 = new Subtype(), st2 = new Subtype();
  17. st1.set(st2);
  18. //新类Subtype接受的参数和返回值具有Subtype类型不仅仅是他的基类的类型
  19. Subtype st3 = st1.get();
  20. st1.f();
  21. }
  22. }

CRG的本质:基类使用其导出类,泛型基类编程了一种所有导出类的公共功能的模板,他的参数和返回值都是导出类类型,在所产生的类中会使用确切的类型,而不是基类类型

自限定

  1. class SelfBounded<T extends SelfBounded>{
  2. T element;
  3. SelfBounded <T> set(T arg){
  4. element = arg;
  5. return this;
  6. }
  7. T get(){
  8. return element;
  9. }
  10. }
  11. class A extends SelfBounded<A>{} //这种定义方式就是自限定
  12. class B extends SelfBounded<A>{} //这样也是可以的
  13. class C extends SelfBounded<C>{
  14. C setAndGet(C arg){
  15. set(arg);
  16. return arg;
  17. }
  18. }
  19. class D{}
  20. class E extends SelfBounded<D>{}//此时这个类是不能编译的
  21. class F extends SelfBounded{};
  22. public class SelfBounding {
  23. public static void main(String[] args) {
  24. A a = new A();
  25. a.set(new A());
  26. a = a.set(new A()).get();
  27. a = a.get();
  28. C c = new C();
  29. c = c.setAndGet(new C());
  30. }
  31. }

自限定参数可以保证类型参数与正在定义的类相同
如果去掉自限定限制也是可以的

  1. class SelfBounded<T>{
  2. T element;
  3. SelfBounded <T> set(T arg){
  4. element = arg;
  5. return this;
  6. }
  7. T get(){
  8. return element;
  9. }
  10. }
  11. class A extends SelfBounded<A>{}
  12. class B extends SelfBounded<A>{}
  13. class C extends SelfBounded<C>{
  14. C setAndGet(C arg){
  15. set(arg);
  16. return arg;
  17. }
  18. }
  19. class D{}
  20. class E extends SelfBounded<D>{}//这个时候这个类是可以编译的
  21. class F extends SelfBounded{};

参数协变

自限定类型的价值是:可以产生协变参数类型(方法中的参数类型会随着子类而变化)

  1. class Base{}
  2. class Derived extends Base{}
  3. interface OrdinaryGetter{
  4. Base get();
  5. }
  6. interface DerivedGetter extends OrdinaryGetter{
  7. //覆盖了从他继承过来的接口中的get方法,返回的也是从Base中导出的类型
  8. Derived get();
  9. }
  10. public class CovariantReturnTypes {
  11. void test(DerivedGetter d){
  12. Derived d2 = d.get();
  13. }
  14. }

在非泛型代码中,参数类型不能随着子类型发生变化

  1. class OrdinarySetter{
  2. void set(Base base){
  3. System.out.println("OrdinarySetter.set");
  4. }
  5. }
  6. class DerivedSetter extends OrdinarySetter{
  7. void set(Derived derived){
  8. System.out.println("DerivedSetter.set");
  9. }
  10. }
  11. public class OrdinaryArguments {
  12. public static void main(String[] args) {
  13. final Base base = new Base();
  14. final Derived derived = new Derived();
  15. final DerivedSetter derivedSetter = new DerivedSetter();
  16. //方法都是子类的方法
  17. derivedSetter.set(derived);
  18. derivedSetter.set(base);//调用的仍然是父类的方法
  19. }
  20. }

在自限定类型中只会接受导出类的方法

混型

最基本的概念是混合多个类的能力,产生一个可以表示混型中所有类型的类
在混型中修改东西,这些东西会应用在混型中所有的类型之上

与接口混合

  1. interface TimeStamped{
  2. long getStamp();
  3. }
  4. class TimeStampedImp implements TimeStamped{
  5. private final long timeStamp;
  6. public TimeStampedImp(){
  7. timeStamp = new Date().getTime();
  8. }
  9. @Override
  10. public long getStamp() {
  11. return timeStamp;
  12. }
  13. }
  14. interface SerialNumbered {
  15. long getSerialNumber();
  16. }
  17. class SerialNumberedImp implements SerialNumbered{
  18. private static long counter = 1;
  19. private final long serialNumber = counter++;
  20. @Override
  21. public long getSerialNumber() {
  22. return serialNumber;
  23. }
  24. }
  25. interface Basic{
  26. public void set(String val);
  27. public String get();
  28. }
  29. class BasicImp implements Basic{
  30. private String value;
  31. @Override
  32. public void set(String val) {
  33. value = val;
  34. }
  35. @Override
  36. public String get() {
  37. return value;
  38. }
  39. }
  40. class Mixin extends BasicImp implements TimeStamped,SerialNumbered{
  41. //继承了一个实现类,并且实现了两个接口,混合了多个类的能力
  42. private TimeStamped timeStamp = new TimeStampedImp();
  43. private SerialNumbered serialNumber = new SerialNumberedImp();
  44. @Override
  45. public long getStamp() {
  46. return timeStamp.getStamp();
  47. //调用的是TimeStampedImp中的getStamp方法
  48. }
  49. @Override
  50. public long getSerialNumber() {
  51. return serialNumber.getSerialNumber();
  52. ////调用的是SerialNumberedImp中的getSerialNumber方法
  53. }
  54. }
  55. public class Mixins {
  56. public static void main(String[] args) {
  57. final Mixin mixin1 = new Mixin();
  58. final Mixin mixin2 = new Mixin();
  59. mixin1.set("test String1");
  60. mixin2.set("test String2");
  61. System.out.println(mixin1.get() + " " + mixin1.getStamp() + " " + mixin1.getSerialNumber());
  62. System.out.println(mixin2.get() + " " + mixin2.getStamp() + " " + mixin2.getSerialNumber());
  63. }
  64. }

装饰器模式

装饰器模式使用分层对象来动态的透明的向单个对象中添加责任,装饰器是通过组合和形式化接口实现的,而混型是基于继承的

  1. class Basic1{
  2. private String value;
  3. public void set(String value){
  4. this.value = value;
  5. }
  6. public String get(){
  7. return value;
  8. }
  9. }
  10. class Decorator extends Basic1{
  11. protected Basic1 basic1;
  12. public Decorator(Basic1 basic1){
  13. this.basic1 = basic1;
  14. }
  15. public void set(String val){
  16. basic1.set(val);
  17. }
  18. public String get(){
  19. return basic1.get();
  20. }
  21. }
  22. class TimeStamped1 extends Decorator{
  23. private final long timeStamp;
  24. public TimeStamped1(Basic1 basic1){
  25. super(basic1);
  26. timeStamp = new Date().getTime();
  27. }
  28. public long getStamp(){
  29. return timeStamp;
  30. }
  31. }
  32. class SerialNumbered1 extends Decorator{
  33. private static long counter = 1;
  34. private final long serialNumber = counter++;
  35. public SerialNumbered1(Basic1 basic1) {
  36. super(basic1);
  37. }
  38. public long getSerialNumber(){
  39. return serialNumber;
  40. }
  41. }
  42. public class Decoration {
  43. public static void main(String[] args) {
  44. final TimeStamped1 t = new TimeStamped1(new Basic1());
  45. final TimeStamped1 t2 = new TimeStamped1(new SerialNumbered1(new Basic1()));
  46. SerialNumbered1 s = new SerialNumbered1(new Basic1());
  47. final SerialNumbered1 s2 = new SerialNumbered1(new TimeStamped1(new Basic1()));
  48. }
  49. }

与动态代理混合

  1. class MixinProxy implements InvocationHandler{
  2. Map<String,Object> delegatesByMethod; //方法名和方法所属对象
  3. public MixinProxy(TwoTuple<Object,Class<?>>...pairs) {
  4. delegatesByMethod = new HashMap<String, Object>();
  5. for (TwoTuple<Object, Class<?>> pair : pairs) { //将方法名和Object对应起来
  6. for (Method method : pair.second.getMethods()) { //将参数循环遍历
  7. String methodName = method.getName();
  8. if (! delegatesByMethod.containsKey(methodName)){ //如果没有他的方法名字,就把他加进去
  9. delegatesByMethod.put(methodName,pair.first);
  10. }
  11. }
  12. }
  13. }
  14. @Override
  15. public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
  16. String methodName = method.getName(); //代表外部要去执行的方法的名字
  17. Object delegate = delegatesByMethod.get(methodName); //代表目标方法的代理者或者说执行者
  18. return method.invoke(methodName, args);//根据方法名去调用外部的方法 ,利用反射。
  19. }
  20. public static Object newInstance(TwoTuple... pairs){
  21. Class[] interfaces = new Class[pairs.length]; //产生代理对象
  22. for (int i = 0; i < pairs.length; i++) {
  23. interfaces[i] = (Class) pairs[i].second;
  24. }
  25. ClassLoader cl = pairs[0].first.getClass().getClassLoader();
  26. return Proxy.newProxyInstance(cl,interfaces,new MixinProxy(pairs));
  27. }
  28. }
  29. public class DynamicProxyMixin {
  30. }