Java 方法前面加 <T> 是做什么?泛型方法 原理、样例

在 Java 中,方法前面加上 <T> 表示该方法是一个泛型方法泛型方法允许你在方法签名中指定一个或多个类型参数,从而使得该方法可以处理多种类型的对象。这增加了代码的灵活性和复用性。

一、基本语法

<T1, T2, ..., Tn> 返回类型 方法名(形参列表) {
    // 方法体
}
  • <T1, T2, ..., Tn>:类型参数列表,可以有一个或多个类型参数。
  • 返回类型:方法的返回类型,可以是具体的类型,也可以是类型参数。
  • 方法名:方法的名称。
  • 形参列表:方法的参数列表,可以使用类型参数作为参数类型。

 二、代码示例

1. 单个类型参数的泛型方法

 假设现在富士康(Foxconn)要生产一批手机,它给手机厂商定下了一个规范:

package com.study.genericity.entity;

/**
 * 富士康的手机生产规范
 */
public abstract class MobilePhone {
    abstract void produce();
}

 OPPO、Huawei 都按照 富士康 的规范(extends MobilePhone)生产手机:

package com.study.genericity.entity;
import lombok.AllArgsConstructor;

@AllArgsConstructor
public class OPPO extends MobilePhone {
    /** 型号 */
    private String model;
    /** 颜色 */
    private String color;
    /** 运行内存 */
    private String ram;
    /** 存储 */
    private String rom;

    @Override
    public void produce() {
        System.out.println("正在生产 OPPO手机 :型号-"+model+" 颜色-"+color+" 运行内存-"+ram+" 存储容量-"+rom);
    }
}
----------------------------------------
package com.study.genericity.entity;
import lombok.AllArgsConstructor;

@AllArgsConstructor
public class Huawei extends MobilePhone {
    /** 型号 */
    private String model;
    /** 颜色 */
    private String color;
    /** 是否折叠 */
    private boolean foldOrNot;
    /** 运行内存 */
    private String ram;
    /** 存储 */
    private String rom;

    @Override
    public void produce() {
        String description = "正在生产 华为手机 :"+(foldOrNot?"折叠屏 ":"")+model+" "+color+" "+ram+" "+rom;
        System.out.println(description);
    }
}

 富士康 为他们开了一条通用生产线生产手机:

package com.study.genericity.entity;

public class Foxconn {
    /** 富士康通用生产线 */
    public static void produce(MobilePhone mobilePhone) {
        mobilePhone.produce();
    }

    public static void main(String[] args) {
        OPPO oppo = new OPPO("Find X7", "白日梦想家", "12GB", "256GB");
        produce(oppo);
        Huawei huawei = new Huawei("Pocket 2", "洛可可白", true, "12GB", "256GB");
        produce(huawei);
    }
}
输出:
正在生产 OPPO手机 :型号-Find X7 颜色-白日梦想家 运行内存-12GB 存储容量-256GB
正在生产 华为手机 :折叠屏 Pocket 2 洛可可白 12GB 256GB

 这个时候来了苹果,他们委托 富士康 生产新版 iPhone。

不过苹果 它财大气粗,它有自己的手机生产规范:

package com.study.genericity.entity;

/**
 * 苹果自己的移动产品生产规范
 */
public abstract class AppleMobile {

    abstract void producePhone();
}
----------------------------------------
package com.study.genericity.entity;

import lombok.AllArgsConstructor;

@AllArgsConstructor
public class Apple extends AppleMobile {
    /** 型号 */
    private String model;
    /** 颜色 */
    private String color;
    /** 运行内存 */
    private String ram;
    /** 存储 */
    private String rom;

    @Override
    public void producePhone() {
        System.out.println("正在生产 尊贵的iPhone :"+model+" "+color+" "+ram+" "+rom);
    }
}

 富士康 本来想拒绝,因为苹果的生产流程已经继承了 AppleMobile 规范, 无法再继承 MobilePhone 规范,两个规范并不兼容(Java 单继承)。但如果为苹果单开一条生产线,成本又特别高昂。

