Ja va 泛型

泛型是 Ja va 语言中一个非常实用的特性,它允许你写代码的时候先不把类型定死,等到真正用的时候再指定。打个比方,就像设计一个“盒子”,你只告诉别人“这个盒子能装东西”,但具体装什么——是苹果还是书本——由使用者决定。这类设计在集合框架里用得最多,因为集合在声明阶段根本不知道你会往里塞什么类型的对象。

一、泛型的概念

用专业点的话说,泛型就是在定义类、接口或方法时,用一个标识符(比如 TE)来表示某个属性的类型,或者方法的返回值类型、参数类型。这个类型参数会在你实际使用的时候确定下来——比如继承、实现接口、声明变量、创建对象时传入具体的类型实参。

二、泛型的引入背景

Ja va 集合框架在 JDK 1.5 之前,容器里能装什么类型是不确定的,所以设计者把元素类型统一设成了 Object。这样一来,你从集合里取出来的东西都得强转,而且直到运行时才能发现类型不对。JDK 1.5 引入泛型之后,情况就完全不同了——除了元素的类型不确定,其他部分(比如元素怎么存、怎么管理)都是确定的,所以干脆把元素类型设计成一个参数,也就是泛型。像 CollectionListArrayList 里的 E,就是那个类型参数。

一个简单的例子

先看一段没有泛型时的代码:

import ja va.util.ArrayList;
import ja va.util.List;

public class test {
    public static void main(String[] args) {
        List list = new ArrayList();
        list.add("string");
        list.add(100);
        for (int i = 0; i < list.size(); i++) {
            String name = (String) list.get(i); // 1
            System.out.println("name:" + name);
        }
    }
}

运行这段代码会抛出 ClassCastException,因为 ArrayList 里同时塞了 StringInteger,而循环里却把它们都当成 String 强转,自然就出错了。

引入泛型之后,问题迎刃而解:

import ja va.util.ArrayList;
import ja va.util.List;

public class test {
    public static void main(String[] args) {
        List list = new ArrayList();
        list.add("string");
        // list.add(100); // 编译错误
        for (int i = 0; i < list.size(); i++) {
            String name = list.get(i); // 2
            System.out.println("name:" + name);
        }
    }
}

如果你试着加一个 100,编译器会直接报错:add(int) 找不到合适的方法 —— 参数不匹配,int 无法转换为 String。这就是泛型带来的编译期类型检查,把运行时错误提前挡在了门外。

泛型的好处总结一下:

三、泛型类

一个泛型类就是拥有一个或多个类型变量的类。看个简单的例子:

public class test {
    public static class Point {
        private T var;
        public void setVar(T x) {
            this.var = x;
        }
        public T getVar() {
            return this.var;
        }
    }
    public static void main(String[] args){
        Point p = new Point();
        p.setVar(new Float(100.12f));
        System.out.println(p.getVar());
    }
}

尖括号里的 T 是形式类型参数,你可以随便起名字(比如 EKV)。当类被使用的时候,就会传入实际类型参数,比如这里的 Float。需要说明的是,泛型类只能用在成员变量上,而且只能使用引用类型。

四、泛型方法

泛型方法有自己的规则:类型参数声明部分(用尖括号括起来)必须放在方法返回类型之前。可以声明一个或多个类型参数,用逗号隔开。类型参数可以用来声明返回值类型,也可以作为方法参数类型的占位符。方法体和其他方法一样,但注意类型参数只能代表引用类型,不能是原始类型(intdoublechar 等)。

public class MethodTest {
    int var = 100;
    String varStr = "Hello Datawhale";
    public  T Method(T a) {
        return a;
    }
    public static void main(String[] args) {
        MethodTest t = new MethodTest();
        System.out.println(t.Method(t.var));
        System.out.println(t.Method(t.varStr));
    }
}

五、泛型接口

实现泛型接口时,可以在子类中指定具体的类型参数。比如下面这个例子:

class InfoImpl implements Info{ // 定义泛型接口的子类
    private String var ; // 定义属性
    public InfoImpl(String var){ // 通过构造方法设置属性内容
        this.setVar(var) ;
    }
    @Override
    public void setVar(String var){
        this.var = var ;
    }
    @Override
    public String getVar(){
        return this.var ;
    }
}
public class GenericsDemo24{
    public void main(String arsg[]){
        InfoImpl i = new InfoImpl("harvic");
        System.out.println(i.getVar()) ;
    }
};

六、类型通配符

当你不确定具体类型参数时,可以用 ? 代替,它表示未知类型。类型通配符只能用在声明类型、方法参数上,不能用在定义泛型类上。看个例子:

public class match {
    public static void test(List list) {
        List list2;
        list2 = new ArrayList();
        list2 = new ArrayList();
        list2 = new ArrayList();
    }
    public static void main(String[] args) {
        test(new ArrayList());
        test(new ArrayList());
    }
}

这段代码里,List 可以接受任何类型的 ArrayList,但你不能往里面写数据(除了 null),因为类型不确定,编译器不让你做任何可能破坏类型安全的操作。

本文转载于:https://blog.csdn.net/weixin_45014634/article/details/119150753 如有侵犯,请联系zhengruancom@outlook.com删除。
免责声明:正软商城发布此文仅为传递信息,不代表正软商城认同其观点或证实其描述。

联系方式: bd@zhengruan.com
网站备案号:苏ICP备2026018738号-1