虽然Inteface中默认常量就是static final 的。因此很多人就认为其实存放常量的最佳地方,effective java中就提过,不建议使用常量接口。其有一个原因就是:代码编译问题

好,我们来看一个简单的例子:

有一个interface A,一个class B,代码如下:

//file A.java
public interface A{
String name = "bright";
}
//file B.java
public class B{
public static void main(String[] args){
System.out.println("Class A's name = " + A.name);
}
}

够简单吧,好,编译A.java和B.java。

运行,输入java B,显然结果如下:

Class A's name = bright

我们现在修改A.java如下:

//file A.java
public interface A{
String name = "bright sea";
}

编译A.java后重新运行B class,输入java B,注意:结果如下

Class A's name = bright

为什么不是"Class A's name = bright sea"?让我们使用jdk提供的反编译工具javap反编译B.class看个究竟,输入:javap -c B ,结果如下:

Compiled from B.java
public class B extends java.lang.Object {
public B();
public static void main(java.lang.String[]);
}
Method B()
0 aload_0
1 invokespecial #1 <Method java.lang.Object()>
4 return
Method void main(java.lang.String[])
0 getstatic #2 <Field java.io.PrintStream out>
3 ldc #3 <String "Class A's name = bright">
5 invokevirtual #4 <Method void println(java.lang.String)>
8 return

注意到标号3的代码了吗?由于引用了一个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修改如下:

//file A.java
public class A{
private static final String name = "bright";
public static String getName(){
return name;
}
}
//file B.java
public class B{
public static void main(String[] args){
System.out.println("Class A's name = " + A.getName());
}
}

同样我们编译A.java和B.java。运行class B,输入java B,显然结果如下:

Class A's name = bright

现在我们修改A.java如下:

//file A.java
public class A{
private static final String name = "bright";
public static String getName(){
return name;
}
}

我们再次编译A.java后重新运行B class,输入java B:结果如下

Class A's name = bright sea

终于得到了我们想要的结果,我们可以再次反编译B.class看看class B的改变,输入:

javap -c B,结果如下:

Compiled from B.java
public class B extends java.lang.Object {
public B();
public static void main(java.lang.String[]);
}
Method B()
0 aload_0
1 invokespecial #1 <Method java.lang.Object()>
4 return
Method void main(java.lang.String[])
0 getstatic #2 <Field java.io.PrintStream out>
3 new #3 <Class java.lang.StringBuffer>
6 dup
7 invokespecial #4 <Method java.lang.StringBuffer()>
10 ldc #5 <String "Class A's name = ">
12 invokevirtual #6 <Method java.lang.StringBuffer append(java.lang.String)>
15 invokestatic #7 <Method java.lang.String getName()>
18 invokevirtual #6 <Method java.lang.StringBuffer append(java.lang.String)>
21 invokevirtual #8 <Method java.lang.String toString()>
24 invokevirtual #9 <Method void println(java.lang.String)>
27 return

注意标号10至15行的代码,class B中已经变为对A class的getName()方法的引用,当常量name的值改变时我们只需对class A中的常量做修改并重新编译,无需编译整个项目工程我们就能改变整个应用对此常量的引用,即保持了java动态优势又保持了我们使用常量的初衷,因而方法二是一个最佳解决方案。

