Java中的泛型

简介: Java中的泛型

一、什么是泛型

(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的父类,不然会报错

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

 


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

相关文章
|
7月前
|
安全 Java 编译器
揭秘JAVA深渊:那些让你头大的最晦涩知识点,从泛型迷思到并发陷阱,你敢挑战吗?
【8月更文挑战第22天】Java中的难点常隐藏在其高级特性中,如泛型与类型擦除、并发编程中的内存可见性及指令重排,以及反射与动态代理等。这些特性虽强大却也晦涩,要求开发者深入理解JVM运作机制及计算机底层细节。例如,泛型在编译时检查类型以增强安全性,但在运行时因类型擦除而丢失类型信息,可能导致类型安全问题。并发编程中,内存可见性和指令重排对同步机制提出更高要求,不当处理会导致数据不一致。反射与动态代理虽提供运行时行为定制能力,但也增加了复杂度和性能开销。掌握这些知识需深厚的技术底蕴和实践经验。
138 2
|
5月前
|
Java API
[Java]泛型
本文详细介绍了Java泛型的相关概念和使用方法,包括类型判断、继承泛型类或实现泛型接口、泛型通配符、泛型方法、泛型上下边界、静态方法中使用泛型等内容。作者通过多个示例和测试代码,深入浅出地解释了泛型的原理和应用场景,帮助读者更好地理解和掌握Java泛型的使用技巧。文章还探讨了一些常见的疑惑和误区,如泛型擦除和基本数据类型数组的使用限制。最后,作者强调了泛型在实际开发中的重要性和应用价值。
130 0
[Java]泛型
|
6月前
|
Java 编译器 容器
Java——包装类和泛型
包装类是Java中一种特殊类,用于将基本数据类型(如 `int`、`double`、`char` 等)封装成对象。这样做可以利用对象的特性和方法。Java 提供了八种基本数据类型的包装类:`Integer` (`int`)、`Double` (`double`)、`Byte` (`byte`)、`Short` (`short`)、`Long` (`long`)、`Float` (`float`)、`Character` (`char`) 和 `Boolean` (`boolean`)。包装类可以通过 `valueOf()` 方法或自动装箱/拆箱机制创建。
72 9
Java——包装类和泛型
|
5月前
|
存储 安全 Java
🌱Java零基础 - 泛型详解
【10月更文挑战第7天】本文收录于「滚雪球学Java」专栏,专业攻坚指数级提升,希望能够助你一臂之力,帮你早日登顶实现财富自由🚀;同时,欢迎大家关注&&收藏&&订阅!持续更新中,up!up!up!!
45 1
|
5月前
|
Java 语音技术 容器
java数据结构泛型
java数据结构泛型
52 5
|
5月前
|
存储 Java 编译器
Java集合定义其泛型
Java集合定义其泛型
36 1
|
6月前
|
安全 Java API
【Java面试题汇总】Java基础篇——String+集合+泛型+IO+异常+反射(2023版)
String常量池、String、StringBuffer、Stringbuilder有什么区别、List与Set的区别、ArrayList和LinkedList的区别、HashMap底层原理、ConcurrentHashMap、HashMap和Hashtable的区别、泛型擦除、ABA问题、IO多路复用、BIO、NIO、O、异常处理机制、反射
|
5月前
|
存储 Java 编译器
【用Java学习数据结构系列】初识泛型
【用Java学习数据结构系列】初识泛型
37 2
|
6月前
|
存储 安全 搜索推荐
Java中的泛型
【9月更文挑战第15天】在 Java 中,泛型是一种编译时类型检查机制,通过使用类型参数提升代码的安全性和重用性。其主要作用包括类型安全,避免运行时类型转换错误,以及代码重用,允许编写通用逻辑。泛型通过尖括号 `&lt;&gt;` 定义类型参数,并支持上界和下界限定,以及无界和有界通配符。使用泛型需注意类型擦除、无法创建泛型数组及基本数据类型的限制。泛型显著提高了代码的安全性和灵活性。
|
5月前
|
安全 Java 编译器
Java基础-泛型机制
Java基础-泛型机制
48 0

热门文章

最新文章