花几分钟快速了解泛型与枚举(有手就会)

简介: 花几分钟快速了解泛型与枚举(有手就会)

Java枚举与泛型

前言

本节给大家讲讲 枚举与泛型 ,本篇内容主要包括以下几个部分:

  • 枚举定义和使用
  • 泛型讲解
  • 代码实操
  • 常见的泛型问题


枚举

定义

啥是枚举?从定义来讲枚举就是情况的各种罗列,在java中它是一种特殊的类,一般表示一组常量,举个例子:

enum Color 
{ 
    RED, BLUE; 
} 
复制代码


上述代码,枚举了颜色的两种成员,分别是 RED, BLUE,枚举也可以定义在类中,我们输出一下:

public class EnumTest
{
    enum Color
    {
        RED, GREEN, BLUE;
    }
    // 执行输出结果
    public static void main(String[] args)
    {
        Color c = Color.RED;
        System.out.println(c); // RED
    }
}
复制代码


结果返回 RED


遍历枚举

如何去遍历它的成员呢?

public class EnumTest
{
    enum Color
    {
        RED, GREEN, BLUE;
    }
    // 执行输出结果
    public static void main(String[] args)
    {
        for (Color c : Color.values()) {
            System.out.println(c);
            // RED
            // GREEN
            // BLUE
        }
    }
}
复制代码


作为条件使用

我们也可以用作条件使用,这样代码可读性会变高一点

public class EnumTest
{
    enum Color
    {
        RED, GREEN, BLUE;
    }
    // 执行输出结果
    public static void main(String[] args)
    {
        Color c = Color.BLUE;
        switch(c) {
            case RED:
                System.out.println("红色");
                break;
            case GREEN:
                System.out.println("绿色");
                break;
            case BLUE:
                System.out.println("蓝色");
                break;
            }
        }
}
复制代码


进阶用法

举一个常用的例子,我们在做API请求返回响应结果时,我们可以利用枚举去定义我们的响应体,根据不同的变量,返回响应的结果。来看一个我写好的例子:

public enum Response implements ResponseInter {
    SUCCESS(200, null, "success"),
    Fail(0, null, "错误"),
    Response(0, null, "");
    private String msg;
    private Integer code;
    private Object data;
    Response(int code, String data, String msg) {
        this.code = code;
        this.msg = msg;
        this.data = data;
    }
    public String getMsg() {
        return msg;
    }
    public void setMsg(String msg) {
        this.msg = msg;
    }
    public Integer getCode() {
        return code;
    }
    public void setCode(Integer code) {
        this.code = code;
    }
    public Object getData() {
        return data;
    }
    public void setData(Object data) {
        this.data = data;
    }
    @Override
    public ResponseData response(int code, String data, String msg) {
        this.code = code;
        this.msg = msg;
        this.data = data;
        return getResponse();
    }
    private ResponseData getResponse() {
        ResponseData response = new ResponseData();
        response.setData(this.data);
        response.setCode(this.code);
        response.setMsg(this.msg);
        return response;
    }
    public ResponseData success() {
       return getResponse();
    }
    public ResponseData fail() {
        return getResponse();
    }
}
复制代码


枚举也是一种特殊的类 ,所以它也可以实现接口。 当我们定义 SUCCESS(200, null, "success")这种带括号的成员时,idea会自动提示你去创建它的构造函数,所以后边我们可以取实例化它。

@FunctionalInterface // 函数式接口
public interface ResponseInter {
    ResponseData response(int code, String data, String msg);
}
复制代码


这里插一个小知识点,@FunctionalInterface表示函数式接口, 成员内部只能有一个接口方法。


如何使用?

public class EnumMain {
    public static void main(String[] args) {
        Response response = Response.SUCCESS;
        String res = JSON.toJSONString(response.success());
        Log.info(res); // {"code":200,"msg":"success"}
        Response response1 = Response.Fail;
        String res1 = JSON.toJSONString(response1.fail());
        Log.info(res1); //{"code":0,"msg":"错误"}
        Response response2 = Response.Response;
        String res2 = JSON.toJSONString(response2.response(200, "这是数据", "success"));
        Log.info(res2); // {"code":200,"data":"这是数据","msg":"success"}
    }
}
复制代码

是不是很简单,这里我只是粗略的定义了一下,其实还可以继续深入下去,比如我们定义各种情况下请求的状态码,这样一来,就不用我们每次手动填写具体的值了。


泛型

