前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Java泛型基础(一)目的泛型类总结

Java泛型基础(一)目的泛型类总结

作者头像
阿杜
发布2018-08-06 11:26:47
6260
发布2018-08-06 11:26:47
举报
文章被收录于专栏:阿杜的世界阿杜的世界

本文首发于个人网站:Java中的泛型(一)

本文主要介绍Java泛型的基本知识,包括目的、泛型类的基本用法和场景应用场景。

目的

  1. 编写更加“泛化”的代码,编写可以应付多重类型的代码
  2. Java中的泛型,用于实现“参数化类型”的概念
  3. 创造可以放不同类型对象的容器类,通过编译器来保证类型的正确;
  4. 能够简单&安全得创建复杂的模型

泛型类

定义

利用Java开发的时候,肯定会有一个类持有另一个或几个类的情况,在编写一些比较基础的组件,例如缓存操作组件,这类组件的逻辑差不多,但是希望能够处理不同的类型。

在Java SE5之前,我们可以通过Object这个类型来实现,举个例子:

代码语言:javascript
复制
package org.java.learn.generics;

/**
 * 作用: User: duqi Date: 2017/11/19 Time: 15:45
 */
public class Holder2 {

    private Object a;

    public Holder2(Object a) {
        this.a = a;
    }

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

    public Object getA() {
        return a;
    }

    public static void main(String[] args) {
        Holder2 h2 = new Holder2(new Automobile());
        //这里需要进行类型的强制转换
        Automobile automobile = (Automobile) h2.getA();

        h2.setA("Not a Automobile");
        String s = (String) h2.getA();

        h2.setA(1); //这里发生了自动装箱
        Integer x = (Integer) h2.getA();
    }
}

上面这段代码,确实满足了一个组件持有不同类型对象的需求,但是也有两个问题:(1)取出对象的时候,需要进行类型的强制转换;(2)同一个容器对象,可以随意存取不同类型的对象,有出错的风险。JavaSE5引入了“泛型”的概念,使得代码可以应用于多个类型,同时还能避免上述我说的两个问题,上面的代码,如果用Java泛型实现,则如下所示:

代码语言:javascript
复制
package org.java.learn.generics;

/**
 * 作用: User: duqi Date: 2017/11/19 Time: 15:48
 */
public class Holder3<T> {

    private T a;

    public Holder3(T a) {
        this.a = a;
    }

    public void setA(T a) {
        this.a = a;
    }

    public T getA() {
        return a;
    }

    public static void main(String[] args) {
        Holder3<Automobile> h3 = new Holder3<>(new Automobile());
        Automobile automobile = h3.getA(); //这里不需要强制转换类型

//        h3.setA("Not an Automobile");  Error
//        h3.setA(1);                    Error
    }
}

上面的Holder3是持有一个类型参数T,还可以持有三个相同类型(或不同类型的)类型参数,代码如下:

代码语言:javascript
复制
package org.java.learn.generics;

/**
 * 作用: User: duqi Date: 2017/11/19 Time: 15:51
 */
public class Holder4<T> {

    private T a;
    private T b;
    private T c;

    public Holder4(T a, T b, T c) {
        this.a = a;
        this.b = b;
        this.c = c;
    }

    public T getA() {
        return a;
    }

    public T getB() {
        return b;
    }

    public T getC() {
        return c;
    }

    public void setA(T a) {
        this.a = a;
    }

    public void setB(T b) {
        this.b = b;
    }

    public void setC(T c) {
        this.c = c;
    }

    public static void main(String[] args) {
        Holder4<Automobile> holder4 = new Holder4<>(new Automobile(),new Automobile(), new Automobile());

        Automobile a = holder4.getA();
        Automobile b = holder4.getB();
        Automobile c = holder4.getC();
    }
}

应用场景

元组

在实际开发中,常常会有“一次方法调用返回多个对象的需求”,我现在有时候会为每个返回值创建一个Class的写法,但是这块不太符合领域模型的思想——混淆了Entity和Object Value的概念。利用元组,可以实现Object Value的概念。

代码语言:javascript
复制
package org.java.learn.util;

/**
 * 作用: User: duqi Date: 2017/11/19 Time: 16:18
 */
public class TwoTuple<A, B> {
    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 "(" + first + ", " + second + ")";
    }
}

这个例子中的final关键字用的非常漂亮,有两个设计上的考虑

  • 访问安全,客户端可以读取first和second两个对象,但是无法修改它们;
  • 体现Object Value的含义,如果开发者需要一个不同元素的元组,必须重新构建一个;

利用继承机制,我们还可以实现元素更多的元组,下面的代码展示了三元组和四元组的实现。不过,从另一个角度考虑——如果一个方法调用需要返回四个以上元素的元组,是不是需要考虑下这个方法本身的设计是否合理了呢。

三元组
代码语言:javascript
复制
package org.java.learn.util;

/**
 * 作用: User: duqi Date: 2017/11/19 Time: 16:32
 */
public class ThreeTuple<A, B, C> extends TwoTuple<A, B> {

    public final C third;

    public ThreeTuple(A first, B second, C third) {
        super(first, second);
        this.third = third;
    }

