Java:泛型

1. 泛型的概念

1.1 什么是泛型

泛型类似标签,出现原因是因为:集合容器类在设计阶段/声明阶段不能确定这个容器到底实际存的是什么类型的对象

因此此时把元素的类型设计成一个参数,这个类型参数叫做泛型

泛型,允许在定义类、接口时通过一个标识表示类中某个属性的类型或者是某个方法的返回值及参数类型

Collection<E>,List<E>,ArrayList<E> 这个<E>就是类型参数,即泛型

1.2 泛型的好处

  1. 解决元素存储的安全性问题,好比商品、药品标签,不会弄错。
  2. 解决获取数据元素时,需要类型强制转换的问题,好比不用每回拿商品、药品都要辨别。

2. 集合中使用泛型

2.1 使用方法

  1. 集合接口或集合类在jdk5.e时都修改为带泛型的结构。
  2. 在实例化集合类时,可以指明具体的泛型类型。
  3. 指明完以后,在集合类或接口中凡是定义类或接口时,内部结构使用到类的泛型的位置,都指定为实例化的泛型类型。
  4. 注意点:泛型的类型必须是类,不能是基本数据类型。需要用到基本数据类型的位置,拿包装类替换。
  5. 如果实例化时,没有指明泛型的类型。默认类型为java.Lang.Object类型。

2.2 具体举例

以ArrayList为例

//导入的包有:import org.junit.Test;import java.util.*;

public class GenericTest {
    @Test
    public void test1(){
        ArrayList<Integer> list = new ArrayList<>();

        list.add(23);
        list.add(97);
        list.add(25);
        list.add(43);
        //编译时,就会进行类型检查,保证数据安全
//        list.add("Tom");

        //遍历方式一:for
        for(Integer score : list){
            //避免了强转操作
            int stuScore = score;
            System.out.println(stuScore);
        }

        //遍历方式二:Iterator
        Iterator<Integer> iterator = list.iterator();
        while(iterator.hasNext()){
            int stuScore = iterator.next();
            System.out.println(stuScore);
        }

    }
}

以HashMap为例

//导入的包有:import org.junit.Test;import java.util.*;

public class GenericTest {
    @Test
    public void test2(){
        Map<String, Integer> map = new HashMap<String, Integer>();

        map.put("Tom",83);
        map.put("Jerry",77);
        map.put("Jack",33);

        //泛型的嵌套
        Set<Map.Entry<String, Integer>> entry = map.entrySet();
        Iterator<Map.Entry<String, Integer>> iterator = entry.iterator();
        //遍历
        while(iterator.hasNext()){
            Map.Entry<String, Integer> e = iterator.next();
            String key = e.getKey();
            Integer value = e.getValue();
            System.out.println(key + ":" + value);
        }
    }
}

3. 自定义泛型结构

3.1 泛型类与泛型接口

如何定义

泛型类与泛型接口的区别主要还是类与接口的区别,所以这里以泛型类举例

public class Order<T> {
    String orderName;
    int orderId;

    //类的内部结构就可以使用泛型
    T orderT;

    public Order(){
    }
    public Order(String orderName,int orderId,T orderT){
        this.orderName = orderName;
        this.orderId = orderId;
        this.orderT = orderT;
    }
}

class Test{
    @org.junit.Test
    public void test1(){
        //要求:如果定义了类是带泛型的,建议在实例化时使用它
        Order<String> order = new Order<String>("AA",1001,"hello");
    }
}

注意事项

  1. 泛型类可能有多个参数,此时应将多个参数一起放在尖括号内。比如:<E1,E2,E3>
  2. 泛型类的构造器如下:public GenericClass(){},而下面是错误的:public GenericClass<E>(){}
  3. 实例化后,操作原来泛型位置的结构必须与指定的泛型类型一致。
  4. 泛型不同的引用不能相互赋值。
  5. 泛型如果不指定,将被擦除,泛型对应的类型均按照Object处理,但不等价于Object。
  6. 如果泛型结构是一个接口或抽象类,则不可创建泛型类的对象。
  7. jdk1.7,泛型的简化操作:ArrayList<Fruit> flist = new ArrayList<>()。
  8. 泛型的指定中不能使用基本数据类型,可以使用包装类替换。
  9. 在静态方法中不能使用类的泛型。
  10. 异常类不能是泛型的。
  11. 不能使用new E[]。但是可以:E[] elements = (E[])new Object[capacity]。
  12. 父类有泛型,子类可以选择保留泛型也可以选择指定泛型类型:
    • 子类不保留父类的泛型:按需实现
      • 没有类型,擦除
      • 具体类型
    • 子类保留父类的泛型:泛型子类
      • 全部保留
      • 部分保留

3.2 泛型方法

在方法中出现了泛型的结构,泛型参数与类的泛型参数没有任何关系

也就是说,泛型方法所属的类是不是泛型类都没有关系

泛型参数在调用时体现泛型参数的类型

泛型方法可以是静态的,是因为泛型参数是在调用方法时确定的

public <E> List<E> testMethod(E[] arr){
    
    ArrayList<E> list = new ArrayList<>();
    for(E e : arr){
        list.add(e);
    }
    return list;
}

4. 泛型在继承上的体现

若子类在继承带泛型的父类时,指明了泛型类型,则实例化子类对象时,不再需要指明泛型。

若子类在继承带泛型的父类时,没有指明了泛型类型,则实例化子类对象时,需要指明泛型。

若类A是类B的父类,但G<A>和G<B>二者不具备子父类关系,二者是并列关系

若类A是类B的父类,A<G>是B<G>的父类

5. 通配符的使用

5.1 通配符的概念

通配符的符号是"?",它的使用方法为使用"?"代替具体的类型参数

例如:类A是类B的父类,G<A>和G<B>是没有关系的,但二者共同的父类是G<?>

//导入的包:import org.junit.Test;import java.util.List;

public class TongPeiFu {
    @Test
    public void test1(){
        List<Object> list1 = null;
        List<Object> list2 = null;

        List<?> list = null;

        list = list1;
        list = list2;
    }
}

5.2 通配符的写入与读取

对于List<?>不能向其内部添加数据,因为不知道其子类添加的是什么数据

对于List<?>允许读取数据,读取数据类型为Object

//导入的包有:import org.junit.Test;import java.util.ArrayList;import java.util.List;

public class TongPeiFu {
    @Test
    public void test2(){
        List<String> list3 = new ArrayList<>();
        list3.add("AA");
        list3.add("BB");
        list3.add("CC");

        List<?> list = list3;
        
        //添加:对于List<?>不能向其内部添加数据
        //除了添加null之外
        list.add(null);

        //获取:允许读取数据,读取数据类型为Object
        Object o = list.get(0);
        System.out.println(o);//AA
    }
}

5.3 有限制的通配符

  1. G<? extends A>:可以作为G<A>和G<B>的父类,其中B是A的子类
  2. G<? super A>:可以作为G<A>和G<B>的父类,其中B是A的父类
//导入的包有:import org.junit.Test;import java.util.ArrayList;import java.util.List;

public class TongPeiFu {
    @Test
    public void test2(){
        List<? extends Person> list1 = null;
        List<? super person> list2 = null;

        List<Student> list3 = null;
        List<Person> list4 = null;
        List<Object> list5 = null;

        //G<? extends A>可以作为包括A以下类的父类
        list1 = list3;
        list1 = list4;
//        list1 = list5;

        //G<? super A>可以作为包括A以上类的父类
//        list2 = list3;
        list2 = list4;
        list2 = list5;
    }
}

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