对泛型的一些新的认识
程序员文章站
2022-03-12 23:06:07
...
一般的类与方法,只能使用具体的类型,要么是基本类型,要么是自定义的类,如果要编写可以应用多种类型的代码,就要有一种基类可以导出任何类型作为参数,让类型作为参数一样可以在通用方法中去使用。
泛型是从Java SE5的重大变化之一,泛型的出现使得类型可以参数化,让代码可以应用与多种的类型。
一般泛型着重用于容器类。
一般的方法return返回时只能返回单个对象,但是使用泛型可以创建一个对象,一次调用方法的返回多个对象。这样做就要创建一个特殊的类来处理这样的工作,这样的处理方式称为元组。将一组对象直接打包存储成一个单个对象。这个容器允许读取其中元素,但是不允许向其中放入新的对象。
这是一个二元的元组,可以存放任意的两种类型。
public class TwoTuple<A, B> {
/**
* final 可以保证安全性 public的安全性
* 声明为final的值不能再被其他赋值成其他值了 只能赋值一次
*/
public final A first;
public final B second;
public TwoTuple(A first, B second) {
this.first = first;
this.second = second;
}
@Override
public String toString() {
return "TwoTuple{" +
"first=" + first +
", second=" + second +
'}';
}
public static void main(String[] args) {
TwoTuple<Integer, Integer> cc = new TwoTuple<>(1, 2);
System.out.println(cc);
}
}
---------------------------------------
结果: TwoTuple{first=1, second=2}
使用继承机制可以将二元扩展成三元及多元元组
public class ThreeTuple<A, B, C> extends TwoTuple<A, B> {
public final C three;
public ThreeTuple(A a, B b, C c) {
super(a, b);
this.three = c;
}
@Override
public String toString() {
return "ThreeTuple{" +
"three=" + three +
", first=" + first +
", second=" + second +
'}';
}
}
public class FourTuple<A, B, C, D> extends ThreeTuple<A, B, C> {
public final D d;
public FourTuple(A a, B b, C c, D d) {
super(a, b, c);
this.d = d;
}
@Override
public String toString() {
return "FourTuple{" +
"d=" + d +
", three=" + three +
", first=" + first +
", second=" + second +
'}';
}
}
// 测试类
class Temp {
}
class They {
}
public class TupleTest {
static TwoTuple<String, Integer> two() {
return new TwoTuple<>("one", 11);
}
static ThreeTuple<Temp, String, Integer> three() {
return new ThreeTuple<>(new Temp(), "two", 22);
}
static FourTuple<They, Temp, String, Integer> four() {
return new FourTuple<>(new They(), new Temp(), "three", 33);
}
public static void main(String[] args) {
TwoTuple<String, Integer> two = two();
System.out.println(two);
System.out.println(three());
System.out.println(four());
}
}
------------------------------
结果:TwoTuple{first=one, second=11}
ThreeTuple{three=22, first=think_15.Temp@677327b6, second=two}
FourTuple{d=33, three=three, first=think_15.They@14ae5a5, second=think_15.Temp@7f31245a}
可以使用泛型来自己实现一个LinkedList的堆栈类
public class LinkedStack<T> {
/**
* 静态内部类
* @param <U>
*/
private static class Node<U> {
U item;
Node<U> next;
public Node() {
this.item = null;
this.next = null;
}
public Node(U item, Node<U> next) {
this.item = item;
this.next = next;
}
/**
* 末端哨兵用来判断堆栈何时为空(当每次调用push方法,就会创建一个Node对象,
* 调用pop时,返回的是top.item,然后end就会指向下一个Node节点 ) 判断下个阶段是否是空节点
*
* @return
*/
boolean end() {
return item == null && next == null;
}
}
private Node<T> top = new Node<T>();
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> sls = new LinkedStack<>();
for (String s : "Push one Number 111".split(" ")) {
sls.push(s);
}
String s;
while ((s = sls.pop()) != null) {
System.out.print(s + " ");
}
}
}
----------------------------------------------
结果:111 Number one Push
使用泛型同时处理两种类型,(可以得到简单的双列表)
public class RandomList<A, T> {
private ArrayList<A> list = new ArrayList<>();
private ArrayList<T> list2 = new ArrayList<>();
private Random random = new Random(47);
public void addFirst(A item) {
list.add(item);
}
public void addSecond(T item) {
list2.add(item);
}
public A selectFirst() {
return list.get(random.nextInt(list.size()));
}
public T selectSecond() {
return list2.get(random.nextInt(list2.size()));
}
public static void main(String[] args) {
RandomList<String, Integer> rl = new RandomList<>();
for (String s : "The quick brown fox jumped over the lazy brown dog".split(" ")) {
rl.addFirst(s);
}
for (int i = 0; i < 11; i++) {
rl.addSecond(new Random().nextInt(100));
}
for (int i = 0; i < 9; i++) {
System.out.print(rl.selectFirst() + " " +rl.selectSecond()+" ");
}
}
}
---------------------------------------------
结果:
brown 61 fox 28 quick 79 brown 49 brown 58 brown 26 quick 8 dog 49 brown 49
泛型接口的表示
//定义一个简单的泛型接口
public interface Generator<T> {
T next();
}
class Latte extends Coffee{}
class Mocha extends Coffee{}
class Cappuccino extends Coffee{}
class Americano extends Coffee{}
class Breve extends Coffee{}
public class Coffee {
private static long cunt = 0;
private final long id = cunt++;
@Override
public String toString() {
return getClass().getSimpleName() +
"id=" + id;
}
}
/
// 该类实现了Iterable的泛型接口,可以直接对对象进行遍历,像foreach遍历集合类一样
public class CoffeeGenerator implements Generator<Coffee>, Iterable<Coffee> {
private Class[] types = {Latte.class, Mocha.class, Cappuccino.class, Americano.class, Breve.class};
private Random random = new Random(47);
public CoffeeGenerator() {
}
private int size = 0;
public CoffeeGenerator(int size) {
this.size = size;
}
@Override
public Coffee next() {
try {
return (Coffee) types[random.nextInt(types.length)].newInstance();
} catch (Exception e) {
throw new RuntimeException(e.getMessage());
}
}
@Override
public Iterator<Coffee> iterator() {
return new CoffeeIterator();
}
//私有 的内部类 实现Iterator接口 遍历的方式
private class CoffeeIterator implements Iterator<Coffee> {
int count = size;
@Override
public boolean hasNext() {
return count > 0;
}
@Override
public Coffee next() {
count--;
return CoffeeGenerator.this.next();
}
}
public static void main(String[] args) {
CoffeeGenerator gen = new CoffeeGenerator();
for (int i = 0; i < 5; i++) {
System.out.println(gen.next());
}
for (Coffee c : new CoffeeGenerator(5)) {
System.out.print(c + " ");
}
}
}
------------------------------------------------
结果: Americanoid=0
Latteid=1
Americanoid=2
Mochaid=3
Mochaid=4
Americanoid=5 Latteid=6 Americanoid=7 Mochaid=8 Mochaid=9
泛型方法
public class GenericMethods {
/**
* 泛型方法
* @param x
* @param <T>
*/
public <T> void f(T x) {
System.out.println(x.getClass().getSimpleName());
}
public <T,A> void ff(T x,A a) {
System.out.println(a.getClass().getName());
System.out.println(x.getClass().getSimpleName());
}
public static void main(String[] args) {
GenericMethods gm = new GenericMethods();
gm.f("x");
gm.f("x");
gm.ff("x",gm);
}
}
-----------------------------------------------------
结果: String
String
GenericMethods
String
泛型方法与泛型类的使用区别:使用泛型类的时,创建对象的时候必须要指定类型参数的值,而使用泛型方法的时候,一般不用指明参数类型,编译器可以对我们传入的对象推断出具体的类型。
学习笔记—《Thinking in Java》
上一篇: Kotlin 泛型
下一篇: php base64转换成图片的方法