zoukankan      html  css  js  c++  java
  • Thinking in java Chapter15 泛型

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

    1 与C++比较

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

    2 简单泛型

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

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

    2.1 元组

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

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

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

    package generics;
    
    import generics.e3.SixTuple;
    import net.mindview.util.*;
    
    class Amphibian{} //两栖动物
    class Vehicle{}//车辆
    public class TupleTest {
        static TwoTuple<String,Integer> f(){
            return new TwoTuple<String,Integer>("hi",47);
        }
    
        static ThreeTuple<Amphibian,String,Integer> g(){
            return new ThreeTuple<Amphibian,String,Integer>(new Amphibian(),"hi",47);
        }
    
        static FourTuple<Vehicle,Amphibian,String,Integer> h(){
            return new FourTuple<Vehicle,Amphibian,String,Integer>(new Vehicle(),new Amphibian(),"hi",47);
        }
    
        static FiveTuple<Vehicle,Amphibian,String,Integer,Double> k(){
            return new FiveTuple<Vehicle,Amphibian,String,Integer,Double>(new Vehicle(),new Amphibian(),"hi",47,11.1);
        }
    
        static SixTuple<Vehicle,Amphibian,String,Integer,Double,Float> i(){
            return new SixTuple<Vehicle,Amphibian,String,Integer,Double,Float>(new Vehicle(),new Amphibian(),"hi",47,11.1,22.22F);
        }
    
    
        public static void main(String[] args) {
            TwoTuple<String,Integer> ttsi = f();
    //        ttsi.first = "there"; //编译错误,final
            System.out.println(ttsi);
            System.out.println(g());
            System.out.println(h());
            System.out.println(k());
            System.out.println(i());
        }
    }
    
    /*
    
     */
    

    2.2 一个堆栈类

    传统的下推堆栈

    11章使用LinkedList

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

    package generics;
    
    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); 
            // push "Phasers"时,创建对象Node<String>("Phasers",top),top.item == null top.next == null ,
            // 并将创建的Node结点,指向top,即top.item == "Phasers",top.next ==  item和next为null的结点
            
            // push "on"时,创建对象Node<String>("on",top),将"Phasers"的结点,作为"on"的next
    
            // push "stun!"时,创建对象Node<String>("stun!",top),将"on"的结点,作为"stun!"的next
        }
    
        public T pop() {
            T result = top.item; // 取值
            if (!top.end())
                top = top.next; // 下移
            return result; // 返回取出的值
        }
    
        public static void main(String[] args) {
            LinkedStack<String> lss = new LinkedStack<String>();
            for (String s : "Phasers on stun!".split(" "))
                lss.push(s);
            String s;
            while ((s = lss.pop()) != null)
                System.out.println(s);
        }
    }
    /*
    stun!
    on
    Phasers
     */
    
    
    

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

    
    package generics.e5;
    
    public class LinkedStack<T> {
        private  class Node{ //将原来的嵌套类 修改 为普通内部类。即Node不能为static
            T item;
            Node next;
    
            Node() {
                item = null;
                next = null;
            }
    
            Node(T item, Node next) {
                this.item = item;
                this.next = next;
            }
    
            boolean end() {
                return item == null && next == null;
            }
        }
    
        private Node top = new Node(); // End Sentinel 未端哨兵
    
        public void push(T item) {
            top = new Node(item, top); //
        }
    
        public T pop() {
            T result = top.item; // 取值
            if (!top.end())
                top = top.next; // 下移
            return result;
        }
    
        public static void main(String[] args) {
            LinkedStack<String> lss = new LinkedStack<String>();
            for (String s : "Phasers on stun!".split(" "))
                lss.push(s);
            String s;
            while ((s = lss.pop()) != null)
                System.out.println(s);
        }
    }
    /*
    stun!
    on
    Phasers
     */
    
    
    复习 嵌套内部类 和普通内部类
    
    两种内部类
    嵌套类(静态内部类 static):形式上(写法上)和外部类有关系, 其实在逻辑上和外部类并没有直接的关系。可以嵌套类做测试代码main,上线后,将测试类删除
    
    普通内部类:不仅在形式上和外部类有关系(写在外部类的里面), 在逻辑上也和外部类有联系。
    1. 内部类对象的创建依赖于外部类对象;
    
    2. 内部类对象持有指向外部类对象的引用。
    
    
    public class Outer {
        int outerField = 0;
        class Inner{
            void InnerMethod(){
                int i = outerField;
            }
        }
    }
    
    javac Outer.java
    
    Outer$Inner.class       Outer.class
    
    javap -v Outer$Inner.class 
    Classfile /Users/erin/JavaProject/thinking_in_java_example/src/main/java/generics/e5/Outer$Inner.class
      Last modified 2019-11-27; size 435 bytes
      MD5 checksum 0e4b5eee2db5f187c00dec5216b5ad8a
      Compiled from "Outer.java"
    class generics.e5.Outer$Inner
      minor version: 0
      major version: 52
      flags: ACC_SUPER
    Constant pool:
       #1 = Fieldref           #4.#16         // generics/e5/Outer$Inner.this$0:Lgenerics/e5/Outer;
       #2 = Methodref          #5.#17         // java/lang/Object."<init>":()V
       #3 = Fieldref           #18.#19        // generics/e5/Outer.outerField:I
       #4 = Class              #20            // generics/e5/Outer$Inner
       #5 = Class              #23            // java/lang/Object
       #6 = Utf8               this$0
       #7 = Utf8               Lgenerics/e5/Outer;
       #8 = Utf8               <init>
       #9 = Utf8               (Lgenerics/e5/Outer;)V
      #10 = Utf8               Code
      #11 = Utf8               LineNumberTable
      #12 = Utf8               InnerMethod
      #13 = Utf8               ()V
      #14 = Utf8               SourceFile
      #15 = Utf8               Outer.java
      #16 = NameAndType        #6:#7          // this$0:Lgenerics/e5/Outer;
      #17 = NameAndType        #8:#13         // "<init>":()V
      #18 = Class              #24            // generics/e5/Outer
      #19 = NameAndType        #25:#26        // outerField:I
      #20 = Utf8               generics/e5/Outer$Inner
      #21 = Utf8               Inner
      #22 = Utf8               InnerClasses
      #23 = Utf8               java/lang/Object
      #24 = Utf8               generics/e5/Outer
      #25 = Utf8               outerField
      #26 = Utf8               I
    {
      final generics.e5.Outer this$0; //在内部类Outer$Inner中, 存在一个名字为this$0 , 类型为Outer的成员变量, 并且这个变量是final的。 其实这个就是所谓的“在内部类对象中存在的指向外部类对象的引用”。但是我们在定义这个内部类的时候, 并没有声明它, 所以这个成员变量是编译器加上的
        descriptor: Lgenerics/e5/Outer;
        flags: ACC_FINAL, ACC_SYNTHETIC
    
      generics.e5.Outer$Inner(generics.e5.Outer); //编译器会为内部类的构造方法添加一个参数, 参数的类型就是外部类的类型。
        descriptor: (Lgenerics/e5/Outer;)V
        flags:
        Code:
          stack=2, locals=2, args_size=2
             0: aload_0         //  将局部变量表中的第一个引用变量加载到操作数栈。 这里有几点需要说明。 局部变量表中的变量在方法执行前就已经初始化完成;局部变量表中的变量包括方法的参数;成员方法的局部变量表中的第一个变量永远是this;操作数栈就是执行当前代码的栈。所以这句话的意思是: 将this引用从局部变量表加载到操作数栈。
             1: aload_1 //将局部变量表中的第二个引用变量加载到操作数栈。 这里加载的变量就是构造方法中的Outer类型的参数。
             2: putfield      #1                  // Field this$0:Lgenerics/e5/Outer;使用操作数栈顶端的引用变量为指定的成员变量赋值。 这里的意思是将外面传入的Outer类型的参数赋给成员变量this$0 。 这一句putfield字节码就揭示了, 指向外部类对象的这个引用变量是如何赋值的。
             5: aload_0
             6: invokespecial #2                  // Method java/lang/Object."<init>":()V
             9: return
          LineNumberTable:
            line 5: 0
    
      void InnerMethod();
        descriptor: ()V
        flags:
        Code:
          stack=1, locals=2, args_size=1
             0: aload_0
             1: getfield      #1                  // Field this$0:Lgenerics/e5/Outer;
             4: getfield      #3                  // Field generics/e5/Outer.outerField:I
             7: istore_1
             8: return
          LineNumberTable:
            line 7: 0
            line 8: 8
    }
    SourceFile: "Outer.java"
    InnerClasses:
         #21= #4 of #18; //Inner=class generics/e5/Outer$Inner of class generics/e5/Outer
    
    
    关于内部类如何访问外部类的成员, 主要是通过以下几步做到的:
    1 编译器自动为内部类添加一个成员变量, 这个成员变量的类型和外部类的类型相同, 这个成员变量就是指向外部类对象的引用;
    2 编译器自动为内部类的构造方法添加一个参数, 参数的类型是外部类的类型, 在构造方法内部使用这个参数为1中添加的成员变量赋值;
    3 在调用内部类的构造函数初始化内部类对象时, 会默认传入外部类的引用。
    https://blog.csdn.net/weixin_39214481/article/details/80372676
    

    2.3 RandomList

    package generics;
    
    import java.util.ArrayList;
    import java.util.Random;
    
    public class RandomList<T> {
        private ArrayList<T> storage = new ArrayList<T>();
        private Random rand = new Random(47);
    
        public void add(T item) {
            storage.add(item);//ArrayList 的 boolean add(E e)
        }
    
        public int size() {
            return storage.size();
        }
    
        public T select() {
            return storage.get(rand.nextInt(storage.size()));
        } //ArrayList 的 E get(int index)
    
        public static void main(String[] args) {
            RandomList<String> rs = new RandomList<String>();
            for (String s : ("The quick brown fox jumped over " +
                    "the lazy brown dog").split(" "))
                rs.add(s);
            for (int i = 0; i < rs.size(); i++)
                System.out.print(rs.select() + " ");
        }
    }
    /*
    brown over fox quick quick dog brown The brown lazy
     */
    

    3 泛型接口

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

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

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

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

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

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

    
    package generics.coffee;
    
    import net.mindview.util.Generator;
    
    import java.util.Iterator;
    import java.util.Random;
    
    public class CoffeeGenerator implements Generator<Coffee>, Iterable<Coffee> {
        private Class[] types = {Latte.class, Mocha.class,
                Cappuccino.class, Americano.class, Breve.class,};
        private static Random rand = new Random(47);
    
        public CoffeeGenerator() {
        }
    
        //For iteration
        private int size = 0;
    
        public CoffeeGenerator(int sz) {
            size = sz;
        }
    
        class CoffeeItertor implements Iterator<Coffee>{
            int count =size;
    
            @Override
            public boolean hasNext() {
                return count > 0;
            }
    
            @Override
            public Coffee next() {
                count--;
                return CoffeeGenerator.this.next();
            }
    
            public void remove() { // 不实现
                throw new UnsupportedOperationException();
            }
        }
    
        @Override
        public Iterator<Coffee> iterator() {
            return new CoffeeItertor();
        }
    
        @Override
        public Coffee next() {
            try {
                return (Coffee) types[rand.nextInt(types.length)].newInstance();
            } catch (Exception e) {
                throw new RuntimeException(e);
            }
        }
    
    
        public static void main(String[] args) {
            CoffeeGenerator gen = new CoffeeGenerator();
            for (int i =0;i < 5;i ++)
                System.out.println(gen.next());
            System.out.println("=====");
            for (Coffee c: new CoffeeGenerator(5))
                System.out.println(c);
        }
    }
    
    

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

    package generics.coffee;
    
    import net.mindview.util.Generator;
    
    import java.util.Random;
    
    public class CoffeeMethod1Generator implements Generator<Coffee> {
        private Class[] types = {
                Latte.class,
                Mocha.class,
                Cappuccino.class,
                Americano.class,
                Breve.class
        };
    
        public CoffeeMethod1Generator() {
        }
    
        private static Random rand = new Random(47);
    
        @Override
        public Coffee next() {
            try {
                return (Coffee) (types[rand.nextInt(types.length)]).newInstance();// 这句话是关键,随机生成一个指定类型范围内的coffee实例
            } catch (Exception e) {
                throw new RuntimeException(e);
            }
        }
    
        public static void main(String[] args) {
            CoffeeMethod1Generator coffee1 = new CoffeeMethod1Generator();
            for (int i = 0; i < 5; i++)
                System.out.println(coffee1.next());
        }
    }
    /*
    Americano 0
    Latte 1
    Americano 2
    Mocha 3
    Mocha 4
     */
    

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

    package generics.coffee;
    
    import java.util.Iterator;
    import java.util.Random;
    
    public class CoffeeMethod2Iterable implements Iterable<Coffee> {
    
        private  Class[] types = {
                Latte.class,
                Mocha.class,
                Cappuccino.class,
                Americano.class,
                Breve.class
        };
    
        private Random rand = new Random(47);
    
    
    
        public Coffee next(){
            try {
                return (Coffee) (types[rand.nextInt(types.length)]).newInstance();
            } catch (Exception e) {
               throw  new RuntimeException(e);
            }
        }
        private int size;
    
        public CoffeeMethod2Iterable(int sz){size = sz;} //因为使用Iterable接口,所以需要有size的构造方法,作为末端哨兵的功能
    
        @Override
        public Iterator<Coffee> iterator() {
            return new CoffeeIerator();
        }
    
    
        private class CoffeeIerator implements Iterator<Coffee> {
            public int index;
            @Override
            public boolean hasNext() {
                return index <= size;
            }
    
            @Override
            public Coffee next() {
                index++;
                return CoffeeMethod2Iterable.this.next();// 外部类对象的引用,使用的方法1中的next方法,获取下一个Coffee对象
            }
        }
    
        public static void main(String[] args) {
            CoffeeMethod2Iterable coffees = new CoffeeMethod2Iterable(5);
            for (Coffee coffee: coffees)
                System.out.println(coffee);
        }
    }
    
    
    

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

    方法一,使用Generator方法

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

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

    package generics;
    
    import net.mindview.util.Generator;
    
    public class Fib2 implements Generator<Integer> {// 实现Generator(只有next方法)接口
    //public class Fib2 implements Generator<int> {// type argument cannot be of primitive type
        private int count = 0;
    
        public int fib(int cnt) {
            if (cnt < 2) return 1;// 斐波那契数列,当为0,1时,为1
            return fib(cnt - 2) + fib(cnt - 1);//大于1时,为前两个数字之和
        }
    
        @Override
        public Integer next() {
            return fib(count++);
        }
    
        public static void main(String[] args) {
            Fib2 fib2 = new Fib2();
            for (int i = 0; i < 10; i++)
                System.out.print(fib2.next() +  " ");
        }
    }
    
    

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

    package generics;
    
    import java.util.Iterator;
    
    public class FibIterator extends Fib2 implements Iterable<Integer> {
        private int n;
    
        public FibIterator(int count) {
            n = count;
        }
    
        @Override
        public Iterator<Integer> iterator() {
            return new Iterator<Integer>() {
                @Override
                public boolean hasNext() {
                    return n > 0;
                }
    
                @Override
                public Integer next() {
                    n--;
                    return FibIterator.this.next();// 继承通过Generator(生成next方法),创建适配器,外部类类对象的引用方法
                }
            };
        }
    
        public static void main(String[] args) {
    //        FibIterator fibIterator = new FibIterator(10);
    //        for (Integer integer: fibIterator)
            for (Integer integer: new FibIterator(10)) //foreach语句,需要边界值。用于hasNext知道何时返回false
                System.out.print(integer + " ");
            
        }
    }
    
    

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

    e7 使用组合代替继承

    package generics.e7;
    
    import generics.Fib2;
    
    import java.util.Iterator;
    
    public class IterableFibonacci implements Iterable<Integer> {
        Fib2 fib2 = new Fib2();// 通过组合方式
    
        private int count;
    
        public IterableFibonacci(int cnt){count = cnt;}
    
        @Override
        public Iterator<Integer> iterator() {
            return new Iterator<Integer>() {
                @Override
                public boolean hasNext() {
                    return count >0;
                }
    
                @Override
                public Integer next() {
                    count--;
                    return fib2.next();
                }
            };
        }
    
        public static void main(String[] args) {
            for (int i : new IterableFibonacci(10))
                System.out.print(i + " ");
        }
    }
    
    
    作业8,与coffee例子一样
    package generics.e8;
    
    import net.mindview.util.Generator;
    
    import java.util.Iterator;
    import java.util.Random;
    
    class StoryCharacter{
        private static long counter;
        private final long id = counter++;
        public String toString(){
            return getClass().getSimpleName() + " " +id;
        }
    }
    
    class GoodGuy extends StoryCharacter{
        public String toString(){
            return super.toString() + " is a good guy";
        }
    }
    
    class BadGuy extends StoryCharacter{
        public String toString(){
            return super.toString() + " is a bad guy";
        }
    }
    
    class Morton extends BadGuy{}
    class Frank extends BadGuy{}
    class Harmonica extends GoodGuy{}
    class Cheyenne extends GoodGuy{}
    
    class CharacterGenerator implements Generator<StoryCharacter>,Iterable<StoryCharacter>{
        private Class[] types = {
                Morton.class,
                Frank.class,
                Harmonica.class,
                Cheyenne.class
        };
    
        private Random rand = new Random(47);
    
    
        // for iteratation;
        private int size;
        public CharacterGenerator(){}
    
        public CharacterGenerator(int count){
            size = count;
        }
    
    
        @Override
        public Iterator<StoryCharacter> iterator() {
            return new Iterator<StoryCharacter>() {
                @Override
                public boolean hasNext() {
                    return size > 0;
                }
    
                @Override
                public StoryCharacter next() {
                    size--;
                    return CharacterGenerator.this.next();
                }
            };
        }
    
        @Override
        public StoryCharacter next() {
            try {
                return (StoryCharacter)(types[rand.nextInt(types.length)]).newInstance();
            } catch (Exception e) {
                throw new RuntimeException(e);
            }
        }
    }
    
    public class E08_CharacterGenerator {
        public static void main(String[] args) {
            CharacterGenerator cg= new CharacterGenerator();
            for (int i = 0; i < 5; i++)
                System.out.println(cg.next());
    
            System.out.println("======");
    
            for (StoryCharacter sc: new CharacterGenerator(5))
                System.out.println(sc);
    
    
        }
    }
    
    

    4 泛型方法

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

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

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

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

    package generics;
    
    public class GenericMethods {
        public <T> void f(T x) {
            System.out.println(x.getClass().getName());
        }
    
        public static void main(String[] args) {
            GenericMethods gm = new GenericMethods();
            gm.f("");
            gm.f(1);
            gm.f(1.0);
            gm.f(1.0F);
            gm.f('c');
            gm.f(gm);
        }
    }
    
    package generics.e10;
    
    public class GenericMethods {
        public <B,C> void f(String a,B b,C c) {//多个类型不同参数,非参数化类型
            System.out.println(a.getClass().getName());
            System.out.println(b.getClass().getName());
            System.out.println(c.getClass().getName());
        }
    
        public static void main(String[] args) {
            GenericMethods gm = new GenericMethods();
            gm.f("",1,gm);
        }
    }
    

    4.1 杠杆利用类型参数推断

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

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

    显示类型说明

    package generics;
    
    import net.mindview.util.New;
    import typeinfo.pets.*;
    
    import java.util.*;
    
    public class LimitsOfInference {
        static void
        f(Map<Person, List<? extends Pet>> petPeople) {
        }
    
        public static void main(String[] args) {
            f(New.<Person, List<? extends Pet>>map()); // 显示的类型说明
            // 如果是在定义该方法的类的内部,需要this.
            // static方法,需要 ClassName.
            f(New.map()); // Does not compile JDK8 正常
        }
    }
    

    4.2 可变参数与泛型方法

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

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

    package generics;
    //: generics/GenericVarargs.java
    
    import java.util.*;
    
    public class GenericVarargs {
        public static <T> List<T> makeList(T... args) {
            List<T> result = new ArrayList<T>();
            for (T item : args)
                result.add(item);
            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);
            ls = makeList("ABCDEFFHIJKLMNOPQRSTUVWXYZ".split(""));
            System.out.println(ls);
        }
    } /* Output:
    [A]
    [A, B, C]
    [, 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]
    *///:~
    

    4.3 用于Generator的泛型方法

    package generics;
    //: generics/Generators.java
    // A utility to use with Generators.
    import generics.coffee.*;
    import java.util.*;
    import net.mindview.util.*;
    
    public class Generators {
        public static <T> Collection<T>
        fill(Collection<T> coll, Generator<T> gen, int n) { //Generator的泛型方法
            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.println(c);
            Collection<Integer> fnumbers = fill(
                    new ArrayList<Integer>(), new Fibonacci(), 12);
            for(int i : fnumbers)
                System.out.print(i + ", ");
        }
    } /* Output:
    Americano 0
    Latte 1
    Americano 2
    Mocha 3
    1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144,
    *///:~
    

    4.4 一个通用的Generator

    package generics;
    
    import net.mindview.util.Generator;
    
    public class BasicGenerator<T> implements Generator<T> {
        private Class<T> type;
    
        public BasicGenerator(Class<T> type){this.type = type;}
    
        @Override
        public T next() {
            try {
                return type.newInstance();
            } catch (Exception e) {
                throw new RuntimeException(e);
            }
        }
    
        public static <T> Generator<T> create(Class<T> type){
            return new BasicGenerator<T>(type);
        }
    
    }
    
    
    
    package generics;
    
    public class CountedObject {
        private static long counter = 0;
        private final long id = counter++;
        public long id(){return id;}
        public String toString(){
            return "CountedObject " + id;
        }
    }
    
    
    package generics;
    
    import net.mindview.util.Generator;
    
    public class BasicGeneratorDemo {
        public static void main(String[] args) {
            Generator<CountedObject> gen = BasicGenerator.create(CountedObject.class);
            //  BasicGenerator<CountedObject> gen = new BasicGenerator(CountedObject.class); 等价
            for (int i = 0; i < 5;i ++)
                System.out.println(gen.next());
        }
    }
    
    

    4.5 简化元组的使用

    4.6一个Set实用工具

    5 匿名内部类

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

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

    package generics;
    
    import net.mindview.util.Generator;
    
    import java.util.*;
    
    class Customer {
        private static long counter = 1;
        private final long id = counter++;
    
        //私有化构造方法,只能通过Generator 获取实例
        private Customer() {
        }
    
        public String toString() {
            return "Customer " + id;
        }
    
        // A method to produce Generator objects:
        // Customer 对象生成器
        // Generator 每次调用 都会创建 一个 Generator对象,但这不是必要的。
        public static Generator<Customer> generator() {
            return new Generator<Customer>() {
                @Override
                public Customer next() {
                    return new Customer();
                }
            };
        }
    }
    
    class Teller {
        private static long counter = 1;
        private final long id = counter++;
    
        private Teller() {
        }
    
        public String toString() {
            return "Teller " + id;
        }
    
        // A single Generator object:
        // 匿名内部类2
        // 单例Generator对象:
        // 可以对比Customer的generator方法 这里只会创建一个generator实例
        public static Generator<Teller> generator =
                new Generator<Teller>() {
                    @Override
                    public Teller next() {
                        return new Teller();
                    }
                };
    }
    
    public class BankTeller {
        public static void serve(Teller t, Customer c) {
            System.out.println(t + " serves " + c);
        }
    
        public static void main(String[] args) {
            Random rand = new Random(47);
            Queue<Customer> line = new LinkedList<Customer>();
            Generators.fill(line, Customer.generator(), 15);
            List<Teller> tellers = new ArrayList<Teller>();
            Generators.fill(tellers, Teller.generator, 4);
            for (Customer c : line)//遍历line,随机取出teller与 Customer 按序输出
                serve(tellers.get(rand.nextInt(tellers.size())), c);
        }
    }
    

    6 构建复杂模型

    1

    1

    1

  • 相关阅读:
    frog-jump
    nth-digit
    binary-watch
    elimination-game
    evaluate-division
    random-pick-index
    integer-replacement
    rotate-function
    longest-substring-with-at-least-k-repeating-characters
    decode-string
  • 原文地址:https://www.cnblogs.com/erinchen/p/11951291.html
Copyright © 2011-2022 走看看