第二十七条 优先考虑泛型方法

本文探讨了泛型在Java中的应用,特别是在方法和类中的使用。通过实例讲解了如何在静态工具类方法中引入泛型,以及如何通过泛型增强方法的灵活性和安全性。文章还介绍了泛型方法的局限性、类型推导的概念,并展示了如何利用泛型创建通用的静态方法。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

如同类一样,方法也可以加入泛型,尤其是静态工具类方法。Collections 骨架类中,全用到了泛型方法。书中例子

    public static Set union(Set s1, Set s2) {
        Set result = new HashSet(s1);
        result.addAll(s2);
        return result;
    }
这个方法可以编译,但是有两条警告,Unchecked call to HashSet(Collection<? extends E>) as a member of raw type HashSet , 为了清除警告,保证方法是安全的,需要将方法修改参数的类型声明,保证从传入的参数到生成的集合,类型是一致的,我们可以增加 <E>, 这个是通用的,增加后,变为

    public static <E> Set union(Set<E> s1, Set<E> s2) {
        Set result = new HashSet(s1);
        result.addAll(s2);
        return result;
    }
简单的增加泛型,就是这样,要在参数中添加泛型,同时也要在返回参数类型处增加泛型,缺一不可。这个方法可以被调用,比如说 s1 和 s2 都是 String 类型的集合,我们可以调用,这时会产生新的集合,

    public static void main(String[] args) {
    Set<String> a = new HashSet<String>();
    a.add("a");
        Set<String> b = new HashSet<String>();
        b.add("b");
        Set<String> set = union(a, b);
        System.out.println(set);
    }
打印的结果是  [a, b] 。 这个方法可以使用,但有个局限,就是参数类型必须一致,返回的类型也与参数的类型一样。 Number 是  Integer 的基类类,Set<Number> s1 ,Set<Integer> s2,理论上说,基类集合能装子类对象, 但是我们调用上述方法,编译会报错,怎么办? 就需要用到 有限制的通配符,可以提高方法的灵活性。 泛型的特点是编译器调用,编译器通过参数类型推倒返回值的类型。 第一个案例中, 由于调用的两个集合都是 <String> 类型,所以知道类型E 就是 String,返回的类型也是Set<String> 类型,这个叫做类型推导。平时创建对象,需要我们自己去new,同时传入对象类型,我们 Map<String, Set<String>> map = new HashMap<String, Set<String>>(); 很麻烦,我们可以自定义个静态方法,来以不变应万变,
    public static <K, V> HashMap<K, V> newHashMap() {
        return new HashMap<K, V>();
    }
这种方法比较有效,说句题外话,这种写法是java 1.8 之前的写法,在1.8时,java改进了,可以直接 Map<String, Set<String>> map = new HashMap<>(); 自动包含了类型推导。

泛型有时会和函数对象一块使用,书中给了个例子,咱们在这举另外一个常见的例子,
    public interface Comparable<T>{
        public int compareTo(T o);
    }
我们经常会用到它来排序,之前提到过,如果大量使用,可以创建一个静态对象,缓存到内存中,避免被大量创建。

书中的例子,咱么可以用 Comparable 来重复写一遍

    private static Comparable<Object> INSTAGE_COMPARABLE = new Comparable<Object>() {

        @Override
        public int compareTo(Object o) {
            return o.hashCode();
        }
    };

    public static <T> Comparable<T> compare(){
        return (Comparable<T>) INSTAGE_COMPARABLE;
    }
不过,如果我们调用compare() 方法,获取该对象,用它来作为排序标准,比较 hashCode 值,这是一种应用。

许多方法都带有一个实现 Comparable 接口的元素类表,进行排序,我们可以这么写 

    public static <T extends Comparable<T>> T max(List<T> list) {

    }
泛型里面多了个东西,继承方法, 类型限制 <T extends Comparable<T>> 可以理解为 每一个 T 类型的对象,都必须要实现 Comparable 接口,这样,就可以通过 Comparable 接口中的方法返回值,来进行比较大小了

    public static <T extends Comparable<T>> T max(List<T> list) {
        Iterator<T> iterator = list.iterator();
        T result = iterator.next();
        T t ;
        while (iterator.hasNext()){
            t = iterator.next();
            if(t.compareTo(result) > 0){
                result = t;
            }
        }
        return result;
    }
我们知道,我们用 t.compareTo(result) > 0 这个比较功能时,对象必须是实现 Comparable 接口的。 上述基本上满足功能,但是还不完美,还有缺陷, 我们发现Collections 中也有用到Comparable ,比如排序,
    public static <T extends Comparable<? super T>> void sort(List<T> list) {

    }
细心的法相了,Comparable<? super T> 里面又多了个关键字,为什么这么写呢,因为这样写灵活性和匹配性更高,下章再继续讲解。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值