Java范型

范型概念

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

使用前

java 复制代码
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

public class Main {
    public static void main(String[] args) {
        List list = new ArrayList();
        list.add(67);
        list.add(78);
        list.add(76);
        list.add(99);

        //1. 问题1:类型不安全。因为add()的参数是Object类型,意味着任何类型的对象都可以添加成功
//        list.add("AA");

        Iterator iterator = list.iterator();
        while(iterator.hasNext()){
            //2. 问题2:需要使用强转操作,繁琐。还有可能导致ClassCastException异常。
            Integer i = (Integer) iterator.next();
            int score = i;

            System.out.println(score);
        }
    }
}

使用后

java 复制代码
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

public class Main {
    public static void main(String[] args) {
        List<Integer> list = new ArrayList<Integer>();

        list.add(78);
        list.add(76);
        list.add(66);
        list.add(99);

        // 编译报错,保证类型的安全
//        list.add("AA");

        Iterator<Integer> iterator = list.iterator();
        while (iterator.hasNext()) {
            // 因为添加的都是Integer类型,避免了强转操作
            Integer i = iterator.next();
            int score = i;

            System.out.println(score);
        }
    }
}
java 复制代码
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;

public class Main {
    public static void main(String[] args) {
        //jdk7的新特性
        HashMap<String, Integer> map = new HashMap<>();

        map.put("Tom", 67);
        map.put("Jerry", 87);
        map.put("Rose", 99);

//        Set<Map.Entry<String, Integer>> entrySet = map.entrySet();
//        Iterator<Map.Entry<String, Integer>> iterator = entrySet.iterator();

        var entrySet = map.entrySet();
        var iterator = entrySet.iterator();

        while (iterator.hasNext()) {
            Map.Entry<String, Integer> entry = iterator.next();
            String key = entry.getKey();
            Integer value = entry.getValue();
            System.out.println(key + "---" + value);
        }
    }
}

自定义范型

自定义泛型类\接口

格式

复制代码
class A<T>{
}
interface B<T1, T2>{
}
java 复制代码
public class Main<T> {
    T t;
    int orderId;

    public Main() {
    }

    public Main(T t, int orderId) {
        this.t = t;
        this.orderId = orderId;
    }

    public T getT() {
        return t;
    }

    public void setT(T t) {
        this.t = t;
    }

    public int getOrderId() {
        return orderId;
    }

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

    @Override
    public String toString() {
        return "Main{" +
                "t=" + t +
                ", orderId=" + orderId +
                '}';
    }
}
java 复制代码
public class Main {
    public static void main(String[] args) {
        // 实例化时,就可以指明类的泛型参数的类型
        Order order = new Order();
        Object obj = order.getT();

        // 泛型参数在指明时,是不可以使用基本数据类型的!但是可以使用包装类替代基本数据类型。
        Order<int> order1 = new Order<>();
        // 在实例化时,可以指明类的泛型参数的具体类型!一旦指明了泛型的类型,则在该泛型中凡是使用泛型
        // 参数的位置,都替换为指定的类型。
        Order<Integer> order2 = new Order<Integer>();
        Integer t = order2.getT();

        Order<String> order3 = new Order<>();
        order3.setT("AA");
    }
}

使用说明

① 我们在声明自定义泛型类以后,可以在类的内部(比如:属性、方法、构造器中)使用类的泛型。

② 我们在创建自定义泛型类的对象时,可以指明泛型参数类型。一旦指明,内部只是使用类的泛型参数的位置,都具体化为指定的类的泛型类型。

③ 如果在创建自定义泛型类的对象时,没有指明泛型参数类型,那么泛型将被擦除,泛型对应的类型均按照Object处理,但不等于Object。

--->经验:泛型要使用一路都用。要不用,一路都不要用。

④ 泛型的指定中必须使用引用数据类型。不能使用基本数据类型,此时只能使用包装类替换。

⑤ 除创建泛型类对象外,子类继承泛型类时,实现类实现泛型接口时,也可以确定泛型结构中的泛型参数。

如果我们在给泛型类提供了类时,子类也不确定泛型的类型,则可以继续使用泛型参数。

我们还可以在现有的父类的泛型参数的基础上,新增泛型参数。

注意点

① 泛型类可能有多个参数,此时应将多个参数一起放在尖括号内。比如:<E1,E2,E3>

② JDK7.0 开始,泛型的简化操作:ArrayList<Fruit> flist = new ArrayList<>();

③ 如果泛型结构是一个接口或抽象类,则不可创建泛型类的对象。

