Java八股文——泛型(二)

news/2025/4/1 15:44:59/

泛型

    • 泛型的多态
    • 基本类型不能作为泛型类型
    • 泛型类型不能实例化
    • 泛型数组
    • 静态方法和静态变量
    • 异常
    • 获取泛型的参数类型

泛型的多态

我们的本意是进行重写,实现多态。可是类型擦除后,只能变为了重载。这样,类型擦除就和多态有了冲突。

桥方法的参数类型都是Object,也就是说,子类中真正覆盖父类两个方法的就是这两个我们看不到的桥方法。而打在我们自己定义的setvaluegetValue方法上面的@Oveerride只不过是假象。而桥方法的内部实现,就只是去调用我们自己重写的那两个方法。

所以,虚拟机巧妙的使用了桥方法,来解决了类型擦除和多态的冲突。

基本类型不能作为泛型类型

因为当类型擦除后,ArrayList的原始类型变为Object,但是Object类型不能存储int值,只能引用Integer的值。

另外需要注意,我们能够使用list.add(1)是因为Java基础类型的自动装箱拆箱操作。

泛型类型不能实例化

如下代码会在编译器中报错:

T test = new T(); // ERROR

因为在 Java 编译期没法确定泛型参数化类型,也就找不到对应的类字节码文件,所以自然就不行了,此外由于T 被擦除为 Object,如果可以 new T() 则就变成了 new Object(),失去了本意。

可以通过反射实现:

static <T> T newTclass (Class < T > clazz) throws InstantiationException, IllegalAccessException {T obj = clazz.newInstance();return obj;
}

泛型数组

Java 的泛型数组初始化时数组类型不能是具体的泛型类型,只能是通配符的形式,因为具体类型会导致可存入任意类型对象,在取出时会发生类型转换异常,会与泛型的设计思想冲突,而通配符形式本来就需要自己强转,符合预期。

错误做法:

List<String>[] lsa = new List<String>[10]; // Not really allowed.
String s = lsa[1].get(0); // Run-time error ClassCastException.

建议做法:

List<?>[] lsa = new List<?>[10]; // OK, array of unbounded wildcard type.
Integer i = (Integer) lsa[1].get(0); // OK

在 Java 中是不能创建一个确切的泛型类型的数组的,除非是采用通配符的方式且要做显式类型转换才可以。

List<String>[] list13 = (List<String>[]) new ArrayList<?>[10]; //OK,但是会有警告 
List<?>[] list15 = new ArrayList<?>[10]; //OK 
List<String>[] list6 = new ArrayList[10]; //OK,但是会有警告

使用反射来初始化泛型数组算是优雅实现:

public class ArrayWithTypeToken<T> {private T[] array;public ArrayWithTypeToken(Class<T> type, int size) {array = (T[]) Array.newInstance(type, size);}public void put(int index, T item) {array[index] = item;}public T get(int index) {return array[index];}public T[] create() {return array;}
}
//...
ArrayWithTypeToken<Integer> arrayToken = new ArrayWithTypeToken<Integer>(Integer.class, 100);
Integer[] array = arrayToken.create();

静态方法和静态变量

泛型类中的静态方法和静态变量不可以使用泛型类所声明的泛型类型参数

public class Test2<T> {    public static T one;   //编译错误    public static  T show(T one){ //编译错误    return null;    }    
}

因为泛型类中的泛型参数的实例化是在定义对象的时候指定的,而静态变量和静态方法不需要使用对象来调用。对象都没有创建,如何确定这个泛型参数是何种类型,所以当然是错误的。

但是要注意区分下面的一种情况:

