Java 接口常量反模式及定义 Java 常量的教程

初学 Java 的人很不经意间就会把常量定义在接口中,大概唯一的理由是接口不能实例化,而使用接口中定义的常量也是不用附着在实例上的。这主要还是 JDK 本身给我们做了很多这样的榜样, 如  java.io.ObjectStreamConstans,多是出现在 Enum 类型到来之前。

其实 Java 的接口常量是一种反模式,理由如下:

1. 接口是不能阻止被实现或继承的,也就是说子接口或实现中是能够覆盖掉常量的定义(重名),这样通过父,子接口(或实现) 去引用常量是可能不一致的
2. 同样的,由于被实现或继承,造成在继承树中可以用大量的接口, 类 或实例去引用 同一个常量,从而造成接口中定义的常量污染了命名空间。(Java 编译器竟然允许使用实例去引用类变量)
3. 接口暗含的意思是:它是需被实现的,代表着一种类型,它的公有成员是要被暴露的 API。而在接口中定义的常量说不上是 API

4. 这点有些重复,Java 允许通过子类去引用父类中定义的常量,各级对像实例去引用父类的常量,所以这会造成相当的混乱不堪。定义的常量不能保证单一的引用方式。

参见: Effective java 第 19 条: 接口只用于定义类型

既然接口中不适于定义常量,那么该在何处为常量安家呢?接口为 实现/继承 而生,如果放在类中,并且这个类是 final,且封闭掉构造方法就行。于是我们先前的接口常量定义

public interface Gender {
  public static final int MALE = 1;
  public static final int FEMALE = 0;
}
就变成了
public final class Gender {
  private Gender() {
  }
 
  public static final int MALE = 1;
  public static final int FEMALE = 0;
}

这就是 JDK 的 java.nio.charset.StandardCharsets 的写法。

在封闭的 final 类中定义常量确实是前进了一大步。但上面那样定义变量还有个致命缺陷,假如某个方法希望接收 Gender 的 MALE 或 FEMALE,所以类型是 int,而实际你可以传入一个 3,于是这个方法可能傻眼了。也就是说这样定义常量没有边界限制。

如果是为了定义一些松散的常量值,是可以使用 final 型封闭的类,如

public final class ConfigConstants {
  private ConfigConstants() {
  }
 
  public static final String FILE_PATH = "/data/credentials.conf";
  public static final int MAX_LIMIT = 100;
}
如果要定义的多个常量值是同质的,那么最好的定义常量的方式应该是枚举(上面的例子是没理由用枚举了)
public enum Gender {
  MALE, 
  FEMALE
}
上面的定义实质就是一个继承了 java.lang.Enum 的 final 类,获得了 java.lang.Enum 中有用方法,并且直接被编译器禁止被实例化,它有有限的两个 Gender 型成员  MALE 和 FEMALE。Java 枚举原理详见: 通过反编译字节码来理解 Java 枚举

最简表述上面的 Gender  枚举是

public final class Gender extends java.lang.Enum {

  public static final Gender MALE;

  public static final Gender FEMALE;

}

我们也能看到 JDK 也倾向于用枚举来定义常量了,如 java.nio.file.StandardOpenOption。

这样对于接受 Gender 类型参数的方法就只能传入 MALE 或 FEMALE 了,不再有其他选项,这就是枚举的意义。

以上是小编为您精心准备的的内容,在的博客、问答、公众号、人物、课程等栏目也有的相关内容,欢迎继续使用右上角搜索按钮进行搜索java
, int
, 实例
, 接口
, static
类型
java接口中定义常量、java 接口定义常量、在java接口中定义常量、接口定义常量、接口中定义常量,以便于您获取更多的相关知识。

时间: 2024-10-27 08:20:58

Java 接口常量反模式及定义 Java 常量的教程的相关文章

一个体现Java接口及工厂模式优点的例子

随着模式概念的普及,了解模式和使用模式的程序员越来越多,很多人在学习模式的时候,都会有这样一种疑惑:"有必要搞得这么复杂吗?".的确,因为教程的例子过于简单化(这样方便读者学习),或者是作者选例子的时候并没有很好体现所讲模式的优点,很多情况下如果仅就其例子的问题来说,用模式是太复杂了.因此才导致这样的误解:"模式就是把简单的问题复杂化吗?".当然不是,随着你开发实践的不断丰富,你终会发现模式强大威力,而且模式也并非贵族化的编程方式,它就是一些经过提炼了的解决问题的方

Java中的常量避免反模式的方法_java

