簡體   English   中英

在java中的子類(子類)中初始化靜態最終變量

[英]initialize static final variable in child class(sub class) in java

我有一個這樣的課程:

public abstract class A {
    public static final int FIELD;
    // some methods
}

我想在子類中初始化變量 FIELD。 我的意思是這樣的:

public class B extends A {
    FIELD = 5;
}

編輯實際上我有多個類擴展 A 並且所有類都有變量 FIELD 但具有不同的值; 所以我發現的方法是重構變量 FIELD 並在超類中聲明它。 還有其他解決方案嗎? 有可能有這樣的東西嗎? 感謝您的幫助。

關鍵是超類的子類沒有在超類中聲明的靜態字段的副本,並且超類在它們之間共享; 所以沒有辦法讓靜態變量在不同的子類中具有不同的值。 因此,我將在所有子類中聲明變量 FIELD。
我在評論中從@LenceJava 得到了所有這些。 謝謝@LanceJava。

不,這是不可能的(至少不是沒有一些嚴重的骯臟技巧)

A被初始化時,該字段必須被初始化。 AB初始化之前被初始化。 B任何內容僅在B初始化時或之后執行。

如果這是可能的,在加載 B 之前使用A.FIELD會發生什么?

您可以做的是將字段設為私有而不是靜態的,並提供一個只允許對其進行一次調用並從B調用它的設置器。

在像這樣的大多數情況下,真正的問題有一個更清晰的解決方案,但是由於您沒有提到您嘗試解決的真正問題,我們在這方面無能為力。

由於它是staticfinal ,因此在初始化時和/或在 static 塊中,您可以為該變量賦值。 只是沒有其他地方。

當你創建一個新的B對象,首先,新的A對象將被自動創建,其最終的變量已其默認的構造函數初始化; 所以你不能再修改它們的值。

final變量在聲明時初始化,並且不能在子類中重新初始化或修改。 java中的final表示常量。 嘗試修改它們的值會導致編譯錯誤。

如果要在派生類中更改它們,則不能在最終類中使用靜態最終變量。

1) 刪除 FIELD 屬性的 final 關鍵字

2)修改代碼如下

import java.io.*;
import java.util.*;

class A {
    public static int FIELD = 4;
}
class B extends A {
    public B(){
        this.FIELD  = 5;
    }
}
public class Test {

    public static void main(String args[]) throws Exception {
    B b = new B();
        System.out.println("B value:"+b.FIELD);
    }

}

輸出是:

B value:5

不管 final 關鍵字是什么,單個靜態變量不適用於多個子類,因為每當實例化新子類時都會重新分配單個靜態變量。 此外,實例化的順序仍然會進一步混淆最后靜態更新的值。

jshell> public abstract class A { public static String STATIC_SUPER_VAR = "A"; }
|  created class A


jshell> public class B extends A { public B() { STATIC_SUPER_VAR = "B"; } }
|  created class B

jshell> B.STATIC_SUPER_VAR
$3 ==> "A"    

jshell> A.STATIC_SUPER_VAR
$4 ==> "A"

jshell> new B()
$3 ==> B@685cb137

jshell> B.STATIC_SUPER_VAR
$4 ==> "B"

jshell> A.STATIC_SUPER_VAR
$5 ==> "B"

jshell> public class C extends A { public C() { STATIC_SUPER_VAR = "C";} }
|  created class C

jshell> new C()
$7 ==> C@5f2108b5

jshell> A.STATIC_SUPER_VAR
$8 ==> "C"

jshell> B.STATIC_SUPER_VAR
$9 ==> "C"

jshell> C.STATIC_SUPER_VAR
$10 ==> "C"

解決方案

我們可以使用靜態 Map 而不是單個靜態變量。

jshell> public abstract class A {
   ...>
   ...>      private static Map<Class<? extends A>, Integer> CLASS_FIELD_HOLDER = new HashMap<>();
   ...>
   ...>      public A (int classSpecificInteger) {
   ...>
   ...>            CLASS_FIELD_HOLDER.put(getClass(), classSpecificInteger);
   ...>      }
   ...>
   ...>
   ...>      public static int getClassSpecificInteger(Class<? extends A> clazz) {
   ...>
   ...>                  return CLASS_FIELD_HOLDER.get(clazz);
   ...>      }
   ...> }
|  created class A

jshell> public class B extends A {
   ...>
   ...>  public B (int classSpecificInteger) {
   ...>
   ...>         super(classSpecificInteger);
   ...>  }
   ...> }
|  created class B

jshell> public class C extends A {
   ...>
   ...>  public C (int classSpecificInteger) {
   ...>
   ...>         super(classSpecificInteger);
   ...>  }
   ...> }
|  created class C

確保子類已初始化,我的意思是在訪問之前更新靜態地圖,否則 NPE

jshell> B.getClassSpecificInteger(B.class)
|  Exception java.lang.NullPointerException
|        at A.getClassSpecificInteger (#5:13)
|        at (#7:1)

現在初始化:

jshell> new B(10);
$8 ==> B@610694f1

jshell> new C(20)
$9 ==> C@50b494a6

現在靜態訪問它,子類中沒有 FIELD:

jshell> B.getClassSpecificInteger(B.class)
$10 ==> 10

jshell> A.getClassSpecificInteger(B.class)
$11 ==> 10

jshell> B.getClassSpecificInteger(C.class)
$12 ==> 20

這應該有效。

public class A {
public final int FIELD;
A(int a){
this.FIELD=a;
}
}
public class B extends A {
B(int a){
super(a);
}
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM