java 泛型

泛型

泛型,即“参数化类型”.

泛型,将类型由原来的具体的类型参数化,类似于方法中的变量参数,此时类型也定义成参数形式(可以称之为类型形参),然后在调用时传入具体的类型(类型实参)。

泛型的好处

  • 类型安全,消除强制类型转换。 泛型消除源代码中的许多强制类型转换。这使得代码更加可读,并且减少了出错机会。

  • 减少重复代码。 提高代码的重用率,同样的逻辑,使用泛型后,能够支持多种类型,不同类型不用写重复代码。

Java泛型中的标记符含义:

E - Element (元素,在集合中使用)

T - Type(Java 类)

K - Key(键)

V - Value(值)

N - Number(数值类型)

? - 表示不确定的java类型

S、U、V - 2nd(第二)、3rd(第三)、4th(第四) 类型


List集合的泛型

比如,最常见的List集合,List常用方法的源码如下:

在List接口中采用泛型定义之后, List<E>中的E表示类型形参,声明List并指定类型E后,凡是出现E的地方均表示相同的类型(类型实参)。

public interface List<E> extends Collection<E> {
    boolean add(E e);

    E get(int index);
}

示例如下:

public class ListTest {
    public static void main(String[] args) {
    	//声明集合list的泛型<E>为 String类型
        List<String> list = new ArrayList<>();
        list.add("ab");
        list.add("cd");
        //由于list指定了泛型是String,那么add(E e)方法的参数E只能是String类型,添加整数到该集合会报错
//        list.add(123);

        //由于 list 指定了泛型是 String,调用get方法直接得到String,而不需要做类型转换
        String first = list.get(0);


    }
}

泛型类、泛型接口和泛型方法

泛型的常见用法有 泛型类、泛型接口、泛型方法。

上面的 interface List<E> 就是一个典型的泛型接口。

泛型类跟泛型接口类似,也可以在类后面声明泛型。

泛型类

示例如下:

/**
 * 泛型类, User<T>定义了泛型类型为T,那么变量T data和方法T getData()中的 T类型也得跟定义的类型一样。
 *
 * @param <T>
 */
public class User<T> {

    private T data;

    public User(T data) {
        this.data = data;
    }

    public User() {
    }

    public T getData() {
        return data;
    }

    public void setData(T data) {
        this.data = data;
    }

    public static void main(String[] args) {
        //User<Integer>定义了泛型类型为Integer, 那么data就必须是 Integer
        User<Integer> user1 = new User<>();
        user1.setData(10);
        System.out.println(user1.getData());

        //User<String>定义了泛型类型为 String, 那么data就必须是 String
        User<String> user2 = new User<>();
        user2.setData("Rui");
        System.out.println(user2.getData());
    }
}

泛型方法

泛型方法的格式如下:

修饰符 <声明泛型的类型> 返回的类型 方法名称();

比如:

public  <T> void getUserName(T t) {}

在返回类型的前面声明 泛型类型 <T> ,那么方法的所有 T 类型与声明的类型一样。

如果需要限制 T的类型为 继承User的类,可以使用 T extends User,如下所示:

public  <T extends User>  void getUserName(T t) {

}

如果是多个泛型,则用逗号隔开,如:

public  <T,M> String getUserName(T t, M m) {}

示例如下:

public class Book {

    /**
     * 泛型方法
     * @param t  泛型对应的参数
     * @param <T> 泛型的类型
     * @return
     */
    public  <T> String getName(T t){
        return t.toString();
    }

    /**
     * 存在多个泛型的泛型方法
     * @param t  第一个泛型对应的参数
     * @param m  第二个泛型对应的参数
     * @param <T>  第一个泛型的类型
     * @param <M>  第二个泛型的类型
     * @return
     */
    public  <T,M> String getMergeName(T t, M m) {
        return t.toString() + m.toString();
    }

    public static void main(String[] args) {
        Book book = new Book();
        System.out.println(book.getName("abc"));
        System.out.println(book.getName(123));
        System.out.println(book.getName(book));

        System.out.println(book.getMergeName("abc", 123));
    }

}

类型通配符

类型通配符?的含义如下:

<?extends T>表示有上限的通配符,能接受其类型和其子类的类型, 此时 T 即泛型类型的上边界

<?super T> 表示有下限的通配符,能接受指定类型及其父类类型,此时 T 即泛型类型的下边界

在List集合中,就有大量的类型通配符的应用。

    boolean addAll(Collection<? extends E> c);
    
    void sort(Comparator<? super E> c);

类型通配符的使用,如下:

public class GenericTest {


    class Father {

    }

    class Son extends Father {

    }

    /**
     * 使用了类型通配符,只允许 继承了Father的类作为泛型的类型
     * @param list
     */
    public static void select(List<? extends Father> list) {

    }



    public static void main(String[] args){
        List<Father> list1 = new ArrayList<>();
        List<Son> list2 = new ArrayList<>();
        List<String> list3 = new ArrayList<>();
        select(list1);
        select(list2);
        //list3的泛型为 String,并没有继承 Father,编译会报错: Required type: List <? extends Father>
//        select(list3);
    }

}
  • 类型通配符与泛型方法的区别:

    类型通配符既可以在方法签名处定义形参的类型, 也可以用于定义变量的类型;

    但是泛型方法中的泛型形参必须在对应方法中声明.

参考资料:

https://www.cnblogs.com/lwbqqyumidi/p/3837629.html

https://juejin.cn/post/6940449645877264391

https://blog.csdn.net/qq_39505065/article/details/89490776

posted on   乐之者v  阅读(157)  评论(0编辑  收藏  举报

相关博文:
阅读排行:
· 全程不用写代码,我用AI程序员写了一个飞机大战
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· 记一次.NET内存居高不下排查解决与启示
· DeepSeek 开源周回顾「GitHub 热点速览」
· 白话解读 Dapr 1.15:你的「微服务管家」又秀新绝活了
历史上的今天:
2019-04-20 Json常用代码
2019-04-20 含有Date属性的对象转化为Json
2018-04-20 java.lang.ClassNotFoundException: org.springframework.web.context.ContextLoaderListener
< 2025年3月 >
23 24 25 26 27 28 1
2 3 4 5 6 7 8
9 10 11 12 13 14 15
16 17 18 19 20 21 22
23 24 25 26 27 28 29
30 31 1 2 3 4 5

导航

统计

点击右上角即可分享
微信分享提示