Java泛型讲解: 泛型基本概念 通配符? 上限和下限、类型擦除

本文介绍了Java泛型的基本概念,包括泛型方法、泛型类,以及如何使用泛型通配符?来处理边界。讨论了泛型的上界extends和下界super的用法,并举例说明了常见的使用错误和类型擦除的概念。最后,解释了类型擦除对方法重载和泛型类型实际使用的影响。

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

转载请注明出处:https://blog.youkuaiyun.com/jiyisuifeng222/article/details/117569239

本文同步发表于我的微信公众号,扫一扫文章底部的二维码或在微信搜索 情花打雪 即可关注,每个工作日都有文章更新。

泛型方法

  • 所有泛型方法声明都有一个类型参数声明部分(由尖括号分隔),该类型参数声明部分在方法返回类型之前(在下面例子中的)
  • 每一个类型参数声明部分包含一个或多个类型参数,参数间用逗号隔开。一个泛型参数,也被称为一个类型变量,是用于指定一个泛型类型名称的标识符。
  • 类型参数能被用来声明返回值类型,并且能作为泛型方法得到的实际参数类型的占位符。

如何使用泛型方法打印不同类型的元素

public class GenericMethod {
    // 泛型方法 print
    public static <E> void printMethod(E input) {
        // 输出泛型元素
        System.out.printf("%s ", input);
    }

   

 public static void main(String args[]) {
        // 不同类型: Integer 和 Character
        Integer intE = 1;
        Character charE = 'A';

        System.out.println("整型元素为:");
        printMethod(intE); // 传递一个整型

        System.out.println("\n字符型元素为:");
        printMethod(charE); // 传递一个字符型元素
    }
}

 

泛型类

  • 普通类的声明:

class NormalClass{

.....

}

  • 在类名后面添加了类型参数声明部分

class GenericClass<E>{

    private E ele;

    public void set(E e){

        this.ele=e;

    }

}

泛型通配符?

类型通配符一般是使用?代替具体的类型参数。例如 List<?> 在逻辑上是List,List.... 等所有List<具体类型实参>的父类。

有界的泛型类型

类型通配符上限extends

class clazz {
    //定义一个泛型方法
    public static <T extends Number> T extendsMethod(T x,T y){
        y=x;
        return y;
    }

    //测试泛型方法
    public static void testExtendsMethod(){
        Integer x=0;
        Double y=1.0;
        System.out.println(extendsMethod(x,y));
        String str1="a";
        Integer integer=1;
        System.out.println(extendsMethod(str1,integer));//报错
    }
}

extends 表示泛型T应该是Number的子类(Integer、Short、Long、Float、Double),也就是规定了T的上界

类型通配符下限super

改为 T super Number  含义:Number本身或者Number的父类

下面是可以用的:
类型通配符下限通过形如 List<? super Number>来定义,表示类型只能接受Number及其父类类型,如 Object 类型的实例。

 

常见使用错误

  • 问题1:赋值类型错误 Incompatible types.Found: 'java.util.List<java.lang.String>',required: 'java.util.List<java.lang.Object>'
   List<Object> objectList1 = new ArrayList<>();
   List<String> stringList1 = new ArrayList<>();
   objectList1 = stringList1;

因为objectList1需要的是Object类型,但是却给了一个String类型的stringList1
如果加入通配符?,改成下面代码就可以了

List<? extends Object> objectList2 = new ArrayList<>();
List<String> stringList2 = new ArrayList<>();
objectList2 = stringList2;
  • 问题2:警告(不过没有报错):Unchecked call to 'add(E)' as a member of raw type 'java.util.List'
 List list1 = new LinkedList();//警告(因为没有加泛型类型)
 //List<String> list1 = new LinkedList();
 list1.add(6);
 list1.add("abc");

另外发现:如果不指定泛型,可以在List中保存多种类型的元素。因为默认为Object类型

  • 问题3:警告:Unchecked assignment: 'java.util.ArrayList' to 'java.util.List<java.lang.String>'
  List<String> rawList = new ArrayList();//警告(没有加尖括号):

 

  • 问题4:可以给Array加泛型吗?不可以

Array<Integer>;//Type Array does not have type parameters

实现原理:类型擦除

什么是类型擦除?
类型参数只存在于编译期,在运行时,Java 的虚拟机并不知道泛型的存在。

示例:

import java.util.ArrayList;
public class ErasedTypeTest {
    public static void main(String[] args) {
        Class c1 = new ArrayList<String>().getClass();
        Class c2 = new ArrayList<Integer>().getClass();
        System.out.println(c1 == c2);//true,这里并不知道类ArrayList<String>和        
        ArrayList<Integer>,只知道ArrayList
    }
}

类型擦除带来的影响:

  • 泛型类型无法用作方法重载

public void testMethod(List<Integer> array) {}

public void testMethod(List<Double> array) {}   

会提示 “compile error

  • 泛型类型无法当做真实类型使用
static <T> void genericMethod(T t) {
  T newInstance = new T();              // compile errror
  Class c = T.class;                    // compile errror
  List<T> list = new ArrayList<T>();    // compile errror
  if (list instance List<Integer>) {}   // compile errror
}

 

关注我的技术公众号,每天都有优质技术文章推送。

微信扫一扫下方二维码即可关注:

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值