关于常量类使用的一个问题。
系统有一个常量类,用来保存一些公用的不可变信息,所有常量都被声明为 public static final,但其中一个常量,用于保存系统的绝对路径(WebRoot),这个常量需要在Servlet启动后加载,所以目前就不能把改常量声明为final,但这存在一个非常大的隐患,就是如果某程序员不小心(或恶意)在代码中修改了改常量,将会导致整个系统无法正常运行(因为系统的配置信息文件都保存在该常量指定的路径中)。
这里有两个问题:
1.这种情况,请问有什么比较好的解决方案;
2.对于常量类,他没有公有的构造方法,没有任何静态或非静态方法,只有static成员变量,请问该常量类在内存中会否存在实例,而它的所有成员变量,究竟是在什么时候被实例化到系统的内存当中?是当Web系统被容器加载的时候吗?还是在该常量被第一次调用的时候才延迟加载?private static String path = null;public static String getPath() {return path;}public static void setPath(String apath) {if (path == null) {path = apath;}} 6 楼 LucasLee 2006-12-27 johnnylzb 写道系统有一个常量类,用来保存一些公用的不可变信息,所有常量都被声明为 public static final,但其中一个常量,用于保存系统的绝对路径(WebRoot),这个常量需要在Servlet启动后加载,所以目前就不能把改常量声明为final,但这存在一个非常大的隐患,就是如果某程序员不小心(或恶意)在代码中修改了改常量,将会导致整个系统无法正常运行(因为系统的配置信息文件都保存在该常量指定的路径中)。
这里有两个问题:
1.这种情况,请问有什么比较好的解决方案;
2.对于常量类,他没有公有的构造方法,没有任何静态或非静态方法,只有static成员变量,请问该常量类在内存中会否存在实例,而它的所有成员变量,究竟是在什么时候被实例化到系统的内存当中?是当Web系统被容器加载的时候吗?还是在该常量被第一次调用的时候才延迟加载?
这个问题还是比较常见的,有很简单的方法。
1.任何时候你需要控制对变量的访问,你不应该直接暴露这个变量,而是使用getter、setter方法来访问。
这样你可以将getter方法设置为public,实例变量是private,那么你可以在内部或者其他合适的地方设置此变量值,而其他地方通过getter访问则是只读的。
2.常量变量跟其他变量一样的实例化,不同的只有初始化时能赋值。如果被声明为static的,则是在第一个实例构造之前被创建。 7 楼 foxty 2006-12-27 johnnylzb 写道foxty 写道johnnylzb 写道第二个问题?
如果纯粹的只有static属性的话,这个类是不会在系统种存在实例对象的。
它的成员变量如果都是static final的并且在编译时能确定其值,则在编译时便已经将常量写入倒其他引用此属性的类中了。在编译的时候已经将常量写入到其他引用此属性的类中?
这句话我不大理解,如果其他类是在系统运行的时候才实例化的呢?在这些类都没有实例化的时候,这些常量已经存在于内存当中吗?我还是不清楚这些常量的实例会在什么时候产生的。
举个例子;
class A{
public static int D = 12;
}
public class B{
public static void main(String[] args)
{
int data = A.D;
//some operations...
}
}
这种情况下,classloader载入class B的时候,同时也会载入class A,但是这个时候类A并未初始化(注意不是实例化)。这个时候A.D所指的12是放在class A的常量池中,当程序运行至int data = A.D的时候,才会初始化class A(注意不是实例化),同时查找A的字段列表(从类A的常量池中)获取12。
======================================
class A{
public static final int D = 12;
}
class B同上。
这种情况下,编译器编译B的时候,发现A.D是一个static而且final的常量,那么它会将这个12直接写入倒class B的字节码当中(即int data = A.D 已经就是int data = 12了),类的载入过程同情况1。
======================================
还有一种特殊情况。
class A{
public static final int D = new java.util.Random().nextInt();
}
class B同上。
这个时候,编译器编译B的时候虽然发现D是一个static且final的属性,但是它的值确需要在运行时才能确定,所以就无法把D的值嵌入倒B的字节码中,当执行B的mian方法时,还是同第一个情况一样,要去查找A的字段列表获取D。类的载入过程同情况1。
8 楼 johnnylzb 2006-12-27 非常清楚,谢谢 9 楼 凤舞凰扬 2006-12-28 johnnylzb 写道1.这种情况,请问有什么比较好的解决方案;
这其实和你操作普通的成员变量类似,你可以将静态变量设置为default(也就是不设置)或者privated,然后通过静态方法去get/set值就可以了。一般来说,设置为public的静态变量应该是final的。
johnnylzb 写道
2.对于常量类,他没有公有的构造方法,没有任何静态或非静态方法,只有static成员变量,请问该常量类在内存中会否存在实例,而它的所有成员变量,究竟是在什么时候被实例化到系统的内存当中?是当Web系统被容器加载的时候吗?还是在该常量被第一次调用的时候才延迟加载?
常量类一样有实例,只是这个实例在未使用new之前是不会装载的。VM所做的只是将静态变量和静态方法分配固定的空间。一般说来,静态变量的装载是随着所在类被装载时,这并不是被调用时才装载。比如说有个类Aimport了这个常量类,但是并没有用到其中的方法,那么常量类的静态方法和变量就会被VM装载。这种import可以是具体的,也可以是*,比如import java.util.*。这也是Java编程规范中建议不要使用*的原因之一。 10 楼 Readonly 2006-12-28 johnnylzb 写道用于保存系统的绝对路径(WebRoot)
题外话,保存系统的WebRoot需要这样做吗? 11 楼 shaucle 2006-12-28 法1 :只读.
private String property1;
<static>{
//load from property files
}
pucblic String getProperty1();
没有set
法2 :只允许设置一次.
void setProperty(){
if(setted){
return or throw
}
//set...
setted = true;
} 12 楼 wjtang 2006-12-28 同意楼上各位意见,有个建议,对于这一类的信息为什么不用property file or xml file 去保存.