从字面意思讲,不确定的类型。有时候我们在写代码时,传参都需要定义具体的类型,不然编译会报错,但是有些情况我们需要复用我们的代码,但是由于强类型的要求下,我们不得已去在定义这样的类,这样显得很麻烦,所以这时候泛型,就有很大的作用了。


定义

先看最简单的一个例子体会一下:

@Data
public class ClassMain <T> {
    private T name;
}
复制代码

泛型类 型在逻辑上看以看成是多个不同的类型,实际上都是相同的基本类型。 通常使用T来代表某种类型, T不是绝对的,可以是任意。


如何使用, 类名<类型>:

ClassMain<String> f = new ClassMain<>();
f.setName("haha");
Log.info(f.getName().getClass()); // class java.lang.String
复制代码


泛型接口

泛型接口使用还是比较多的,看一个例子:

public interface InterfaceMain<T> {
    T hello(ClassMain<T> ...obj);
}
复制代码


@Data
public class ClassMain <T> implements InterfaceMain <T> {
    private T name;
    @Override
    public T hello(ClassMain<T> ...obj) {
        return this.name;
    }
}
复制代码

...obj这个表示不定参数,意思是说你可以传多个同类型的参数。


泛型通配符

有时候你在使用别人写好的类时,经常看到这样的标记, 它表示一些不确定的类型:

// 泛型通配符
// 适合一些不确定的类型
public T hello1(ClassMain<?> obj) {
    return this.name;
}
复制代码


泛型方法

通过一个例子感受一下:

public class MethodMain <T> {
    private T name;
    public <T> T hello(MethodMain<T> obj) {
        return obj.getMsg(obj.name);
    }
    public T getMsg(T name) {
        return name;
    }
    public <T> void getMsg(T ...arg) {
        for(T args :arg) {
            Log.info("泛型可变参 --->" + args);
        }
    }
    // 静态方法使用泛型时,需要定义成泛型方法, 并且与定义类无关
    public static <T> void get1(T ...arg) {
        Log.info(arg.getClass().getName());
    }
    // 泛型中的边界
    // extends 继承 String 类型
    // 还有一个是 super 反之
    public static <T extends String> void get2(T ...arg) {
        Log.info(arg.getClass().getName());
    }
}
复制代码

这种通常叫 泛型边界, 常用来约束我们的泛型,使它严谨一些。


泛型一问一答❓

  • Java中的泛型是什么 ? 使用泛型的好处是什么?

泛型防止了那种情况的发生,它提供了编译期的类型安全,确保你只能把正确类型的对象放入集合中,避免了在运行时出现ClassCastException


  • Java的泛型是如何工作的 ? 什么是类型擦除 ?

泛型是通过类型擦除来实现的,编译器在编译时擦除了所有类型相关的信息,所以在运行时不存在任何类型相关的信息。


  • 什么是泛型中的限定通配符和非限定通配符 ?

限定通配符对类型进行了限制。有两种限定通配符,一种是它通过确保类型必须是T的子类来设定类型的上界,另一种是它通过确保类型必须是T的父类来设定类型的下界。泛型类型必须用限定内的类型来进行初始化,否则会导致编译错误。另一方面表示了非限定通配符,因为可以用任意类型来替代。


  • ListList 之间有什么区别 ❓

这两个List的声明都是限定通配符的例子,List可以接受任何继承自T的类型的List,而List可以接受任何T的父类构成的List。例如List可以接受ListList


  • 如何编写一个泛型方法,让它能接受泛型参数并返回泛型类型?

编写泛型方法并不困难,你需要用泛型类型来替代原始类型,比如使用T, E or K,V等被广泛认可的类型占位符。 最简单的情况下,一个泛型方法可能会像这样:

public V put(K key, V value) {
    return cache.put(key, value);
}
复制代码


  • 编写一段泛型程序来实现LRU缓存?

LinkedHashMap可以用来实现固定大小的LRU缓存,当LRU缓存已经满了的时候,它会把最老的键值对移出缓存。LinkedHashMap提供了一个称为removeEldestEntry()的方法,该方法会被put()和putAll()调用来删除最老的键值对。


  • 你可以把List传递给一个接受List参数的方法吗?

    因为乍看起来String是一种Object,所以List应当可以用在需要List的地方,但是事实并非如此。真这样做的话会导致编译错误。如果你再深一步考虑,你会发现Java这样做是有意义的,因为List可以存储任何类型的对象包括String, Integer等等,而List却只能用来存储String

    List<Object> objectList;
    List<String> stringList;
    objectList = stringList;  //compilation error incompatible types
    复制代码


    • Array中可以用泛型吗?

    前提是你要知道Array事实上并不支持泛型,因为List可以提供编译期的类型安全保证,而Array却不能。

