Java编程思想—泛型(1)

Java编程思想—泛型(1)

泛型

简单使用

三个Holder进行对比,引出类型参数的概念

public class Apple {
}


public class Holder_1 {

//    明确指定持有的对象
    private Apple apple;

    public Holder_1(Apple apple) {
        this.apple = apple;
    }

    public Apple getApple() {
        return apple;
    }
}



public class Holder_2 {

    private Object object;

    public Holder_2(Object object) {
        this.object = object;
    }

    public void setObject(Object object) {
        this.object = object;
    }

    public Object getObject() {
        return object;
    }

    public static void main(String[] args) {

        Holder_2 holder_2 = new Holder_2(new Apple());

//        需要转型为Apple
        Apple a1 = (Apple) holder_2.getObject();

        holder_2.setObject("String");

//        同上
        String s = (String) holder_2.getObject();

        System.out.println(s);
//Holder_2可以存储任何对象
    }
}



public class Holder_3<T> {

    private T a;

    public Holder_3(T a) {
        this.a = a;
    }

    public T getA() {
        return a;
    }

    public void setA(T a) {
        this.a = a;
    }


    public static void main(String[] args) {

        Holder_3<Apple> holder_3 = new Holder_3<>(new Apple());


//        此处不需要转型了
        Apple apple = holder_3.getA();

//        错误
//        holder_3.setA("String");

//        比起Holder_2的Object类型,Holder_3我们可以不指定类型
//        而是以后再决定,所以使用  类型参数,用尖括号括住,放在 类名后面



    }
}




元组类库

前面的例子都是持有一个对象,那么我们肯定有时想要持有多个对象,那么就从元组的角度来进行引出这个操作思路。

先简单的上一个2维元组(持有两个对象)


public class TwoTuple<A,B> {

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

first和second字段虽然用的public修饰,但是final能够保证安全。

那么我们想要持有更多更多的对象呢,可以考虑用继承实现

public class ThreeTuple<A,B,C> extends TwoTuple<A,B> {

    public final C third;
    public ThreeTuple(A a, B b, C c) {
        super(a, b);
        third = c;
    }
    public String toString() {
        return "(" + first + ", " + second + ", " + third + ")";
    }
}


public class FourTuple<A,B,C,D> extends ThreeTuple<A,B,C> {
    public final D fourth;
    public FourTuple(A a, B b, C c, D d) {
        super(a, b, c);
        fourth = d;
    }
    public String toString() {
        return "(" + first + ", " + second + ", " +
                third + ", " + fourth + ")";
    }



}


public class FiveTuple<A,B,C,D,E>
        extends FourTuple<A,B,C,D> {
    public final E fifth;
    public FiveTuple(A a, B b, C c, D d, E e) {
        super(a, b, c, d);
        fifth = e;
    }
    public String toString() {
        return "(" + first + ", " + second + ", " +
                third + ", " + fourth + ", " + fifth + ")";
    }

}




前面准备了那么多,是时候用一下了

public class Apple {
}


public class Orange {
}



public class TupleTest {


    static TwoTuple<String,Integer> f(){
        return new TwoTuple<>("Hello",100);
    }

    static ThreeTuple<Apple,String,Integer> g(){
        return new ThreeTuple<>(new Apple(),"APPLE",1000);
    }

    public static void main(String[] args) {

        TwoTuple<String,Integer> twoTuple = f();

        System.out.println(twoTuple);

        ThreeTuple<Apple,String,Integer> threeTuple = g();

        System.out.println(threeTuple);

    }

}


泛型接口

考虑在接口中使用泛型。

从生成器的角度来进行学习,生成器就是一种专门负责创建对象的类。

在生成器中只定义一个方法,用来产生新的对象。


public interface Generator<T> {
    
//    方法next返回的类型是参数化的T
    T next();
    
}

接下来用各种咖啡来实现下这个Generator接口。

public class Coffee {

    private static long counter = 0;

//   counter 每次赋值后自动+1   id用来记录生成次数
    private final long id = counter++;
    public String toString() {
        return getClass().getSimpleName() + " " + id;
    }


}

public class Latte extends Coffee{
//    拿铁
}

public class Americano extends Coffee{
//    美式
}


public class Breve extends Coffee{
}


public class Cappuccino extends Coffee{
//    卡普契诺
}


public class Mocha extends Coffee{
//    摩卡
}

现在,可以实现Generator< Coffee >接口了。使得它能够随机生成不同类型的Coffee对象

public class CoffeeGenerator implements Generator<Coffee>,Iterable<Coffee>{

//    存放Class类
    private Class[] types = {
      Latte.class,
      Mocha.class,
      Cappuccino.class,
        Americano.class,
        Breve.class

    };

//    用来生成随机数
    private static Random random = new Random(47);

//    无参构造函数
    public CoffeeGenerator() {
    }

//    用来进行迭代
    private int size = 0;

