简述java泛型

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接: https://blog.csdn.net/swadian2008/article/details/96359869

目录

一、使用泛型——实现更加灵活的容器

1、使用Object实现

2、使用泛型实现

二、简单的容器实例

1、重新写一个List集合

2、实现内部链接存储机制——堆栈


为什么需要泛型:

1、为了编写可以应用于多种类型的代码,使代码更直接和优雅。

2、java单继承体系和接口仍然使程序的约束性太强(主要是受限于特定的类型)

一、使用泛型——实现更加灵活的容器

1、使用Object实现

1.1、首先创建一个“Apple”对象

public class Apple {}

1.2、为了使一个类的应用不局限于一个类型,可以使用Object的方式

public class UserObject {

    private Object object;

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

    public Object getObject() {
        return object;
    }

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

    public static void main(String[] args) {
        UserObject userObject = new UserObject(new Apple());
        // 这个方法不能自动的识别类型,如果不进行强转,得出仍然是一个Object
        Apple apple = (Apple) userObject.getObject();
        // 在已经传入了确定对象的情况下,UserObject的参数仍然可以进行随意的变化
        // 这不过是因为在java中所有的对象都是Object,Apple也是其中一个,所以并不能确定明确的类型使用
        userObject.setObject("这不是一个Apple对象");
    }
}

思考:

(1)使用Object的方式可以实现类和方法的复用,但是编译器却不能识别存储的具体对象,每次都需要进行类型的强转

(2)即使传入了具体对象,这个类的存储类型也不会具体的确认下来

2、使用泛型实现

使用泛型,如果想持有什么类型的对象,将其置于尖括内,此时该泛型的类型就自动的确认了下来。

public class UserGenetic<T> {
    
    private T genetic;

    public UserGenetic(T genetic) {
        this.genetic = genetic;
    }

    public T getGenetic() {
        return genetic;
    }

    public void setGenetic(T genetic) {
        this.genetic = genetic;
    }

    public static void main(String[] args) {
        UserGenetic<Apple> userGenetic = new UserGenetic<>(new Apple());
        // 不再需要进行强转
        Apple genetic = userGenetic.getGenetic();
        // userGenetic.setGenetic("这不是Apple对象"); 编译不能通过,因为String不是Apple对象
    }
}

二、简单的容器实例

1、重新写一个List集合

简单重写一个List,然后满足任意对象简单的存值和取值功能:

public class NewList<T> {

    // 底层通过list来实现的新集合
    private List<T> list = new ArrayList<>();

    public void add(T item){
        System.out.println("这是来自新集合的存储逻辑..." + item);
        list.add(item);
    }

    public T select(Integer index){
        System.out.println("这是来自新集合的取值逻辑..." + index);
        return list.get(index);
    }

    public static void main(String[] args) {
        NewList<String> list = new NewList<>();
        for(String str :"这 是 一 个 新 集 合".split(" ")){
            list.add(str);
        }
        System.out.println(list.select(0));
    }
    
}

有没有发现,其实有点像List集合的源码,源码基本上都不指定确定的类型,从而能创建出更加灵活和通用的工具类。体会到泛型的强大和好处了吧,其实,泛型也就是另一种类型罢了

2、实现内部链接存储机制——堆栈

public class LinkedStack<T> {

    // 存储节点
    private static class Node<E> {
        /**
         * 泛型对象
         */
        private E item;

        /**
         * 节点本身
         */
        private Node<E> next;

        // 初始化链式存储表为空
        public Node() {
            item = null;
            next = null;
        }

        // 构造方法,注意参数包含了节点本身对象,这个是链式的关键
        public Node(E item, Node<E> next) {
            this.item = item;
            this.next = next;
        }

        // 哨兵判空模式,结合取值时使用,即建立一个结束点或者条件
        // 当碰到这个条件时,说明已经达到容器末端
        boolean end() {
            return item == null && next == null;
        }
    }

    // 这是一个哨兵,末端的值为空
    private Node<T> top = new Node<T>();

    // 注意,第一次添加时,top是一个哨兵
    public void push(T item) {
        top = new Node<T>(item, top);
    }

    //
    public T pop() {
        // 获取第一个参数的值(泛型Item)
        T result = top.item;
        // 如果item 和 next 不为空,把next放到原item的位置,以此循环,一个一个取值
        if (!top.end()) {
            top = top.next;
        }
        return result;//最后返回哨兵的item == null;
    }

    public static void main(String[] args) {
        LinkedStack<String> lss = new LinkedStack<>();
        for (String s : "a b c d e f g".split(" ")) {
            lss.push(s);
        }
        String s;
        while ((s = lss.pop()) != null) {
            System.out.print(s);
            // 打印结果:gfedcba 先进后出的堆栈
        }
    }
}

使用泛型来实现内部链式存储机制,关键在于容器本身包含了一个自己对象,然后另一个对象又是自身对象的延伸,当不断的去存储值时,实际是在不断的新建对象,只是这个新建的对象包含了之前建立的对象的值,因此,这个容器最后看起来就像一条长长的链子,一环扣一环。

猜你喜欢

转载自blog.csdn.net/swadian2008/article/details/96359869