![](/img/trans.png)
[英]Why do you have to use .class in Java to get the Class object? Why not just the class name like in Ruby?
[英]Why do you name the class twice during instantiation in Java?
實例化一個對象時,為什么要指定類兩次?
OddEven number = new OddEven();
為什么你不能只說number = new OddEven();
? 當我聲明一個字符串時,我只說一次String
:
String str = "abc";
實際上,我的問題不是“你為什么要這樣做”——顯然,你這樣做是因為你必須這樣做——而是,為什么創造者選擇讓 Java 語法像這樣工作?
我的想法是:
因為你可以這樣做:
Superclass x = new Subclass();
引用的類型可以是所聲明的實際對象的超類,因此您需要同時指定兩者。 例如,您可以執行以下操作:
List<String> stringList = new ArrayList<String>();
您的程序與實現 List 的對象進行交互,而您並不關心實現。,
看似多余的類型名稱的原因是您正在執行兩個單獨的操作,每個操作都需要您指定一個類型。
在左側,您聲明了一個具有特定類型的變量(存儲位置)。 在右側,您正在創建具有特定類型的新對象。 中間的“=”會導致對您創建的新對象的引用放置在您創建的存儲位置中。
每邊的類型不必相同。 例如,這是合法代碼:
Object number = new OddEven();
關鍵字 String 在第二個示例中只出現一次的原因是右側隱含了類型 String,因為“xxx”是一個 String 常量。 它只是以下的簡寫:
String string = new String("xxx");
當你寫:
OddEven number = new OddEven();
實際上,你要做兩件事情:1)你聲明一個變量number
型OddEven
2)分配給類的新實例的引用OddEven
。 但是因為一個變量可以保存一個類型的任何子類型,所以寫作number = new OddEven();
編譯器知道number
變量的真實類型是不夠的。 所以,你也必須聲明它。 Java 是一種強類型語言,這意味着每個變量和每個表達式都有一個在編譯時已知的類型。 您可能需要閱讀整個第 4 章Java 語言規范 (JLS) 的類型、值和變量以了解更多信息。
現在,當你寫:
String str = "abc";
事情有點不同。 用雙引號括起來的字符,這里的"abc"
,被稱為字符串文字,它已經是對String
實例的引用,並且總是引用類String
的同一個實例。 引用 JLS 的第3.10.5節字符串文字:
每個字符串文字是基准(§4.3)到一個實例( 第4.3.1節, §12.5類的)
String
(§4.3.3) 。String
對象具有常量值。 字符串字面量——或者更一般地說,作為常量表達式值的字符串(第 15.28 節) ——被“ 嵌入”,以便使用String.intern
方法共享唯一的實例。
所以, String str = "abc";
肯定不是轉換成String str = new String("abc");
這絕對不等同於我在一些評論和答案中讀到的。 運行以下類:
public class Test {
public static void main(String[] args) {
String one = "abc";
String two = "abc";
String abc = new String("abc");
System.out.println(one == two);
System.out.println(one == abc);
}
}
產生以下輸出:
true
false
並演示了one
和two
是對同一個實例的引用,而abc
是對另一個實例的引用(即創建了一個額外的不必要的對象)。
實際上,使用new String(String)
是一種構建新字符串的低效方式,只能用於強制將子字符串復制到新的底層字符數組,如
String tiny = new String(monster.substring(10,20))
將“奇偶數”視為定義對象和“new OddEven();” 作為填充對象。
我不打算詳細介紹超類和子類,因為其他人已經解釋過了。
當您說String name = "foo"
,Java 編譯器內部會創建一個值為 "foo" 的 String 對象,並將其引用分配給name
變量。 因此,這里不是創建一個新的 String 對象,而是為另一個 String 對象分配一個引用。
順便說一句,編譯器無論如何都會為我們創建“foo”。 它首先在字符串池中查找,如果它不存在,則才創建“foo”。 否則,Compiler 從字符串池返回一個引用。 這是 Java 編譯器在內部執行的一些優化。
String name = "foo"
與 OddEvenNumber OddEvenNumber oddEven = anotherOddEvenObject;
數組示例:
聲明和初始化 - 當您知道數組的長度時:
int[] numberArray = new int[10];
聲明然后初始化 - 當您還不知道數組的長度並且可能從方法或用戶輸入中獲取它時
int[] numberArray;
int length = 10; // let’s say we got this from the user
numberArray = new int[length];
僅初始化 - 當您不需要重用時:
return new int[10];
第一個OddEven
是類型,第二個是實例。 它甚至不必是OddEven
,它可以是OddEven
任何子類。 這並不意味着您輸入了兩次。 任何 IDE 都有代碼模板,您只需在其中鍵入一次名稱。
第一個聲明是您想要在您擁有的范圍內使用的變量類型,在本例中是 OddEven,第二個聲明是用於實例化(在本例中初始化)引用的構造函數。
您可以說 INumberInstance = new OddEven(),其中 INumberInstance 是 OddEven 可以轉換到的某個類(例如 OddEven 的超類)。
在java中創建新對象的方法是:
Class_name reference_variable = new Class_name(param_if_any);
但字符串類是一個例外。
您可以創建一個新的字符串對象作為
String s = "abc";
或者
String s = new String("abc");
正如 Jim 所說,Java 是一種靜態類型語言。 這意味着每個變量都有一個在編譯時已知的類型。
例如:
public class A
{
public void foo() { }
}
public class B
{
public void foo() { }
}
public class Main
{
public static void main(final String[] argv)
{
A a = new A();
B b = new B();
a.foo();
b.foo();
}
}
編譯器查看 "a.foo()" 和 "b.foo()" 並檢查 a 是否屬於 A 類型,並且 A 有一個名為 "foo" 的方法,該方法不帶參數。 編譯器對“b.foo()”做同樣的事情。
如果你可以這樣寫 main:
public class Main
{
public static void main(final String[] argv)
{
a = new A(); // in Java you would really do Object a = new A();
b = new B(); // in Java you would really do Object b = new B();
a.foo();
b.foo();
}
}
那么編譯器就無法進行該驗證,並且必須在運行時進行。
的Java的設計者並沒有做語法冗余。 Scala是另一種使用 JVM 的語言,它也是靜態類型的。 Scala 使用類型推斷來減少冗長。 例如,這里有一個名為 x 的 MyPair 類型變量的聲明。 MyPair 將兩個變量相互關聯。 它是一個泛型類,因此您可以指定第一個變量的類型為 Int,第二個變量的類型為 String:
var x: MyPair[Int, String] = new MyPair[Int, String](1, "scala")
Scala 類型推斷允許您刪除冗余類型聲明:
var x = new MyPair[Int, String](1, "scala")
Scala 甚至根據構造函數參數推斷類型,所以你可以這樣寫:
var x = new MyPair(1, "scala")
考慮下面的例子,
我們可以指定對象類型如下,
List<String> abc;
在method1()中,如果你想使用最適合它要求的數組列表,那么我們可以像下面這樣實例化,
abc = new ArrayList<String>();
在method2()中,如果你想使用最適合它要求的Linked array list,那么我們可以像下面這樣實例化,
abc = new LinkedList<String>();
因此,我們的想法是我們可以指定“SuperClass”的類型,並在適當的操作中動態地使用適合不同要求的任何子類(例如“LinkedList”和“ArrayList”)進行實例化。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.