Java SE 学习笔记 :泛型篇(下)

简介: Java SE 学习笔记 :泛型篇(下)

5.2  自定义泛型方法

附注:如何在IDEA中找出一个类的所有子类?


六、类型变量的上限

我们在声明<T>等类型变量时,可以给它限定“上限”。

语法格式:

<T extends 上限> : 表示T的类型必须是<=上限,即要么是上限本身,要是继承上限类或实现了上限接口的类型。

举例如下:

学生类,包含姓名和成绩。

现在成绩类型不确定,但是要求成绩必须是Number或Number的子类对象。

java.Lang.Number表示数值类型,例如它的子类有。

代码如下:

在上面的案例需求中再加一个要求,成绩不仅要求是Number类或它的子类,还要求实现Comparable接口

一个类型变量的上限可以是1个,也可以是多个。但是要求如果有多个的话,类只能有一个,其他的都是接口类型。而且类在左边,其他的类型在右边。

如果自定义的方法实现了类型变量的下限,那么传参给方法的实参中的类也必须实现该接口。此举意在编译前提醒检测类型变量的类型转换问题

6.1 定义泛型类的类型变量时指定上限

代码举例如下:

6.2  定义泛型方法的类型变量时指定上限

编写一个数组工具类,包含可以给任意对象数组进行从小到大排序,调用元素对象的compareTo方法比较元素的大小关系。要求数组的元素类型必须是java.lang.Comparable<T>接口类型。

代码举例如下:

public class MyArrays {
    public static <T extends Comparable<T>> void sort(T[] arr){
        for (int i = 1; i < arr.length ; i++) {
            for (int j = 0; j < arr.length-i ; j++) {
                if (((Comparable)(arr[j])).compareTo(arr[j+1])>0){
                    T temp=arr[j];
                    arr[j]=arr[j+1];
                    arr[j+1]=temp;
                }
            }
        }
    }
}
import org.junit.Test;
public class TestArrays {
    @Test
    public void test01(){
        Integer[] nums={4,7,1,2,89,34,67};
        System.out.println("排序前:");
        for (Integer num : nums) {
            System.out.print(num+"\t");
        }
        System.out.println();
        MyArrays.sort(nums);
        System.out.println("排序后:");
        for (Integer num : nums) {
            System.out.print(num+"\t");
        }
    }
}

运行效果:


七、泛型擦除

如果用户在使用泛型类或泛型接口时,没有主动指定泛型的类型,就会发生泛型的擦除。

泛型擦除后,类型变量按照哪个类型处理? 是统一按照object处理吗?

不是

答案:泛型擦除后,自动按照类型变量声明时的第一个上限处理,如果类型变量上面时没有指定上限,那么按照Object处理

代码举例如下:

 


八、泛型通配符

8.1  为什么要使用泛型通配符?

当我们声明一个变量/形参时,这个变量/形参的类型是一个泛型类或泛型接口,例如:Comparator<T>类型,但是我们仍然无法确定这个泛型类或泛型接口的类型变量<T>的具体类型,此时我们考虑使用类型通配符 ?

代码举例如下:

import java.util.ArrayList;
import java.util.Collection;
public class TestWildcard {
    public static void m4(Collection<?> coll){
        for (Object o : coll) {
            System.out.println(o);
        }
    }
    public static void main(String[] args) {
        //右边泛型指定为任意类型或不指定都可以
        m4(new ArrayList<Object>());//Collection<?> coll = new ArrayList<Object>();
        m4(new ArrayList<>());//Collection<?> coll = new ArrayList<>();
        m4(new ArrayList());//Collection<?> coll = new ArrayList();
        m4(new ArrayList<String>());//Collection<?> coll = new ArrayList<String>();
    }
}

在Java中,泛型的指定是必须左右两边一致的

8.2  类型通配符的三种使用形式

  • <?>:完整形式为:类名<?> 或接口名<?>,此时?代表任意类型
  • <? extends 上限>:完整形式为:类名<? extends 上限类型> 或接口名<? extends 上限类型>,此时?代表上限类型本身或者上限的子类,即?代表 <= 上限的类型。
  • <? super 下限>:完整形式为:类名<? super 下限类型> 或接口名<? super 下限类型>,此时?代表下限类型本身或者下限的父类,即?代表>= 下限的类型。

案例:

声明一个集合工具类MyCollections,要求包含:

  • public static boolean different(Collection<?> c1, Collection<?> c2):比较两个Collection集合,此时两个Collection集合的泛型可以是任意类型,如果两个集合中没有相同的元素,则返回true,否则返回false。
  • public static <T> void addAll(Collection<? super T> c1, T... args):可以将任意类型的多个对象添加到一个Collection集合中,此时要求Collection集合的泛型指定必须>=元素类型。
  • public static <T> void copy(Collection<? super T> dest,Collection<? extends T> src):可以将一个Collection集合的元素复制到另一个Collection集合中,此时要求原Collection泛型的类型<=目标Collection的泛型类型。