    public CoffeeGenerator(int size) {
        this.size = size;
    }

//    生成对象
    @Override
    public Coffee next() {
        try {
            //            在types数组长度范围内随机挑选并且实例化
            return (Coffee)
                    types[random.nextInt(types.length)].newInstance();
// Report programmer errors at run time:
        } catch(Exception e) {
            throw new RuntimeException(e);
        }
    }

//    内部类实现Iterator接口,用以迭代
    class CoffeeIterator implements Iterator<Coffee>{

        int count = size;

//        判断能否进行迭代
        @Override
        public boolean hasNext() {
            return count > 0;
        }

//        进行迭代,返回一个具体对象
        @Override
        public Coffee next() {
            count--;
            return CoffeeGenerator.this.next();
        }
    };

//返回CoffeeIterator迭代器
    @Override
    public Iterator<Coffee> iterator() {
        return new CoffeeIterator();
    }

    public static void main(String[] args) {

        CoffeeGenerator generator = new CoffeeGenerator();

        for (int i = 0; i < 5 ; i++) {
            System.out.println(generator.next());
        }

        System.out.println("___________________________________");

        for (Coffee c : new CoffeeGenerator(5)){
            System.out.println(c);
        }

    }
}



Fibonacci数列也可以借助这个生成器

public class Fibonacci implements Generator<Integer> {

    private int count = 0;
    
    public Integer next() { 
        return fib(count++); 
    }
    
//    用递归进行运算
    private int fib(int n) {
        if(n < 2) return 1;
        return fib(n-2) + fib(n-1);
    }
    
    
    public static void main(String[] args) {
        Fibonacci gen = new Fibonacci();
        for(int i = 0; i < 18; i++)
            System.out.print(gen.next() + " ");
    }


}


当然前面的Fibonacci是不能用foreach循环来进行迭代的,如果你需要的话,那么就可以通过继承来实现。

public class IterableFibonacci extends Fibonacci implements Iterable<Integer> {

    private int n;

    public IterableFibonacci(int count) {
        n = count;
    }

    public Iterator<Integer> iterator() {
        return new Iterator<Integer>() {
            public boolean hasNext() {
                return n > 0;
            }

            public Integer next() {
                n--;
                return IterableFibonacci.this.next();
            }

            public void remove() { // Not implemented
                throw new UnsupportedOperationException();
            }
        };
    }
}

泛型方法

同样,泛型也可以同在方法中。

要定义泛型方法,只需要把泛型参数列表放在返回值之前就可以。

比如:

public <T> void f(T x){
// .......
}

先上个例子:

public class GenericMethods {

    public <T> void f(T x){
        System.out.println(x.getClass().getSimpleName());
        System.out.println("___________________________");
    }

    public static void main(String[] args) {
        GenericMethods genericMethods =
                new GenericMethods();

        genericMethods.f("s");

        genericMethods.f(1);

        genericMethods.f(1.0);

        genericMethods.f(false);

        genericMethods.f('c');

        genericMethods.f(genericMethods);
    }


}

很重要:

使用泛型类时,必须在创建对象的时候指定类型参数的值,而在泛型方法中,通常不必指明参数类型,因为编译器会帮我们找出具体的类型,这称为

参数类型推断

可变参数

泛型方法结合可变参数

public class GenericVarargs {

    public static <T> List<T> makeList(T...args){

        List<T> res = new ArrayList<>();
        
// 循环遍历
        for (T item : args){

            res.add(item);

        }

        return res;

    }

    public static void main(String[] args) {

        List<String> ls = makeList("A");

        System.out.println(ls);

        ls = makeList("A","b","C");

        System.out.println(ls);



    }

}

考虑之前的生成器的使用,也可以考虑用上泛型方法。

public class Generators {

