2024年最全【Core Java系列2】被骗了!原来Java根本就没有泛型,java数据结构和算法面试题及答案

最后

2020年在匆匆忙忙慌慌乱乱中就这么度过了,我们迎来了新一年,互联网的发展如此之快,技术日新月异,更新迭代成为了这个时代的代名词,坚持下来的技术体系会越来越健壮,JVM作为如今是跳槽大厂必备的技能,如果你还没掌握,更别提之后更新的新技术了。

更多JVM面试整理:

本文已被CODING开源项目:【一线大厂Java面试题解析+核心总结学习笔记+最新讲解视频+实战项目源码】收录

需要这份系统化的资料的朋友,可以点击这里获取

如下就是一个泛型的定义示例:

package com.zwx.coreJava.genericity;

public class GenericMethod {

public T test(T arg){

System.out.println(“generic method”);

return null;

}

}

那么定义了泛型的方法应该如何调用呢?

我们把上面例子中的参数改为多参数看一下

package com.zwx.coreJava.genericity;

public class GenericMethod {

public T test(T…arg){

System.out.println(“generic method”);

return null;

}

public static void main(String[] args) {

GenericMethod genericMethod = new GenericMethod();

genericMethod.test(“1”,1);

}

}

上面这段代码可以正常编译输出,并没有起到限制的作用,所以如果非要限制,可以采用如下调用方式:

genericMethod.test(“1”,1);

在方法前面加上泛型就可以起到限制作用,这时候代码就会编译不通过了。

泛型的继承

==================================================================

上面的泛型定义实际上并没有太多限制,还是可以传入任意类型,那么假如我想限制一下泛型,比如说只能是某一个类的子类,又该如何定义呢?

如果想限定泛型为某一个类的子类,那么就需要用到extends关键字。注意:泛型的继承只能使用extends,而不能使用implements(即使是接口也只能用extends关键字)

package com.zwx.coreJava.genericity;

import java.io.Serializable;

public class GenericClass2{

public static void main(String[] args) {

GenericClass2 genericClass2 = new GenericClass2();

}

}

上面这个示例就会编译不通过,因为我们的MyItem类并没有实现Serializable接口,只有实现了Serializable接口的类才能被正常传进去。

泛型的多继承

===================================================================

在泛型里面支持多继承,可以通过“&”或者“,”来实现。

我们先看一个&的例子:

package com.zwx.coreJava.genericity;

import java.io.Serializable;

public class GenericClass2<T extends MyItem & Serializable & Cloneable>{

public static void main(String[] args) {

GenericClass2 genericClass2 = new GenericClass2();

}

}

这里要求必须只能有一个类,而且如果有一个类,那么这个类必须放在第一位。如上面的例子,MyItem只能放在第一位。而下面这句话需要编译通过,那么MyItemSub必须是如下定义:

public class MyItemSub extends MyItem implements Serializable,Cloneable {

}

也就是说必须同时满足所有条件。

接下来再看一个逗号的例子:

package com.zwx.coreJava.genericity;

public class GenericClass2<T extends MyItem,Serializable,Cloneable>{

public static void main(String[] args) {

GenericClass2 genericClass2 = new GenericClass2<MyItemSub,MyItemSub,MyItemSub>();

}

}

但是这种写法似乎只对第一个限制类型有用,后面的限制并没有用上,因为我除了第1个参数,后面2个参数我传任意类型都可以编译通过。

泛型的继承规则


我们新建一个类继承MyItem:

package com.zwx.coreJava.genericity;

public class MyItemSub extends MyItem {

}

这时候我们再去测试一下这个例子:

package com.zwx.coreJava.genericity;

public class GenericClass3{

public static void main(String[] args) {

MyItemSub myItemSub = new MyItemSub();

MyItem myItem = myItemSub;//编译通过

GenericClass3 myItemSubGenericClass = new GenericClass3<>();

GenericClass3 myItemGenericClass = myItemSubGenericClass;//编译失败

}

}

可以看到最后这一句话编译不通过,也就是说:GenericClass3和GenericClass3没有任何关系(当然这个仅限于编译阶段),并不会因为泛型里面有继承关系就影响到了外面的继承关系。

泛型通配符

==================================================================

