首页 > 编程笔记 > Java笔记 阅读:2

Java中的泛型(附带实例)

泛型(Generics)是 Java 语言引入的一个非常重要的机制,它允许程序在编译阶段检查类型是否非法,进而可以避免类型转换失败的风险。

泛型一般应用于方法和类,被声明了泛型的方法和类可以不明确指定某个类型,它就好比模板,可以匹配多种类型。

我们先了解一下泛型标记符,这些标记符用于表示不同的类型,它能匹配传入的任意 Java 类型。常见的泛型标记符如下:
实际上 Java 并没有限定只能用以上这些符号作为泛型标记符,我们可以使用 A~Z 中的任意一个英文字母作为标记符,编译器也能编译成功。之所以提出以上五个标记符是为了增加代码的可读性,这只是一种开发约定。

Java泛型方法

泛型方法是指一个方法具备了泛型的机制,它可以接收不同类型的参数,在调用时传入任意类型的参数,编译器能够根据不同类型的参数处理不同类型的方法调用。

下面来看泛型方法的语法,其实就是在普通方法中添加泛型标记符,同时参数列表的类型也要使用泛型标记符:
访问修饰符 非访问修饰符 <泛型标记符> 返回类型 方法名(参数列表){
    方法体
}

下面是泛型方法的 7 个示例:
public <T> String join(T t)
public <T> T join(T t)
public <T> String join(T t,int num)
public <T> String join(int num,T t)
public <T> void join(T t)
public static <T> String join(T t)
public <E> void printArray(E[] arr)
仔细观察它与普通方法之间的差异,其中的 T 和 E 就是泛型标记符,参数列表中的泛型参数不影响其他参数,顺序也可以根据需要确定。此外,方法的返回值类型也可以用泛型标记符表示。

如果需要,我们还可以在一个方法中声明多个泛型标记符。比如下面的两个示例,每个方法都同时声明了 T 和 E 两个泛型参数:
public <T,E> String join(T t,E e)
public <T,E> String join(T t,E e,int num)

根据上述泛型方法的语法编写下面的实例:
public class GenericsTest {
    public static void main(String[] args) {
        print(10.11, "Double");
        print(10, "Integer");
        print("hello", "String");
    }
    
    public static <E> void print(E e, String s) {
        if (s.equals("Double"))
            System.out.println("E is a Double type : " + e);
        if (s.equals("Integer"))
            System.out.println("E is a Integer type : " + e);
        if (s.equals("String"))
            System.out.println("E is a String type : " + e);
    }
}
输出结果为:

E is a Double type : 10.11
E is a Integer type : 10
E is a String type : hello

定义一个 print() 泛型方法,调用时传入两个参数,第一个参数可以是 Double 类型、Integer 类型、String 类型或其他任意引用类型。

注意对于基本数据类型,编译器会自动转换成对应的包装类,比如“10.11”会转换为 Double 类型,而“10”则会转换为 Integer 类型。

Java泛型类型

泛型类型是指一个类具备了泛型的机制,它可以接收不同类型的参数,在创建对象时传入指定类型的参数。

泛型类型的语法如下,其实就是在普通类的类名后面添加泛型标记符:
访问修饰符 class 类名<泛型标记符>{
   
}
下面是泛型类型定义的例子,可以在类名后面添加 <E> 使类具备泛型机制,当然也支持多个类型参数,即用多个泛型标记符来表示,比如 <E,T,K,V>。
public class GenericsTest<E>
public class GenericsTest<E,T,K,V>

根据泛型类型语法我们来看下面的实例:
public class GenericsTest {
    public static void main(String[] args) {
        String data2 = "hello world";
        Info data3 = new Info("200", true);
        Result<String> r2 = new Result<String>(data2);
        Result<Info> r3 = new Result<Info>(data3);
        System.out.println(r2);
        System.out.println(r3);
    }
}

class Result<T> {
    T data;
   
    public Result(T t) {
        this.data = t;
    }
    
    public String toString() {
        return data.toString();
    }
}

class Info {
    String code;
    boolean isSuccess;
    
    public Info(String s, boolean b) {
        this.code = s;
        this.isSuccess = b;
    }
    
    public String toString() {
        return code + "-" + isSuccess;
    }
}
输出结果为:

hello world
200-true

其中 Result<T> 是我们定义的泛型类,可以在创建对象时通过指定不同的类型来确定 Result 类中 data 属性的类型,比如指定为 Result<String> 时 data 属性的类型为 String,而指定为 Result<Info> 时 data 属性的类型为 Info。这样我们就可以创建不同类型的对象来保存在 Result 对象中了。

Java泛型接口

类似地,我们也可以定义泛型接口,它能让一个普通接口具有泛型的能力。

比如在下面的实例中定义一个 MyInterface<T> 泛型接口,里面包含了一个 test(T t)泛型方法,我们就可以在实现接口时指定类型,比如 MyInterface<String> 和 MyInterface<int[]>。
public class GenericsTest {
    public static void main(String[] args) {
        new MyImplement().test("hello");
        new MyImplement2().test(new int[] { 1, 2, 3, 4, 5 });
    }
}

interface MyInterface<T> {
     public abstract void test(T t);
}

class MyImplement implements MyInterface<String> {
    public void test(String s) {
        System.out.println(s);
    }
}

class MyImplement2 implements MyInterface<int[]> {
    public void test(int[] arr) {
        System.out.println(Arrays.toString(arr));
    }
}
输出结果为:

hello
[1, 2, 3, 4, 5]

相关文章