代码演示如下:

import java.util.Collection;
public class MyCollections {
    public static boolean different(Collection<?> c1, Collection<?> c2){
        return c1.containsAll(c2) && c2.containsAll(c1);
    }
    public static <T> void addAll(Collection<? super T> c1, T... args){
        for (int i = 0; i < args.length; i++) {
            c1.add(args[i]);
        }
    }
    public static <T> void copy(Collection<? super T> dest,Collection<? extends T> src){
        for (T t : src) {
            dest.add(t);
        }
    }
}
public class MyCollectionsTest {
    public static void main(String[] args) {
        Collection<Integer> c1 = new ArrayList<Integer>();
        MyCollections.addAll(c1,1,2,3,4,5);
        System.out.println("c1 = " + c1);
        Collection<String> c2 = new ArrayList<String>();
        MyCollections.addAll(c2,"hello","java","world");
        System.out.println("c2 = " + c2);
        System.out.println("c1 != c2 " + MyCollections.different(c1, c2));
        Collection<Object> c3 = new ArrayList<>();
        MyCollections.copy(c3,c1);
        MyCollections.copy(c3,c2);
        System.out.println("c3 = " + c3);
    }
}

运行效果如下:

8.3  使用类型通配符来指定类型参数的问题

(1)如果把"泛型类<T>"指定为"泛型类<?>";那么该泛型类中所有参数是T类型的方法或成员都无法正常使用。参数类型不是T类型的方法照常使用。

代码举例如下:

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
public class TestProblem {
    @Test
    public void test01(){
        Collection<?> coll = new ArrayList<>();
//        coll.add("hello");
//        coll.add(1);
//        coll.add(1.0);
        /*
        上面所有添加操作都报错。
        为什么?
        因为<?>表示未知的类型,集合的元素是不确定的,那么添加任意类型对象都有风险。
        void add(E t)方法无法正常使用
        因为此时E由?表示,即表示直到add方法被调用时,E的类型仍然不确定,所以该方法无法正常使用
         */
        Collection<?> coll2 = Arrays.asList("hello","java","world");
        for (Object o : coll2) {
            System.out.println(o);
        }
    }
}

(2)如果把"泛型类<T>"指定为"泛型类<? extends 上限>":那么该泛型类中所有参数是T类型的方法或成员都无法正常使用。参数类型不是T类型的方法照常使用。

代码举例如下:

个人理解:如果把"泛型类<T>"指定为"泛型类<? extends 上限>",之所以无法正常使用,是因为

Java编译器在编译时无法确定添加到集合coll中的元素的类型是否<= Number,泛型类<? extends 上限> 中只说了要<=Number[上限],Number类以下的部分或者说它的子类,编译器是不知道的。

(3)如果把"泛型类<Tdd>"指定为"泛型类<? super 下限>":那么该泛型类中所有参数是T类型的方法或成员都可以使用,但是有要求。参数类型不是T类型的方法照常使用。

相关文章
|
5天前
|
存储 安全 Java
🌱Java零基础 - 泛型详解
【10月更文挑战第7天】本文收录于「滚雪球学Java」专栏,专业攻坚指数级提升,希望能够助你一臂之力,帮你早日登顶实现财富自由🚀;同时,欢迎大家关注&&收藏&&订阅!持续更新中,up!up!up!!
6 1
|
13天前
|
Java 语音技术 容器
java数据结构泛型
java数据结构泛型
23 5
|
10天前
|
存储 Java 编译器
Java集合定义其泛型
Java集合定义其泛型
14 1
|
13天前
|
存储 Java 编译器
【用Java学习数据结构系列】初识泛型
【用Java学习数据结构系列】初识泛型
16 2
|
10天前
|
安全 Java 编译器
Java基础-泛型机制
Java基础-泛型机制
11 0
|
1月前
|
存储 安全 搜索推荐
Java中的泛型
【9月更文挑战第15天】在 Java 中,泛型是一种编译时类型检查机制,通过使用类型参数提升代码的安全性和重用性。其主要作用包括类型安全,避免运行时类型转换错误,以及代码重用,允许编写通用逻辑。泛型通过尖括号 `&lt;&gt;` 定义类型参数,并支持上界和下界限定,以及无界和有界通配符。使用泛型需注意类型擦除、无法创建泛型数组及基本数据类型的限制。泛型显著提高了代码的安全性和灵活性。
|
13天前
|
Java 数据安全/隐私保护
java学习笔记(基础习题)
java学习笔记(基础习题)
26 0
|
13天前
|
Java 程序员 开发工具
java学习笔记
java学习笔记
29 0
|
1月前
|
Oracle Java 关系型数据库
Java(TM) Platform SE binary 已停止工作”的解决方法
Java(TM) Platform SE binary 已停止工作”的解决方法
134 2
|
17天前
|
Java
【Java】什么是泛型?什么是包装类
【Java】什么是泛型?什么是包装类
13 0