Java泛型

泛型传递

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

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

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

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

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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
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泛型所决定的,如下例调用:
1
2
3
4
5
6
7
8
9
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。

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

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值