重识java ——泛型基础

加油.png

做过 java/Android 的童鞋都知道,不管我们后台写 json 接口返回,还是移动端解析 json 接口,我们会将最终结果做统一的格式处理,具体代码可以是这样的:

public class Result {
    
    private Integer code; //状态码
    private String msg;//消息
    private Object data;//最终返回的数据体
    // ...省略 set get 方法
}

最终调用如下:

Result result = new Result();
result.setCode(200);
result.setMsg("成功");
result.setData("我是最终数据结果");
//执行序列化,反序列化操作

分析:

优点:看到 Object 上帝类,就知道最终 data 这个参数可以设置任意类型参数,对于数据格式固定,这种写法明显降低了代码量,对最终结果做了统一处理。
缺点:我们试图获取构造的对象数据时,有可能不清楚当初传入的是什么类型,强制类型转换为其他类型,或者由于程序员的疏忽而强制转换为其他类型,这在编译时是正常通过的,因为 Object 可以强制转换为任意类型,只是对象中我们传入的类型有可能不能强制转换,最终在运行时,由 java 抛出类型转换异常,这无疑是一种程序潜在的不安全。如下代码:

//编译正常,运行时抛异常
 Integer data = (Integer) result.getData();
 System.out.println("data:" + data);

实际传入为 String ,强制转为 Integer,抛出 ClassCastException 异常。

那么,基于此,java 提供的泛型就是为了解决这个痛点的。

泛型特点

泛型是计算机程序中一种重要的思维方式,它将数据结构和算法与数据类型分离开,使得同一套数据结构和算法能够应用于各种数据类型,而且可以保证类型安全,提高可读性。

普通泛型类

用泛型对 Result 类做下修改:

public class Result<T> {

    private Integer code; //状态码
    private String msg;//消息
    private T data;//数据体

    // ...省略 部分 set,get 方法
    public T getData() {
        return data;
    }
    public void setData(T data) {
        this.data = data;
    }

    public static void main(String[] args) {
        //指定泛型为 String
        Result<String> result = new Result();
        result.setCode(200);
        result.setMsg("成功");
        result.setData("我是最终数据结果");
        //不需要类型转换,直接返回泛型类型
        String data = result.getData();
        System.out.println("data:" + data);
    }
}

分析:

  1. 取消 Object ,改用 T 类型参数,泛型就是类型参数化,处理的数据类型不是固定的,而是可以作为参数传入
  2. 创建对象的时候,指定了泛型类型,最终获取数据时,java 编译器在内部会帮助识别类型,不需要类型转换,在编译时期就把类型安全解决掉,不会有后期的安全隐患。

多参数类型参数

类型参数可以有多个,用逗号隔开,简单改写代码如下:

public class Result<T,U> {

    private Integer code; //状态码
    private String msg;//消息
    private T data1;
    private U data2;

    // ...省略部分 set get 方法

    public T getData1() {
        return data1;
    }
    public U getData2() {
        return data2;
    }
    public static void main(String[] args) {

        Result<String,String> result = new Result();
        result.setCode(200);
        result.setMsg("成功");
        result.setData1("我是第一个结果");
        result.setData2("我是第二个结果");
        String data1 = result.getData1();
        String data2 = result.getData2();
        System.out.println("data1:" + data1 + ",data2:" + data2);
    }
}

泛型方法

泛型也可以指定在具体的方法上,与所在的类是否是泛型没关系,如下,添加静态方法:
计算:找出 泛型数组中,指定元素的索引值,找不到则返回 -1

//查找数组指定元素索引
    public static <T> int indexOf(T[] arr,T element){
        for (int i = 0; i < arr.length; i++) {
            if (arr[i].equals(element)){
                return i;
            }
        }
        return -1;
    }

调用如下:

 int index = indexOf(new Integer[]{1, 3, 5}, 10);
  System.out.println(index);
  //结果为:-1

  int index1 = indexOf(new String[]{"张少林", "福建", "漳州", "25"}, "张少林");
  System.out.println(index1);
  //结果:0

以上可知,泛型方法与泛型类达到的效果一致,同一段代码,与所传入的参数类型无关,可以方便的在各种数据类型之间进行复用,且是类型安全的。