在应用中,我们往往需要一个常量文件,用于存储被多个地方引用的共享常量.在设计应用时,我也遇到了类似的情况,很多地方都需要各种各样的常量. 我确定需要一个单独的文件来存储这些静态公共常量.但是我不是特别确定是应该用接口还是类(枚举不满足我的需求).我有两种选择: 使用接口,如: package one; public interface Constants { String NAME="name1"; int MAX_VAL=25; } 或 package two; public cla

Java中的常量:如何避免反模式

在应用中,我们往往需要一个常量文件,用于存储被多个地方引用的共享常量.在设计应用时,我也遇到了类似的情况,很多地方都需要各种各样的常量. 我确定需要一个单独的文件来存储这些静态公共常量.但是我不是特别确定是应该用接口还是类(枚举不满足我的需求).我有两种选择: 使用接口,如: package one; public interface Constants { String NAME="name1"; int MAX_VAL=25; } 或 package two; public cla

深入理解java三种工厂模式_java

适用场合: 7.3 工厂模式的适用场合 创建新对象最简单的办法是使用new关键字和具体类.只有在某些场合下,创建和维护对象工厂所带来的额外复杂性才是物有所值.本节概括了这些场合. 7.3.1 动态实现 如果需要像前面自行车的例子一样,创建一些用不同方式实现同一接口的对象,那么可以使用一个工厂方法或简单工厂对象来简化选择实现的过程.这种选择可以是明确进行的也可以是隐含的.前者如自行车那个例子,顾客可以选择需要的自行车型号:而下一节所讲的XHR工厂那个例子则属于后者,该例中所返回的连接对象的类型取决

Java访问在接口中定义的常量

我们在定义常量的时候,可以把常量定义在接口里面,如: package org.zy.demo.base; public interface InterfaceDemo { final String name="this is my name"; } 上面是我定义的接口和常量. 常量的定义没有指明 public static 我实现此接口: package org.zy.demo.base; public class InterfaceImpl implements InterfaceD

java接口中定义的常量的访问方法

我们在定义常量的时候,可以把常量定义在接口里面,如: packageorg.zy.demo.base; publicinterfaceInterfaceDemo{ finalStringname="thisismyname"; } 上面是我定义的接口和常量. 常量的定义没有指明publicstatic 我实现此接口: packageorg.zy.demo.base; publicclassInterfaceImplimplementsInterfaceDemo{ } 那么我们如何访问呢

Java 理论与实践: 伪typedef反模式

将泛型添加到 Java 语言中增加了类型系统的复杂性,提高了许多变量和方法声明的冗长程度.因为没有提供 "typedef" 工具来定义类型的简短名称,所以有些开发人员转而把扩展当作 "穷人的 typedef",结果收到了良好的效果. 对于 Java 5.0 中新增的泛型工具,一个常见的抱怨就是,它使代码变得太冗长.原来用一行就够的变量声明不再存在了,与声明参数化类型有关的重复非常讨厌,特别是还没有良好地支持自动补足的 IDE.例如,如果想声明一个 Map,它的键是

Java接口的定义,使用,以及事件的监听方法

众所周知,类是对所有对象所共有的方法和属性的定义,即类是一个抽象的规则,定义一个类无非是两个用途,或者生成对象调用其方法,或者用作给其他类来继承,而在后一个用途上,我们要求子类必须重写父类的方法时就需要定义一个接口. 接口本身也是一个类,但是接口定义的是一个没有任何方法体实现的方法,而这也是接口定义的规则,只能定义方法名,返回值,以及参数表,而不能有实现.并且,接口不能用来直接创建对象. 在定义接口的时候,一个class类可以实现多个接口,而一个class类只能继承一个class,这也就意味着我

JAVA之旅(一)——基本常识,JAVA概念,开发工具,关键字/标识符,变量/常量,进制/进制转换,运算符,三元运算

JAVA之旅(一)--基本常识,JAVA概念,开发工具,关键字/标识符,变量/常量,进制/进制转换,运算符,三元运算 Android老鸟重新学一遍JAVA是什么感觉?枯燥啊,乏味啊,而且归纳写博客,都是很痛苦的事情,但是程序之路这么长,你必须精通的不能再精通一门语言才行(有点说大了哈),但是最起码你要如鱼得水吧,我准备的资料有: JAVA编程思想 深入浅出JAVA 黑马,传智,慕课,极客学院等-的视频 Google搜索 我们既然是重新学一遍,那我们尽量就是用记事本去敲代码好了,这里我用notep