JWorld@TW the best professional Java site in Taiwan
      註冊 | 登入 | 全文檢索 | 排行榜  

» JWorld@TW » Java SE 討論區  

按列印兼容模式列印這個話題 列印話題    把這個話題寄給朋友 寄給朋友   
reply to topicthreaded modego to previous topicgo to next topic
本主題所含的標籤
無標籤
作者 static final field 帶來的隱憂! [精華]
Duncan

還隱隱作痛

版主

發文: 7816
積分: 39
於 2003-08-01 15:40 user profilesend a private message to usersend email to Duncanreply to postreply to postsearch all posts byselect and copy to clipboard. 
ie only, sorry for netscape users:-)add this post to my favorite list
翻開 Java core classes 處處可見到 static final field 的使用,這些公開的唯讀資訊不外乎是作為 hint、state、option or mask。優雅的 Java programmer 通常會 access static final field 透過 FieldName or ClassName.FieldName 的寫法,端看所在 scope 而定,而不直接使用對應的常數值。透過 field name 來讀取資訊通常基於兩個理由:首先是因為 field name 通常是有意義的單字或句子,這比直接記憶常數來的容易,儘管 field name 往往很長(比對應的常數要長,Math.PI, Math.E 算是少數的例外),這在 IDE 的幫助下不算是很大的問題;另一個理由是,透過 static final field 來使用(final 可以確保唯讀性)而非直接使用常數,可以使得一旦 static final field 的值隨著實做細節變更時,可以減少對 client code 帶來的衝擊,改變了 static final field value 不需要改寫所有用到此常數的部分,這樣幾乎沒有把影響擴散出去。

關於第二點,其實不然

以下的敘述針對於 Java 八個 primitive types(boolean, byte, char, short, int, long, float, double)與 java.lang.String

Java compiler 對於 access static final field 會有特殊的作法,會在編譯時期找出被 access 的 filed 所屬之 class,直接讀出 static final field 的值而後推入 stack 來使用,並非推入 field full qualified name, type descriptor 以 getstatic instruction 來擷取 field value。這種 inline 的作法可以提升執行效率,但是卻擴大了影響層面,一旦 static final field value 改變了。

改變了 static final field value,意味著你必須重新編譯所有參考(使用)到此 field 的 class。你說這沒什麼大不了的,對於使用 IDE or Ant 來製作 project 的人來說的確是沒什麼大不了,但是如果被改變的 field 是屬於已散佈的 library 的一部份呢?這同時也暗示著,一旦你變更 static final field,hot swap/deploy 便是行不通的,換句話說,一個 class 要能夠 hot swap,一個前提是其 static final field value 要保持一致性。

另外一個隱憂是:誰能保證未來隨著 Java platform 版本的演進,core classes 中的 static final field 都不會變更?

我們不能一廂情願地認為,Java 的主導者會 take care 相容性的問題。有時因為實做細節的變更,static final field 也需要隨之變動,core class API 都可以 deprecate 了,還有什麼不可以。如果有一天,隨著版本演進,部分的 static final field value 變更了,那麼使用到這些 field 的 legacy Java application 便不能再使用,必須在新版的 JRE 環境下重新編譯,可是你不一定會有 source。

雖然不能確保這種麻煩事不會發生,但在我們發展實用的 library 時應盡量避免。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
// DuncanProfile.java
import java.awt.Color;
 
public interface DuncanProfile {
  public static final String NAME = "Duncan";
  public static final char SEX = 'M';
  public static final boolean MARRIED = false;
  public static final byte AGE = 26;
  public static final float WEIGHT_IN_KG = 70.0f;
  public static final double HEIGHT_IN_CM = 175.0;
  public static final short SIBLINGS = 2;
  public static final int INCOME_MONTHLY = 0;
  public static final long FORTUNE = 500;
  
  public static final Color SKIN_COLOR = Color.yellow;
}
 
// DumpProfile.java
public class DumpProfile {
 
  public static void main(String[] args)
  {
    System.out.println(DuncanProfile.NAME);
    System.out.println(DuncanProfile.SEX);
    System.out.println(DuncanProfile.AGE);
    System.out.println(DuncanProfile.MARRIED);
    System.out.println(DuncanProfile.WEIGHT_IN_KG);
    System.out.println(DuncanProfile.HEIGHT_IN_CM);
    System.out.println(DuncanProfile.SIBLINGS);
    System.out.println(DuncanProfile.INCOME_MONTHLY);
    System.out.println(DuncanProfile.FORTUNE);
    System.out.println(DuncanProfile.SKIN_COLOR);
  }
}