在某些时候,我们可以通过通配符“?”来作为泛型,?表示不限制类型。(下面例子中Manager类是Employee的子类,两个类都是空类,就不贴代码了

package com.zwx.coreJava.genericity.wildcard;

import java.util.ArrayList;

import java.util.List;

public class MyWildcard {

public static void main(String[] args) {

List<?> list = new ArrayList<>();

list.add(null);//编译通过

list.add(1);//报错

}

可以看到,虽然?表示允许任意类型,但是和List还是有本质区别的,使用通配符作为泛型的不能直接设置元素,除了null值

不过虽然不能直接设值,但是我们可以通过间接的方式设置值进去。

package com.zwx.coreJava.genericity.wildcard;

import java.util.ArrayList;

import java.util.List;

public class MyWildcard {

public static void main(String[] args) {

List<?> list = MyWildcard.init();

Object obj = list.get(0);//通过

list.add(new Employee());//不通过

}

public static List<?> init(){

List list = new ArrayList<>();

list.add(new Employee());

return list;

}

}

虽然我不能直接设置值进去,但是我可以get获得list的元素。这是因为设置的时候无法确认?到底是什么类型,所以Java会拒绝编译,但是get元素的时候我可以直接赋值给Object,因为任何对象都是Object的子类,所以相当于知道了list内部对象的上界就是Object对象。用Object来接收不会有问题。

泛型通配符和extends关键字


通配符也可以使用extends关键字。

package com.zwx.coreJava.genericity.wildcard;

import java.util.ArrayList;

import java.util.List;

public class MyWildcard {

public static void main(String[] args) {

List<? extends Employee> list = MyWildcard.init();

Employee employee = list.get(0);//通过

list.add(new Manager());//不通过

public static List<? extends Employee> init(){

List list = new ArrayList<>();

list.add(new Employee());

return list;

}

}

使用extends关键字和直接使用通配符区别不大,唯一的区别就是取值的时候我可以确定对象一定是Employee的子类,所以我可以直接使用Employee对象来接收。

换句话说就是:这种写法我可以知道list内部元素的上界,但是我不知道你的下界,所以我只允许取值(用上界接收),不允许设值(设值要用下界)

泛型通配符和super关键字


通配符还可以使用super关键字,限定类型为某个类的超类:

package com.zwx.coreJava.genericity.wildcard;

import java.util.ArrayList;

import java.util.List;

public class MyWildcard {

public static void main(String[] args) {

List<? super Employee> list = MyWildcard.init();

Employee employee = list.get(0);//不通过

Object obj = list.get(0);//编译通过

list.add(new Employee());//通过

}

public static List<? super Employee> init(){

List list = new ArrayList<>();

list.add(new Employee());

return list;

}

}

可以看到,这里就允许设值,因为super关键字限定了元素必须为Employee的父类,也就是我知道了元素的下限,所以我可以设值,但是取值因为不知道上界,所以只能用最顶层的Object。

T和?通配符的区别

======================================================================

这两种表示方法有区别吗?这两个有本质的区别。总结一下主要有如下区别:

  • 1、T表示的是形参,也就是说如果我们想要用T,那么必须要先定义才能用;而?通配符则表示的是实参,也就是说不需要定义,我就可以直接拿来使用。

  • 2、T相当于是占位符,如果我们定义了T,而实际传进去的是String,那么实际的约束类型就是String类型,而不是T;而?通配符可以理解为就是一种真实存在的特殊类型。

  • 3、T可以使用多继承,而?通配符不行,只能用单继承

  • 4、T不能使用super关键字,而?通配符可以使用super关键字。

  • 5、?通配符表示的对象是存在继承关系的,而T表示的不同泛型之间没有任何关系,所以下面这个示例是成立的。

List<?> list = new ArrayList<>();

List<? extends Employee> list1 = new ArrayList<>();

list = list1;

泛型擦除

=================================================================

我们先看一个例子:

package com.zwx.coreJava.genericity.erasure;

import com.zwx.coreJava.genericity.wildcard.Employee;

import java.util.ArrayList;

import java.util.List;

public class TestErasure {

public static void main(String[] args) {

最后

本文已被CODING开源项目:【一线大厂Java面试题解析+核心总结学习笔记+最新讲解视频+实战项目源码】收录

需要这份系统化的资料的朋友,可以点击这里获取

reJava.genericity.erasure;

import com.zwx.coreJava.genericity.wildcard.Employee;

import java.util.ArrayList;

import java.util.List;

public class TestErasure {

public static void main(String[] args) {

最后

[外链图片转存中…(img-AZHsjJpn-1715095549925)]

[外链图片转存中…(img-EmsGHBqD-1715095549926)]

[外链图片转存中…(img-TfDhmD6j-1715095549926)]

本文已被CODING开源项目:【一线大厂Java面试题解析+核心总结学习笔记+最新讲解视频+实战项目源码】收录

需要这份系统化的资料的朋友,可以点击这里获取

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值