    @Override
    public String toString() {
        return "(" + first + ", " + second + ", " + third + ")";
    }
}
四元组
代码语言:javascript
复制
package org.java.learn.util;

/**
 * 作用: User: duqi Date: 2017/11/19 Time: 16:36
 */
public class FourTuple<A, B, C, D> extends ThreeTuple<A, B, C> {

    public final D forth;

    public FourTuple(A first, B second, C third, D forth) {
        super(first, second, third);
        this.forth = forth;
    }

    @Override
    public String toString() {
        return "(" + first + ", " + second + ", " + third + "," + forth + ")";
    }
}

堆栈

再看一个比元祖复杂一点的例子,这里利用自己实现的链表存储机制构建了一个下推堆栈。

代码语言:javascript
复制
package org.java.learn.util;

/**
 * 作用: User: duqi Date: 2017/11/19 Time: 16:40
 */
public class LinkedStack<T> {

    private static class Node<U> {
        U item;
        Node<U> next;

        public Node() {
            item = null;
            next = null;
        }

        public Node(U item, Node<U> next) {
            this.item = item;
            this.next = next;
        }

        /**
         * 是否到达堆栈底部
         *
         * @return
         */
        boolean end() {
            return item == null || next == null;
        }
    }

    /**
     * 末端哨兵
     */
    private Node<T> top = new Node<>();
    public void push(T item) {
        top = new Node<>(item, top);
    }
    public T pop() {
        T res = top.item;
        if (!top.end()) {
            top = top.next;
        }
        return res;
    }

    public static void main(String[] args) {
        LinkedStack<String> lss = new LinkedStack<>();
        for (String s: "Phasers on stun!".split(" ")) {
            lss.push(s);
        }
        String s;
        while ((s = lss.pop()) != null) {
            System.out.println(s);
        }
    }
}

书中的练习题5:移除Node类上的类型参数,并修改LinkedStack.java的代码,说明内部类可以访问外部类的类型参数,我自己试了下,代码如下:

代码语言:javascript
复制
package org.java.learn.util;

/**
 * 作用: User: duqi Date: 2017/11/19 Time: 16:40
 */
public class LinkedStack2<T> {

    /**
     * 这里不能使用静态内部类
     */
    private class Node {
        T item;
        Node next;

        public Node() {
            item = null;
            next = null;
        }

        public Node(T item, Node next) {
            this.item = item;
            this.next = next;
        }

        /**
         * 是否到达堆栈底部
         *
         * @return
         */
        boolean end() {
            return item == null || next == null;
        }
    }

    /**
     * 末端哨兵
     */
    private Node top = new Node();
    public void push(T item) {
        top = new Node(item, top);
    }
    public T pop() {
        T res = top.item;
        if (!top.end()) {
            top = top.next;
        }
        return res;
    }

    public static void main(String[] args) {
        LinkedStack<String> lss = new LinkedStack<>();
        for (String s: "Phasers on stun!".split(" ")) {
            lss.push(s);
        }
        String s;
        while ((s = lss.pop()) != null) {
            System.out.println(s);
        }
    }
}

代码显示,静态内部类,无法访问其外部类的类型参数,但是非静态内部类可以。

RandomList

书中还给出一个随机列表的例子——一个持有特定类型对象的列表,select()方法可以随机取出列表中的一个元素。这是一个抽奖demo,或者我们可以用它决定每天中午吃什么?。

代码语言:javascript
复制
package org.java.learn.generics;

import java.util.ArrayList;
import java.util.List;
import java.util.Random;

/**
 * 作用: 持有特定类型对象的列表,select()方法可以随机取一个元素
 * User: duqi
 * Date: 2017/11/19
 * Time: 17:08
 */
public class RandomList<T> {

    private ArrayList<T> storage = new ArrayList<>();

    private Random random = new Random(47);

    public void add(T item) {
        storage.add(item);
    }
    public T select() {
        return storage.get(random.nextInt(storage.size()));
    }

    public static void main(String[] args) {
        RandomList<String> randomList = new RandomList<>();
        for (String s: "The queick brown for jumped over the lazy brown dog".split(" ")) {
            randomList.add(s);
        }
        for (int i = 0; i < 11; i++) {
            System.out.print(randomList.select() + " ");
        }
    }
}

总结

泛型的东西很多,我之前看《Java核心技术》学过一遍,最近为了给团队的同学做分享,准备再结合《Java编程思想》复习一遍,发现《Java编程思想》这本书写得非常有深度,需要思考、实践和回味,才能准确得get到作者想要表达的意思。

本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2017.12.09 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 目的
  • 泛型类
    • 定义
      • 应用场景
        • 元组
        • 堆栈
        • RandomList
    • 总结
    相关产品与服务
    容器服务
    腾讯云容器服务(Tencent Kubernetes Engine, TKE)基于原生 kubernetes 提供以容器为核心的、高度可扩展的高性能容器管理服务,覆盖 Serverless、边缘计算、分布式云等多种业务部署场景,业内首创单个集群兼容多种计算节点的容器资源管理模式。同时产品作为云原生 Finops 领先布道者,主导开源项目Crane,全面助力客户实现资源优化、成本控制。
    领券
    问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档