前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >泛型传递

泛型传递

作者头像
四火
发布2022-07-18 13:51:32
4160
发布2022-07-18 13:51:32
举报
文章被收录于专栏:四火的唠叨

最近在读代码的过程中,经常遇到一些利用泛型来对调用链中的参数进行类型约束的情形,特指对于调用链中后面环节的参数类型和返回值,由前面环节的参数类型来确定,我草率地把它称作泛型传递(技巧很简单,但是用得好会很有趣;我不知道这个东西正儿八经的名字叫做什么)。

在说这个事情以前,对于 Java 的泛型,还是和其它语言中有些许的不同,这里需要结合使用方法泛型和类泛型,如有不明,对于其中的使用可以参考这篇 《泛型趣谈》,而其实下面要说的内容,其实也就是这篇文章中提到的 “链式调用”。另外,也顺便提一句,“泛型” 和 “范型” 可是完全不相干的东西,相差十万八千里(若有混淆,关于 “范型”,可以移步阅读这篇文章)。

很多情况下,我们写代码要解决的直接问题就是平衡变化和不变这两部分,很多情况下需要寻找抽象的不变的那一部分,把变化的部分留给 “外部”(开发者/使用者/其它系统/调用者)去解决。处理变化点的方式有很多,简单可以分为运行时和编译期间两种,各种各样的设计模式和方法技巧,都是围绕变与不变这样的问题。

  • 对于运行时来说,处理变化问题,核心就是使用 if-else 这样的分支选择;除了这个办法,还有就是多态。
  • 对于编译期间来说,方法重载是最基本的方法,但是现在也可以用泛型来进行规约;不过,遗憾的是 Java 的泛型始终只能做到编译期间类型检查而已,编译后的字节码里面早就擦除了泛型的信息。

无论如何,利用泛型来实现参数类型的约束已经非常有用了,最近在写的一些代码,很多情况下,需要结合 Class<T> 和泛型传递来实现参数约束,如下代码:

代码语言:javascript
复制
interface Transformer<Input, Output> {
	public Output transforme(Input input);
}

class Builder {
	private static Builder instance = new Builder();

	private Builder() {
	}

	public static Builder getInstance() {
		return instance;
	}

	public <Input, Output> BuilderAfterTransformerBinding<Input, Output> bindTransformer(
			Class<? extends Transformer<Input, Output>> clazz) {
		return new BuilderAfterTransformerBinding<Input, Output>(clazz);
	}
}

class BuilderAfterTransformerBinding<Input, Output> {
	private Transformer<Input, Output> transformer;

	public BuilderAfterTransformerBinding(
			Class<? extends Transformer<Input, Output>> clazz) {
		try {
			transformer = clazz.newInstance();
		} catch (Exception e) {
			throw new RuntimeException(e);
		}
	}

	public Wrapper<Output> wrap(Input input) {
		return new Wrapper<Output>(transformer.transforme(input));
	}
}

class Wrapper<T> {
	private T t;

	public Wrapper(T t) {
		this.t = t;
	}
}

这段代码中,

  • Transformer 接口就是用来把某 Input 转成 Output 之用的;
  • Builder 类是链式调用的入口;
  • Wrapper 类是一个普通的包装类;
  • BuilderAfterTransformerBinding 类是链式调用第二步的对象,对于调用者来说,他调用其中的 wrap 方法时,传入的参数(上述代码中的 Input)是由链式调用第一步的 Class 泛型所决定的,如下例调用:
代码语言:javascript
复制
byte[] byteArray = ...;
Builder.getInstance().bindTransformer(
	new Transformer<byte[], String>() {
		@Override
		public String transforme(byte[] input) {
			... ...
		}
	}.getClass())
.wrap(byteArray);

其中链式调用的第一步传入的 Class 中,定义了泛型 Input 是 byte[],Output 是 String,那么第二步 wrap 方法的入参也必须是 byte[],返回值必须为 String。

泛型传递的类型约束也是在编译期间达成的,用得好的话它的作用无法替代。在框架的代码定义上显得冗余,但是对于框架代码的客户来说,写类型确定的链式调用是很愉快的。

文章未经特殊标明皆为本人原创,未经许可不得用于任何商业用途,转载请保持完整性并注明来源链接 《四火的唠叨》

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档