javap -c -private DumpProfile
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
Compiled from "DumpProfile.java"
public class DumpProfile extends java.lang.Object{
public DumpProfile();
  Code:
   0:  aload_0
   1:  invokespecial  #9; //Method java/lang/Object."<init>":()V
   4:  return
 
public static void main(java.lang.String[]);
  Code:
   0:  getstatic  #21; //Field java/lang/System.out:Ljava/io/PrintStream;
   3:  ldc  #23; //String Duncan
   5:  invokevirtual  #29; //Method java/io/PrintStream.println:(Ljava/lang/String;)V
   8:  getstatic  #21; //Field java/lang/System.out:Ljava/io/PrintStream;
   11:  bipush  77
   13:  invokevirtual  #32; //Method java/io/PrintStream.println:(C)V
   16:  getstatic  #21; //Field java/lang/System.out:Ljava/io/PrintStream;
   19:  bipush  26
   21:  invokevirtual  #35; //Method java/io/PrintStream.println:(I)V
   24:  getstatic  #21; //Field java/lang/System.out:Ljava/io/PrintStream;
   27:  iconst_0
   28:  invokevirtual  #38; //Method java/io/PrintStream.println:(Z)V
   31:  getstatic  #21; //Field java/lang/System.out:Ljava/io/PrintStream;
   34:  ldc  #39; //float 70.0f
   36:  invokevirtual  #42; //Method java/io/PrintStream.println:(F)V
   39:  getstatic  #21; //Field java/lang/System.out:Ljava/io/PrintStream;
   42:  ldc2_w  #43; //double 175.0d
   45:  invokevirtual  #47; //Method java/io/PrintStream.println:(D)V
   48:  getstatic  #21; //Field java/lang/System.out:Ljava/io/PrintStream;
   51:  iconst_2
   52:  invokevirtual  #35; //Method java/io/PrintStream.println:(I)V
   55:  getstatic  #21; //Field java/lang/System.out:Ljava/io/PrintStream;
   58:  iconst_0
   59:  invokevirtual  #35; //Method java/io/PrintStream.println:(I)V
   62:  getstatic  #21; //Field java/lang/System.out:Ljava/io/PrintStream;
   65:  ldc2_w  #48; //long 500l
   68:  invokevirtual  #52; //Method java/io/PrintStream.println:(J)V
   71:  getstatic  #21; //Field java/lang/System.out:Ljava/io/PrintStream;
   74:  getstatic  #58; //Field DuncanProfile.SKIN_COLOR:Ljava/awt/Color;
   77:  invokevirtual  #61; //Method java/io/PrintStream.println:(Ljava/lang/Object;)V
   80:  return
 
}
 


Duncan edited on 2003-08-02 01:39
reply to postreply to post

給我
辣味豆腐 其餘免談
作者 Re:static final field 帶來的隱憂! [Re:Duncan]
markscat



發文: 0
積分: 0
於 2003-10-22 23:17 user profilesend a private message to userreply to postreply to postsearch all posts byselect and copy to clipboard. 
ie only, sorry for netscape users:-)add this post to my favorite list
老大,你的意思就是要我們粗魯一點囉^^|||

reply to postreply to post
作者 Re:static final field 帶來的隱憂! [Re:markscat]
Duncan

還隱隱作痛

版主

發文: 7816
積分: 39
於 2003-10-23 13:01 user profilesend a private message to usersend email to Duncanreply to postreply to postsearch all posts byselect and copy to clipboard. 
ie only, sorry for netscape users:-)add this post to my favorite list
markscat wrote:
老大,你的意思就是要我們粗魯一點囉^^|||


你所謂的"粗魯"是指不使用 static name 而直接使用常數嗎?我可沒有透露出這樣的意思在裡頭!千萬不要誤會了。


reply to postreply to post

給我
辣味豆腐 其餘免談
作者 Re:static final field 帶來的隱憂! [Re:Duncan]
aladdin

老婆不准我用兒子照片



發文: 175
積分: 3
於 2003-10-24 02:48 user profilesend a private message to userreply to postreply to postsearch all posts byselect and copy to clipboard. 
ie only, sorry for netscape users:-)add this post to my favorite list
我覺得Enumerative type是需要的。

剛在JCP裡找了一下看到這篇:
http://jcp.org/aboutJava/communityprocess/jsr/tiger/enum.html

1. Compile-time type safety.
2. Performance comparable to int constants.
3. Type system provides a namespace for each enum type, so you don't have to prefix each constant name.
4. Typesafe constants aren't compiled into clients, so you can add, reorder or even remove constants without the need to recompile clients. (If you remove a constant that a client is using, you'll fail fast with an informative error message.)
5. Printed values are informative. (Which would you rather see in a stack trace: "Indigo" or "6?")
6. Enum constants can be used in collections (e.g., as HashMap keys).
7. You can add arbitrary fields and methods to an enum class.
8. An enum type can be made to implement arbitrary interfaces.

Duncan 大大,這個第四點會解決問題嗎?


reply to postreply to post
作者 Re:static final field 帶來的隱憂! [Re:Duncan]
Duncan

還隱隱作痛

版主

發文: 7816
積分: 39
於 2004-08-03 15:40 user profilesend a private message to usersend email to Duncanreply to postreply to postsearch all posts byselect and copy to clipboard. 
ie only, sorry for netscape users:-)add this post to my favorite list
要避免 String 與八種 primitive type 的 static final field 被編譯進 client code,在 sun JDK 編譯器下可以把 static final field 的設值延遲到 class initializer 裡進行(這樣 static final field 就不會有 ConstantValue attribute,編譯器在編譯時沒辦法光靠 load class bytecode 就得知 static final field 的值)。

reply to postreply to post

給我
辣味豆腐 其餘免談
作者 Re:static final field 帶來的隱憂! [Re:Duncan]
jfire





發文: 128
積分: 0
於 2011-04-11 04:09 user profilesend a private message to usersend email to jfirereply to postreply to postsearch all posts byselect and copy to clipboard. 
ie only, sorry for netscape users:-)add this post to my favorite list
文章標題的重點錯了

不是static final field帶來隱憂
而是"public" static final field 才對


reply to postreply to post
» JWorld@TW »  Java SE 討論區

reply to topicthreaded modego to previous topicgo to next topic
  已讀文章
  新的文章
  被刪除的文章
Jump to the top of page

JWorld@TW 本站商標資訊

Powered by Powerful JuteForum® Version Jute 1.5.8