浅谈 Java 注解(annotation)

背景

之前我一直以为,Java 注解(annotation)和 Python 或者 JavaScript 里的装饰器(decorator)是类似的东西,毕竟看起来很像嘛,都是一个 @ 符号;甚至功能也很像,就是给原本的对象“添加”一些效果。

今天才发现,虽然 Python 和 JavaScript 里的装饰器确实是一回事,但 Java 注解和它们完全不同!

注解 vs 装饰器

装饰器

先来看看 Python 和 JavaScript 里的装饰器吧。之所以叫“装饰器”,的确是因为实现了设计模式里的“装饰器模式”(decorator pattern)。

举个例子,Python 里:

# python
@my_decorator
def my_function():
	# do something...
	return True

就相当于:

# python
def my_function():
	# do something...
	return True

my_function = my_decorator(my_function) # 这就是装饰器模式的常规用法,Java 里只能这么用

换句话说,my_decorator 接受一个函数,然后输出另一个(通常来说)与之兼容的函数(在 Java 里相当于需要实现同样的接口),但于此同时额外添加了一些功能。

(为什么不把这些功能直接写到原函数里呢?因为那样就破坏了单依职责原则。不相关的逻辑,就应该放到不同的组件中,装饰器模式可以帮助我们实现这一点。)

由于这种模式使用频率如此之高,为了更好的可读性,Python 就增加了“装饰器”这么一个语法糖。上面两种写法完全是等价的。

JavaScript 也是一样,只不过装饰器在 JavaScript 中仍然是一个实验性 feature。

Java 注解

Java 注解乍一看完全就是一回事啊,给一个对象(或者类)增加一个注解,相当于就是给它额外增加了一些功能,并且(通常来说)也不会破坏兼容性,很好地实现了逻辑分离。

举个简单例子,在单元测试里,可以用 Mockito 提供的 @Mock 注解来声明一个 mock 对象:

@Mock
List<String> mockedList;

@Test
public void simpleTest() {
    Mockito.when(mockedList.size()).thenReturn(100);
    assertEquals(100, mockedList.size());
}

其实这 @Mock 注解的作用,不就相当于是执行了:

mockedList = Mockito.mock(mockedList);

而已嘛!和上面的装饰器如出一辙呀。

确实如此,但从实现原理上,两者还是截然不同的。

区别就在于,如果你只是定义了一些注解,无论你怎么加,它们都不会对被注解的对象(或者类)产生任何影响。注解真的就只是注解,相当于增加了一些“元信息”而已。

要想让注解产生影响,你必须在另外的地方写一些“注解处理逻辑”。通过 Java 的反射 API,你可以获取对象的注解信息,然后再根据这些注解信息来对该对象进行改造。

优缺点对比

感觉装饰器和注解更有千秋吧:

  • 装饰器的优点在于清晰明了。通过查看装饰器的定义代码,你一下子就能看出来它是干嘛的;而注解的声明逻辑和处理逻辑是分散在不同地方的,想要读懂就比较麻烦;
  • 注解的好处是更灵活。可以这么说,装饰器能实现的,注解都能实现;而注解能实现的,有时候用装饰器实现可能会比较别扭;

比方说,用 Mockito 你可以写出下面的代码:

@Mock
ComponentA mockedComponentA; // 这是一个 mock 对象

@InjectMocks
ComponentB componentB = new ComponentB(); // 上面的 mockedComponentA 会被用做这个对象的成员,当然,前提是 ComponentB 的定义中有一个 ComponentA 类型的成员

@Test
public void testComponentB() {
    // do something
}

假如把 @Mock@InjectMocks 换成装饰器,这个功能即便能实现,感觉也会比较别扭。用注解就比较自然。

小结

其实大多数情况下,两者还是非常相似的。只是没想到,背后的原理这么不一样。

参考链接

Creating a Custom Annotation in Java

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值