啃知识系列_泛型和泛型边界

本文详细探讨了Java中的泛型,包括泛型的基本用法、类型参数、类型擦除和边界。重点讲解了类型擦除的概念,即在运行时泛型类型被转换为Object,以及如何通过泛型边界来限制类型参数,确保方法调用的正确性。同时,文章提到了泛型方法、类型参数推断和泛型数组的注意事项,以及如何在运行时恢复类型信息。
摘要由CSDN通过智能技术生成

这两天看Java编程思想,重新学习了一下泛型的知识。 以前很多不懂得地方也梳理了一下。

在没有使用泛型之前,我们编写一个类,想要持有其他类型的任何对象。

public class Holder {
    private Object a;
    public Holder(Object a){
        this.a = a;
    }

    public Object get() {
        return a;
    }

    public void set(Object a) {
        this.a = a;
    }

    public static void main(String[] args) {
        Holder h = new Holder(new AutoMobile());
        AutoMobile m = (AutoMobile) h.get();
        h.set("Not AutoMobile");
        String s = (String) h.get();
    }
}

class AutoMobile{}
这个例子,我们先后存了两种类型的对象,但是当我们从holder中取出对象的时候,需要强制类型转换才可以。

泛型的主要目的之一就是用来制定容器要持有什么类型的对象,而且编译器来保证类型的正确性。

因此,与其我们用Object,更喜欢暂时不指定类型,而是之后决定使用什么类型,这时候我们需要使用类型参数,下面例子中T就是类型参数。

public class HolderT<T> {
    private T t;
    public HolderT(T t){
        this.t = t;
    }

    public T get() {
        return t;
    }

    public void set(T t) {
        this.t = t;
    }

    public static void main(String[] args) {
        HolderT<AutoMobile> h = new HolderT<AutoMobile>(new AutoMobile());
        AutoMobile a = h.get();
//        h.set("Not AutoMobile");  编译器报错,因为我们要制定存储的事AutoMobile类型的对象
        HolderT<String> h2 = new HolderT<String>("Not AutoMobile");
        String s = h2.get();
    }
}
现在当创建HolderT的时候必须指明想要持有的对象,将其置于尖括号中。之后get和set的时候都已经制定了现在持有的对象。

这里初步讲下泛型的基本用法,接下来会写一些我觉的需要注意的泛型的例子和用法。


现在我们实现一个堆栈类。

public class LinedStack<T> {
    private static class Node<U>{
        U item;
        Node next;
        Node(){
            this.item = null;
            this.next = null;
        }
        Node(U item,Node next){
            this.item = item;
            this.next = next;
        }

        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) {
        LinedStack<Integer> stack = new LinedStack<Integer>();
        stack.push(1);
        stack.push(2);
        System.out.println(stack.pop());
        System.out.println(stack.pop());
    }

}
这里的Node也是泛型的,他有自己的类型参数U。

这里我们使用了末端哨兵来判断堆栈何时为空。这里我关注的是一点,如果我不给他的内部类Node设定自己的类型参数,而是跟外部的类型参数一样。

如果直接去掉U的类型参数,会报错。这里就需要先说一说类型擦除的概念。这个稍后再说。先让我们看看泛型方法。


之前我们看到的泛型都是作用在类上,但他同样可以作用在方法上。泛型方法使得该方法独立于类而产生变化。以下是一些基本的指导建议:

无论何时,只要你能做到,就应该只使用泛型方法,因为他使得事情更清楚明白,另外,对于一个static的方法而言,无法访问泛型类的泛型类型参数,所以,如果static方法需要使用泛型能力,就必须使其成为泛型方法。

要定义泛型方法,只需要将泛型参数列表置于返回类型之前就可以。

public class GenericMehtods {
    public static <T> void f(T t){
        System.out.println(t.getClass().getName());
    }

    public static void main(String[] args) {
        f("");
        f(1);
        
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值