    public static <T> Collection<T> fill
            (Collection<T> collection, Generator<T> generator,int n){

        for (int i = 0; i < n; i++) {

            collection.add(generator.next());

        }

        return collection;

    }

    
//    用生成器,可以很方便的填充一个Collection
    public static void main(String[] args) {

        Collection<Coffee> coffees = fill(
                new ArrayList<>(),
                new CoffeeGenerator(),
                5

        );

        for (Coffee coffee : coffees) {
            System.out.println(coffee);
        }

        System.out.println("______________________________");
        
    }

}


现在考虑一个通用的Generator,可以为任何类构造一个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();
        }
    }

    public static <T> Generator<T> create(Class<T> type){
        return new BasicGenerator<T>(type);
    }


//    这个类提供了一个基本实现,用来生成某个类的对象
}

用个简单的有默认构造函数的类来测试下

public class CountedObject {

    private static long counter = 0;

    private final long id = counter++;

    public long getId() {
        return id;
    }

    @Override
    public String toString() {
        return "CountedObject" + id;
    }
}


接下来就使用BasicGenerator来为CountedObject创建一个Generator

public class BasicGeneratorDemo {

    public static void main(String[] args) {


        Generator<CountedObject> generator =
                BasicGenerator.create(CountedObject.class);

        for (int i = 0; i < 10; i++) {
            System.out.println(generator.next());
        }

    }
}

现在有了参数类型推断,以及static方法,回看之前的元组工具,我们可以考虑重新编写,使得它更加通用。

public class Tuple {


    public static <A,B> TwoTuple<A,B> tuple(A a, B b) {
        return new TwoTuple<A,B>(a, b);
    }


    public static <A,B,C> ThreeTuple<A,B,C>
    tuple(A a, B b, C c) {
        return new ThreeTuple<A,B,C>(a, b, c);
    }


    public static <A,B,C,D> FourTuple<A,B,C,D>
    tuple(A a, B b, C c, D d) {
        return new FourTuple<A,B,C,D>(a, b, c, d);
    }


    public static <A,B,C,D,E>
    FiveTuple<A,B,C,D,E> tuple(A a, B b, C c, D d, E e) {
        return new FiveTuple<A,B,C,D,E>(a, b, c, d, e);
    }


}


测试下:

public class TupleTest2 {


    static TwoTuple<String, Integer> f() {
        return tuple("hi", 47);
    }

    static TwoTuple f2() {
        return tuple("hi", 47);
    }



    public static void main(String[] args) {
        TwoTuple<String,Integer> ttsi = f();
        System.out.println(ttsi);
        System.out.println(f2());
    }
}

此处,f()和f2(),前者返回一个参数化的TwoTuple对象,后者返回的是非参数化TwoTuple对象。

接下来造一个实用的Set工具。当然还是使用泛型方法。

public class Sets {


//    在前三个方法中,都将第一个参数Set复制了一份,将Set中的所有引用都存入一个新的
//    HashSet对象中,因此,我们并未直接修改参数中的Set。返回的值是一个全新的Set对象。
//这四个方法表达了如下的数学集合操作:union()返回一个Set,它将两个参数合并在一起,
// intersection()返回的Set只包含两个参数共有的部分,difference()
// 方法从superset中移除subset包含的元素1complement()返回的Set包含除了交集之外的所有元素。


    public static <T> Set<T> union(Set<T> a, Set<T> b) {
        Set<T> result = new HashSet<T>(a);
        result.addAll(b);
        return result;
    }

    public static <T>
    Set<T> intersection(Set<T> a, Set<T> b) {
        Set<T> result = new HashSet<T>(a);
        result.retainAll(b);
        return result;
    }

    // Subtract subset from superset:
    public static <T> Set<T>
    difference(Set<T> superset, Set<T> subset) {
        Set<T> result = new HashSet<T>(superset);
        result.removeAll(subset);
        return result;
    }
    
    // Reflexive--everything not in the intersection:
    public static <T> Set<T> complement(Set<T> a, Set<T> b) {
        return difference(union(a, b), intersection(a, b));
    }
    
}


接下来用26个字母来测试下:

//字母表
public enum Alphabet {

    A,
    B,
    C,
    D,
    E,
    F,
    G,
    H,
    I,
    J,
    K,
    L,
    M,
    N,
    O,
    P,
    Q,
    R,
    S,
    T,
    U,
    V,
    W,
    X,
    Y,
    Z

}


public class AlphabetSet {


