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

在应用中,我们往往需要一个常量文件,用于存储被多个地方引用的共享常量。在设计应用时,我也遇到了类似的情况,很多地方都需要各种各样的常量。

我确定需要一个单独的文件来存储这些静态公共常量。但是我不是特别确定是应该用接口还是类(枚举不满足我的需求)。我有两种选择:

使用接口,如:

package one;
public interface Constants {
String NAME="name1";
int MAX_VAL=25;
}
或
package two;
public class Constants {
public static final String NAME="name1";
public static final int MAX_VAL=25;
}

我的观点是使用接口。因为接口会自动将成员变量设置为静态的(static)、不可变的(final),这一点可以防止某些情况下错误地添加新的常量。这也使得代码看起来更简单和清晰。

同时,一个的简单测试显示,同样的接口(字节码文件)占用的空间是209个字节(ubuntu 14.04机器上),而类(字节码文件)占用的空间是366个字节(同样的操作系统)。更少的字节码文件意味着加载和维护的成本更低。此外,JVM 加载接口的时候,不需要担心类提供的额外特征(如重载、方法的动态绑定等),因此加载更快。

这看起来非常好,但是这是一个典型反模式的例子。虽然使用接口来保存常量看起很有帮助,但是这给应用后期的扩展留下一个漏洞。

假设存在在一个类,紧密】依赖于这些常量。开发者在该类中写满了通过接口对常量的引用。如:

代码如下:

packagename.Constant.CONSTANT_NAME

所以,为了“清理”这段代码,他可能想实现该接口,这样他就不需要到处写“packagename.Constants”,所有的常量可以直接访问。

但是,一旦他实现了该接口,所有的常量就都变成“契约”(因为所有的常量都是公共的、静态的)的一部分。这导致为这个类增加了不必要的常量。这会动摇整个基础,并引起混乱。Java 中没有一种方式可以阻止类实现接口。

而另一种方式,我们可以将类设置为final,这样就不能扩展。甚至,我们可以将构造器设置为私有的,以防止对这个类实例化,这样就永远不会破坏约定。此外,如果一个特殊的常量在同一个类中被多次使用,则开发者可以使用静态引入。

所有对于常量类,比较好的设计应该是:

package three;
//make the class non-extendable by adding final 增加final关键字来避免继承
public final class Constants {
//Hide the constructor 隐藏构造器
private Constants(){}
public static String NAME="name";
}

静态引入的例子:

import static three.Constants.NAME;
public class UseConstants {
 public static void main(String[] args) {
   System.out.println("the value of constants is"+NAME);
 }
}

这个设计问题也称为接口常量反模式(Constant Interface Anti-pattern)。

以上就是java常量在使用过程中如何避免反模式的解决方法,希望对大家的学习有所帮助。

(0)

