Java泛型常见面试题(面试必问)
作者:Java架构没有996 发布时间:2021-11-20 20:51:55
1、泛型的基础概念
1.1 为什么需要泛型
List list = new ArrayList();//默认类型是Object
list.add("A123");
list.add("B234");
list.add("C345");
System.out.println(list);
for(int i=0;i<list.size();i++){
//若要将list中的元素赋给String变量,需要进行类型转换,不然会报Incompatible types错误,显示list.get(i)返回的是Object
String str = (String) list.get(i);
System.out.println(str);
}
list.add(123);//因为类型是Object,我们可以把Integer类型或者其他数据类型的元素也加入list之中
System.out.println(list.get(3));
for(int i=0;i<list.size();i++){
//String str = (String) list.get(i);//但是在这里会报错java.lang.ClassCastException,我们不能直接将Integer类型的数据转换成String
System.out.println(list.get(i).getClass());
}
如代码中所示,当我们定义了一个List,list默认的类型是所有对象的基类Object,那么我们取出数据的时候需要经过一次类型转换才能进行对象的实际类型的相关操作。因为List中的类型是Object,那么我们先添加了String类型的数据,然后再添加Integer或者其他类型的数据也是允许的,因为编译时List中是Object类型的数据,然而运行的时候却是它本身的类型,所以当我们将List中的数据当作String处理时会抛出java.lang.ClassCastException
。
那么有没有什么办法可以使集合能够记住集合内元素各类型,且能够达到只要编译时不出现问题,运行时就不会出现java.lang.ClassCastException
异常呢?答案就是使用泛型。
1.2 什么是泛型
Java泛型设计原则是:只要在编译时期没有出现警告,那么运行时期就不会出现ClassCastException异常。
泛型,即“参数化类型”,把类型明确的工作推迟到创建对象或调用方法的时候才去明确的特殊类型,把<数据类型>当作是参数一样传递。
什么是泛型?为什么要使用泛型?
泛型,即“参数化类型”。一提到参数,最熟悉的就是定义方法时有形参,然后调用此方法时传递实参。那么参数化类型怎么理解呢?
顾名思义,就是将类型由原来的具体的类型参数化,类似于方法中的变量参数,此时类型也定义成参数形式(可以称之为类型形参),
然后在使用/调用时传入具体的类型(类型实参)。
泛型的本质是为了参数化类型(在不创建新的类型的情况下,通过泛型指定的不同类型来控制形参具体限制的类型)。也就是说在泛型使用过程中,
操作的数据类型被指定为一个参数,这种参数类型可以用在类、接口和方法中,分别被称为泛型类、泛型接口、泛型方法。
相关术语:
ArrayList中的E称为类型参数变量
ArrayList中的Integer称为实际类型参数
整个称为ArrayList泛型类型
整个ArrayList称为参数化的类型
ParameterizedType
泛型的作用:
代码更加简洁【不用强制转换】
程序更加健壮【只要编译时期没有警告,那么运行时就不会抛出ClassCastException
的异常】
可读性和稳定性【在编写集合的时候,就限定了类型】
List<String> strlist = new ArrayList<String>();
List<Integer> intlist = new ArrayList<Integer>();
strlist.add("A");
strlist.add("B");
//strlist.add(123);//编译时报错
for(String str:strlist){
System.out.println(str);
//A
//B
}
//加入Java开发交流君样:756584822一起吹水聊天
System.out.println(strlist.getClass());//class java.util.ArrayList
System.out.println(intlist.getClass());//class java.util.ArrayList
System.out.println(strlist.getClass()==intlist.getClass());//true
泛型擦除
泛型是提供给javac编译器使用的,它用于限定集合的输入类型,让编译器在源代码级别上,即挡住向集合中插入非法数据。但编译器编译完带有泛型的java程序后生成的class文件中将不再带有泛型信息,以此使程序的运行效率不受到影响,这个过程称之为“擦除”。
泛型这个概念是JDK5提出的,JDK5以前的版本是没有泛型的,需要建通JDK5以下的集合。当把带有泛型特性的集合赋值给老版本的集合的时候,会把泛型给擦除了,它保留的是类型参数的上限,即Object。而当我们将没有类型参数的集合赋给带类型参数的集合,也不会报错,仅仅是会提示“未经检查的转换(Unchecked assignment)”,甚至也可以将它赋给其他不同类型的带有泛型特性的集合,只是依旧会抛出ClassCastException异常。
//类型被擦除了,保留的是类型的上限,String的上限就是Object
List list = strlist;
List<String> stringList2 = list;
List<Integer> intList2 = list;//你也可以把它赋给Integer类型的集合,但是当你把这个集合当成Integer的集合操作的时候,依旧会抛出ClassCastException异常
for (Integer i:intList2){//java.lang.ClassCastException
System.out.println(i);
}
2、泛型的定义和使用
2.1 泛型类\泛型接口
泛型类、泛型接口就是把泛型定义在类或者接口上,在用户使用该类的时候才把类型明确下来。我们常用的集合,List,Map<K,V>,Stack……就是泛型类。在类上定义的泛型,在泛型类的方法、变量中都可以使用。
由于类型参数变量T在java泛型中仅仅是一个占位符,在传递参数之后才能使用,即在完成实例创建之后才能使用,所以在泛型类中,不能定义包含泛型类型的静态变量和静态方法,会报错cannot be referenced from a static context。泛型类中包含泛型类型的变量和方法必须在创建了实例明确了传递的类型参数后才可以使用。
class Myset<T>{
private T value;
//public static T sval;//cannot be referenced from a static context
public static int sval2;
//加入Java开发交流君样:756584822一起吹水聊天
public Myset(){
}
public Myset(T val){
this.value = val;
}
public void setValue(T value) {
this.value = value;
}
public T getValue() {
return value;
}
/* public static T getSval(){//cannot be referenced from a static context
return sval;
}*/
}
Myset<String> myset = new Myset<>();
myset.setValue("12345");
System.out.println(myset.getValue());//12345
myset = new Myset<>("23");
//加入Java开发交流君样:756584822一起吹水聊天
System.out.println(myset.getClass());//class liwx.learning.Myset
2.2 泛型方法
public static <T> void PrintArray(T [] arr){
System.out.print("[");
for(T t:arr){
System.out.print(t+",");
}
System.out.println("]");
}
Integer[] a = {1,2,3,4,5,6,7};
PrintArray(a);//[1,2,3,4,5,6,7,]
2.3 泛型类的继承
泛型类的子类有两种继承方式
子类不明确泛型类的参数变量,子类也是泛型类
子类明确泛型类的参数变量,子类不是泛型类
//子类不明确泛型类的参数变量,子类也是泛型类
class MyChiSet1<T> extends Myset<T>{
public MyChiSet1(){
}
public MyChiSet1(T val){
super(val);
}
//加入Java开发交流君样:756584822一起吹水聊天
}
//子类明确泛型类的参数变量,子类不是泛型类
class MyChiSet2 extends Myset<String>{
public MyChiSet2(){
}
public MyChiSet2(String val){
super(val);
}
}
2.4 类型通配符?及其上下限
通配符<?>和类型参数变量的区别是什么?通配符<?>是实参而不是类型形参,而且List<?>在逻辑上是List,List等所有List<具体类型实参>的父类,它的使用比类型形参T更加灵活,但传入的通配符通常进行的是许多于具体类型无关的操作,如果涉及到具体类型相关的操作,以及返回值,还是需要使用泛型方法T。
当我们使用?号通配符的时候,只能调用与对象无关的方法,不能调用对象与类型有关的方法。因为直到外界使用才知道具体的类型是什么。
//虽然Object是所有类的基类,但是List<Object>在逻辑上与List<Integer>等并没有继承关系,这个方法只能传入List<Object>类型的数据
public static void showOList(List<Object> list){
System.out.println(list.size());
}
//同理,这个方法只能传入List<Number>类型的数据,并不能传入List<Integer>
public static void showList(List<Number> list){
System.out.println(list.size());
}//加入Java开发交流君样:756584822一起吹水聊天
//使用通配符,List<?>在逻辑上是所有List<Number>,List<Integer>,List<String>……的父类,可以传递所有List类型的数据,但是不能在List<?>类型的数据进行于具体类型相关的操作,如add
public static void showList2(List<?> list){
System.out.println("<?>");
System.out.println(list.size());
}
//设置通配符上限,可以传入List<Number及Number的子类>
public static void showNumList(List<? extends Number> list){
System.out.println(list.size());
}
//设置通配符上限,List<? super Number>只可以传入List<Number及其父类>
public static boolean Compare(List<? super Number> list1,List<? super Integer> list2){
return list1.size()>list2.size();
}
List<Integer> Intgetlist = new ArrayList<>();
List<Number> Numberlist = new ArrayList<>();
//虽然Number是Integet的父类,但是传入List,它们逻辑上没有了继承关系
System.out.println(Intgetlist.getClass()==Numberlist.getClass());//true
//加入Java开发交流君样:756584822一起吹水聊天
//showList(java.util.List<java.lang.Number>)
//List<Integer>和List<Number>逻辑上无继承关系,所以无法调用
//showList(Intgetlist);//showList(java.util.List<java.lang.Number>)in FXtest cannot be applied to(java.util.List<java.lang.Integer>)
showList(Numberlist);
//public static void showList2(List<?> list)
//通配符List<?>在逻辑上是所有List<具体参数类型>的父类,方法可以传入其子类类型的数据
showList2(Intgetlist);
showList2(Numberlist);
// public static void showNumList(List<? extends Number> list)
//当设定了通配符上限,只能传入List<Number及其子类>的数据
List<String> Stringlist = new ArrayList<>();
showNumList(Intgetlist);
showNumList(Numberlist);//加入Java开发交流君样:756584822一起吹水聊天
//showNumList(Stringlist);//showNumList(java.util.List<? extends java.lang.Number>)in FXtest cannot be applied to(java.util.List<java.lang.String>)
//public static boolean Compare(List<? super Number> list1,List<? super Integer> list2)
//当设定了通配符下限,List<? super Number>只能传入List<Number及其父类>的数据,不能传入子类Integer的List,
// 而List<? super Integer>则可以传入其父类Number的List
//Compare(Intgetlist,Numberlist);
Compare(Numberlist,Intgetlist);
通配符的使用在逻辑上还原了泛型类传入数据类型的参数父类子类的继承关系,同时也可以按照需求设定通配符的上限了下限。
List<?>在逻辑上是所有List<具体参数类型>的父类,可对所有List数据进行操作
List<? extends Type>设定了通配符的上限,可对所有Type及Type的子类进行操作
List<? super Type>设定了通配符的下限,可对所有Type及Type的父类进行操作
来源:https://blog.csdn.net/wj1314250/article/details/117674889
猜你喜欢
- 1.点击上传按钮进行如下操作,通过表单名称以及input名称获取相应的值,对于上传的文件,使用.files来获取,因为包含文件的上传,所以采
- 一 介绍本节给知识追寻者给大家带来的是springSecurity入门篇,主要是简述下springSecrurity的启动原理和简单的入门搭
- 访问Controller返回400BadRequest问题SpringMVC使用自定义类型接收参数时, form提交会返回400 Bad R
- Maven工程分模块开发完成 父工程配置了 tomcat7插件,运行 run命令执行run指令时失败,报错信息如下:D:\java\JDK8
- 前言SpringBoot是我们经常使用的框架,那么你能不能针对SpringBoot实现自动配置做一个详细的介绍。如果可以的话,能不能画一下实
- 一、导航栏UINavigationBar1、导航栏的使用在iOS开发中,我们通常会使用导航控制器,导航控制器中封装了一个UINavigati
- 1、概述本文通过手动实现迭代器来了解foreach语句的本质。2、使用foreach语句遍历集合在C#中,使用foreach语句来遍历集合。
- 面向过程和面向对象的区别面向过程:当事件比较简单的时候,利用面向过程,注重的是事件的具体步骤和过程,注重的是过程中的具体行为,以函数为最小单
- 1.为项目添加POIPOI官网链接点进去之后下载(上边的是编译好的类,下边的是源代码) 解压文件夹,把下面三个文件复制到WebCo
- 在进行详解之前,我想先声明一下,本次我们进行讲解说明的是 Kafka 消息存储的信息文件内容,不是所谓的 Kafka 服务器运行产生的日志文
- 在本博客中,可以找到一篇《c#实现输出的字符靠右对齐的示例》它有教大家怎样实现字符串输出进行左齐或者是右对齐。本篇的方法,超简单,是使用st
- 不废话了,直接给大家贴代码了。class term { String str; int id; &
- 1. json数据类型类型描述Number数字型String字符串型Boolean布尔型Array数组Object对象null空值(1)js
- 1.我做的是一个动态表格,就是在输入框里每输入一次数据并点击“添加”按钮,表格中就会新增一行记录。<table id="st
- 首先我们设计了模块层次图,当然图中只是给出一种实现方式,不局限于此。具体见下图。主要功能介绍如下:1)请求接口层。处理HTTP请求,及响应2
- 这篇文章主要介绍了springboot集成fastDfs过程代码实例,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习
- 找不同给定两个字符串 s 和 t ,它们只包含小写字母。字符串 t 由字符串 s 随机重排,然后在随机位置添加一个字母。
- mongodb是最早热门非关系数据库的之一,使用也比较普遍,一般会用做离线数据分析来使用,放到内网的居多。由于很多公司使用了云服务,服务器默
- 测试spring cloud 使用consul注册服务的时候,出现critical,如下:怎么解决这个问题,现在只能看到health che
- 官方 JSON.NET 地址 http://james.newtonking.com/pages/json-net.aspxXML TO J