Java中的泛型

目录

一、什么是泛型

(1)、 解释:

(2)、语法:

二、泛型类的使用

三、擦除机制

注意:

四、泛型的上界

(1)、语法

(2)、示例

(3)、复杂示例

​编辑

五、泛型的方法

(1)、语法

(2)、示例

六、通配符

(1)、通配符解决什么问题

(2)、通配符的上界

(3)、通配符的下届

都看到这里了,点个赞再走吧,谢谢谢谢谢!!!


一、什么是泛型

(1)、 解释:

        一般的类和方法,只能使用具体类型,要么是基本类型,要么是自定义类型,如果我们要编写可以应用多种类型的的代码就能使用到泛型

(2)、语法:

        

代码示例:

class MyArray<T> {
    public T[] array = (T[])new Object[10];
    public T getPos(int pos) {
        return this.array[pos];
    }
    public void setVal(int pos, T val) {
        this.array[pos] = val;
    }
}
public class Test {
    public static void main(String[] args) {
        MyArray<Integer> myArray = new MyArray<>();
        myArray.setVal(0, 10);
        myArray.setVal(1, 20);
        int ret = myArray.getPos(0);
        System.out.println(ret);//输出10
    }
}

代码解释:类名后的 <T> 代表占位符,表示当前类是一个泛型类


二、泛型类的使用

语法:

注意:泛型的使用只能接受类,所以基本数据类型必须使用包装类

如下图:

我们也可以写成如下形式:

编译器可以根据上下文推导出类型的实参,可以省略类型的实参。


三、擦除机制

Java的泛型机制是在编译级别实现的,将所有T替换成Object这种机制我们称为擦除机制。

(代码是上面的代码)通过命令:javap -c 查看字节码文件,所有的T都是Object

注意:

        泛型类不能实例化,演示代码如下:

class MyArray<T> {
    public T[] array = (T[])new Object[10];
    public T getPos(int pos) {
        return this.array[pos];
    }
    public void setVal(int pos, T val) {
        this.array[pos] = val;
    }
    public T[] getArray() {
        return this.array;
    }
}

public static void main(String[] args) {
        MyArray<Integer> myArray = new MyArray<>();
        Integer[] array = myArray.getArray();
}

运行代码时会报错,报错结果如下:

原因:

因为擦除机制在编译时将所有的T类型都转换为Object类型,所以调用getArray方法是拿到的是Object类型,而不是Integer类型将Object[]分配给Integer[]引用,是不安全的,程序会报错;

通俗的来讲,因为Object默认是任何类型的父类,可以存放任何类型可能是String,可能是Person,运行时直接把Object传给Integer类型的数组,编译器认为是不安全的。


四、泛型的上界

(1)、语法

(2)、示例

而调用MyArray,E的类型,我们可以传入Number,也可以传入Number的子类。

(3)、复杂示例

E必须是实现了Comparable接口的类型。


五、泛型的方法

(1)、语法

(2)、示例

代码如下:

public class Test {
    public static <E> void swap(E[] array, int i, int j) {
        E t = array[i];
        array[i] = array[j];
        array[j] = t;
    }
    public static void main(String[] args) {
        Integer[] array = {1,2,3,4,5};
        System.out.println(Arrays.toString(array));
        //不使用类推到
        Test.<Integer>swap(array, 0, 1);
        System.out.println(Arrays.toString(array));
        System.out.println("==============");
        //使用使用类推到
        swap(array, 0, 1);
        System.out.println(Arrays.toString(array));
    }
}

执行代码结果如下:

六、通配符

(1)、通配符解决什么问题

代码示例:

class Message<T> {
private T message ;
public T getMessage() {
return message;
}
public void setMessage(T message) {
this.message = message;
}
}
public class TestDemo {
public static void main(String[] args) {
Message<String> message = new Message<>() ;
message.setMessage("hello world");
fun(message);
}
public static void fun(Message<String> temp){
System.out.println(temp.getMessage());
}

上述程序带来了新的问题,如果泛型设置的不是String类,而是Integer类呢

我们想让fun能接受所有泛型类型,但又不能更改fun的形参类型,这时候就可以用到通配符<?>

通配符的使用如下:

(2)、通配符的上界

语法:

代码示例:

class Food {
}
class Fruit extends Food {
}
class Apple extends Fruit {
}
class Banana extends Fruit {
}

class Message<T> {
    private T message;

    public T getMessage() {
        return message;
    }
    public void setMessage(T message) {
        this.message = message;
    }
}
public class Test2 {
    public static void main(String[] args) {
        Message<Fruit> message1 = new Message<>();
        message1.setMessage(new Fruit());
        fun(message1);

        Message<Banana> message2 = new Message<>();
        message2.setMessage(new Banana());
        fun(message2);

        Message<Food> message3 = new Message<>();
        message3.setMessage(new Food());
        //fun(message3);//err
    }
    public static void fun(Message<? extends Fruit> tmp) {
        System.out.println(tmp.getMessage());
    }
}

由上述例子我们可以看出,我们想调用fun方法,传入的参数的类型必须是Fruit或者是Fruit的子类,不然会报错

此时无法在fun函数中对temp进行添加元素,因为temp接收的是Fruit和他的子类,此时存储的元素应该是哪个子类无法确定。所以添加会报错!但是可以获取元素。
 

(3)、通配符的下届

语法:

class Food {
}
class Fruit extends Food {
}
class Apple extends Fruit {
}
class Banana extends Fruit {
}

class Message<T> {
    private T message;

    public T getMessage() {
        return message;
    }
    public void setMessage(T message) {
        this.message = message;
    }
}
public class Test2 {
    public static void main(String[] args) {
        Message<Fruit> message1 = new Message<>();
        message1.setMessage(new Fruit());
        fun2(message1);
        
        Message<Food> message2 = new Message<>();
        message2.setMessage(new Food());
        fun2(message2);
        Message<Apple> message3 = new Message<>();
        message3.setMessage(new Apple());
        //fun2(message3);//err
    }
    public static void fun2(Message<? super Fruit> tmp) {
        System.out.println(tmp.getMessage());
    }
}

调用fun2方法时,我们传入的类型只能是Fruit类或者Fruit的父类,不然会报错

通配符的下界,不能进行读取数据,只能写入数据
 


都看到这里了,点个赞再走吧,谢谢谢谢谢!!!

评论 29
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

tao滔不绝

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值