Java泛型

本文详细介绍了Java中的泛型,包括泛型的概念、基本语法、主要好处,如类型安全、消除转换、提升性能和代码重用。此外,还讲解了泛型的三种使用方式:泛型类、泛型接口和泛型方法,以及泛型通配符的使用,如无边界、上边界和下边界通配符。最后,讨论了泛型擦除现象及其示例。

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

一、泛型概述

泛型:是JDK5中引入的一个新特性,泛型提供了编译时类型安全检测机制,该机制允许程序员在编译时检测到非法的类型
泛型的本质是参数化类型,即给类型指定一个参数,然后在使用时再指定此参数具体的值,那样这个类型就可以在使用时决定了,这种参数类型可以用在类、接口和方法中,分别被称为泛型类、泛型接口、泛型方法

在学习集合时,我们都知道集合中是可以存储任意类型的对象,只要把对象存储集合后,那么他们都会被提升为Object类型,当我们在取出每一个对象,并且进行相应的操作,这时我们必须采用类型转换,这个时候就可以使用泛型解决该问题

二、泛型基本语法

Java1.7之前语法:

类名<具体的数据类型> 对象名 = new 类名<具体的数据类型>();

Java1.7以后语法:

// Java1.7以后,后面的<>中的具体数据类型可以省略不写
类名<具体的数据类型> 对象名 = new 类名<>();

三、泛型的好处

泛型的好处是在编译的时候检查类型安全,并且所有的强制转换都是自动和隐式的,提高代码的重用率

  • 泛型的作用
    1. 安全性
    2. 消除转换
    3. 提升性能
    4. 重用性

1、安全性

保证了类型的安全性
在没有泛型之前,从集合中读取到的每一个对象都必须进行类型转换,如果不小心插入了错误的类型对象,在运行时转换处理就会出错

没有泛型的情况下使用集合:

package cn.com.example11;

import java.util.ArrayList;

public class GenericClass {

    
    public static void noGeneric(){

        ArrayList arrayList = new ArrayList();
        
        arrayList.add(1);
        arrayList.add("admin");
        
        // 编译正常
    }


}

有泛型的情况下使用集合:

package cn.com.example11;

import java.util.ArrayList;

public class GenericClass {

    public static void useGeneric(){

        ArrayList<Integer> arrayList = new ArrayList<>();

        arrayList.add(1);
        arrayList.add("admin");

        // 编译不通过
    }
}

相当于告诉编译器每一个集合接收的对象类型是什么,编译器在编译期就会做类型检查,告知是否插入了错误类型的对象,使得程序更加安全,增强了程序的健壮性

2、消除转换

泛型的一个附带好处就是消除源代码中的许多强制类型转换,这使得代码更加可读,并且减少了出错机会

没有泛型的代码需要强制转换:

ArrayList arrayList = new ArrayList();
        
  arrayList.add("admin");
  
  String name = (String)arrayList.get(0);

使用泛型时代码不需要强制转换:

 ArrayList<String> arrayList = new ArrayList<String>();

  arrayList.add("admin");

  String name = arrayList.get(0);

3、提升性能

在非泛型编程中,将简单类型作为Object传递时,会引起装箱和拆箱操作,这两个过程都是具有很大开销的,引入泛型后,就不必进行装箱和开箱,所以运行效率相对较高,特别在对集合操作非常频繁的系统中,这个特点带来的性能提升更加明显

4、重用性

提高了代码的重用性

四、泛型分类

泛型有三种使用方式:泛型类、泛型接口和泛型方法。

1、泛型方法

泛型方法:把泛型定义在方法上

语法格式:

public <泛型类型> 返回类型 方法名(泛型类型 变量名){

}

泛型方法

package cn.com.example11;

public class GenericMethod {


    public static  <T>T genericMethodHandler(T value){

        return value;

    }

    public static void main(String[] args) {

        System.out.println(genericMethodHandler(20) + 1); // 20

        System.out.println(genericMethodHandler("20") + 1); // 201

    }


}

