Java 泛型你真的理解了吗?

泛型是JDK 1.5引入的新特性

泛型是jdk1.5后 引入的新特性,泛型在源码中使用的非常广泛,平常开发中也经常使用
那既然使用的这么广泛,你是否真正理解了,并能运用自如呢?
先抛出一个问题,既然泛型是在jdk 1.5后才引入,那之前源码是怎么写的呢?是为什么要引入呢?
搞清楚了这个,我想才能真正理解泛型设计的精髓!

对比不同版本的JDK api

JDK1.6的ArrayList

JDK1.4的ArrayList

不同之处在于 get(int index), remove(int index)
1.4版本返回的是object类型
1.6版本返回的是泛型的类型

为什么是object

我们都知道object是所有类的超类,那么在早期没有泛型概念的时候
其实就是用object来接收所有对象,代表任意类型

public class ObjectDemo{
    private Object obj;
    public Object getObj() {
        return obj;
    }
    public void setObj(Object obj) {
        this.obj = obj;
    }
}
        ObjectDemo od=new ObjectDemo();
        od.setObj(new String("qingguguo"));
        String s = (String) ot.getObj();
        System.out.println("姓名是:" + s);

        od.setObj(new Integer(20));
        String ss = (String) ot.getObj();//强转会报类型转换异常
        System.out.println("姓名是:" + ss);

按照现在泛型的写法如下:

public class ObjectDemo2<T>{
    private T obj;
    public T getObj() {
        return obj;
    }
    public void setObj(T obj) {
        this.obj = obj;
    }
}

ObjectDemo2<String> od=new ObjectDemo2<String>();
        od.setObj(new String("qingguguo"));
        String s =  ot.getObj();//这里都不用强转了
        System.out.println("姓名是:" + s);

        od.setObj(new Integer(20));//编译期就会报错

在向上转型为object的时候没有任何问题,但是向下转型的时候就可能会类型转换异常
这样的程序不安全,不健壮,所以java在JDK1.5后引入了泛型,以提高程序的安全性

泛型的应用

泛型类 ,如:Arraylist
泛型方法
泛型接口,如: List Map
泛型高级通配符

泛型类

泛型类:把泛型定义在类上

/*
 * 如果创建对象不写<T>, 那么默认就是object :new ObjectDemo()和new ObjectDemo<String>();
 */
public class ObjectDemo<T> {
    private T obj;

    public T getObj() {
        return obj;
    }

    public void setObj(T obj) {
        this.obj = obj;
    }
}

会根据传的类型返回传入的类型 对比下,这个用法有点意思,好好体会

public class ObjectTool<T> {
       public void show(String s) {
           System.out.println(s);
     }

  public void show(Integer i) {
        System.out.println(i);
      }

  public void show(Boolean b) {
            System.out.println(b);
        }

  public void show(T t) { //但是这个方法并不是泛型方法
    System.out.println(t);
    }
}

泛型方法

泛型方法:把泛型定义在方法上
1把泛型定义在方法上,方法上的泛型可以和类上的定义的泛型不一致,
2
类上不定义泛型,方法上也可以定义泛型,类上的泛型和方法上的泛型互不干涉

在调用方法的时候指明泛型的具体类型 ,下面这个示例要好好琢磨一下

泛型方法的基本说明:
 * @param tClass 传入的泛型实参  http://blog.csdn.net/s10461/article/details/53941091
 * @return T 返回值为T类型
 * 
 *     1)public 与 返回值中间<T>非常重要,可以理解为声明此方法为泛型方法。
 *     2)只有声明了<T>的方法才是泛型方法,泛型类中的使用了泛型的成员方法并不是泛型方法。
 *     3)<T>表明该方法将使用泛型类型T,此时才可以在方法中使用泛型类型T。
 *     4)与泛型类的定义一样,此处T可以随便写为任意标识,常见的如T、E、K、V等形式的参数常用于表示泛型。
 */
public <T> T show(Class<T>  tClass) {
        System.out.println(t);
    }
/*
 *把泛型定义在方法上,方法上的泛型可以和类上的定义的泛型不一致,
 *类上不定义泛型,方法上也可以定义泛型,类上的泛型和方法上的泛型互不干涉
 */
 public class ObjectTool {  //泛型方法
    public <T> void show(T t) {
        System.out.println(t);
    }
}
/**
*泛型方法  泛型类,泛型可不一致
*/
 public class ObjectTool2<E> {  
        private E key;

        public ObjectTool2(E key) {  //这个方法并不是泛型方法
            this.key = key;
        }

        //虽然在方法中使用了泛型,但是这并不是一个泛型方法。
        //这只是类中一个普通的成员方法,只不过他的返回值是在声明泛型类已经声明过的泛型。
        //所以在这个方法中才可以继续使用 E 这个泛型。
        public E getKey(){
            return key;
        }

   //这个方法显然是有问题的,在编译器会给我们提示这样的错误信息"cannot reslove symbol M"
   //因为在类的声明中并未声明泛型M,所以在使用M做形参和返回值类型时,编译器会无法识别。
       public M show2(M m) { 
           return m;
        }

     //这才是一个真正的泛型方法。
     //首先在public与返回值之间的<T>必不可少,这表明这是一个泛型方法,并且声明了一个泛型T
     //这个T可以出现在这个泛型方法的任意位置.
     // 泛型的数量也可以为任意多个
    public <T> void show(T t) {
        System.out.println(t);
    }
 /**
     * 这个方法是有问题的,编译器会为我们提示错误信息:"UnKnown class 'E' "
     * 虽然我们声明了<T>,也表明了这是一个可以处理泛型的类型的泛型方法。
     * 但是只声明了泛型类型T,并未声明泛型类型E,因此编译器并不知道该如何处理E这个类型。
    public <T> T showKeyName(Generic<E> container){
        ...
    }  
    */

    /**
     * 这个方法也是有问题的,编译器会为我们提示错误信息:"UnKnown class 'T' "
     * 对于编译器来说T这个类型并未项目中声明过,因此编译也不知道该如何编译这个类。
     * 所以这也不是一个正确的泛型方法声明。
    public void showkey(T genericObj){

    }
    */
}