package com.study.genericity.entity;

public class Foxconn {
    /** 富士康通用生产线 */
    public static void produce(MobilePhone mobilePhone) {
        mobilePhone.produce();
    }

    /** 为苹果单开一条流水线 */
    public static void produce(AppleMobile appleMobile) {
        appleMobile.producePhone();
    }

    public static void main(String[] args) {
        OPPO oppo = new OPPO("Find X7", "白日梦想家", "12GB", "256GB");
        produce(oppo);
        Huawei huawei = new Huawei("Pocket 2", "洛可可白", true, "12GB", "256GB");
        produce(huawei);
        Apple apple = new Apple("iPhone 16 Pro", "白", "16GB", "128GB");
        produce(apple);
    }
}
输出:
正在生产 OPPO手机 :型号-Find X7 颜色-白日梦想家 运行内存-12GB 存储容量-256GB
正在生产 华为手机 :折叠屏 Pocket 2 洛可可白 12GB 256GB
正在生产 尊贵的iPhone :iPhone 16 Pro 白 16GB 128GB

 这可愁坏了 富士康 的老总,这个时候,聪明的工程师 小林 为老板想了一个办法,他用 泛型方法 的方式,定义了一条通用的流水线,可以忽略类型规范:

package com.study.genericity.entity;

import java.util.function.Consumer;

public class Foxconn {

    /** 用 泛型方法 定义通用生产流水线 */
    public static <T> void produce(Consumer<T> consumer, T phone) {
        consumer.accept(phone);
    }

    public static void main(String[] args) {
        OPPO oppo = new OPPO("Find X7", "白日梦想家", "12GB", "256GB");
        produce(OPPO::produce, oppo);
        Huawei huawei = new Huawei("Pocket 2", "洛可可白", true, "12GB", "256GB");
        produce(Huawei::produce, huawei);
        Apple apple = new Apple("iPhone 16 Pro", "白", "16GB", "128GB");
        // 苹果 定制化生产
        produce(Apple::producePhone, apple);
    }
}
输出:
正在生产 OPPO手机 :型号-Find X7 颜色-白日梦想家 运行内存-12GB 存储容量-256GB
正在生产 华为手机 :折叠屏 Pocket 2 洛可可白 12GB 256GB
正在生产 尊贵的iPhone :iPhone 16 Pro 白 16GB 128GB

富士康 老板高兴坏了,因为这条流水线太好用,老板甚至放弃了自定义的手机生产规范 MobilePhone,给手机厂商更高的自由度(不用再继承 MobilePhone),去生产定制化的手机产品:

package com.study.genericity.entity;
import lombok.AllArgsConstructor;

@AllArgsConstructor
public class Huawei {
    /** 型号 */
    private String model;
    /** 颜色 */
    private String color;
    /** 是否折叠 */
    private boolean foldOrNot;
    /** 运行内存 */
    private String ram;
    /** 存储 */
    private String rom;
    /** 定制化生产 */
    public void produceHuawei() {
        String description = "正在生产 华为手机 :"+(foldOrNot?"折叠屏 ":"")+model+" "+color+" "+ram+" "+rom;
        System.out.println(description);
    }
}
---------------------------------------------
package com.study.genericity.entity;
import lombok.AllArgsConstructor;

@AllArgsConstructor
public class OPPO {
    /** 型号 */
    private String model;
    /** 颜色 */
    private String color;
    /** 运行内存 */
    private String ram;
    /** 存储 */
    private String rom;
    /** 定制化生产 */
    public void produceOPPO() {
        System.out.println("正在生产 OPPO手机 :型号-"+model+" 颜色-"+color+" 运行内存-"+ram+" 存储容量-"+rom);
    }
}
---------------------------------------------
package com.study.genericity.entity;

import java.util.function.Consumer;

public class Foxconn {

    /** 用 泛型方法 定义通用生产流水线 */
    public static <T> void produce(Consumer<T> consumer, T phone) {
        consumer.accept(phone);
    }

