博客
关于我
Java--泛型(通配符、泛型边界、泛型与继承)
阅读量:270 次
发布时间:2019-03-03

本文共 6057 字,大约阅读时间需要 20 分钟。

1. 通配符

有时泛型实例的作用域无法指明具体的参数类型。通配符类型,表示任何类型,通配符类型的符号是“?”,因此通配符类型可应用与所有继承自Object的类上。

1.1 通配符的使用

示例:

package Generic;import java.util.Date;public class Test
{ public static void main(String[] args) { Class
c1 = Integer.class; System.out.println(c1.getCanonicalName()); Class
c2 = String.class; System.out.println(c2.getCanonicalName()); Class
c3 = Date.class; System.out.println(c3.getCanonicalName()); }}

运行结果:在这里插入图片描述


1.2 通配符的捕获

考虑下面问题:现有一个方法用于交换List中的两个元素,由于事先并无法知道List中存在的元素类型,所以将参数类型设置成了含有通配符的实例,如List
list。对于该方法来说,并不知道通配符所代表的具体类型,因此,零时存储List中的元素变得困难,因为Java不允许声明通配符常量,即 ? a 这样声明对象是不合法的。所以出现了一种巧妙的解决办法。

示例:

package Generic;import java.util.ArrayList;import java.util.List;public class Tool {       public 
void exchange(List
list, int i, int j) { T t = list.get(i); list.set(i, list.get(j)); list.set(j, t); } public static void main(String[] args) { List
list = new ArrayList<>(); list.add(3); list.add(5); new Tool().exchange(list, 0, 1); System.out.println(list); }}

运行结果:

在这里插入图片描述


2. 泛型边界

边界是指为某一区域划定一个界限,在界限内是允许的,如果超出了界限就不合法Java的泛型边界是指为泛型参数指定范围,在范围内可以合法访问,如果超出了这个界限就是非法访问。Java泛型系统允许使用extends和 super关键字设置边界。前者设定上行边界,即指明参数类型的顶层类,限定实例化泛型类时传入的具体类型,只能是继承自顶层类的。后者设置下行边界,即指定参数类型的底层类,限定传入的参数类型只能是设定类的父类。但设定下行边界时有一定的限制,必须与通配符连用。要为通配符建立一个上行边界:
.superclass用作上行边界的类名还可以指定通配符的下行边界:
·只有subclass或其超类接受实参

2.1 含边界的泛型类

为什么要定义泛型边界呢?就拿工厂作为例子把,对于Car工厂来说,它能生产的产品只能是Car,如果让它生产Computer,显然就不合理了。对于Car工厂来说还存在下列问题,对于不同品牌的汽车来说,除了有轮子、发动机、座椅零件外还要有品牌标识,这样各种品牌汽车就不同了,因此对于汽车工厂来说,除了能生产通用的汽车之外,还应能生产具体品牌的汽车。如何做呢?Java泛型的边界给我们提供了解决方案。

car.java

package Generic.boundary;public class Car {   }

BenzCar.java

package Generic.boundary;public class BenzCar extends Car {       public BenzCar() {           System.out.println("生产奔驰汽车!");    }}

BMWCar.java

package Generic.boundary;public class BMWCar extends Car {       public BMWCar() {           System.out.println("生产宝马汽车!");    }}

CarFactory.java

package Generic.boundary;public class CarFactory
{ public T create(Class
clazz) throws Exception { System.out.println("装载发动机"); System.out.println("装载座椅"); System.out.println("装载轮子"); return clazz.newInstance(); }}

GenericTest.java

package Generic.boundary;public class GenericTest {       public static void main(String[] args) throws Exception {           CarFactory
carFactory01 = new CarFactory<>(); CarFactory
carFactory02 = new CarFactory<>(); System.out.println("开始生产奔驰汽车"); carFactory01.create(BenzCar.class); System.out.println("🐟🐟🐟🐟🐟🐟🐟🐟🐟🐟🐟🐟🐟🐟🐟🐟🐟🐟"); System.out.println("开始生产宝马汽车"); carFactory02.create(BMWCar.class); }}

运行结果:

在这里插入图片描述


2.2 含边界的方法

含边界的的泛型方法与泛型类定义类似,只需要在参数声明参数类型时,使用extends关键字即可,具体的使用方法如下。

示例:

package Generic;public class Sortor {       public 
T getMax(T x, T y) { if ((int) x > (int) y) { return x; } else return y; } public static void main(String[] args) { System.out.println("泛型方法获取的最大数是: " + new Sortor().getMax(5, 4)); }}

运行结果:

在这里插入图片描述


2.3 多边界

Java泛型还允许为参数类型设置多个边界,设置的方法如下:

示例:

Speakable .java

package Generic.multipleBorders;public interface Speakable {       String speak();}

Flyable.java

package Generic.multipleBorders;public interface Flyable {   }

Parrot.java

package Generic.multipleBorders;public class Parrot implements Speakable, Flyable {       @Override    public String speak() {           return "我是一只鹦鹉";    }}

Factory.java

