JAVA泛型浅析

Java范型generics,是JDK1.5引入的新特性,是一种编译时类型安全检测机制,可以在编译时检测到非法的类型。范型的本质是将类型参数化,将类型指定成一个参数。java中的集合就有使用,并且对外提供的三方库和SDK中使用也极为常见。
特点是运行效率高,在定义时不设限在使用时再写入具体类型。 定义泛型参数时还可以使用继承,例如 <T extends User> ,后面都可以使用User类或它的子类接收在必要的时再强转指定类型。

泛型只在编译期间生效,运行期泛型会被擦除,比如List<String> 和 List<Integer>的两个空集合,equals判断为true。
范型的参数只能是引用类型,不能是基本数据类型。

三种使用范围:范型类、范型接口、范型方法。

1、范型类:  用在构造方法在实例化的时候检测类型

范型的参数可以是系统定义的类也可以是自定义类;构造方法传入的实参类型需要与范型的参数类型相同,<T>  类型由调用方决定。

1.1 定义一个泛型类

public class GenericUser<T> {
    private T name;
    private T age;

    public GenericUser(T nameOrAge) {
        //这里为了学习总结,实际不会这样乱赋值
        this.name = nameOrAge;
        this.age = nameOrAge;
    }
    public GenericUser() {
    }


    public T getName(){
        return name;
    }

    public T getAge(){
        return age;
    }
 //注意:静态方法使用范型:必须将静态方法也定义成范型方法,否则报错。即使类已经定义了也会报错,必须在修饰符和返回值之间static之后加上这个范型
    private static <T> T getNameS(T t){
        return t;
    }

}

1.2 使用泛型类

GenericUser<String> genericUser1 = new GenericUser<>("Tom");
Log.e(TAG, "onClick: name= "+genericUser1.getName() );
GenericUser<Integer> genericUser2 = new GenericUser<>(8);
Log.e(TAG, "onClick: age="+genericUser2.getAge() );
//todo 不是使用定义了范型的类就一定要传入范型,如果传了什么就用什么,如果不传就可以是任意类型。需要做类型判断
GenericUser genericUser3 = new GenericUser<>("随便写");
Log.e(TAG, "onClick: name="+genericUser3.getName()+"   age="+genericUser3.getAge());


结果打印:
//2024-02-18 18:33:34.884 22735-22735/com.example.testdemo3 E/FanXingActivity: onClick: name= Tom
//2024-02-18 18:33:34.884 22735-22735/com.example.testdemo3 E/FanXingActivity: onClick: age=8
//2024-02-18 18:33:34.885 22735-22735/com.example.testdemo3 E/FanXingActivity: onClick: name=随便写   age=随便写

2、泛型方法

在方法调用时检测类型,在返回值类型之前的<T>是范型方法的象征,此处表示声明了一个范型T,范型数量也可以多个比如<T,E>;
下面getNanme1和getNanme2是泛型方法,但getNanme3方法不是范型方法它只是在形参中使用了范型而已。

private <T> T getName1(GenericUser<T> user){
    return user.getName();
}
//也有这种返回但不传入
private <T> T getName1(T str){
    GenericUser<T> genericUser = new GenericUser<>(str);
    Log.e(TAG, "getName1: name= "+genericUser.getAge() );
    return genericUser.getAge();
}

private <T,E> T getName2(GenericUser<T> user){
    return user.getName();
}
//不是泛型方法
private String getName3(GenericUser<String> user){
    return user.getName();
}

//范型方法也可以普通方法一样使用可变参数
private <T> void getName4(T...ts){
    for (T t : ts) {
        Log.e(TAG, "getName4: "+t );
    }
}

3、泛型接口:一般和范型类或方法搭配使用且与范型类用法类似

interface GenericInter<T> {
    T getNumber();
}

3.1 泛型类使用泛型接口

当实现范型接口的类不传范型实参:比如下面的也需要在类名增加GenericInterUser1<T>和接口一样的范型。

public class GenericInterUser1<T> implements GenericInter<T>{
    @Override
    public T getNumber() {
        return null;
    }
}

如果当实现范型接口的类传入自己范型参数: 如GenericInterUser1不需要在类名加范型参数

public class GenericInterUser2 implements GenericInter<String>{
    private String number = "000001";
    @Override
    public String getNumber() {
        return number;
    }
}

泛型的子类限制

public class GenericUserSun<T extends Number> extends GenericUser{
    private T age;
    public GenericUserSun(T age){
        super(age);
        this.age = age;
    }

    public T getAge() {
        return age;
    }
}

//上面案例GenericUserSun可以传入的泛型就有了限制,不是所有类型都可以,而必须是Number的子类,比如Integer、Byte、Short、Float等等。

注意:如果我们想写一个接口实现类做泛型参数也要使用<T extends 接口>和类一样 而不是<T implements 接口>,报错如下。

  • 6
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值