Thinking in java Chapter15 泛型

  • 1 与C ++比较
  • 2 简单泛型 泛型 类
  • 3 泛型 接口
  • 4 泛型 方法
  • 5 匿名内部类
  • 6 构建复杂模型
  • 7
  • 8
  • 9
  • 10

“泛型”意思就是:适用于许多许多的类型

<h2 id="1">1 与C++比较 </h2> -------------------------

C++模版,了解泛型的边界所在

<h2 id="2">2 简单泛型 </h2> -----------------------

使用泛型的目的之一: 指定容器持有什么类型,让编译器确保正确性,而不是在运行期发现错误

java泛型的核心概念:告诉编译器想使用什么类型,然后编译器帮你处理一切细节

2.1 元组

元组允许读取元素,但不能插入新元素,不可以修改元素值,因为元素被设置为final。

元组可以任意长度,可以存储任何类型对象。

创建一个元组,使其返回一组任意类型的对象。

1package generics; 2 3import generics.e3.SixTuple; 4import net.mindview.util.*; 5 6class Amphibian{} //两栖动物 7class Vehicle{}//车辆 8public class TupleTest { 9 static TwoTuple<String,Integer> f(){ 10 return new TwoTuple<String,Integer>("hi",47); 11 } 12 13 static ThreeTuple<Amphibian,String,Integer> g(){ 14 return new ThreeTuple<Amphibian,String,Integer>(new Amphibian(),"hi",47); 15 } 16 17 static FourTuple<Vehicle,Amphibian,String,Integer> h(){ 18 return new FourTuple<Vehicle,Amphibian,String,Integer>(new Vehicle(),new Amphibian(),"hi",47); 19 } 20 21 static FiveTuple<Vehicle,Amphibian,String,Integer,Double> k(){ 22 return new FiveTuple<Vehicle,Amphibian,String,Integer,Double>(new Vehicle(),new Amphibian(),"hi",47,11.1); 23 } 24 25 static SixTuple<Vehicle,Amphibian,String,Integer,Double,Float> i(){ 26 return new SixTuple<Vehicle,Amphibian,String,Integer,Double,Float>(new Vehicle(),new Amphibian(),"hi",47,11.1,22.22F); 27 } 28 29 30 public static void main(String[] args) { 31 TwoTuple<String,Integer> ttsi = f(); 32// ttsi.first = "there"; //编译错误,final 33 System.out.println(ttsi); 34 System.out.println(g()); 35 System.out.println(h()); 36 System.out.println(k()); 37 System.out.println(i()); 38 } 39} 40 41/* 42 43 */

2.2 一个堆栈类

传统的下推堆栈

11章使用LinkedList

不用LinkedList,实现自己内部的链式存储机制

