关于常量类使用的一个有关问题
关于常量类使用的一个问题。
系统有一个常量类,用来保存一些公用的不可变信息,所有常量都被声明为 public static final,但其中一个常量,用于保存系统的绝对路径(WebRoot),这个常量需要在Servlet启动后加载,所以目前就不能把改常量声明为final,但这存在一个非常大的隐患,就是如果某程序员不小心(或恶意)在代码中修改了改常量,将会导致整个系统无法正常运行(因为系统的配置信息文件都保存在该常量指定的路径中)。
这里有两个问题:
1.这种情况,请问有什么比较好的解决方案;
2.对于常量类,他没有公有的构造方法,没有任何静态或非静态方法,只有static成员变量,请问该常量类在内存中会否存在实例,而它的所有成员变量,究竟是在什么时候被实例化到系统的内存当中?是当Web系统被容器加载的时候吗?还是在该常量被第一次调用的时候才延迟加载?
如果纯粹的只有static属性的话,这个类是不会在系统种存在实例对象的。
它的成员变量如果都是static final的并且在编译时能确定其值,则在编译时便已经将常量写入倒其他引用此属性的类中了。
如果纯粹的只有static属性的话,这个类是不会在系统种存在实例对象的。
它的成员变量如果都是static final的并且在编译时能确定其值,则在编译时便已经将常量写入倒其他引用此属性的类中了。在编译的时候已经将常量写入到其他引用此属性的类中?
这句话我不大理解,如果其他类是在系统运行的时候才实例化的呢?在这些类都没有实例化的时候,这些常量已经存在于内存当中吗?我还是不清楚这些常量的实例会在什么时候产生的。
这个问题还是比较常见的,有很简单的方法。
1.任何时候你需要控制对变量的访问,你不应该直接暴露这个变量,而是使用getter、setter方法来访问。
这样你可以将getter方法设置为public,实例变量是private,那么你可以在内部或者其他合适的地方设置此变量值,而其他地方通过getter访问则是只读的。
2.常量变量跟其他变量一样的实例化,不同的只有初始化时能赋值。如果被声明为static的,则是在第一个实例构造之前被创建。
如果纯粹的只有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。
这其实和你操作普通的成员变量类似,你可以将静态变量设置为default(也就是不设置)或者privated,然后通过静态方法去get/set值就可以了。一般来说,设置为public的静态变量应该是final的。
2.对于常量类,他没有公有的构造方法,没有任何静态或非静态方法,只有static成员变量,请问该常量类在内存中会否存在实例,而它的所有成员变量,究竟是在什么时候被实例化到系统的内存当中?是当Web系统被容器加载的时候吗?还是在该常量被第一次调用的时候才延迟加载?
常量类一样有实例,只是这个实例在未使用new之前是不会装载的。VM所做的只是将静态变量和静态方法分配固定的空间。一般说来,静态变量的装载是随着所在类被装载时,这并不是被调用时才装载。比如说有个类Aimport了这个常量类,但是并没有用到其中的方法,那么常量类的静态方法和变量就会被VM装载。这种import可以是具体的,也可以是*,比如import java.util.*。这也是Java编程规范中建议不要使用*的原因之一。
题外话,保存系统的WebRoot需要这样做吗?
系统有一个常量类,用来保存一些公用的不可变信息,所有常量都被声明为 public static final,但其中一个常量,用于保存系统的绝对路径(WebRoot),这个常量需要在Servlet启动后加载,所以目前就不能把改常量声明为final,但这存在一个非常大的隐患,就是如果某程序员不小心(或恶意)在代码中修改了改常量,将会导致整个系统无法正常运行(因为系统的配置信息文件都保存在该常量指定的路径中)。
这里有两个问题:
1.这种情况,请问有什么比较好的解决方案;
2.对于常量类,他没有公有的构造方法,没有任何静态或非静态方法,只有static成员变量,请问该常量类在内存中会否存在实例,而它的所有成员变量,究竟是在什么时候被实例化到系统的内存当中?是当Web系统被容器加载的时候吗?还是在该常量被第一次调用的时候才延迟加载?
1 楼
together
2006-12-27
常量就应该是final的。
如果需要用到webroot,单独写一个方法去调用好了。request.getRealPath虽然会出现warning,也是能用的。
不然就servlet.getServletContext.getRealPath。系统初始化的时候赋值。
要是怕别人随便改动变量值的话,定期检查代码吧。
如果需要用到webroot,单独写一个方法去调用好了。request.getRealPath虽然会出现warning,也是能用的。
不然就servlet.getServletContext.getRealPath。系统初始化的时候赋值。
要是怕别人随便改动变量值的话,定期检查代码吧。
2 楼
johnnylzb
2006-12-27
第二个问题?
3 楼
foxty
2006-12-27
johnnylzb 写道
第二个问题?
如果纯粹的只有static属性的话,这个类是不会在系统种存在实例对象的。
它的成员变量如果都是static final的并且在编译时能确定其值,则在编译时便已经将常量写入倒其他引用此属性的类中了。
4 楼
johnnylzb
2006-12-27
foxty 写道
johnnylzb 写道
第二个问题?
如果纯粹的只有static属性的话,这个类是不会在系统种存在实例对象的。
它的成员变量如果都是static final的并且在编译时能确定其值,则在编译时便已经将常量写入倒其他引用此属性的类中了。
这句话我不大理解,如果其他类是在系统运行的时候才实例化的呢?在这些类都没有实例化的时候,这些常量已经存在于内存当中吗?我还是不清楚这些常量的实例会在什么时候产生的。
5 楼
codeutil
2006-12-27
不要用 public static final,这个在编译之后就已经写到其它的class里了,比如
A.class 有 public static final String path="123";
B.class用了它.
然后编译好文件,这个时候修改path为"312",只重新编译A.class,不重新编译B.class,这个时候B.class里的path是不变的.
建议限制为通过get方法访问,且set方法只能够在未初始化的时候执行一次赋值(非null的) 操作.
A.class 有 public static final String path="123";
B.class用了它.
然后编译好文件,这个时候修改path为"312",只重新编译A.class,不重新编译B.class,这个时候B.class里的path是不变的.
建议限制为通过get方法访问,且set方法只能够在未初始化的时候执行一次赋值(非null的) 操作.
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.这种情况,请问有什么比较好的解决方案;
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;
}
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 去保存.