再次认识java泛型

再次认识java泛型

一、什么是泛型

定义类、接口、方法时;同时声明了一个或多个类型变量(如:),称为泛型类,泛型接口,泛型方法,它们统统称为泛型。

这个写法,表示定义了一个泛型类型,定义好之后我们就可以在后面去使用这个泛型类型。

public class ArrayList{

......

}

泛型的本质,是把具体的数据类型作为参数传给类型变量。

泛型的作用:提供了在编译阶段所能操作的数据类型,并自动进行检查的能力。这样可以避免强制类型转换,及可能出现的异常。

例子

package org.example.general;

import java.util.ArrayList;

public class GenExample1 {

public static void main(String[] args) { // ArrayList 本身是一个泛型类,在实例化的时候没有指定泛型类型,那么默认是Object类型

ArrayList arr = new ArrayList();

arr.add("abc");

arr.add(123);

arr.add(true);

for(int i = 0;i < arr.size();i++){

String temp = (String) arr.get(i);

System.out.println(temp);

}

}

}

运行结果:

abc

Exception in thread "main" java.lang.ClassCastException: java.lang.Integer cannot be cast to java.lang.String

at org.example.general.GenExample1.main(GenExample1.java:13)

可以看到获取第二个数据的时候,报了类型转换异常。

我们优化一下代码,给ArrayList定义变量的时候加上泛型标识,如下:

可以发现,在编译阶段就已经报错了。因此后面我们添加元素的时候,就只能添加String类型,这样就规范了值的传入,也就能避免后面的类型转换异常了。

二、泛型类

定义泛型类

修饰符 class 类名 <类型变量,类型变量,...> {

......

}

注意,类型变量建议用大写英文字母,常用的有:E,T,K,V等。

例如,当我们定义类的时候,类中有变量我们不确定它的类型,我们就可以定义泛型类,如下:

package org.example.general;

public class Student { // 有几个类型不确定,就写几个大写字母,这里的T、K表示定义了两个泛型类型为T、K

private T name; // 在这里使用泛型类型 T

private K age; // 在这里使用泛型类型 K

public Student(){};

public Student(T name,K age){

this.name = name;

this.age = age;

}

public T getName() {

return name;

}

public void setName(T name) {

this.name = name;

}

public K getAge() {

return age;

}

public void setAge(K age) {

this.age = age;

}

}

在我们创建对象的时候,来确定泛型类的数据类型,如下:

package org.example.general;

public class GenExample2 {

public static void main(String[] args) {

Student stu1 = new Student<>("小明",22);

System.out.println(stu1.getName());

}

}

再看例子二:

package org.example.general;

public class GenExample3{

public static void main(String[] args) {

People per1 = new People<>();

per1.setHobby(new Hdance());

per1.getHobby();

People per2 = new People<>();

per2.setHobby(new Hsing());

per2.getHobby();

}

}

class People {

private T hobby;

public void setHobby(T hobby) {

this.hobby = hobby;

}

public void getHobby(){

System.out.println(hobby.toString());

}

}

class Hsing{

@Override

public String toString() {

return "唱歌";

}

}

class Hdance{

@Override

public String toString() {

return "跳舞";

}

}

三、泛型接口

定义泛型接口

修饰符 interface 接口名<类型变量,类型变量...>{

......

}

什么时候用到了泛型接口:接口当中,方法的参数类型或方法的返回值类型确定不了,这个时候就可以使用泛型接口。

例如该场景:

系统需要处理学生和老师的数据需要提供两个功能:1、保存对象数据2、根据名称查询数据

代码如下:

定义学生类:

package org.example.generalinterface;

public class Student {

}

定义老师类:

package org.example.generalinterface;

public class Teacher {

}

定义操作类:

package org.example.generalinterface;

public interface Operator {

public abstract void saveData(E obj);

public abstract E getData();

}

// 接口中的泛型在什么时候被确定

// 方式一:实现类实现泛型接口,没有指定具体的泛型类型,那么默认是object类型

class OperatorImpl1 implements Operator{

@Override

public void saveData(Object obj) {

}

@Override

public Object getData() {

return null;

}

}

// 方式二:实现类实现接口时,直接指定接口中泛型的类型(使用最多的方式)

class OperatorImpl2 implements Operator{

@Override

public void saveData(Teacher obj) {

}

@Override

public Teacher getData() {

return null;

}

}

// 方式三:实现类实现了泛型接口,泛型没有指定,那么泛型在实现类实例化的时候被确定

class OperatorImpl3 implements Operator{

@Override

public void saveData(E obj) {

}

@Override

public E getData() {

return null;

}

}

四、泛型方法

定义泛型方法

修饰符 <类型变量,类型变量...> 返回值类型 方法名(形参列表里){

......

}

例如

public static void test(T t){

}

在调用方法的时候确定泛型类型。

什么时候使用泛型方法:当我们定义方法的时候参数类型或返回值类型不确定的时候,就可以使用泛型方法,当我们调用泛型方法的时候来确定泛型方法。例如:

ackage org.example.generalMethod;

public class GenExample1 {

public static void main(String[] args) {

GenExample1.show("abc"); // 输出string

GenExample1.show(123); // 输出integer

} // 第一个 表示我们定义了一个泛型类型,在show后面的T是使用泛型类型。

public static void show(T t){

if(t instanceof String){

System.out.println("string");

} else if (t instanceof Integer) {

System.out.println("interger");

}

}

}

通配符

?号,可以在使用泛型的时候代表一切类型,E T K V 是在定义泛型的时候使用。这个通配符一般会结合集合去用。

package org.example.generalMethod;

import java.util.ArrayList;

public class GenExample2 {

public static void main(String[] args) {

ArrayList str = new ArrayList<>();

ArrayList inte = new ArrayList<>();

method(str);

method(inte);

} // 通配符不需要定义泛型,就可以使用泛型

public static void method(ArrayList arr){

}

}

泛型的上下限

泛型上限: ? extends Car,?能接收的必须是Car或者他的子类

泛型下限: ? super Car,?能接收的必须是Car或者其父类。

可以看到超过上限,编译的时候就报错了。

黄金推荐

黄字笔顺、笔画顺序
beat365手机客户端下载

黄字笔顺、笔画顺序

✨ 10-11 💎 价值: 8660
「胫」详细解释
久发365电子游戏网址多少

「胫」详细解释

✨ 07-11 💎 价值: 4702
Neon District
365bet娱乐

Neon District

✨ 09-20 💎 价值: 700