同泛型类一样,泛型方法也可以传入多个类型参数,用户最终调用不需要关心传入的具体类型是啥,java 编译器会自动处理。代码如下:

 public static <U,V> Result<U,V> makeResult(U first,V second){
        Result<U, V> pair = new Result<>(first, second);
        return result;
    }

//调用:
Result<String, Integer> result = makeResult("张少林", 25);

泛型接口

接口也可以是泛型的,java 中的 Comparable<T>,Comparator<T> 就是泛型接口,定义如下:

public interface Comparable<T> {
      public int compareTo(T o);
}

public interface Comparator<T> {
      ......
}

实现 接口,必须制定泛型类型,如:Integer 类 指定泛型类型为 Integer

public final class Integer extends Number implements Comparable<Integer> {
    public int compareTo(Integer anotherInteger) {
        return compare(this.value, anotherInteger.value);
    }
}

限定类型参数

之前的泛型写法中,类型参数默认是派生自 Object 的,这时候,类型参数传入任何类型都是可以的,而我们可以自定义类型参数的上界,类型参数上界可以是个具体类,接口,其他类型参数,此时类型参数必须为上界类型的子类或者是它本身,或者实现了上界接口。

  1. 上界为具体类
public class Pair<U,V> {

    U first;
    V second;

    public Pair(U first, V second) {
        this.first = first;
        this.second = second;
    }

    public U getFirst() {
        return first;
    }

    public V getSecond() {
        return second;
    }
}

public class NumberPair<U extends Number,V extends Number> extends Pair<U,V>{


    public NumberPair(U first, V second) {
        super(first, second);
    }

    public static void main(String[] args) {
        NumberPair<Integer, Integer> numberPair = new NumberPair<>(666, 999);
        System.out.println(numberPair.getFirst() + "," + numberPair.getSecond());
//结果是:666,999
     //编译错误
        new NumberPair<String,String>("cdsc","csdc")
    }
}

很明显,假如传入的类型参数,不是派生自 Number 类,在编译时,就会提示错误。

  1. 上界为接口

泛型方法中,类型参数必须实现某个接口,从而依赖接口的方法,具体例子如下,获取数组中的最大值,具体类型依赖 Comparable<T> 接口的方法,compareTo,也就是每个具体类型实现 compareTo 的比较逻辑即可:

    public static <T extends Comparable<T>> T max(T[] arr){
        T max = arr[0];
        for (int i = 0; i < arr.length; i++) {
            if (arr[i].compareTo(max)>0) {
                max = arr[i];
            }
        }
        return max;
    }
  1. 上界为其他类型参数,在不知道类型参数具体的上界是什么的时候,可以定义为其他的类型参数,类似如下代码:
public static  <T extends E> void addAll(List<T> c){
        for (int i = 0; i < c.size(); i++) {
            add(c.get(i));
        }
    }

至此,java 泛型基础总结先到这里了,还没完,路还很长。

更多原创文章会在公众号第一时间推送,欢迎扫码关注 张少林同学

张少林同学.jpg
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,293评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,604评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,958评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,729评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,719评论 5 366
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,630评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,000评论 3 397
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,665评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,909评论 1 299
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,646评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,726评论 1 330
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,400评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,986评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,959评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,197评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 44,996评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,481评论 2 342

推荐阅读更多精彩内容

  • 我好幸福!
    麻月英阅读 210评论 0 0
  • 2018年1月1日,这一天似乎每个人都沉浸在跨年的喜悦中,给自己一个祝福,给自己一个目标!我却没有任何激动和期盼,...
    有梦的僵尸阅读 128评论 0 2
  • 星空中出现的那个太阳 还有藏在田野中的老人 艰难的存在了许久 然后就是扭曲再扭曲 扭曲出令人兴奋的失落 古老的牧场...
    只是喜欢苏东坡阅读 110评论 0 0
  • STAR面试法,是企业招聘面试过程中可采用的技巧,它的用途是对应聘者做出全面而客观的评价。其中,“STAR”是SI...
    xiaoyushidai阅读 32,573评论 1 21