相关文章
|
Java 程序员 开发者
只用一行代码,你能玩出什么花样?
只用一行代码,你能玩出什么花样?
95 1
|
存储 算法 架构师
火车残骸和基本类型偏执问题解决方案
坏味道:缺乏封装。封装,将碎片式代码封装成可复用模块。但不同级别程序员对封装理解程度差异大,往往写代码的人认为自己提供了封装,但实际上,我们还是看到许多的代码散落在那里。
117 0
|
算法 uml
一文简单全面了解策略模式的使用【花几分钟轻松掌握一个知识点】
您好,我是码农飞哥,感谢您阅读本文,欢迎一键三连哦。 本文重点:介绍策略模式概念以及实际应用。 干货满满,建议收藏,需要用到时常看看。小伙伴们如有问题及需要,欢迎踊跃留言哦~ ~ ~
148 0
一文简单全面了解策略模式的使用【花几分钟轻松掌握一个知识点】
|
存储 Java 索引
【Java编程进阶】花费数小时,带你学透Java数组,这些常用方法你还记得吗?
数组在 Java 编程中是一个非常基础且重要的概念,简单来说,就是把具有相同数据类型的数据存储在地址连续的内存空间中,目的是在程序设计中方便这一类数据的管理。每一个内容都有编号,这个编号从 0 开始,称为数组下标。数组分为一维数组和二维数组,还有一些和数组相关的重要内容,例如数组中元素的查找,排序等,下面做详细的讲解。
102 0
【Java编程进阶】花费数小时,带你学透Java数组,这些常用方法你还记得吗?
|
Java 数据库连接 数据库
信不信十分钟让你彻底搞懂java反射
概念:反射是Java的一种机制,让我们可以在运行时获取类的信息 作用:通过反射,我们可以在程序运行时动态创建对象,还能获取到类的所有信息,比如它的属性、构造器、方法、注解等;
18074 2
信不信十分钟让你彻底搞懂java反射
|
Java 编译器 C++
不懂泛型,怎么装逼,一文把泛型说的明明白白,安排!!!
泛型是Java中的高级概念,也是构建框架必备技能,比如各种集合类都是泛型实现的,今天详细聊聊Java中的泛型概念,希望有所收获。记得点赞,关注,分享哦。
130 0
不懂泛型,怎么装逼,一文把泛型说的明明白白,安排!!!
|
算法 测试技术
蓝桥杯——我该如何枚举
蓝桥杯十道题,前面五道都是填空题,填空题只需要填上答案就可以。很多人并没有使用或者第一时间选择枚举,难道是害怕超时吗?经过了解几个小伙伴的想法后才知道原来大家不是不想用枚举,也不是不了解枚举,而是不知道该如何进行有效的枚举。由此可见,暴力枚举在蓝桥杯中占比较大,而且能够轻松得分,小伙伴们学废了吗
247 0
蓝桥杯——我该如何枚举
|
机器学习/深度学习 存储 Java
优化枚举的基本思路与进阶内容 |周末学习
优化枚举的基本思路与进阶内容 |周末学习
|
NoSQL 安全 程序员
还在频繁定义常量?不试试用枚举代替(备战2022春招或暑期实习,每天进步一点点,打卡100天,Day5)
还在频繁定义常量?不试试用枚举代替(备战2022春招或暑期实习,每天进步一点点,打卡100天,Day5)
124 0
还在频繁定义常量?不试试用枚举代替(备战2022春招或暑期实习,每天进步一点点,打卡100天,Day5)
|
设计模式 Java 编译器
恕我直言,我怀疑你没怎么用过枚举
我们是否一样? 估计很多小伙伴(也包括我自己)都有这种情况,在自学Java语言看书时,关于枚举enum这一块的知识点可能都有点 “轻敌” ,觉得这块内容非常简单,一带而过,而且在实际写代码过程中也不注意运用。 是的,我也是这样!直到有一天我提的代码审核没过,被技术总监一顿批,我才重新拿起了《Java编程思想》,把枚举这块的知识点重新又审视了一遍。 为什么需要枚举 常量定义它不香吗?为啥非得用枚举? 举个栗子,就以B站上传视频为例,视频一般有三个状态:草稿、审核和发布,我们可以将其定义为静态常量: public class VideoStatus { public st
137 0