欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

对泛型的一些新的认识

程序员文章站 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》

相关标签: 基础 java