相关推荐

  • java中定义常量方法介绍

    java没有叫全局变量的东西(有全局变量还叫OO吗?):原因:Java将所有设计都基于对象的基础上.Java的全局变量只能对一个类内部而言.能够在类内的任何地方使用的变量就是全局变量,而只在某个特定的函数或者局部的程序块内使用的变量则是局部变量. 所以:声明为static的变量实质上就是全局变量.当声明一个对象时,并不产生static变量的拷贝,而是该类所有的实例变量共用同一个static变量. 使用:java中只有static和非static变量,这个属于每个类的,如果需要全局变量比如PI(3

  • JAVA中使用双括号来初始化静态常量的小技巧

    这貌似是个不为人知的语言技巧.我看到一般人写Java里初始化静态常量都是 复制代码 代码如下: public static final Map<String, String> DATA = new TreeMap<String, String>(); static{ DATA.put("a", "A"); //blah blah blah} 使用所在类的static块来初始化DATA,其实还有另外一种写法: 复制代码 代码如下: public

  • 浅谈Java多线程编程中Boolean常量的同步问题

    在JAVA中通过synchronized语句可以实现多线程并发.使用同步代码块,JVM保证同一时间只有一个线程可以拥有某一对象的锁.锁机制实现了多个线程安全地对临界资源进行访问.   同步代码写法如下:   代码1: Object obj = new Object(); ... synchronized(obj) { //TODO: 访问临界资源 } JAVA的多线程总是充满陷阱,如果我们用Boolean作为被同步的对象,可能会出现以下两种情况:   一. 以为对一个对象加锁,实际同步的是不同对

  • Java中的字符串常量池详细介绍

    Java中字符串对象创建有两种形式,一种为字面量形式,如String str = "droid";,另一种就是使用new这种标准的构造对象的方法,如String str = new String("droid");,这两种方式我们在代码编写时都经常使用,尤其是字面量的方式.然而这两种实现其实存在着一些性能和内存占用的差别.这一切都是源于JVM为了减少字符串对象的重复创建,其维护了一个特殊的内存,这段内存被成为字符串常量池或者字符串字面量池. 工作原理 当代码中出现字

  • Java单例模式的应用示例

    单例模式用于保证在程序的运行期间某个类有且仅有一个实例.其优势在于尽可能解决系统资源.通过修改构造方法的访问权限就可以实现单例模式. 代码如下: 复制代码 代码如下: public class Emperor {    private static Emperor emperor = null;// 声明一个Emperor类的引用 private Emperor() {// 将构造方法私有    } public static Emperor getInstance() {// 实例化引用   

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

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

  • Java 中组合模型之对象结构模式的详解

    Java 中组合模型之对象结构模式的详解 一.意图 将对象组合成树形结构以表示"部分-整体"的层次结构.Composite使得用户对单个对象和组合对象的使用具有一致性. 二.适用性 你想表示对象的部分-整体层次结构 你希望用户忽略组合对象与单个对象的不同,用户将统一使用组合结构中的所有对象. 三.结构 四.代码 public abstract class Component { protected String name; //节点名 public Component(String n

  • 详解Java 中的三种代理模式

    代理模式 代理(Proxy)是一种设计模式,提供了对目标对象另外的访问方式;即通过代理对象访问目标对象.这样做的好处是:可以在目标对象实现的基础上,增强额外的功能操作,即扩展目标对象的功能. 这里使用到编程中的一个思想:不要随意去修改别人已经写好的代码或者方法,如果需改修改,可以通过代理的方式来扩展该方法. 举个例子来说明代理的作用:假设我们想邀请一位明星,那么并不是直接连接明星,而是联系明星的经纪人,来达到同样的目的.明星就是一个目标对象,他只要负责活动中的节目,而其他琐碎的事情就交给他的代理

  • Java中判断对象是否相等的equals()方法使用教程

    Object类中的equals方法用于检测一个对象是否等于另一个对象.在Object类中,这个方法判断两个对象是否具有相同的引用,如果两个对象具有相同的引用,它们一定是相等的.从这点上看,将其作为默认操作也是合乎情理的.然而,对于多数类类说,这种判断并没有什么意义,例如,采用这种方式比较两个PrintStream是否相等就完全没有意义.然而,经常需要检测两个对象状态的相等性,如果两个对象的状态相等,就认为这两个对象是相等的.所以一般在自定义类中都要重写equals比较. 下面给出编写一个完美eq

  • java中接口(interface)及使用方法示例

    1.接口:一种把类抽象的更彻底,接口里只能包含抽象方法的"特殊类".接口不关心类的内部状态数据,定义的是一批类所遵守的规范.(它只规定这批类里必须提供某些方法,提供这些方法就可以满足实际要求). 在JAVA编程语言中是一个抽象类型,是抽象方法的集合,接口通常以interface来声明.一个类通过继承接口的方式,从而来继承接口的抽象方法. 接口并不是类,编写接口的方式和类很相似,但是它们属于不同的概念.类描述对象的属性和方法.接口则包含类要实现的方法. 除非实现接口的类是抽象类,否则该类

  • JAVA中4种解析XML文件的方法

    XML是一种通用的数据交换格式,它的平台无关性.语言无关性.系统无关性.给数据集成与交互带来了极大的方便.XML在不同的语言环境中解析方式都是一样的,只不过实现的语法不同而已. XML的解析方式分为四种: 1.DOM解析: 2.SAX解析: 3.JDOM解析: 4.DOM4J解析. 其中前两种属于基础方法,是官方提供的平台无关的解析方式:后两种属于扩展方法,它们是在基础的方法上扩展出来的,只适用于java平台. 针对以下XML文件,会对四种方式进行详细描述: <?xml version="

  • Java中避免过多if-else的几种方法

    太多的if-else不太直观,难以维护. 以下面代码为例,展示几种替代if else的方法. String input = "three"; @Test public void testElse() { if ("one".equals(input)) { System.out.println("one"); } else if ("two".equals(input)) { System.out.println("

  • java中反射和注解的简单使用方法

    目录 什么反射? Java反射机制提供的功能 反射相关的主要API Class 类 获取Class 类的实例( 四种方法) 哪些类型可以有Class 对象? 演示Class类的常用方法 有了Class对象,能做什么? 调用运行时类的指定结构 1. 调用指定方法 关于setAccessible 调用Class对象的newInstance()方法 综合案例: 注解 什么是注解? 常见的Annotation JDK 中的元注解 自定义 Annotation 最后通过反射获取注解信息: 总结 什么反射?

  • Java中的static关键字修饰属性和方法(推荐)

    目录 static关键字 1.static修饰属性(静态属性) 1.1.哪些成员属性可以被static修饰. 1.2.静态属性的访问. 2.static关键字修饰方法 1.那些方法可以使用static修饰 2.常见的问题 static关键字 static关键词与对象无关.static关键字主要修饰四个部分的内容 这里我们主要介绍static修饰属性和修饰方法. 1.static修饰属性(静态属性) 1.1.哪些成员属性可以被static修饰. 我们把static修饰的属性称为静态属性,又叫类属性

  • java中this与super关键字的使用方法

    java中this与super关键字的使用方法 这几天看到类在继承时会用到this和super,这里就做了一点总结,与各位共同交流,有错误请各位指正~ this this是自身的一个对象,代表对象本身,可以理解为:指向对象本身的一个指针. this的用法在java中大体可以分为3种: 1.普通的直接引用 这种就不用讲了,this相当于是指向当前对象本身. 2.形参与成员名字重名,用this来区分: class Person { private int age = 10; public Perso

随机推荐