④ 不能使用new E[]。但是可以:E[] elements = (E[])new Object[capacity];

参考:ArrayList源码中声明:Object[] elementData,而非泛型参数类型数组。

⑤ 在类/接口上声明的泛型,在本类或本接口中即代表某种类型,但不可以静态方法中使用类的泛型。

⑥ 异常类不能是带泛型的。

自定义范型方法

格式

java 复制代码
权限修饰符 <T> 返回值类型 方法名(形参列表) { 
    //通常在形参列表或返回值类型的位置会出现泛型参数T
}

public <E> E method(E e) {
    //函数体
}

说明

  • 声明泛型方法时,一定要添加泛型参数<T>

  • 泛型参数在方法调用时,指明其具体的类型

  • 泛型方法可以根据需要声明为static的

  • 泛型方法所属的类是否是一个泛型类,都可以

注:

  1. 类SuperA是类A的父类,则G<SuperA>与G<A>的关系:G<SuperA>和G<A>是并列的两个类,没有任何子父类的关系

比如:ArrayList<Object>、ArrayList<String>没有关系

  1. 类SuperA是类A的父类或接口,SuperA<G>与A<G>的关系:SuperA<G>与A<G>有继承或实现的关系。即A<G>的实例可以赋值给SuperA<G>类型的引用(或变量)

比如:List<String>与ArrayList<String>

通配符

通配符:?

使用说明:

  • 举例:ArrayList<?>

  • G<?> 可以看做是G<A>类型的父类,即可以将G<A>的对象赋值给G<?>类型的引用(或变量)

读写数据的特点(以集合ArrayList<?>为例说明)

  • 读取数据:允许的,读取的值的类型为Object类型

  • 写入数据:不允许的。特例:写入null值。

无限制条件的通配符

java 复制代码
import java.util.ArrayList;
import java.util.List;

public class Main {
    public static void main(String[] args) {
        List<?> list = null;

        List<String> list1 = new ArrayList<>();
        list1.add("AA");

        list = list1;

        // 读取数据(以集合为例说明)
        Object obj = list.get(0);
        System.out.println(obj);

        // 写入数据(以集合为例说明)
        // 写入数据,操作失败。
//        list.add("BB");
        // 特例:可以将null写入集合中。
        list.add(null);
    }
}

有限制条件的通配符

List<? extends A> : 可以将List<A>或List<B>赋值给List<? extends A>。其中B类是A类的子类。

java 复制代码
import java.util.List;

public class Main {
    public static void main(String[] args) {
        List<? extends Father> list = null;//<=

        List<Object> list1 = null;
        List<Father> list2 = null;
        List<Son> list3 = null;

//    list = list1;
        list = list2;
        list = list3;
    }
}

List <? super A> : 可以将List<A>或List<B>赋值给List<? extends A>。其中B类是A类的父类。

java 复制代码
import java.util.List;

public class Main {
    public static void main(String[] args) {
        List<? super Father> list = null;//>=

        List<Object> list1 = null;
        List<Father> list2 = null;
        List<Son> list3 = null;

        list = list1;
        list = list2;
//        list = list3;
    }
}
相关推荐
tongluowan0072 分钟前
怎么保证缓存和数据库的一致性
java·数据库·缓存·一致性
一条泥憨鱼2 分钟前
【Java 进阶】LinkedHashMap 与 TreeMap
java·开发语言·数据结构·笔记·后端·学习
ゆづき2 分钟前
假如编程语言们有外号
java·c语言·c++·python·学习·c#·生活
凤山老林3 分钟前
63-Java LinkedList(链表)
java·开发语言·链表
恣艺10 分钟前
用Go从零实现一个高性能KV存储引擎:B+Tree索引、WAL持久化、LRU缓存的工程实践
开发语言·数据库·redis·缓存·golang
TDengine (老段)10 分钟前
TDengine 支持数据类型深度解析 — 类型体系、存储编码与选型指南
java·大数据·数据库·系统架构·时序数据库·tdengine·涛思数据
浮尘笔记2 小时前
Java Snowy框架CI/CD云效自动化部署流程
java·运维·服务器·阿里云·ci/cd·自动化
kkeeper~9 小时前
0基础C语言积跬步之深入理解指针(5下)
c语言·开发语言
一直不明飞行9 小时前
Java的equals(),hashCode()应该在什么时候重写
java·开发语言·jvm
REDcker9 小时前
有限状态机与状态模式详解 FSM建模Java状态模式与C++表驱动模板实践
java·c++·状态模式