Java泛型(11):潜在类型机制
泛型的目标之一就是能够编写尽可能广泛应用的代码。
为了实现这一点,我们需要各种途径来放松对我们的代码将要作用的类型所做的限制,同时不丢失静态类型检查的好处。即写出更加泛化的代码。
Java泛型看起来是向这个方向迈进了一步。但是还是有一定的限制:
(1)当你在编写或使用只是持有对象<T>的泛型时,这些代码可以适用于任何类型。这些代码就可以真正应用于任何地方,因此相当泛化。
(2)当要在泛型类型上执行操作时,就会产生问题,因为擦除要求指定可能会用到的泛型类型的边界,以安全的调用代码中的泛型对象上的具体方法。
这是对泛化的明显限制。因为必须限制你的泛型类型,使它们继承特定类或实现特定接口。
某些编程语言(Python、C++)提供一种解决方案称为潜在类型机制,它只要求泛型代码实现某个方法的子集,而不是特定类或接口。
尽管Java不支持潜在类型机制,但这并不意味着有界泛型代码不能在不同的类型层次结构之间应用,只不过需要付出一些额外的努力。
(0)以下面例子作为原型:
interface Performs {
void speak();
void sit();
}
class Dog implements Performs {
@Override public void speak() { System.out.println("Dog Speaking..."); }
@Override public void sit() { System.out.println("Dog Sitting..."); }
public void run() { System.out.println("Dog Running..."); }
}
class Robot implements Performs {
@Override public void speak() { System.out.println("Robot Speaking..."); }
@Override public void sit() { System.out.println("Robot Sitting..."); }
public void calc() { System.out.println("Robot Calculating..."); }
}
class Actions {
public static void perform(Performs p) {
p.speak();
p.sit();
}
}
public class DogsAndRobots {
public static void main(String[] args) {
Actions.perform(new Dog());
Actions.perform(new Robot());
}
}
(1)反射
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method; class Dog1 {
public void speak() { System.out.println("Dog1 Speaking..."); }
public void sit() { System.out.println("Dog1 Sitting..."); }
public void run() { System.out.println("Dog1 Running..."); }
}
class Robot1 {
public void speak() { System.out.println("Robot1 Speaking..."); }
public void sit() { System.out.println("Robot1 Sitting..."); }
public void calc() { System.out.println("Robot1 Calculating..."); }
}
class Actions1 {
public static void perform(Object obj) {
Class<?> objClass = obj.getClass();
try {
Method speak = objClass.getMethod("speak");
speak.invoke(obj);
Method sit = objClass.getMethod("sit");
sit.invoke(obj);
} catch (NoSuchMethodException | InvocationTargetException | IllegalAccessException e) {
e.printStackTrace();
}
}
}
public class DogsAndRobots1 {
public static void main(String[] args) {
Actions1.perform(new Dog1());
Actions1.perform(new Robot1());
}
}
(2)将一个方法应用于序列 (apply方法可以接受任何实现Iterable接口的事物,然而,这样的代码还是不够泛化。)
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List; class Dog2 {
public void speak() { System.out.println("Dog2 Speaking..."); }
public void sit() { System.out.println("Dog2 Sitting..."); }
public void run(int length) { System.out.println("Dog2 runs " + length + " miles."); }
} class SmartDog extends Dog2 {} class Actions2 {
// PECS
public static <T, S extends Iterable<? extends T>> void apply(S seq, Method f, Object... args) {
seq.forEach(p -> {
try {
f.invoke(p, args);
} catch (IllegalAccessException | InvocationTargetException e) {
e.printStackTrace();
}
});
}
} class FilledList<T> extends ArrayList<T> {
// PECS
public FilledList(Class<? extends T> type, int size) throws Exception {
for(int i = 0; i < size; i++) {
add(type.newInstance());
}
}
} public class DogsAndRobots2 {
public static void main(String[] args) throws Exception {
List<Dog2> dog2s = new ArrayList<>();
for (int i = 0; i < 3; i++) {
dog2s.add(new Dog2());
}
Actions2.apply(dog2s, Dog2.class.getMethod("speak"));
Actions2.apply(new FilledList<>(SmartDog.class, 2), SmartDog.class.getMethod("run", int.class), 1);
}
}
(3)用适配器仿真潜在类型机制
import java.util.*;
interface Addable<T> { void add(T t); }
interface Generator<T> { T next(); }
class SimpleQueue<T> implements Iterable<T> {
private LinkedList<T> storage = new LinkedList<T>();
public void add(T t) { storage.offer(t); }
public T get() { return storage.poll(); }
public Iterator<T> iterator() {
return storage.iterator();
}
}
class Dog3 {
public void speak(){ System.out.println("Dog2 Speaking..."); }
public void sit() { System.out.println("Dog2 Sitting..."); }
public void run(int length) { System.out.println("Dog2 runs " + length + " miles."); }
}
class BigDog extends Dog3 {}
class SmallDog extends Dog3 {}
class Fill {
// Classtoken version:
public static <T> void fill(Addable<T> addable, Class<? extends T> classToken, int size) {
for (int i = 0; i < size; i++)
try {
addable.add(classToken.newInstance());
} catch (Exception e) {
throw new RuntimeException(e);
}
}
// Generator version:
public static <T> void fill(Addable<T> addable, Generator<T> generator, int size) {
for (int i = 0; i < size; i++)
addable.add(generator.next());
}
}
// To adapt a base type, you must use composition.
// Make any Collection Addable using composition:
class AddableCollectionAdapter<T> implements Addable<T> {
private Collection<T> c;
public AddableCollectionAdapter(Collection<T> c) {
this.c = c;
}
public void add(T item) {
c.add(item);
}
}
// A Helper to capture the type automatically:
class Adapter {
public static <T> Addable<T> collectionAdapter(Collection<T> c) {
return new AddableCollectionAdapter<>(c);
}
}
// To adapt a specific type, you can use inheritance.
// Make a SimpleQueue Addable using inheritance:
class AddableSimpleQueue<T> extends SimpleQueue<T> implements Addable<T> {
public void add(T item) { super.add(item); }
}
public class DogsAndRobots3 {
public static void main(String[] args) {
List<Dog3> dog3s = new ArrayList<>();
// Adapt a Collection:
Fill.fill(new AddableCollectionAdapter<>(dog3s), BigDog.class, 3);
// Helper method captures the type:
Fill.fill(Adapter.collectionAdapter(dog3s), SmallDog.class, 2);
for(Dog3 elem : dog3s) {
System.out.println(elem.getClass().getSimpleName());
}
System.out.println("----------------------");
// Use an adapted class:
AddableSimpleQueue<Dog3> dog3Queue = new AddableSimpleQueue<>();
Fill.fill(dog3Queue, BigDog.class, 4);
Fill.fill(dog3Queue, SmallDog.class, 1);
for(Dog3 elem : dog3Queue) {
System.out.println(elem.getClass().getSimpleName());
}
// BigDog
// BigDog
// BigDog
// SmallDog
// SmallDog
// ----------------------
// BigDog
// BigDog
// BigDog
// BigDog
// SmallDog
}
}
Java泛型(11):潜在类型机制的更多相关文章
- JAVA混型和潜在类型机制
一.混型 ①.定义 二.利用JAVA如何实现混型 ①.代理 ②.装饰器模式 ③.动态代理模式 ④.装饰器模式与代理模式的区别 三.潜在类型机制 ①.定义 四.JAVA的潜在类型机制的补偿 ① ...
- Java泛型中的类型擦除机制简单理解
Java的泛型是JDK1.5时引入的.下面只是简单的介绍,不做深入的分析. Java的泛型是伪泛型.为什么说Java的泛型是伪泛型呢?因为,在编译期间,所有的泛型信息都会被擦除掉.正确理解泛型概念的首 ...
- Java泛型-内部原理: 类型擦除以及类型擦除带来的问题
一:Java泛型的实现方法:类型擦除 大家都知道,Java的泛型是伪泛型,这是因为Java在编译期间,所有的泛型信息都会被擦掉,正确理解泛型概念的首要前提是理解类型擦除.Java的泛型基本上都是在编译 ...
- java泛型总结(类型擦除、伪泛型、陷阱)
JDK1.5开始实现了对泛型的支持,但是java对泛型支持的底层实现采用的是类型擦除的方式,这是一种伪泛型.这种实现方式虽然可用但有其缺陷. <Thinking in Java>的作者 B ...
- java 泛型没有协变类型, 所以要重用extends, 但使用List<? extends Fruit> 可以是ArrayList<Fruit>()、ArrayList<Apple>()、ArrayList<Orange>(), 因此不能add元素进去
class Fruit{} class Apple extends Fruit{} class SubApple extends Apple{} class Orange extends Fruit{ ...
- JAVA泛型中的类型擦除及为什么不支持泛型数组
一,数组的协变性(covariant array type)及集合的非协变性 设有Circle类和Square类继承自Shape类. 关于数组的协变性,看代码: public static doubl ...
- 使用Java泛型返回动态类型
返回一个指定类型的集合,并且clazz必须继承IGeoLog对象或者是其本身 <T extends IGeoLog> List<T> getLogListSql(Class&l ...
- java 泛型思考
java泛型并没有像C++那样原生支持,因此,为了保证迁移兼容性,编译器在编译时会擦除具体类型,因此不能通过泛型调用具体方法. 如果调用必须用extends关键字限定范围,也正是由于这个原因,java ...
- Java泛型总结---基本用法,类型限定,通配符,类型擦除
一.基本概念和用法 在Java语言处于还没有出现泛型的版本时,只能通过Object是所有类型的父类和类型强制转换两个特点的配合来实现类型泛化.例如在哈希表的存取中,JDK1.5之前使用HashMap的 ...
随机推荐
- MyBatis-12-动态SQL
12.动态SQL 什么事动态SQL:动态SQL就是指根据不同的条件生成不同的SQL语句 利用动态SQL这一特性可以彻底摆脱这种痛苦 动态 SQL 元素和 JSTL 或基于类似 XML 的文本处理器相似 ...
- 软raid实现
几种raid类型,我就不在这里赘述了,企业一般都是用raid卡,所以一般使用软raid的非常少,但是也有用的,所以就写一个软raid的实验吧,其实用处不大. 实验环境:centos6.9 需要的硬件: ...
- oracle impdp 覆盖导入 table_exists_action关键字使用
oracle10g之后impdp的table_exists_action参数table_exists_action选项:{skip 是如果已存在表,则跳过并处理下一个对象:append是为表增加数据: ...
- spring-boot-configuration-processor 是干啥用的
spring默认使用yml中的配置,但有时候要用传统的xml或properties配置,就需要使用spring-boot-configuration-processor了 引入pom依赖 <de ...
- 【细谈Java并发】谈谈LinkedBlockingQueue(转)
最近在看concurrent包的知识,看到LinkedBlockingQueue,发现一篇好文推荐给大家.原文地址:[细谈Java并发]谈谈LinkedBlockingQueue 1.简介 上篇我们介 ...
- web+下载文件夹
文件下载的实质就是文件拷贝,将文件从服务器端拷贝到浏览器端,所以文件下载需要IO技术将服务器端的文件读取到,然后写到response缓冲区中,然后再下载到个人客户端. "> <m ...
- luogu 2577 [ZJOI2005]午餐 贪心+dp
发现让 $b$ 更大的越靠前越优,然后依次决策将每个人分给哪个窗口. 令 $f[i][j]$ 表示考虑了前 $i$ 个人,且第一个窗口的总等待时间为 $j$ 的最小总时间. 然后转移一下就好了~ #i ...
- hdu6568 Math (概率dp)
题目链接: http://acm.hdu.edu.cn/showproblem.php?pid=6568 题意: 在$0$到$L$的坐标轴运输货物,在每个整数点可能丢失货物,丢失概率为$p$,丢失后可 ...
- JDK快捷安装,以及详细安装步骤
一,直接快捷安装 安装JDK之前先打开终端输入以下内容检查是否有JDK环境 java javac java -version 输入完弹出一堆东西就是安装完成了 如果安装可以使用 rpm -qa | g ...
- How to install WireShark on Linux
https://linuxtechlab.com/install-wireshark-linux-centosubuntu/