    public static void main(String[] args) {
        OPPO oppo = new OPPO("Find X7", "白日梦想家", "12GB", "256GB");
        // OPPO 定制化生产
        produce(OPPO::produceOPPO, oppo);
        Huawei huawei = new Huawei("Pocket 2", "洛可可白", true, "12GB", "256GB");
        // 华为 定制化生产
        produce(Huawei::produceHuawei, huawei);
        Apple apple = new Apple("iPhone 16 Pro", "白", "16GB", "128GB");
        // 苹果 定制化生产
        produce(Apple::producePhone, apple);
    }
}
输出:
正在生产 OPPO手机 :型号-Find X7 颜色-白日梦想家 运行内存-12GB 存储容量-256GB
正在生产 华为手机 :折叠屏 Pocket 2 洛可可白 12GB 256GB
正在生产 尊贵的iPhone :iPhone 16 Pro 白 16GB 128GB

2、返回类型也是泛型的泛型方法

 输入:

一个列表,和 几个数据。

输出:

数据包含在 列表 中的一个新的列表。

示例:

输入 [2,5,7,9,10] 和 5,27 输出 [5]

输入 ["福建", "江西", "浙江"] 和 "江苏","福建" 输出 ["福建"]

 一种 泛型方法 的实现:

package com.study.genericity.entity;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

public class Test {

    @SafeVarargs
    public static <T> List<T> filter(List<T> list, T... args) {
        List<T> result = new ArrayList<T>();
        for (T t : args) {
            if (list.contains(t)) {
                result.add(t);
            }
        }
        return result;
    }

    public static void main(String[] args) {
        List<Integer> list1 = Arrays.asList(2,5,7,9,10);
        System.out.println( filter(list1, 5, 27) );
        List<String> list2 = Arrays.asList("福建", "江西", "浙江");
        System.out.println( filter(list2, "江苏", "福建") );
    }
}
输出:
[5]
[福建]

 在这个例子中,filter 方法是一个泛型方法,它的入参是类型参数<T>的 泛型列表 List<T> 和 类型参数<T>的可变参数;它的返回类型还是 类型参数<T>的 泛型列表 List<T>。

这种返回类型也是泛型的泛型方法,在很多框架中都有大量的使用。

比如 cn.hutool.json.JSONUtil :

// 根据 JSON 字符串和 bean Class 类型,解析 JSON 数据 为 指定类型
public static <T> T toBean(String jsonString, Class<T> beanClass) {
        return toBean(parseObj(jsonString), beanClass);
}

Java中,泛型方法<T>和不<T>的区别如下: 1. <T>表示这是一个泛型方法,可以接受任意类型的参数,并且在方法内部可以使用T来代表实际类型。不<T>则表示这是一个普通方法,只能接受特定类型的参数。 2. <T>可以增强方法的通用性,可以使方法适应不同类型的参数。不<T>则只能接受特定类型的参数,不够通用。 3. <T>可以避免类型转换的问题,可以在编译时检查类型是否匹配。不<T>则需要手动进行类型转换,容易出错。 4. <T>可以提高代码的可读性和简洁性,可以减少重复代码的编写。不<T>则需要编写多个方法来适应不同类型的参数,代码冗余。 例如,下面是一个定义了泛型类型参数T的泛型方法: ``` public <T> T getMax(T[] array) { T max = array[0]; for (int i = 1; i < array.length; i++) { if (array[i].compareTo(max) > 0) { max = array[i]; } } return max; } ``` 在这个方法中,<T>表示这是一个泛型方法,并且T是一个类型参数。在方法体内部,可以使用T来代表实际的类型。这个方法可以接受任意类型的数组参数,并返回数组中的最大值。 而如果不<T>,则需要编写多个方法来适应不同类型的参数,例如: ``` public int getMax(int[] array) { int max = array[0]; for (int i = 1; i < array.length; i++) { if (array[i] > max) { max = array[i]; } } return max; } public double getMax(double[] array) { double max = array[0]; for (int i = 1; i < array.length; i++) { if (array[i] > max) { max = array[i]; } } return max; } ``` 这些方法都是重复的代码,可以通过使用泛型方法来避免这种情况。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值