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));
}
}
网友评论