2、泛型类

泛型类:把泛型定义在类上

定义泛型类,在类名后面添加一对尖括号,并在尖括号中填写类型参数,参数可以有多个,多个参数使用逗号分隔

后面的参数类型也是有规范的,通常类型参数我们都使用大写的单个字母表示

T:任意类型 type
E:集合中元素类型 element
K:key-value形式 key
V:key-value形式 value

语法格式:

public  class  类名 <泛型类型1,...> {

}

注意:泛型类型必须是引用类型

泛型类:

package cn.com.example11;


public class GenericClass<T> {


    private T name;
    
    public GenericClass(){
        
    }
    
    public GenericClass(T name){
        
        this.name = name;
    }
    
    
    public T getName(){
        
        return name;
    }
    
    public void setName(T name){
        
        this.name = name;
    }


}

测试类:

GenericClass<String> genericClass = new GenericClass<>("admin");

System.out.println(genericClass.getName());

GenericClass<Integer> genericClass1 = new GenericClass<>(20);

System.out.println(genericClass1.getName());

3、泛型接口

泛型接口:定义在接口上

语法格式:

public interface 接口名<泛型类型>{

}

泛型接口

src/service/IGeneric.java

package cn.com.example11;

public interface IGeneric<T> {
    
    void setValue(T value);
}

实现类

src/service/impl/GenericStringImpl.java

public class GenericStringImpl implements IGeneric<String>{

    @Override
    public void setValue(String value) {

        System.out.println(value);
    }
}


public class GenericIntegerImpl implements IGeneric<Integer>{

    @Override
    public void setValue(Integer value) {

        System.out.println(value);
    }
}

4、泛型接口范围扩大

泛型接口范围只在当前接口以及实现类中,如果想要把范围延伸到实现类以外的类中,那么需要进行接口范围扩大

泛型接口

public interface IGeneric<T>{

  T getValue();

}

实现类

public class GenericImpl<T> implements IGeneric<T>{

  public T name;

  T getValue(){
  
    return name;
  }

}

实现类子类

// 第一种方式
public class Generic extends GenericImpl<String>{

  @Override
    public String getValue() {
    
        return super.getValue();
    }

}


// 第二种方式
public class Generic extends GenericImpl{

  @Override
    public String getValue() {
      GenericImpl<String> genericImpl = new GenericImpl<>();
        return super.getValue();
    }

}

4、泛型通配符

泛型通配符是用于解决泛型之间引用传递问题的特殊语法,分别是:无边界的通配符、上边界的通配符【泛型上限】、下边界的通配符【泛型下限】

4.1、无边界通配符

<?>:表示参数类型可以是任意类型
public class Symbol<?>{

}

无边界通配符的主要作用就是让泛型能够接收未知类型的数据,和T、E、K、V不同的是,它们有对应的类型描述

4.2、上边界通配符

<? extends User>:表示参数类型必须是User类类型或User的子类类型
public class Symbol<? extends User>{

}

4.3、下边界通配符

<? super User>:表示参数类型必须是User类类型或User的父类类型
public class Symbol <? super User>{

}

五、泛型擦除

泛型擦除:通过反射机制可以添加指定类型【泛型】以外的数据类型

public class Generic{

  public static void genericErase(){
  
    // 实例化List集合,指定泛型String类型
    List<String> list = new ArrayList<>();
  
    list.add("admin");
    list.add("user");
    list.add("guest");
    
    // 开始泛型擦除 - 往list集合中添加一个Integer类型的数据
    // 1、获取该集合的Class对象
    Class clazz = list.getClass();
    
    // 2、获取指定的方法对象
    Method method = clazz.getMethod("add",Object.class);
    
    // 3、运行方法
    method.invoke(list,20);
    
    // 4、输出集合
    System.out.println(list); // ["admin","user","guest",20]
  
  }


}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

刘程云

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值