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

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

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. 【CEOI1999】Sightseeing trip

    Description https://loj.ac/problem/10072 Solution 现在我连普及组题都不会了?(bushi) 懒得讲了,看这吧.

  2. C++踩坑记录(一)std:;string的析构

    之前写服务端程序有一个往消息队列里面推json的过程,然后发现推进去C#端取到的无论如何都是个空指针 简单复现一下现场 string str1 = string("hello1") ...

  3. jQuery超酷响应式瀑布流效果

    参考 http://www.sucaihuo.com/js/74.html <script src="scripts/blocksit.min.js"></scr ...

  4. Linux部署Django:报错 nohup: ignoring input and appending output to ‘nohup.out’

    一.部署 Django 到远程 Linux 服务器 利用 xshell 通过 ssh 连接到 Linux服务器,常规的启动命令是 python3 manage.py runserver 但是,关闭 x ...

  5. 数据库 MySQL:Windows 环境安装教程

    1. 双击 MySQL 安装包,出现安装界面,选择“next” 2. 勾选接受协议,点击“next” 3. 安装类型选择自定义“Custom”,点击“next” 4. 选择安装路径,点击“next” ...

  6. sql random string

    begindeclare chars_str varchar(62) default 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123 ...

  7. Java8-Stream-No.04

    import java.util.OptionalInt; import java.util.stream.IntStream; public class Streams4 { public stat ...

  8. Docker Gitlib创建项目后仓库连接IP地址不一致问题(包括进入docker中容器命令及退出命令)

    首次在内网搭建Gitlab环境,在成功后在Gitlab上新建了一个项目. 然而在IDEA上clone项目时发现,项目地址如下: git@0096ce63c43f:root/jump.git 或者这样 ...

  9. 微信小程序开发入门教程(二)---分析官方云开发例子中的一些功能

    接上一篇文章:https://www.cnblogs.com/pu369/p/11326538.html 1.官方云开发的例子中,点击获取 openid,对应代码在E:\wxDEV\helloyun\ ...

  10. Eclipse 导入项目