public class Test2<T> {    public static <T> T show(T one){ //这是正确的    return null;    }    
}

因为这是一个泛型方法,在泛型方法中使用的T是自己在方法中定义的 T,而不是泛型类中的T。

异常

不能抛出也不能捕获泛型类的对象

不能再catch子句中使用泛型变量

但是在异常声明中可以使用类型变量。下面方法是合法的:

public static<T extends Throwable> void doWork(T t) throws T {try{...} catch(Throwable realCause) {t.initCause(realCause);throw t; }
}

获取泛型的参数类型

既然类型被擦除了,那么如何获取泛型的参数类型呢?可以通过反射(java.lang.reflect.Type)获取泛型

java.lang.reflect.Type是Java中所有类型的公共高级接口, 代表了Java中的所有类型. Type体系中类型的包括:数组类型(GenericArrayType)、参数化类型(ParameterizedType)、类型变量(TypeVariable)、通配符类型(WildcardType)、原始类型(Class)、基本类型(Class), 以上这些类型都实现Type接口。

public class GenericType<T> {private T data;public T getData() {return data;}public void setData(T data) {this.data = data;}public static void main(String[] args) {GenericType<String> genericType = new GenericType<>();Type superClass = genericType.getClass().getGenericSuperclass();//getActualTypeArguments 返回确切的泛型参数, 如Map<String, Integer>返回[String, Integer]final Type actualTypeArgument = ((ParameterizedType) superClass).getActualTypeArguments()[0];System.out.println(actualTypeArgument);}
}
public interface ParameterizedType extends Type {// 返回确切的泛型参数, 如Map<String, Integer>返回[String, Integer]Type[] getActualTypeArguments();//返回当前class或interface声明的类型, 如List<?>返回ListType getRawType();//返回所属类型. 如,当前类型为O<T>.I<S>, 则返回O<T>. 顶级类型将返回null Type getOwnerType();
}

http://www.ppmy.cn/news/8215.html

相关文章

MPS | 简单易用的工业电源模块

工业与医疗应用中&#xff0c;在较高输入电压条件下&#xff0c;输出正压和负压的应用需求越来越多。 在应对输出负压条件时&#xff0c;传统解决方案电路复杂且体积庞大&#xff0c;研发周期较长。以半导体测试为例&#xff0c;新一代的测试机通常需要具备以下特点&#xff1…

第二十五讲:OSPF路由协议邻居认证配置

在相同OSPF区域的路由器上启用身份验证的功能&#xff0c;只有经过身份验证的同一区域的路由器才能互相通告路由信息。这样做不但可以增加网络安全性&#xff0c;对OSPF重新配置时&#xff0c;不同口令可以配置在新口令和旧口令的路由器上&#xff0c;防止它们在一个共享的公共…

二氧化碳捕获和电化学转化(Python代码实现)

&#x1f4a5;&#x1f4a5;&#x1f49e;&#x1f49e;欢迎来到本博客❤️❤️&#x1f4a5;&#x1f4a5; &#x1f3c6;博主优势&#xff1a;&#x1f31e;&#x1f31e;&#x1f31e;博客内容尽量做到思维缜密&#xff0c;逻辑清晰&#xff0c;为了方便读者。 ⛳️座右铭&a…

Spring之IOC入门案例

目录 一&#xff1a;IOC入门案例实现思路分析 1.IOC容器管理什么&#xff1f; 2. 如何将被管理的对象告知 IOC 容器 ? 3.被管理的对象交给 IOC 容器&#xff0c;要想从容器中获取对象&#xff0c;就先得思考如何获取到 IOC 容器 ? 4.IOC 容器得到后&#xff0c;如何从容…

Python笔记 | 卡布列克常数

0x00 前言 任意一个不是由完全相同数字组成的四位数&#xff0c;如果对它们的每位数字重新排序&#xff0c;组成一个较大的数和一个较小的数&#xff0c;然后用较大数减去较小数&#xff0c;差不够四位数时补零&#xff0c;类推下去&#xff0c;最后将变成一个固定的数&#xf…

【ROS-melodic Learning】——机器人导航(古月居代码报错与解决方案)

文章目录遇见的问题及解决方案1. cannot launch node of type [arbotix_python/arbotix_driver]: arbotix_python2. Couldnt find executable named XXX.py3. Joint state with name: "base_l_wheel_joint" was received but not found in URDF4. The ‘state_publis…

Python GUI编程:音乐播放器(多线程、爬虫、进度条、文件)

文章目录1. 程序运行结果2.程序实现原理3. GUI布局4. 功能介绍5. 代码实现1. 程序运行结果 Python实现音乐播放器(爬虫、多线程、进度条、文件)2.程序实现原理 本音乐播放器GUI方面运用Python的tkinter实现&#xff0c;播放的音乐来自网络爬虫和本电脑已经有的。为了使整个程序…

新冠感染发病过程记录

新冠感染发病过程记录新冠感染发病过程记录12月25~12月28期间12月28日&#xff08;周三&#xff09;12月29日&#xff08;周四&#xff09;12月30日&#xff08;周五&#xff09;12月30日&#xff08;周六&#xff09;新冠感染发病过程记录 南方广东毒&#xff0c;不比北方的差…