泛型方法与可变参数

泛型方法与可变参数

再看一个泛型方法和可变参数的例子:吊炸天

 public static <T> void printMsg(T... args) {
        for (T t : args) {
            System.out.print(t + " ,");
        }
    }

printMsg("111", 222, "aaaa", "2323.4", 55.55, true, false, 'B');

输出结果:111111 ,222 ,aaaa ,2323.4 ,55.55 ,true ,false ,B ,

静态方法与泛型

如果静态方法要使用泛型的话,必须将静态方法也定义成泛型方法

public class StaticGenerator<T> {
    ....
    ....
    /**
     * 如果在类中定义使用泛型的静态方法,需要添加额外的泛型声明(将这个方法定义成泛型方法)
     * 即使静态方法要使用泛型类中已经声明过的泛型也不可以。
     * 如:public static void show(T t){..},此时编译器会提示错误信息:
          "StaticGenerator cannot be refrenced from static context"
     */
    public static <T> void show(T t){

    }
}

泛型方法总结:

泛型方法能使方法独立于类而产生变化,以下是一个基本的指导原则:
无论何时,如果你能做到,你就该尽量使用泛型方法。也就是说,如果使用泛型方法将整个类泛型化,那么就应该使用泛型方法。另外对于一个static的方法而已,无法访问泛型类型的参数。所以如果static方法要使用泛型能力,就必须使其成为泛型方法。

泛型接口

/*
 * 泛型接口:把泛型定义在接口上
 */
public interface Inter<T> {
    public abstract void show(T t);
}

那么实现类就会有两种情况要考虑:
实现类在实现接口的时候

//第一种情况:明确了类型
public class InterImpl implements Inter<String> {
    @Override
    public void show(String t) {
        System.out.println(t);
    }
 }

//第二种情况:还是不明确类型,比较多是这种情况
//必须在实现类上也加上泛型
public class InterImpl<T> implements Inter<T> {

    @Override
    public void show(T t) {
        System.out.println(t);
    }
}

泛型高级通配符

  • 泛型高级(通配符)
  • ?:任意类型,如果没有明确,那么就是Object以及任意的Java类了
  • ? extends E:向下限定,E及其子类
  • ? super E:向上限定,E极其父类

泛型数组

在java中是”不能创建一个确切的泛型类型的数组”的

    List<String>[] ls1 = new ArrayList<String>[10];//这样是不允许的
    
    List<?>[] ls2 = new ArrayList<?>[10];
    List<String>[] ls3 = new ArrayList[10];
    ArrayList[] ls4 = new ArrayList[10];

   //在泛型方法中添加上下边界限制的时候,
    //必须在权限声明与返回值之间的<T>上添加上下边界,即在泛型声明的时候添加
    public <T> T showKeyName6(List<T extends String> container) {//编译器会报错:"Unexpected bound"

        return container;
    }

    public <T extends Number> T showKeyName(List<T> list) {
        System.out.println("container key :" + list.size());
        T test = list.get(0);
        return test;
    }

泛型擦除

有这样的一个问题:ArrayList<Integer>的一个对象,能在这个集合中添加一个字符串数据吗?如果能,怎么做?
// 集合对象
ArrayList<Integer> array = new ArrayList<Integer>();
array.add(10);
array.add("hello");//这样写肯定会报错
这些都是给编译器看的!
泛型只是在编译阶段才有,运行时是没有的,通过反编译class文件就可以看到
运行时泛型已经擦除了,所以
可以通过反射的方式拿到add方法,默认就是object方法,再调用array.add("hello")

总结

基础决定了上层建筑,源码以及很多设计模式都用到了泛型,用的如此之广泛,
高级点的多个泛型,接口实现.如果没搞清楚,可能看的一脸懵逼。

1.泛型把明确类型的工作推迟到创建对象或者调用方法的时候才去明确;
2.<数据类型>数据类型只能是引用类型;
3.如果有泛型,不传的话默认就是object,但是建议有泛型最好就传入数据类型;
3.泛型把运行时期的类型转换问题提前到编译期,避免了强制类型转换;
4.优化程序设计,程序更健壮。

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

推荐阅读更多精彩内容

  • 现在开始深入学习java的泛型了,以前一直只是在集合中简单的使用泛型,根本就不明白泛型的原理和作用。泛型在java...
    sakura_L阅读 422评论 0 0
  • 近期更新了博文:他有故事他有酒,他有别人陪他走。 一大早收到博友的回复:我没有什么故事,偶尔失眠的时候一遍遍叫她的...
    C小树阅读 619评论 0 1
  • 她是一个母亲 女儿是她的稻草 分婉时的痛 早已失去了记忆 女儿到来 给苦闷的脸增添了微笑 丈夫是一个酒鬼 半夜三更...
    一辉而明阅读 186评论 2 1