    public static void main(String[] args) {


        Set<Alphabet> set1 =
                EnumSet.range(A,D);

        Set<Alphabet> set2 =
                EnumSet.range(A,X);

        System.out.println(set1);

        System.out.println("______________________________");

        System.out.println(set2);

        System.out.println("______________________________");

        System.out.println("union" + Sets.union(set1,set2));

        System.out.println("______________________________");

        System.out.println("intersection" + Sets.intersection(set1,set2));


    }
}



泛型还可以用在内部类以及匿名内部类中

class Customer {

    private static long counter = 1;

    private final long id = counter++;

    private Customer() {
    }

    @Override
    public String toString() {
        return "Customer" + id;
    }

    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() {
    }

    @Override
    public String toString() {
        return "Teller" + id;
    }

    public static Generator<Teller> generator =
            new Generator<Teller>() {
                @Override
                public Teller next() {
                    return new Teller();
                }
            };


}



public class BankTeller {


    public static void serve(Teller teller, Customer customer){

        System.out.println(teller + "服务" + customer);

    }

    public static void main(String[] args) {

        Random random = new Random(47);

        Queue<Customer> line = new LinkedList<>();

//        用Customer生成器往line中填充20个Customer对象
        Generators.fill(line,Customer.generator(),20);

        List<Teller> tellers = new ArrayList<>();
        //同上
        Generators.fill(tellers,Teller.generator,3);


//        从tellers集合随机选择一个Teller为Customer服务
        for (Customer customer :line) {
            serve(tellers.get(random.nextInt(tellers.size())),customer);
        }


    }

}


构建复杂的模型

考虑用泛型来构建一个复杂的数据模型,比如List元组。

public class TupleList<A,B,C,D>
        extends ArrayList<FourTuple<A,B,C,D>> {

    public static void main(String[] args) {

        TupleList<Apple, Orange,String,Long> tuples =
                new TupleList<>();


        tuples.add(new
                FourTuple<Apple, Orange,String,Long>(new Apple(),new Orange(),"A,",100L));

//        ,,,当然你可添加更多的数据
        for(FourTuple<Apple, Orange,String,Long> fourTuple : tuples){

            System.out.println(fourTuple);

            
        }

        
    }

}



这里可以考虑构建一个比上面更加复杂的模型,比如一个零售店,它有走廊,货架,商品:

public class Product {

//    商品id
    private final int id;

//    描述
    private String description;

//    价格
    private double price;

//    构造函数
    public Product(int IDnumber, String descr, double price){
        id = IDnumber;
        description = descr;
        this.price = price;
        System.out.println(toString());
    }


    public String toString() {
        return id + ": " + description + ", price: $" + price;
    }

//    改变价格的函数
    public void priceChange(double change) {
        price += change;
    }

//    Product生成器
    public static Generator<Product> generator =
            new Generator<Product>() {

                private Random rand = new Random(47);

//                id以及价格都是随机生成
                public Product next() {
                    return new
                            Product(rand.nextInt(1000), "Test",
                            Math.round(rand.nextDouble() * 1000.0) + 0.99);
                }
            };


}


//货架
public class Shelf extends ArrayList<Product> {

    public Shelf(int nProducts) {

//        进行数据填充 把Product填充进当前Shelf实例
        Generators.fill(this, Product.generator, nProducts);


    }


}

//走廊
public class Aisle extends ArrayList<Shelf> {

    public Aisle(int nShelves, int nProducts) {

        for(int i = 0; i < nShelves; i++)
            add(new Shelf(nProducts));
    }


}

public class Office {
}


public class CheckoutStand {
}


//零售店
public class Store extends ArrayList<Aisle> {

    private ArrayList<CheckoutStand> checkouts =
            new ArrayList<CheckoutStand>();


    private Office office = new Office();

//    构造函数
    public Store(int nAisles, int nShelves, int nProducts) {
        for(int i = 0; i < nAisles; i++)
            add(new Aisle(nShelves, nProducts));
    }

//String格式
    public String toString() {
        StringBuilder result = new StringBuilder();
        for(Aisle a : this)
            for(Shelf s : a)
                for(Product p : s) {
                    result.append(p);
                    result.append("\n");
                }
        return result.toString();
    }
    public static void main(String[] args) {


        System.out.println(new Store(14, 5, 10));
    }
}


发布了189 篇原创文章 · 获赞 58 · 访问量 18万+

猜你喜欢

转载自blog.csdn.net/Coder_py/article/details/103879795