Java Interface是存放常量的最好地方吗?(转)的更多相关文章

  1. Java Interface 是常量存放的最佳地点吗?(转帖学习,非原创)

    Java Interface 是常量存放的最佳地点吗?(转帖学习,非原创) 由于java interface中声明的字段在编译时会自动加上static final的修饰符,即声明为常量.因而inter ...

  2. JAVA基础——变量和常量

    JAVA的变量和常量知识总结 一.认识java标识符 标识符就是用于给 Java 程序中变量.类.方法等命名的符号. 使用标识符时,需要遵守几条规则: 1.  标识符可以由字母.数字.下划线(_).美 ...

  3. JAVA 基础基本语法---常量与变量

    JAVA 基础基本语法---常量与变量 语法:计算机能够识别的语言的规则: 0. 基本语法 编写Java程序时,应注意以下几点: 大小写敏感:Java是大小写敏感的,这就意味着标识符Hello与hel ...

  4. Java学习笔记三:Java的变量、常量、变量的类型及使用规则

    Java的变量.常量.变量的类型及使用规则 每一种语言都有一些具有特殊用途的词,Java也不例外,它们被称为关键字.关键字对 Java 的编译器有着特殊的意义. 一:Java中的关键字: 注:Java ...

  5. Java基础二:常量池

    目录: 自动装箱与拆箱 常量池 ==与equals()区别 1. 自动装箱与拆箱 Java是一个近乎纯洁的面向对象编程语言,但是为了编程的方便还是引入了基本数据类型,但是为了能够将这些基本数据类型当成 ...

  6. 转载:Java中的字符串常量池详细介绍

    引用自:http://blog.csdn.net/langhong8/article/details/50938041 这篇文章主要介绍了Java中的字符串常量池详细介绍,JVM为了减少字符串对象的重 ...

  7. Java提高篇之常量池

    一.相关概念 1. 什么是常量 用final修饰的成员变量表示常量,值一旦给定就无法改变! final修饰的变量有三种:静态变量.实例变量和局部变量,分别表示三种类型的常量. 2. Class文件中的 ...

  8. Java复习3.变量.常量.String.

    Java 中的变量常量数据类型 20131004 前言: 还是国庆节,无聊的很,就没事复习点Java的知识,其实C/C++基本上是现在大型企业面试的语言,但是多学习点Java是没有坏处的,而且,将来工 ...

  9. Java中的字符串常量池,栈和堆的概念

    问题:String str = new String(“abc”),“abc”在内存中是怎么分配的?    答案是:堆内存.(Tips:jdk1.8 已经将字符串常量池放在堆内存区) 题目考查的为Ja ...

随机推荐

  1. Android sqlite 数据库在java代码中的增删改查

    private void queryPerson(PersonSQLiteOpenHelper personSQLiteOpenHelper) { SQLiteDatabase sqLiteDatab ...

  2. HTML表单和验证事件

    1.表单验证<form></form> (1).非空验证(去空格) (2).对比验证(跟一个值对比) (3).范围验证(根据一个范围进行判断) (4).固定格式验证:电话号码, ...

  3. leetcode面试准备:Divide Two Integers

    leetcode面试准备:Divide Two Integers 1 题目 Divide two integers without using multiplication, division and ...

  4. dll的加载方式主要分为两大类,显式和隐式链接

    之前简单写过如何创建lib和dll文件及简单的使用(http://blog.csdn.net/betabin/article/details/7239200).现在先再深入点写写dll的加载方式. d ...

  5. perl unload utf-8 oracle 数据库

    perl unload utf-8 Oracle [oracle@oadb sbin]$ sqlplus / as sysdba SQL*Plus: Release 11.2.0.4.0 Produc ...

  6. linux操作Oracle导入导出dmp数据命令

    --清空该表数据 :非索引清空TRUNCATE TABLE  GE_INTERFACE_MESSAGE; --数据库导出 指定导出某个用户的所有数据 包括表 索引 序列 存储过程 函数 等exp CX ...

  7. 【转】eclipse android 设置及修改生成apk的签名文件 -- custom debug keystore

    原文网址:http://hold-on.iteye.com/blog/2064642 android eclipse 设置及修改生成apk的签名文件 1. 问题: 平时在使用eclipse进行andr ...

  8. 如何区分Shapefile,Coverage,Geodatabase(转载)

    转自:http://www.cnblogs.com/linhugh/archive/2012/04/06/2435266.html 在过去20年中,矢量数据模型是GIS中变化最大的方面,例如,ESRI ...

  9. http Error 503 server unavailable

    服务器的环境为: 系统:Windows server 2008 64位 数据库:Oracle 10g WEB应用服务:IIS 7.0+.Net Framework 4.0 无法打开服务元数据库路径“/ ...

  10. tomcat web容器中,调用jersey client端报错的处理

    在web工程中,写main方法,运行ok. 发布到tomcat中后,报错. javax.ws.rs.core.UriBuilder.uri(Ljava/lang/String;)Ljavax/ws/r ...