package Generic.multipleBorders;public class Factory
{ public T create(Class
t) throws Exception { return t.newInstance(); }}

FactoryTest.java

package Generic.multipleBorders;public class FactoryTest {       public static void main(String[] args) throws Exception {           Factory
factory = new Factory<>(); Parrot parrot = factory.create(Parrot.class); System.out.println(parrot.speak()); }}

运行结果:

在这里插入图片描述

这个例子定义了一个多边界的泛型Factory,其表现方式为:Factory<T extends Speakable & Flyable> ,表示传入的参数必须同时继承自Speakable和Flyable


2.4 通配符与边界

除了可以在泛型类和泛型方法定义时进行边界限定,还可以对泛型实例进行边界限定,对泛型实例的限定需要与通配符一起使用,其使用方法如下:

示例:

Animal .java

package Generic.wildcardsAndBoundaries;public class Animal {   }

Bird.java

package Generic.wildcardsAndBoundaries;public class Bird extends Animal {   }

Fish.java

package Generic.wildcardsAndBoundaries;public class Fish extends Animal {   }

Zoo.java

package Generic.wildcardsAndBoundaries;public class Zoo
{ private T t; public Zoo(T t) { this.t = t; } public T pop() { return this.t; }}

Test.java

package Generic.wildcardsAndBoundaries;public class Test {       public static void main(String[] args) {           Zoo
zoo = new Zoo
(new Bird()); zoo = new Zoo
(new Fish());// zoo = new Zoo<>(new Integer(2)); 报错 }}
这个例子在实例化参数Zoo时,使用了通配符与extends关键字对参数类型进行限定:Zoo
zoo 限定了实例 zoo 中持有的对象只能是Animal的子类注意:创建具体实例时,必须指明具体的参数类型,如 Z00=new Zoo
( new Bird()), 这里就不能使用
,而必须使用像Bird这样具体的参数。

除了可以使用通配符与extends关键子限制参数类型范围以外,还可以super关键连用限定参数类型的范围。其使用方法如下。

package Generic.wildcardsAndBoundaries;public class Test {       public static void main(String[] args) {           Zoo
zoo = new Zoo
(new Bird()); zoo = new Zoo
(new Animal());// zoo = new Zoo
(new Fish()); 会报错 }}
这个例子使用通配符和super 关键字共同为声明的实例限定了参数范围:Zoo
zoo,表明实例化时传入的参数只能是 Bird类或其父类。

3. 泛型与继承

泛型的继承很容易给人带来一个误区,考虑下面的代码是否合法?

package Generic.wildcardsAndBoundaries;public class Test {       public static void main(String[] args) {           Zoo
zoo = new Zoo<>(new Animal()); Zoo
birdZoo = new Zoo<>(new Bird());// zoo=birdZoo; 编译器会报错 }}

运行结果:

编译器会报错

直觉可能会告诉你合法,因为Animal是Bird的父类,那么Zoo
就是Zoo
的父类,但事实并非如此,当试图 zoo=birdZoo时 编译器会报错。其实Zoo
和Zoo
什么关系都没有,为什么要这样设计呢,因为这是为了确保泛型的安全。

转载地址:http://iakl.baihongyu.com/

你可能感兴趣的文章
使用开源可视化工具来理解你的 Python 代码 | Linux 中国
查看>>
【2021 ECUG Con】聚势而来,与你相约花开时
查看>>
硬核观察 | 有人在比特币骗局中损失了 10 个比特币
查看>>
初识 Python: global 关键字 | Linux 中国
查看>>
在 Ubuntu 17.10 上安装 AWFFull Web 服务器日志分析应用程序 | Linux 中国
查看>>
基于日出和日落时间自动切换到明/暗 Gtk 主题 | Linux 中国
查看>>
FreeDOS 的简单介绍 | Linux 中国
查看>>
查看一个归档或压缩文件的内容而无需解压它 | Linux 中国
查看>>
极致技术探索:显卡工作原理 | Linux 中国
查看>>
如何在 Linux 中不使用功能键在 TTY 之间切换 | Linux 中国
查看>>
如何在 Ubuntu 系统中添加一个辅助 IP 地址 | Linux 中国
查看>>
LCTT 2018:五周年纪念日 | Linux 中国
查看>>
【每日安全资讯】安全研究员发现39万个网站因公开的.git repo处于危险中
查看>>
如何在 Ubuntu 16.04 强制 APT 包管理器使用 IPv4 | Linux 中国
查看>>
使用 top 命令了解 Fedora 的内存使用情况 | Linux 中国
查看>>
怎样解决 “sub process usr bin dpkg returned an error code 1” 错误
查看>>
Bat:一种具有语法高亮和 Git 集成的 Cat 类命令 | Linux 中国
查看>>
在 Linux 上操作目录 | Linux 中国
查看>>
如何禁用 Ubuntu 服务器中终端欢迎消息中的广告 | Linux 中国
查看>>
【每日安全资讯】一个让你用微信支付的勒索病毒 一场黑吃黑的表演
查看>>