Java泛型的使用

Wesley13
• 阅读 838

泛型的定义:

泛型,就是允许在定义类、接口时通过一个标识表示类中某个属性的类型或者是某个方法的返回值及参数类型。这个类型参数将在使用时(例如,继承或实现这个接口,用这个类型声明变量、创建对象时)确定(即传入实 际的类型参数,也称为类型实参)。

泛型的引入背景:

集合容器类在设计阶段或声明阶段不能确定这个容器到底实际存储的是什么类型的对象,所以在JDK1.5之前只能把元素类型设计为Object,JDK1.5之后使用泛型来解决。因为这个时候除了元素的类型不确定,其他的部分是确定的,此时把元素的类型设计成一个参数,这个类型参数叫做泛型。Collection,List,ArrayList 这个就是类型参数,即泛型。

在集合中使用泛型

1.集合中没有使用泛型时:

1.任何类型都可以添加到集合中:类型不安全。
2.读取出来的对象需要强转:还可能会有报异常:java.lang.ClassCastException

//在集合中没有使用泛型时
@Test
public void test1(){
    ArrayList list = new ArrayList();
    list.add(66);
    list.add(55);
    list.add(77);
    list.add(59);

    //类型不安全
    // list.add("AA");

    for (Object score : list){
 //在进行向下强转时可能会出异常:java.lang.ClassCastException
        int stuScore = (int) score;
        System.out.println(stuScore);
    }
}
2.在集合中使用泛型后:

只有指定类型才可以添加到集合中:类型安全。
读取出来的对象不需要强转:便捷。
可以保证如果程序在编译时没有发出警告,运行时就不会产生 ClassCastException异常。

    //在集合中使用泛型的情况,以ArrayList为例
@Test
public void test2(){
  ArrayList<Integer> list = new ArrayList<Integer>();
  list.add(66);
  list.add(59);
  list.add(86);
  list.add(90);
  //在编译时,就会进行类型检查,保证数据的安全性。
 //      list.add("haha");

    Iterator<Integer> iterator = list.iterator();
    while(iterator.hasNext()){
        int stucore = iterator.next();
        System.out.println(stucore);
    }
}

//在集合中使用泛型的情况,HashMap为例
@Test
public void test3(){
    Map<String,Integer> map = new HashMap<String,Integer>();
    map.put("AA",66);
    map.put("BB",59);
    map.put("DD",86);
    map.put("CC",96);

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

}

小结:

1.在实例化集合类时,可以指明具体的泛型类型。
2.指明以后,在集合类或接口中凡是定义类或接口时,内部的结构(比如:方法、构造器、属性等)使用到类的泛型的位置,都指定为实例化的泛型类型。
3. 泛型的类型必须是类,不能是基本数据类型,需要用到基本数据类型的位置,用包装类来替换。
4. 如果实例化时,并没有指明泛型的类型,则默认类型为java.lang.Object类型。

自定义泛型类

  1. 泛型类可能有多个参数,此时应将多个参数一起放在尖括号内。
  2. 泛型类的构造器如下:public GenericClass(){}。 而public GenericClass(){} 是错误的
  3. 实例化后,操作原来泛型位置的结构必须与指定的泛型类型一致。
  4. 泛型不同的引用不能相互赋值。
  5. 泛型如果不指定,将被擦除,泛型对应的类型均按照Object处理,但不等价于Object。泛型要使用就全部都使用。要不用,就全部都不使用。
  6. 如果泛型结构是一个接口或抽象类,则不可创建泛型类的对象。
  7. jdk1.7以后,泛型的简化操作:ArrayList arrli = new ArrayList<>();
  8. 泛型的指定中不能使用基本数据类型,可以使用包装类替换。
  9. 在类或接口上声明的泛型,在本类或本接口中即代表某种类型,可以作为非静态属性的类型、非静态方法的参数类型、非静态方法的返回值类型。但在静态方法中不能使用类的泛型。
  10. 异常类不能是泛型。
  11. 不能使用new E[]。但是可以是:E[] elements = (E[])new Object[capacity];
  12. 父类有泛型时,子类除了指定或保留父类的泛型,还可以增加自己的泛型。

参考代码如下:
Order.java:

   //自定义泛型类  
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;
    }

    public String getOrderName() {
        return orderName;
    }

    public void setOrderName(String orderName) {
        this.orderName = orderName;
    }

    public int getOrderId() {
        return orderId;
    }

    public void setOrderId(int orderId) {
        this.orderId = orderId;
    }

    //不是泛型方法
    public T getOrderT() {
        return orderT;
    }
    //不是泛型方法
    public void setOrderT(T orderT) {
        this.orderT = orderT;
    }
    //不是泛型方法
    @Override
    public String toString() {
        return "Order{" +
                "orderName='" + orderName + '\'' +
                ", orderId=" + orderId +
                ", orderT=" + orderT +
                '}';
    }

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

SubOrder.java

//SubOrder 不再是泛型类
public class SubOrder extends Order<Integer> {

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

SubOrder1.java

//SubOrder1仍然是泛型类
public class SubOrder1<T> extends Order<T> {

}

对上述方法进行测试:

 @Test
public void test1(){
    //如果定义了泛型类,实例化时没有指明类的泛型,则默认此泛型类型为Object类型
    //如果定义了类是带泛型的,建议在实例化的时候要指明类的泛型
//        Order order = new Order();
//        order.setOrderT(123);
//        order.setOrderT("abc");

       //建议,实例化时指明类的泛型
    Order<String> order = new Order<>("AA",1001,"haha");
    order.setOrderT("AA:hello");
}

@Test
public void test2(){
    SubOrder sub = new SubOrder();
    //由于子类在继承带泛型的父类时,指明了泛型类型,则实例化子类对象时,不再需要指明泛型类型
    sub.setOrderT(1111);

    SubOrder1<String> sub1 = new SubOrder1<>();
    sub1.setOrderT("AAA");
}

@Test
public void test3(){

    //泛型不同的引用不能相互赋值。
    ArrayList<String> list  = null;
    ArrayList<Integer> list1 =null;
//  list =list1;

}

//测试泛型方法
@Test
public void test4(){
   Order<String> order = new Order<>();
   Integer[] arr = new Integer[]{1,2,3,4};
   //泛型方法在调用时,指明泛型参数的类型,这个类型与类的泛型没有任何关系。
    List<Integer> list = order.copyFromArrayToList(arr);

//  Iterator<Integer> iterator = list.iterator();
//   while (iterator.hasNext()){
//     System.out.println(iterator.next());
//   }
    System.out.println(list);
}

通配符

通配符就是英文格式下的 ? 类A是类B的父类,G< A> 和G是没有关系的,二者的共同父类是G<?>

@Test
public void test3(){
    List<Object> list1 = null;
    List<String> list2 = null;
    List<?> list3 = null;

    list3 = list1;
    list3 = list2;

    print(list1);
    print(list2);

    //
    List<String> list4 = new ArrayList<>();
    list4.add("HH");
    list4.add("AA");
    list4.add("QQ");
    list4.add("WW");

    list3 = list4;

  //添加:对于List<?>就不能向其内部添加数据。除了可以添加null以外
//  list3.add("DD");
//   list3.add("?");
// list3.add('?');
// list3.add(null);

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

public void print(List<?> list){
    Iterator<?> iterator = list.iterator();
    while (iterator.hasNext()){
        Object obj = iterator.next();
        System.out.println(obj);
    }
}
点赞
收藏
评论区
推荐文章
待兔 待兔
5个月前
手写Java HashMap源码
HashMap的使用教程HashMap的使用教程HashMap的使用教程HashMap的使用教程HashMap的使用教程22
Wesley13 Wesley13
3年前
java 泛型详解
对java的泛型特性的了解仅限于表面的浅浅一层,直到在学习设计模式时发现有不了解的用法,才想起详细的记录一下。本文参考java泛型详解、Java中的泛型方法、java泛型详解1\.概述泛型在java中有很重要的地位,在面向对象编程及各种设计模式中有非常广泛的应用。什么是泛型?为什么要使用泛型?泛型,即“参数化类型”。一提到参数,最熟
Wesley13 Wesley13
3年前
java几个类的简单使用
RandomRandom类用来创建一个新的随机数生成器。对象数组ArrayList集合的长度是可以随意改变的。ArrayList<E这个<E代表泛型泛型:装在集合当中的所有元素,全部都是统一的类型。泛型只能是引用类型,不能使用基本元素。importjava.util.ArrayList;
Stella981 Stella981
3年前
Gson通过借助TypeToken获取泛型参数的类型的方法
最近在使用Google的Gson包进行Json和Java对象之间的转化,对于包含泛型的类的序列化和反序列化Gson也提供了很好的支持,感觉有点意思,就花时间研究了一下。由于Java泛型的实现机制,使用了泛型的代码在运行期间相关的泛型参数的类型会被擦除,我们无法在运行期间获知泛型参数的具体类型(所有的泛型类型在运行时都是Object类型)。但是有的时候
Wesley13 Wesley13
3年前
Java泛型详解
引言Java泛型是jdk1.5中引入的一个新特性,泛型提供了编译时的类型检测机制,该机制允许程序员在编译时检测到非法的类型。泛型是Java中一个非常重要的知识点,在Java集合类框架中泛型被广泛应用。本文我们将从零开始来看一下Java泛型的设计,将会涉及到通配符处理,以及让人苦恼的类型擦除。泛型基础
Easter79 Easter79
3年前
Thinking in java Chapter15 泛型
1与C比较2简单泛型泛型类3泛型接口4泛型方法5匿名内部类6构建复杂模型78910“泛型”意思就是:适用于许多许多的类型<h2id"1"1与C比较</h2C
Stella981 Stella981
3年前
20175209 《Java程序设计》第八周学习总结
20175209《Java程序设计》第八周学习总结一、教材知识点总结1.泛型1.泛型类声明:格式classPeople<EPeople是泛型类名称E是泛型列表,可以是任何对象或接口,但不能是基本类型数据
Wesley13 Wesley13
3年前
Java泛型一览笔录
1、什么是泛型?泛型(Generics)是把类型参数化,运用于类、接口、方法中,可以通过执行泛型类型调用分配一个类型,将用分配的具体类型替换泛型类型。然后,所分配的类型将用于限制容器内使用的值,这样就无需进行类型转换,还可以在编译时提供更强的类型检查。2、泛型有什么用?泛型主要有两个好处:(1)消除显
Wesley13 Wesley13
3年前
JAVA 泛型中的通配符 T,E,K,V 傻傻分不清楚 ?
前言Java泛型(generics)是JDK5中引入的一个新特性,泛型提供了编译时类型安全检测机制,该机制允许开发者在编译时检测到非法的类型。泛型的本质是参数化类型,也就是说所操作的数据类型被指定为一个参数。泛型带来的好处在没有泛型的情况的下,通过对类型Object的引用来实现参数的“任意化”,“任意化”带
可莉 可莉
3年前
20175209 《Java程序设计》第八周学习总结
20175209《Java程序设计》第八周学习总结一、教材知识点总结1.泛型1.泛型类声明:格式classPeople<EPeople是泛型类名称E是泛型列表,可以是任何对象或接口,但不能是基本类型数据