选择显示字体大小

java interface 是常量存放的最佳地点吗?

xml:namespace prefix = o ns = "urn:schemas-microsoft-com:office:office" /> 

由于java interface中声明的字段在编译时会自动加上static final的修饰符,即声明为常量。因而interface通常是存放常量的最佳地点。然而在java的实际应用时却会产生一些问题。

问题的起因有两个,第一,是我们所使用的常量并不是一成不变的,而是相对于变量不能赋值改变。例如我们在一个工程初期定义常量∏=3.14,而由于计算精度的提高我们可能会重新定义∏=3.14159,此时整个项目对此常量的引用都应该做出改变。第二,java是动态语言。与c++之类的静态语言不同,java对一些字段的引用可以在运行期动态进行,这种灵活性是java这样的动态语言的一大优势。也就使得我们在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
4 return

method void main(java.lang.string[])
0 getstatic #2
3 ldc #3
5 invokevirtual #4
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
4 return

method void main(java.lang.string[])
0 getstatic #2
3 new #3
6 dup
7 invokespecial #4
10 ldc #5
12 invokevirtual #6
15 invokestatic #7
18 invokevirtual #6
21 invokevirtual #8
24 invokevirtual #9
27 return

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


 


关键字 本文所属关键字

相关 与本文相关文章

分类 所有文章关键字导航

源码编程相关

Java   Asp   PHP   .Net   XML   C/C++   CGI   VB   Jsp   J2ee   J2se   J2me   EJB   Servlet   Tomcat   Resin   Struts   Weblogic   Eclipse   ANT   GUI   JMS   Web servise   IDEA   Webphere   Hibernate   Spring   Jboss   Applet   Swing   Socket   Javamail   Perl   Ajax   P2P   安全   模式   框架   测试   开源   游戏

SQL数据库相关

My-SQL   Ms-SQL   Access   DB2   Oracle   Sybase   SQLserver   索引   存储过程   加密   数据库   分页   视图  

手机无线相关

3G   Wap   CDMA   GRPS   GSM   IVR   彩信   短信   无线   增值业务

网页设计制作相关

HTML   CSS   网页配色   网页特效   Javascript   VBscript   Dreamweaver   Frontpage   JS   Web   网站设计

网站建设推广相关

建站经验   网站优化   网站排名   推广   Alexa

操作系统/服务器相关

Windows XP   Windows 2000   Windows 2003   Windows Me   Windows 9.x   Linux   UNIX   注册表   操作系统   服务器   应用服务器

图形图像多媒体相关

Photoshop   Fireworks   Flash   Coreldraw   Illustrator   Freehand   Photoimpact   多媒体   图形图像

标准 网站致力的规范

Valid CSS!

无不良内容,无不良广告,无恶意代码

Valid XHTML 1.0 Transitional

creativecommons