Java 中的 Generics 泛型

参考视频(B 站 UP 主 AlbertShen
):https://www.bilibili.com/video/BV1H94y1a7bJ/?spm_id_from=333.1007.top_right_bar_window_history.content.click&vd_source=d55a4a2d31b98315ece09779a92b618b

需求:创建一个类,用来打印 Integer 类型的变量

public class IntegerPrinter {
	Integer content;
	IntegerPrinter(Integer content) {
		this.content = content;
	}

	public void print() {
		System.out.println(content);
	}
}

接下来在 main 方法中进行调用:

public class Main {
	public static void main(String[] args) {
		IntegerPrinter printer = new IntegerPrinter(123);
		printer.print();
	}
}

这个时候,如果我们想换个类型打印,比如打印 String 类型,此时就不能再用这个类了,必须要新建一个字符串的打印类:

public class StringPrinter {
	String content;
	StringPrinter(String content) {
		this.content = content;
	}

	public void print() {
		System.out.println(content);
	}
}

这里我们会发现一个问题,如果我们想新打印一个类型的话,就需要新建一个打印类,会给代码带来很多的重复性,是需要避免的。

正因如此,Java 中引入了 Generics 泛型的概念,以至于只需要创建一个类,就可以处理所有的类型,在类名后面通过 <> 来声明泛型 T

public class Printer<T> {
	T content;
	Printer(T content) {
		this.content = content;
	}

	public void print() {
		System.out.println(content);
	}
}

在调用时,需要在声明时使用 <> 来定义需要打印的类型,比如我们要答应 Integer 类型:

public class Main {
	public static void main(String[] args) {
		Printer<Integer> printer = new Printer(123);
		printer.print();
	}
}

如果此时我们想打印 String 类型的变量,不需要再去单独写一个 String 类型的打印类,只需要在声明时将泛型定义为 String 类型即可:

public class Main {
	public static void main(String[] args) {
		Printer<String> printer = new Printer("hello world");
		printer.print();
	}
}

❗注意:<> 中的类型不能为 Java 中的基本数据类型,必须是经过包装后的类型。

在声明泛型时也可以定义多个参数的类型,比如:

public class Printer<T, K> {
	T content;
	K content2;
	Printer(T content, K content2) {
		this.content = content;
		this.content2 = content2;
	}

	public void print() {
		System.out.println(content);
		System.out.println(content2);
	}
}

在使用时,就需要传入两个类型:

public class Main {
	public static void main(String[] args) {
		Printer<String, Integer> printer = new Printer("hello world", 123);
		printer.print();
	}
}

在定义泛型时,可以对泛型进行约束,比如约束传入的类型必须是某个类型的子类:

public class Printer<T extends Vehicle> {
	T content;
	Printer(T content) {
		this.content = content;
	}

	public void print() {
		System.out.println(content);
	}
}

此时,在声明该类时,必须传入 Vehicle 的子类才行:

public class Main {
	public static void main(String[] args) {
		Printer<Car> printer = new Printer(new Car());
		printer.print();
	}
}
public class Main {
	public static void main(String[] args) {
		Printer<Bus> printer = new Printer(new Bus());
		printer.print();
	}
}

<T extends Vehicle> 这个在 Java 中称为 Bounding Generics,即有界限的泛型。

当然,我们也可以用接口来进行约束,假如现在有一个接口 Thing,可以在声明泛型时约束传入的类必须是 Thing 的子类型,Thing 虽然是接口,但声明接口的子类型还是用 extends 关键字:

public class Printer<T extends Thing> {
	T content;
	Printer(T content) {
		this.content = content;
	}

	public void print() {
		System.out.println(content);
	}
}

也可以用类和接口来共同约束,类和接口中间用 & 符号连接,注意类必须放在接口前面:

public class Printer<T extends Vehicle & Thing> {
	T content;
	Printer(T content) {
		this.content = content;
	}

	public void print() {
		System.out.println(content);
	}
}

此时传入的类型 T 必须同时满足是 Vehicle 的子类,同时实现了 Thing 接口。因为显式声明了 T 必须是 Vehicle 的子类,那么 T 类型的 content 变量就可以拿到 Vehicle 里定义的方法和变量。

public class Vehicle {
	String brand;
	String color;

	public String getBrand() {
		return brand;
	}

	public String getColor() {
		return color;
	}
}
public class Printer<T extends Vehicle & Thing> {
	T content;
	Printer(T content) {
		this.content = content;
	}

	public void print() {
		System.out.println(content.getColor());
	}
}

除了给类型添加泛型外,还可以给方法添加泛型,方法是在返回值类型前面通过 <> 来声明泛型:

public static <T> void pring(T content) {
	System.out.pprintln(content);
}

此时该 print 方法就可以打印所有类型的变量了。

如果要对方法的泛型进行约束,方式和对类的泛型进行约束的方式一致:

public static <T extends Vehicle> void pring(T content) {
	System.out.pprintln(content);
}
public static <T extends Thing> void pring(T content) {
	System.out.pprintln(content);
}
public static <T extends Vehicle & Thing> void pring(T content) {
	System.out.pprintln(content);
}

和类泛型一样,方法泛型也可以传入多个参数,声明方式相同:

public static <T, K> void pring(T content, K content2) {
	System.out.pprintln(content);
	System.out.pprintln(content2);
}

此时,如果我们想写一个方法可以打印存放不同类型元素的 List,可以采用 ? 通配符的方式来声明泛型:

public static void pring(List<?> content) {
	System.out.pprintln(content);
}

也可以进行一些类型上的约束:

public static void pring(List<? extends Vehicle> content) {
	System.out.pprintln(content);
}

通配符中还有一种,叫下界通配符(Lower Bounded Wildcard),使用 super 关键字来表示:

public static void pring(List<? super Vehicle> content) {
	System.out.pprintln(content);
}

此时传入的类型必须是 Vehicle 本身或者它的父类。

  • 4
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值