为什么 接口只用于定义类型,不应该使用常量接口 ?
2017-03-12 00:12
405 查看
接口只用于定义类型,不应该使用常量接口
2014-12-10 且看且珍惜 文章来源 阅 1247 转 6转藏到我的图书馆
微信分享:
《Effective Java》中说的感觉比较合理,貌似这个问题也是这里提出的,后面那篇是一开始搜到的,也有点用,反正就是不要这么使用就对了。《Effective Java》第19条:接口只用于定义类型当类实现接口时,接口就充当可以引用这个类的实例的类型(type)。因此,类实现了接口,就表明客户端可以对这个类的实例实施某些动作(接口中定义的方法)。为了任何其他目的而定义接口是不恰当的。有一种接口被称为常量接口(constant interface),它不满足上面的条件。这种接口没有包含任何方法,它只包含静态的final域,每个域都导出一个常量。使用这些常量的类实现这个接口,以避免用类名来修饰常量名。下面是一个例子: ?
在Java平台类库中有几个常量接口,例如 java.io.ObjectStreamConstants。这些接口应该被认为是反面的典型,不值得效仿。 如果要导出常量,可以有几种合理的选择方案: 如果这些常量与某个现有的类或者接口紧密相关,就应该把这些常量添加到这个类或者接口中。例如,在Java平台类库中所有的数值包装类,如Integer和Double,都导出了 MIN_VALUE和 MAX_VALUE常量。 如果这些常量最好被看作枚举类型的成员,就应该用枚举类型(enum type)(见第30条)来导出这些常量。 否则,应该使用不可实例化的工具类(utility class)(见第4条)来导出这些常量。 下面的例子是前面的PhysicalConstants例子的工具类翻版: ?
?
===== Java Interface(接口) 是常量存放的最佳地点吗?(不是)由于java interface中声明的字段在编译时会自动加上static final的修饰符,即声明为常量。因而interface通常是存放常量的最佳地点。然而在java的实际应用时却会产生一些问题。 问题的起因有两个, 第一,是我们所使用的常量并不是一成不变的,而是相对于变量不能赋值改变。 例如我们在一个工程初期定义常量 ∏=3.14,而由于计算精度的提高我们可能会重新定义 ∏=3.14159,此时整个项目对此常量的引用都应该做出改变。 第二,java是动态语言。 与c++之类的静态语言不同,java对一些字段的引用可以在运行期动态进行,这种灵活性是java这样的动态语言的一大优势。也就使得我们在java工程中有时部分内容的改变不用重新编译整个项目,而只需编译改变的部分重新发布就可以改变整个应用。 讲了这么多,你还不知道我要说什么吗?好,我们来看一个简单的例子: 有一个interface A,一个class B,代码如下: ?
运行,输入java B,显然结果如下: ?
?
?
Class A's name = bright sea?让我们使用jdk提供的反编译工具javap反编译B.class看个究竟,输入:javap -c B ,结果如下: ?
static final的字段,编译器已经将 interface A中 name的内容编译进了class B中,而不是对 interface A中的 name的引用。因此除非我们重新编译 class B, interface A中 name发生的变化无法在 class B中反映。如果这样去做那么java的动态优势就消失殆尽。 解决方案,有两种解决方法。 第一种方法是不再使用常量,将所需字段放入class中声明,并去掉final修饰符。但这种方法存在一定的风险,由于不再是常量着因而在系统运行时有可能被其他类修改其值而发生错误,也就违背了我们设置它为常量的初衷,因而不推荐使用。 第二种方法,将常量放入class中声明,使用class方法来得到此常量的值。为了保持对此常量引用的简单性,我们可以使用一个静态方法。我们将A.java和B.java修改如下: ?
?
?
?
javap -c B,结果如下: ?
class B中已经变为对 A class的 getName()方法的引用,当常量 name的值改变时我们只需对 class A中的常量做修改并重新编译,无需编译整个项目工程我们就能改变整个应用对此常量的引用,既保持了java动态优势又保持了我们使用常量的初衷,因而方法二是一个最佳解决方案。 引用地址:http://www.360doc.com/content/14/1210/17/16650130_431828218.shtml |
相关文章推荐
- 接口只用于定义类型,不应该使用常量接口
- 5.3.1 使用接口更改已装箱值类型中的字段(以及为什么不应该这样做)
- EffectiveJava(19)导出常量的几种方式 - - 接口只用于定义类型
- 浅谈Java接口中为什么只能定义常量
- 定义新的标签类型,应该使用自定义roleType,还是自定义arcroleType?
- 为什么接口中只能定义常量?
- 接口只用于定义类型
- 使用集合接口的时候应该使用通用类型代替具体的实现类型
- C#与Java对比学习:类型判断、类与接口继承、代码规范与编码习惯、常量定义
- 接口只用于定义类型
- 为什么不应该使用“volatile”类型
- 第19条:接口只用于定义类型
- 第19条:接口只用于定义类型
- 为什么接口中定义的变量必须为常量?
- 接口中定义的变量为什么是常量
- 为什么不要工程中不要随意使用define定义常量
- 接口只用于定义类型
- 接口只用于定义类型。
- C#与Java对比学习:类型判断、类与接口继承、代码规范与编码习惯、常量定义
- 应该使用FOUNDATION_EXPORT还是#define来定义常量?