1package generics; 2 3public class LinkedStack<T> { 4 private static class Node<U> { 5 U item; 6 Node<U> next; 7 8 Node() { 9 item = null; 10 next = null; 11 } 12 13 Node(U item, Node<U> next) { 14 this.item = item; 15 this.next = next; 16 } 17 18 boolean end() { 19 return item == null && next == null; 20 } 21 } 22 23 private Node<T> top = new Node<T>(); // End Sentinel 末端哨兵 24 25 public void push(T item) { 26 top = new Node<T>(item, top); 27 // push "Phasers"时,创建对象Node<String>("Phasers",top),top.item == null top.next == null , 28 // 并将创建的Node结点,指向top,即top.item == "Phasers",top.next == item和next为null的结点 29 30 // push "on"时,创建对象Node<String>("on",top),将"Phasers"的结点,作为"on"的next 31 32 // push "stun!"时,创建对象Node<String>("stun!",top),将"on"的结点,作为"stun!"的next 33 } 34 35 public T pop() { 36 T result = top.item; // 取值 37 if (!top.end()) 38 top = top.next; // 下移 39 return result; // 返回取出的值 40 } 41 42 public static void main(String[] args) { 43 LinkedStack<String> lss = new LinkedStack<String>(); 44 for (String s : "Phasers on stun!".split(" ")) 45 lss.push(s); 46 String s; 47 while ((s = lss.pop()) != null) 48 System.out.println(s); 49 } 50} 51/* 52stun! 53on 54Phasers 55 */ 56 57

内部类可以访问外部类堆类型参数

1package generics.e5; 2 3public class LinkedStack<T> { 4 private class Node{ //将原来的嵌套类 修改 为普通内部类。即Node不能为static 5 T item; 6 Node next; 7 8 Node() { 9 item = null; 10 next = null; 11 } 12 13 Node(T item, Node next) { 14 this.item = item; 15 this.next = next; 16 } 17 18 boolean end() { 19 return item == null && next == null; 20 } 21 } 22 23 private Node top = new Node(); // End Sentinel 未端哨兵 24 25 public void push(T item) { 26 top = new Node(item, top); // 27 } 28 29 public T pop() { 30 T result = top.item; // 取值 31 if (!top.end()) 32 top = top.next; // 下移 33 return result; 34 } 35 36 public static void main(String[] args) { 37 LinkedStack<String> lss = new LinkedStack<String>(); 38 for (String s : "Phasers on stun!".split(" ")) 39 lss.push(s); 40 String s; 41 while ((s = lss.pop()) != null) 42 System.out.println(s); 43 } 44} 45/* 46stun! 47on 48Phasers 49 */ 50 51 52复习 嵌套内部类 和普通内部类 53 54两种内部类 55嵌套类(静态内部类 static):形式上(写法上)和外部类有关系, 其实在逻辑上和外部类并没有直接的关系。可以嵌套类做测试代码main,上线后,将测试类删除 56 57普通内部类:不仅在形式上和外部类有关系(写在外部类的里面), 在逻辑上也和外部类有联系。 581. 内部类对象的创建依赖于外部类对象; 59 602. 内部类对象持有指向外部类对象的引用。 61 62 63public class Outer { 64 int outerField = 0; 65 class Inner{ 66 void InnerMethod(){ 67 int i = outerField; 68 } 69 } 70} 71 72javac Outer.java 73 74Outer$Inner.class Outer.class 75 76javap -v Outer\$Inner.class 77Classfile /Users/erin/JavaProject/thinking_in_java_example/src/main/java/generics/e5/Outer$Inner.class 78 Last modified 2019-11-27; size 435 bytes 79 MD5 checksum 0e4b5eee2db5f187c00dec5216b5ad8a 80 Compiled from "Outer.java" 81class generics.e5.Outer$Inner 82 minor version: 0 83 major version: 52 84 flags: ACC_SUPER 85Constant pool: 86 #1 = Fieldref #4.#16 // generics/e5/Outer$Inner.this$0:Lgenerics/e5/Outer; 87 #2 = Methodref #5.#17 // java/lang/Object."<init>":()V 88 #3 = Fieldref #18.#19 // generics/e5/Outer.outerField:I 89 #4 = Class #20 // generics/e5/Outer$Inner 90 #5 = Class #23 // java/lang/Object 91 #6 = Utf8 this$0 92 #7 = Utf8 Lgenerics/e5/Outer; 93 #8 = Utf8 <init> 94 #9 = Utf8 (Lgenerics/e5/Outer;)V 95 #10 = Utf8 Code 96 #11 = Utf8 LineNumberTable 97 #12 = Utf8 InnerMethod 98 #13 = Utf8 ()V 99 #14 = Utf8 SourceFile 100 #15 = Utf8 Outer.java 101 #16 = NameAndType #6:#7 // this$0:Lgenerics/e5/Outer; 102 #17 = NameAndType #8:#13 // "<init>":()V 103 #18 = Class #24 // generics/e5/Outer 104 #19 = NameAndType #25:#26 // outerField:I 105 #20 = Utf8 generics/e5/Outer$Inner 106 #21 = Utf8 Inner 107 #22 = Utf8 InnerClasses 108 #23 = Utf8 java/lang/Object 109 #24 = Utf8 generics/e5/Outer 110 #25 = Utf8 outerField 111 #26 = Utf8 I 112{ 113 final generics.e5.Outer this$0; //在内部类Outer$Inner中, 存在一个名字为this$0 , 类型为Outer的成员变量, 并且这个变量是final的。 其实这个就是所谓的“在内部类对象中存在的指向外部类对象的引用”。但是我们在定义这个内部类的时候, 并没有声明它, 所以这个成员变量是编译器加上的 114 descriptor: Lgenerics/e5/Outer; 115 flags: ACC_FINAL, ACC_SYNTHETIC 116 117 generics.e5.Outer$Inner(generics.e5.Outer); //编译器会为内部类的构造方法添加一个参数, 参数的类型就是外部类的类型。 118 descriptor: (Lgenerics/e5/Outer;)V 119 flags: 120 Code: 121 stack=2, locals=2, args_size=2 122 0: aload_0 // 将局部变量表中的第一个引用变量加载到操作数栈。 这里有几点需要说明。 局部变量表中的变量在方法执行前就已经初始化完成;局部变量表中的变量包括方法的参数;成员方法的局部变量表中的第一个变量永远是this;操作数栈就是执行当前代码的栈。所以这句话的意思是: 将this引用从局部变量表加载到操作数栈。 123 1: aload_1 //将局部变量表中的第二个引用变量加载到操作数栈。 这里加载的变量就是构造方法中的Outer类型的参数。 124 2: putfield #1 // Field this$0:Lgenerics/e5/Outer;使用操作数栈顶端的引用变量为指定的成员变量赋值。 这里的意思是将外面传入的Outer类型的参数赋给成员变量this$0 。 这一句putfield字节码就揭示了, 指向外部类对象的这个引用变量是如何赋值的。 125 5: aload_0 126 6: invokespecial #2 // Method java/lang/Object."<init>":()V 127 9: return 128 LineNumberTable: 129 line 5: 0 130 131 void InnerMethod(); 132 descriptor: ()V 133 flags: 134 Code: 135 stack=1, locals=2, args_size=1 136 0: aload_0 137 1: getfield #1 // Field this$0:Lgenerics/e5/Outer; 138 4: getfield #3 // Field generics/e5/Outer.outerField:I 139 7: istore_1 140 8: return 141 LineNumberTable: 142 line 7: 0 143 line 8: 8 144} 145SourceFile: "Outer.java" 146InnerClasses: 147 #21= #4 of #18; //Inner=class generics/e5/Outer$Inner of class generics/e5/Outer 148 149 150关于内部类如何访问外部类的成员, 主要是通过以下几步做到的: 1511 编译器自动为内部类添加一个成员变量, 这个成员变量的类型和外部类的类型相同, 这个成员变量就是指向外部类对象的引用; 1522 编译器自动为内部类的构造方法添加一个参数, 参数的类型是外部类的类型, 在构造方法内部使用这个参数为1中添加的成员变量赋值; 1533 在调用内部类的构造函数初始化内部类对象时, 会默认传入外部类的引用。 154https://blog.csdn.net/weixin_39214481/article/details/80372676

2.3 RandomList

1package generics; 2 3import java.util.ArrayList; 4import java.util.Random; 5 6public class RandomList<T> { 7 private ArrayList<T> storage = new ArrayList<T>(); 8 private Random rand = new Random(47); 9 10 public void add(T item) { 11 storage.add(item);//ArrayList 的 boolean add(E e) 12 } 13 14 public int size() { 15 return storage.size(); 16 } 17 18 public T select() { 19 return storage.get(rand.nextInt(storage.size())); 20 } //ArrayList 的 E get(int index) 21 22 public static void main(String[] args) { 23 RandomList<String> rs = new RandomList<String>(); 24 for (String s : ("The quick brown fox jumped over " + 25 "the lazy brown dog").split(" ")) 26 rs.add(s); 27 for (int i = 0; i < rs.size(); i++) 28 System.out.print(rs.select() + " "); 29 } 30} 31/* 32brown over fox quick quick dog brown The brown lazy 33 */
<h2 id="3">3 泛型接口 </h2> -----------------------

用Coffee和斐波那契数列 分别实现 Generator接口,Iterator接口方式,展示泛型接口。

泛型也可以用于接口,例如生成器,生成器是专门负责创建对象类。

是工厂方法设计模式的一种应用。但工厂方法一般需要参数,

生成器不需要任何参数,一般只定义一个方法。

public interface Generator<T> { T next(); } //接口使用泛型 与 类使用泛型,没有什么区别。

这个例子中,有两种繁殖Coffee的方法, 一种是实现了有next()的Generator, 第二种是实现有遍历功能Iterable 这里两种都是运用了泛型,在Generator和Iterable的泛型类型中加入了Coffee 下面是书上例子,后续对书上例子拆分,清楚显示两种方法。 其中第二个例子中,实现Iterable的Iterator方法,生成Coffee的Iterator方法(hasNext(),next())使用类第一种方法的next方法。

1package generics.coffee; 2 3import net.mindview.util.Generator; 4 5import java.util.Iterator; 6import java.util.Random; 7 8public class CoffeeGenerator implements Generator<Coffee>, Iterable<Coffee> { 9 private Class[] types = {Latte.class, Mocha.class, 10 Cappuccino.class, Americano.class, Breve.class,}; 11 private static Random rand = new Random(47); 12 13 public CoffeeGenerator() { 14 } 15 16 //For iteration 17 private int size = 0; 18 19 public CoffeeGenerator(int sz) { 20 size = sz; 21 } 22 23 class CoffeeItertor implements Iterator<Coffee>{ 24 int count =size; 25 26 @Override 27 public boolean hasNext() { 28 return count > 0; 29 } 30 31 @Override 32 public Coffee next() { 33 count--; 34 return CoffeeGenerator.this.next(); 35 } 36 37 public void remove() { // 不实现 38 throw new UnsupportedOperationException(); 39 } 40 } 41 42 @Override 43 public Iterator<Coffee> iterator() { 44 return new CoffeeItertor(); 45 } 46 47 @Override 48 public Coffee next() { 49 try { 50 return (Coffee) types[rand.nextInt(types.length)].newInstance(); 51 } catch (Exception e) { 52 throw new RuntimeException(e); 53 } 54 } 55 56 57 public static void main(String[] args) { 58 CoffeeGenerator gen = new CoffeeGenerator(); 59 for (int i =0;i < 5;i ++) 60 System.out.println(gen.next()); 61 System.out.println("====="); 62 for (Coffee c: new CoffeeGenerator(5)) 63 System.out.println(c); 64 } 65} 66

将上面的例子拆分下,第一种方法,使用Generator的next方法生成coffee

1package generics.coffee; 2 3import net.mindview.util.Generator; 4 5import java.util.Random; 6 7public class CoffeeMethod1Generator implements Generator<Coffee> { 8 private Class[] types = { 9 Latte.class, 10 Mocha.class, 11 Cappuccino.class, 12 Americano.class, 13 Breve.class 14 }; 15 16 public CoffeeMethod1Generator() { 17 } 18 19 private static Random rand = new Random(47); 20 21 @Override 22 public Coffee next() { 23 try { 24 return (Coffee) (types[rand.nextInt(types.length)]).newInstance();// 这句话是关键,随机生成一个指定类型范围内的coffee实例 25 } catch (Exception e) { 26 throw new RuntimeException(e); 27 } 28 } 29 30 public static void main(String[] args) { 31 CoffeeMethod1Generator coffee1 = new CoffeeMethod1Generator(); 32 for (int i = 0; i < 5; i++) 33 System.out.println(coffee1.next()); 34 } 35} 36/* 37Americano 0 38Latte 1 39Americano 2 40Mocha 3 41Mocha 4 42 */

将上面的例子拆分下,第二种方法

1package generics.coffee; 2 3import java.util.Iterator; 4import java.util.Random; 5 6public class CoffeeMethod2Iterable implements Iterable<Coffee> { 7 8 private Class[] types = { 9 Latte.class, 10 Mocha.class, 11 Cappuccino.class, 12 Americano.class, 13 Breve.class 14 }; 15 16 private Random rand = new Random(47); 17 18 19 20 public Coffee next(){ 21 try { 22 return (Coffee) (types[rand.nextInt(types.length)]).newInstance(); 23 } catch (Exception e) { 24 throw new RuntimeException(e); 25 } 26 } 27 private int size; 28 29 public CoffeeMethod2Iterable(int sz){size = sz;} //因为使用Iterable接口,所以需要有size的构造方法,作为末端哨兵的功能 30 31 @Override 32 public Iterator<Coffee> iterator() { 33 return new CoffeeIerator(); 34 } 35 36 37 private class CoffeeIerator implements Iterator<Coffee> { 38 public int index; 39 @Override 40 public boolean hasNext() { 41 return index <= size; 42 } 43 44 @Override 45 public Coffee next() { 46 index++; 47 return CoffeeMethod2Iterable.this.next();// 外部类对象的引用,使用的方法1中的next方法,获取下一个Coffee对象 48 } 49 } 50 51 public static void main(String[] args) { 52 CoffeeMethod2Iterable coffees = new CoffeeMethod2Iterable(5); 53 for (Coffee coffee: coffees) 54 System.out.println(coffee); 55 } 56} 57 58

以下用另外一个例子,是Generator<T>接口实现,生成斐波那契数列

方法一,使用Generator方法

类型参数为Integer ,基本类型无法作为类型参数

自动打包、自动拆包 可以在基本类型和相应的包装器类型之间进行转换

1package generics; 2 3import net.mindview.util.Generator; 4 5public class Fib2 implements Generator<Integer> {// 实现Generator(只有next方法)接口 6//public class Fib2 implements Generator<int> {// type argument cannot be of primitive type 7 private int count = 0; 8 9 public int fib(int cnt) { 10 if (cnt < 2) return 1;// 斐波那契数列,当为0,1时,为1 11 return fib(cnt - 2) + fib(cnt - 1);//大于1时,为前两个数字之和 12 } 13 14 @Override 15 public Integer next() { 16 return fib(count++); 17 } 18 19 public static void main(String[] args) { 20 Fib2 fib2 = new Fib2(); 21 for (int i = 0; i < 10; i++) 22 System.out.print(fib2.next() + " "); 23 } 24} 25

使用实现Iterable接口生成斐波那契生成器,通过使用继承

1package generics; 2 3import java.util.Iterator; 4 5public class FibIterator extends Fib2 implements Iterable<Integer> { 6 private int n; 7 8 public FibIterator(int count) { 9 n = count; 10 } 11 12 @Override 13 public Iterator<Integer> iterator() { 14 return new Iterator<Integer>() { 15 @Override 16 public boolean hasNext() { 17 return n > 0; 18 } 19 20 @Override 21 public Integer next() { 22 n--; 23 return FibIterator.this.next();// 继承通过Generator(生成next方法),创建适配器,外部类类对象的引用方法 24 } 25 }; 26 } 27 28 public static void main(String[] args) { 29// FibIterator fibIterator = new FibIterator(10); 30// for (Integer integer: fibIterator) 31 for (Integer integer: new FibIterator(10)) //foreach语句,需要边界值。用于hasNext知道何时返回false 32 System.out.print(integer + " "); 33 34 } 35} 36

使用实现Iterable接口生成斐波那契生成器,通过使用组合

e7 使用组合代替继承

1package generics.e7; 2 3import generics.Fib2; 4 5import java.util.Iterator; 6 7public class IterableFibonacci implements Iterable<Integer> { 8 Fib2 fib2 = new Fib2();// 通过组合方式 9 10 private int count; 11 12 public IterableFibonacci(int cnt){count = cnt;} 13 14 @Override 15 public Iterator<Integer> iterator() { 16 return new Iterator<Integer>() { 17 @Override 18 public boolean hasNext() { 19 return count >0; 20 } 21 22 @Override 23 public Integer next() { 24 count--; 25 return fib2.next(); 26 } 27 }; 28 } 29 30 public static void main(String[] args) { 31 for (int i : new IterableFibonacci(10)) 32 System.out.print(i + " "); 33 } 34} 35 36 37 38作业8,与coffee例子一样 39package generics.e8; 40 41import net.mindview.util.Generator; 42 43import java.util.Iterator; 44import java.util.Random; 45 46class StoryCharacter{ 47 private static long counter; 48 private final long id = counter++; 49 public String toString(){ 50 return getClass().getSimpleName() + " " +id; 51 } 52} 53 54class GoodGuy extends StoryCharacter{ 55 public String toString(){ 56 return super.toString() + " is a good guy"; 57 } 58} 59 60class BadGuy extends StoryCharacter{ 61 public String toString(){ 62 return super.toString() + " is a bad guy"; 63 } 64} 65 66class Morton extends BadGuy{} 67class Frank extends BadGuy{} 68class Harmonica extends GoodGuy{} 69class Cheyenne extends GoodGuy{} 70 71class CharacterGenerator implements Generator<StoryCharacter>,Iterable<StoryCharacter>{ 72 private Class[] types = { 73 Morton.class, 74 Frank.class, 75 Harmonica.class, 76 Cheyenne.class 77 }; 78 79 private Random rand = new Random(47); 80 81 82 // for iteratation; 83 private int size; 84 public CharacterGenerator(){} 85 86 public CharacterGenerator(int count){ 87 size = count; 88 } 89 90 91 @Override 92 public Iterator<StoryCharacter> iterator() { 93 return new Iterator<StoryCharacter>() { 94 @Override 95 public boolean hasNext() { 96 return size > 0; 97 } 98 99 @Override 100 public StoryCharacter next() { 101 size--; 102 return CharacterGenerator.this.next(); 103 } 104 }; 105 } 106 107 @Override 108 public StoryCharacter next() { 109 try { 110 return (StoryCharacter)(types[rand.nextInt(types.length)]).newInstance(); 111 } catch (Exception e) { 112 throw new RuntimeException(e); 113 } 114 } 115} 116 117public class E08_CharacterGenerator { 118 public static void main(String[] args) { 119 CharacterGenerator cg= new CharacterGenerator(); 120 for (int i = 0; i < 5; i++) 121 System.out.println(cg.next()); 122 123 System.out.println("======"); 124 125 for (StoryCharacter sc: new CharacterGenerator(5)) 126 System.out.println(sc); 127 128 129 } 130} 131
<h2 id="4">4 泛型方法 </h2> -----------------------

泛型方法所在的类可以是泛型类,也可以不是泛型类,

并且泛型标识符可以完全不一样,也就是说泛型方法和泛型类无关。

普通static方法无法访问泛型类的类型参数,如果要是使用泛型就要定义成泛型静态方法

定义泛型方法只需要将泛型参数列表置于返回值前 public <T> void f(T x)

1package generics; 2 3public class GenericMethods { 4 public <T> void f(T x) { 5 System.out.println(x.getClass().getName()); 6 } 7 8 public static void main(String[] args) { 9 GenericMethods gm = new GenericMethods(); 10 gm.f(""); 11 gm.f(1); 12 gm.f(1.0); 13 gm.f(1.0F); 14 gm.f('c'); 15 gm.f(gm); 16 } 17} 18 19 20package generics.e10; 21 22public class GenericMethods { 23 public <B,C> void f(String a,B b,C c) {//多个类型不同参数,非参数化类型 24 System.out.println(a.getClass().getName()); 25 System.out.println(b.getClass().getName()); 26 System.out.println(c.getClass().getName()); 27 } 28 29 public static void main(String[] args) { 30 GenericMethods gm = new GenericMethods(); 31 gm.f("",1,gm); 32 } 33}

4.1 杠杆利用类型参数推断

使用泛型方法时编译期会通过类型参数推断来为我们找出具体类型,而不必自己声明时什么类型

类型推断只对赋值操作有效,其它时候不起作用 JDK8不存在例子中编译问题

显示类型说明

1package generics; 2 3import net.mindview.util.New; 4import typeinfo.pets.*; 5 6import java.util.*; 7 8public class LimitsOfInference { 9 static void 10 f(Map<Person, List<? extends Pet>> petPeople) { 11 } 12 13 public static void main(String[] args) { 14 f(New.<Person, List<? extends Pet>>map()); // 显示的类型说明 15 // 如果是在定义该方法的类的内部,需要this. 16 // static方法,需要 ClassName. 17 f(New.map()); // Does not compile JDK8 正常 18 } 19}

4.2 可变参数与泛型方法

泛型方法与可变参数列表能够很好地共存

下面的方法展示了和类库java.util.Arrays.asList()方法相同的功能

1package generics; 2//: generics/GenericVarargs.java 3 4import java.util.*; 5 6public class GenericVarargs { 7 public static <T> List<T> makeList(T... args) { 8 List<T> result = new ArrayList<T>(); 9 for (T item : args) 10 result.add(item); 11 return result; 12 } 13 14 public static void main(String[] args) { 15 List<String> ls = makeList("A"); 16 System.out.println(ls); 17 ls = makeList("A", "B", "C"); 18 System.out.println(ls); 19 ls = makeList("ABCDEFFHIJKLMNOPQRSTUVWXYZ".split("")); 20 System.out.println(ls); 21 } 22} /* Output: 23[A] 24[A, B, C] 25[, A, B, C, D, E, F, F, H, I, J, K, L, M, N, O, P, Q, R, S, T, U, V, W, X, Y, Z] 26*///:~

4.3 用于Generator的泛型方法

1package generics; 2//: generics/Generators.java 3// A utility to use with Generators. 4import generics.coffee.*; 5import java.util.*; 6import net.mindview.util.*; 7 8public class Generators { 9 public static <T> Collection<T> 10 fill(Collection<T> coll, Generator<T> gen, int n) { //Generator的泛型方法 11 for(int i = 0; i < n; i++) 12 coll.add(gen.next()); 13 return coll; 14 } 15 public static void main(String[] args) { 16 Collection<Coffee> coffee = fill( 17 new ArrayList<Coffee>(), new CoffeeGenerator(), 4); 18 for(Coffee c : coffee) 19 System.out.println(c); 20 Collection<Integer> fnumbers = fill( 21 new ArrayList<Integer>(), new Fibonacci(), 12); 22 for(int i : fnumbers) 23 System.out.print(i + ", "); 24 } 25} /* Output: 26Americano 0 27Latte 1 28Americano 2 29Mocha 3 301, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144, 31*///:~

4.4 一个通用的Generator

1package generics; 2 3import net.mindview.util.Generator; 4 5public class BasicGenerator<T> implements Generator<T> { 6 private Class<T> type; 7 8 public BasicGenerator(Class<T> type){this.type = type;} 9 10 @Override 11 public T next() { 12 try { 13 return type.newInstance(); 14 } catch (Exception e) { 15 throw new RuntimeException(e); 16 } 17 } 18 19 public static <T> Generator<T> create(Class<T> type){ 20 return new BasicGenerator<T>(type); 21 } 22 23} 24 25 26 27package generics; 28 29public class CountedObject { 30 private static long counter = 0; 31 private final long id = counter++; 32 public long id(){return id;} 33 public String toString(){ 34 return "CountedObject " + id; 35 } 36} 37 38 39package generics; 40 41import net.mindview.util.Generator; 42 43public class BasicGeneratorDemo { 44 public static void main(String[] args) { 45 Generator<CountedObject> gen = BasicGenerator.create(CountedObject.class); 46 // BasicGenerator<CountedObject> gen = new BasicGenerator(CountedObject.class); 等价 47 for (int i = 0; i < 5;i ++) 48 System.out.println(gen.next()); 49 } 50} 51

4.5 简化元组的使用

4.6一个Set实用工具

<h2 id="5">5 匿名内部类 </h2> ------------------------

泛型用于内部类及匿名内部类。

示例使用匿名内部类实现Generator接口

1package generics; 2 3import net.mindview.util.Generator; 4 5import java.util.*; 6 7class Customer { 8 private static long counter = 1; 9 private final long id = counter++; 10 11 //私有化构造方法,只能通过Generator 获取实例 12 private Customer() { 13 } 14 15 public String toString() { 16 return "Customer " + id; 17 } 18 19 // A method to produce Generator objects: 20 // Customer 对象生成器 21 // Generator 每次调用 都会创建 一个 Generator对象,但这不是必要的。 22 public static Generator<Customer> generator() { 23 return new Generator<Customer>() { 24 @Override 25 public Customer next() { 26 return new Customer(); 27 } 28 }; 29 } 30} 31 32class Teller { 33 private static long counter = 1; 34 private final long id = counter++; 35 36 private Teller() { 37 } 38 39 public String toString() { 40 return "Teller " + id; 41 } 42 43 // A single Generator object: 44 // 匿名内部类2 45 // 单例Generator对象: 46 // 可以对比Customer的generator方法 这里只会创建一个generator实例 47 public static Generator<Teller> generator = 48 new Generator<Teller>() { 49 @Override 50 public Teller next() { 51 return new Teller(); 52 } 53 }; 54} 55 56public class BankTeller { 57 public static void serve(Teller t, Customer c) { 58 System.out.println(t + " serves " + c); 59 } 60 61 public static void main(String[] args) { 62 Random rand = new Random(47); 63 Queue<Customer> line = new LinkedList<Customer>(); 64 Generators.fill(line, Customer.generator(), 15); 65 List<Teller> tellers = new ArrayList<Teller>(); 66 Generators.fill(tellers, Teller.generator, 4); 67 for (Customer c : line)//遍历line,随机取出teller与 Customer 按序输出 68 serve(tellers.get(rand.nextInt(tellers.size())), c); 69 } 70}
<h2 id="6">6 构建复杂模型 </h2> ------------------------- <h2 id="1">1 </h2> ------------------ <h2 id="1">1 </h2> ------------------ <h2 id="1">1 </h2> ------------------
点赞
收藏

评论区

加载中...

相关推荐

MySQL:[Err] 1292 - Incorrect datetime value: ‘0000-00-00 00:00:00‘ for column ‘CREATE_TIME‘ at row 1

文章目录问题用navicat导入数据时,报错:原因这是因为当前的MySQL不支持datetime为0的情况。解决修改sql\mode:sql\mode:SQLMode定义了MySQL应支持的SQL语法、数据校验等,这样可以更容易地在不同的环境中使用MySQL。全局s

Oracle 分组与拼接字符串同时使用

SELECTT.,ROWNUMIDFROM(SELECTT.EMPLID,T.NAME,T.BU,T.REALDEPART,T.FORMATDATE,SUM(T.S0)S0,MAX(UPDATETIME)CREATETIME,LISTAGG(TOCHAR(

手写Java HashMap源码

HashMap的使用教程HashMap的使用教程HashMap的使用教程HashMap的使用教程HashMap的使用教程22

KVM调整cpu和内存

一.修改kvm虚拟机的配置1、virsheditcentos7找到“memory”和“vcpu”标签,将<namecentos7</name<uuid2220a6d1a36a4fbb8523e078b3dfe795</uuid

Java的泛型详解(一)

Java的泛型详解(一)编写的代码可以被不同类型的对象所重用。因为上面的一个优点,泛型也可以减少代码的编写。1|2泛型的使用简单泛型类publicclassPair{privateTfirst;privateTsecond;publicPair(){firstnull;secondnull;

20175209 《Java程序设计》第八周学习总结

20175209《Java程序设计》第八周学习总结一、教材知识点总结1.泛型1.泛型类声明:格式classPeople<EPeople是泛型类名称E是泛型列表,可以是任何对象或接口,但不能是基本类型数据