泛型的目标之一就是能够编写尽可能广泛应用的代码。

为了实现这一点,我们需要各种途径来放松对我们的代码将要作用的类型所做的限制,同时不丢失静态类型检查的好处。即写出更加泛化的代码。

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):潜在类型机制的更多相关文章

  1. JAVA混型和潜在类型机制

    一.混型 ①.定义 二.利用JAVA如何实现混型 ①.代理   ②.装饰器模式  ③.动态代理模式   ④.装饰器模式与代理模式的区别 三.潜在类型机制 ①.定义 四.JAVA的潜在类型机制的补偿 ① ...

  2. Java泛型中的类型擦除机制简单理解

    Java的泛型是JDK1.5时引入的.下面只是简单的介绍,不做深入的分析. Java的泛型是伪泛型.为什么说Java的泛型是伪泛型呢?因为,在编译期间,所有的泛型信息都会被擦除掉.正确理解泛型概念的首 ...

  3. Java泛型-内部原理: 类型擦除以及类型擦除带来的问题

    一:Java泛型的实现方法:类型擦除 大家都知道,Java的泛型是伪泛型,这是因为Java在编译期间,所有的泛型信息都会被擦掉,正确理解泛型概念的首要前提是理解类型擦除.Java的泛型基本上都是在编译 ...

  4. java泛型总结(类型擦除、伪泛型、陷阱)

    JDK1.5开始实现了对泛型的支持,但是java对泛型支持的底层实现采用的是类型擦除的方式,这是一种伪泛型.这种实现方式虽然可用但有其缺陷. <Thinking in Java>的作者 B ...

  5. 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{ ...

  6. JAVA泛型中的类型擦除及为什么不支持泛型数组

    一,数组的协变性(covariant array type)及集合的非协变性 设有Circle类和Square类继承自Shape类. 关于数组的协变性,看代码: public static doubl ...

  7. 使用Java泛型返回动态类型

    返回一个指定类型的集合,并且clazz必须继承IGeoLog对象或者是其本身 <T extends IGeoLog> List<T> getLogListSql(Class&l ...

  8. java 泛型思考

    java泛型并没有像C++那样原生支持,因此,为了保证迁移兼容性,编译器在编译时会擦除具体类型,因此不能通过泛型调用具体方法. 如果调用必须用extends关键字限定范围,也正是由于这个原因,java ...

  9. Java泛型总结---基本用法,类型限定,通配符,类型擦除

    一.基本概念和用法 在Java语言处于还没有出现泛型的版本时,只能通过Object是所有类型的父类和类型强制转换两个特点的配合来实现类型泛化.例如在哈希表的存取中,JDK1.5之前使用HashMap的 ...

随机推荐

  1. GDB调试器教程

    启动和退出GDBGDB(GNU Project Debugger)几乎适用于所有类Unix系统,小巧方便且不失功能强大,Linux/Unix程序员经常用它来调试程序. 总的来说有几下几种方法启动GDB ...

  2. Java8-Stream-No.01

    import java.util.ArrayList; import java.util.List; import java.util.Optional; public class Streams1 ...

  3. 洛谷P1080 国王游戏【大数】【贪心】

    题目:https://www.luogu.org/problemnew/show/P1080 题意: 一个国王和n个大臣,每个人左右手上都有一个数值. 现在将国王排在队首,将大臣进行排序.每个大臣的值 ...

  4. Ubuntu本地软件源制作

    操作 获取需要的deb包 #执行安装后,安装的包会保存在/var/cache/apt/archives 目录下 apt-get install vim #查看 正在处理用于 man-db (2.8.7 ...

  5. vue-cli 本地代理 造成session丢失 而登录不上去 解决办法

    本地代理造成session丢失,登录不成功,是由于代理配置造成的 devServer: { port: 8000, proxy:{ '/qiantai':{ target:'线上地址/qiantai' ...

  6. LVS集群之IP TUN模式以及网站压力测试

    今天来看一下LVS的第三种模式IP TUN. TUN方式,是通过给数据包加上新的IP头部来实现,这个可以跨整个广域网. 环境: 主机名 IP 系统 角色 tiandong63 RIP:192.168. ...

  7. RSA加密算法c++简单实现

    RSA是一种非对称加密算法,在公开密钥和电子商业中RSA被广泛使用.它是基于一个很简单的数论事实,两个素数相乘很容易,对两素数乘积因式分解很困难.原理就不再阐述了,我谈谈算法的编程实现过程. 一.RS ...

  8. Spring事件监听ApplicationListener源码流程分析

    spring的事件机制是基于观察者设计模式的,ApplicationListener#onApplicationEvent(Event)方法,用于对事件的处理 .在容器初始化的时候执行注册到容器中的L ...

  9. Qt网络获取本机网络信息

    下面我们就讲解如何获取自己电脑的IP地址以及其他网络信息.这一节中,我们会涉及到网络模块(QtNetwork Module)中的QHostInfo ,QHostAddress ,QNetworkInt ...

  10. 【Java】给整数加上千分位分隔符

    package com.testEmp; import java.text.DecimalFormat; public class NumberFormat { public static void ...