[英]What is a reasonable order of Java modifiers (abstract, final, public, static, etc.)?
[英]Why are Java primitive types' modifiers public, abstract, and final?
在對Java類型做一些反思的過程中,我遇到了一個我不明白的怪事。
檢查int
的修飾符會返回public
、 abstract
和final
。 我理解public
和final
,但是基本類型上的abstract
對我來說並不明顯。 為什么會這樣?
編輯:我不是在思考Integer
而是在int
:
import java.lang.reflect.Modifier;
public class IntegerReflection {
public static void main(final String[] args) {
System.out.println(String.format("int.class == Integer.class -> %b", int.class == Integer.class));
System.out.println(String.format("int.class modifiers: %s", Modifier.toString(int.class.getModifiers())));
System.out.println(String.format("Integer.class modifiers: %s", Modifier.toString(Integer.class.getModifiers())));
}
}
運行時的輸出:
int.class == Integer.class -> false
int.class modifiers: public abstract final
Integer.class modifiers: public final
抽象類是不完整或被認為不完整的類。
根據定義,不能有int.class
實例。 你不能編譯這種代碼:
int a = new int();
int
沒有構造函數。 沒有創建對象。 int.class
甚至不擴展Object
。 如果您運行以下代碼行,您將獲得null
作為結果。
System.out.println(int.class.getSuperclass());
所以因為你永遠不可能有一個真正的int.class
實例,它被定義為abstract
。 此外,根據Integer API , Integer.TYPE
字段(包含int.class
)是一個僅表示原始類型的類。
下面的代碼證明了這一點:
int a = 4;
System.out.println(int.class.isInstance(a));
這將返回false
。
因此, int.class
可能只是在系統中用於表示目的,如Integer
API 中所述。 還有一個void.class
類型但沒有null.class
類型這一事實讓我認為這主要用於反射。 不過,這只是猜測。
如果有人感興趣, int.class
基本上不包含反射包識別的任何內容,並且可能只是一個虛擬類。 如果運行以下代碼,您將看到它沒有構造函數、字段和方法。
Method[] intMethods = int.class.getMethods();
if(intMethods.length == 0) {
System.out.println("No methods.");
}
else {
for(Method method : intMethods) {
System.out.println(method.getName());
}
}
Constructor[] intConstructors = int.class.getConstructors();
if(intConstructors.length == 0) {
System.out.println("No constructors.");
}
else {
for(Constructor constructor: intConstructors) {
System.out.println(constructor.getName());
}
}
Field[] intFields = int.class.getFields();
if(intFields.length == 0) {
System.out.println("No fields.");
}
else {
for(Field field: intFields) {
System.out.println(field.getName());
}
}
如果你跑
System.out.println(Modifier.toString(int.class.getModifiers()));
你得到
public abstract final
可能是因為你不能對它進行子類化——即最終的,並且你不能實例化它——即抽象的。
來自 Oracle 的抽象方法和類
抽象類不能被實例化,但它們可以被子類化。
事實是它也最終意味着它不能是子類。
抽象類是不完整或被認為不完整的類。 只有抽象類才可能有抽象方法,即聲明了但尚未實現的方法。
如果一個類的定義是完整的並且不需要或不需要子類,則可以將其聲明為 final。 因為 final 類從來沒有任何子類,所以不能在子類中覆蓋 final 類的方法。 一個類不能既是最終的又是抽象的,因為這樣一個類的實現永遠不可能完成。
根據規范,一個類不能同時是 Abstract 和 Final。 但是,JVM 似乎沒有將原始類型視為類,這在技術上是正確的,因為原始類型不是類並且由 JVM 提供給語言運行時(使用Class getPrimitiveClass(const char *name)
)。
所以int
和其他所有原始類型,
> a. Should be accessible from within the language: Make it `public`
> b. Should not be extensible : Make it `final`
> c. Should not be instantiated with `new` : Make it `abstract`.
我從 JVM 規范中得出的關於原始類型為什么是abstract
是因為,它們被認為是不完整的。
也許這只是primitive class
不同於normal class
的特殊標記。
JVM代碼實現:
mirror::Class* ClassLinker::InitializePrimitiveClass(ObjPtr<mirror::Class> primitive_class,
Primitive::Type type) {
Handle<mirror::Class> h_class(hs.NewHandle(primitive_class));
// public final static
h_class->SetAccessFlags(kAccPublic | kAccFinal | kAccAbstract);
h_class->SetPrimitiveType(type);
h_class->SetIfTable(GetClassRoot(kJavaLangObject)->GetIfTable());
// ...
return h_class.Get();
}
為什么 Java 原始類型的修飾符是 public、abstract 和 final?
Class.getModifiers()
的 Java 11 javadoc指出:
如果底層類是數組類,則其
public
、private
和protected
修飾符與其組件類型的修飾符相同。 如果這個Class
表示一個基本類型或void
,其public
修飾符始終是真實的,它的protected
和private
修飾符始終為false。 如果此對象表示數組類、原始類型或void
,則其final
修飾符始終為 true,其interface
修飾符始終為 false。 它的其他修飾符的值不是由本規范確定的。
因此 javadoc 指定原始類型是public
和final
。 這很直觀。 這將是在這兩種情況下選擇的原因。
從技術上講,對原始類型進行abstract
是沒有意義的。 原始類型不是類,不能使用new
實例化。 然而,考慮到其他 Java API 的工作方式(例如反射方法查找),有必要擁有代表所有 Java 類型的Class
對象。 因此, Integer.TYPE
== int.class
和類似的需要存在。
無論如何,無論出於何種原因,規范對代表原始類型的Class
的abstract
修飾符說“未指定”。
但是, Class
修飾符表示為整數中的位,JVM 實現必須返回該整數中“抽象”位位置的值。 雖然根據規范,這兩種選擇(1 或 0)都沒有任何意義,但對於一位 Java 工程師(可能早在 1990 年代)來說,在原始類型情況下為位選擇2特定值比 / 更好1 (比如說)在運行時隨機返回 1 或 0。
所以底線是:
abstract
的選擇是(或可能是)完全任意的,所以不要賦予它任何意義。abstract
行為,那么理論上存在您的代碼將在 Java 的未來版本中崩潰的風險……如果他們改變了行為。 1 - 在我看來,它更好,因為對於Class
API 的用戶來說,確定性行為比非確定性行為更容易。 以這種方式實現它很可能更簡單。
2 - 我們很可能永遠不會確切知道為什么做出特定選擇。 也許有人扔了一枚硬幣? 沒關系。
如果您反映到從抽象類繼承的類中,然后嘗試挖掘該實例的基類,則在抽象類中定義為抽象的屬性將沒有價值,但它是類定義的一部分。
這是一個例子:
public class absBase{
private string name;
private int ID;
public abstract int GetID();
}
public class concreteClass:absBase{
@Override
public int GetID(){
return ID + 1;
}
}
因此,如果您正在反映 absBase,並查看 GetID,那么根據定義,它必須是抽象的,如果您查看creteClass.GetID(),但它是公開的。 希望有幫助。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.