2009-12-24 37 views
11

Khi bạn khởi tạo một đối tượng, tại sao bạn chỉ định lớp hai lần?Tại sao bạn đặt tên cho lớp hai lần trong quá trình khởi tạo trong Java?

OddEven number = new OddEven(); 

Tại sao bạn không thể nói number = new OddEven();? Khi tôi tuyên bố một chuỗi, tôi chỉ nói một lần String:

String str = "abc"; 

Trên thực tế, câu hỏi của tôi không phải là "tại sao bạn làm điều đó theo cách này" - rõ ràng, bạn làm điều đó bởi vì bạn phải - nhưng đúng hơn, tại sao những người sáng tạo lại chọn làm cho cú pháp Java hoạt động như thế này?

những suy nghĩ của tôi là:

  1. Có gì đó cơ bản như cách Java hoạt động ở mức thấp mà âm nên cần gõ tên hai lần, hoặc
  2. Những người sáng tạo tự do lựa chọn để làm điều đó theo cách này để giữ một số khía cạnh của cú pháp thống nhất - khai báo kiểu đầu tiên? Hay nó giống như người tiền nhiệm của nó?
+1

Ví dụ chuỗi là thú vị, tôi tự hỏi nếu đó là ngôn ngữ ngữ nghĩa đường được thực hiện trong nền, chuyển đổi chuỗi str = "abc"; thành String str = new String ("abc"); – GrayWizardx

+3

GrayWizardx: Không. Bạn sẽ luôn nhận được chính xác cùng một đối tượng 'String' từ cùng một chuỗi ký tự (ngay cả khi chữ xuất hiện trong các tệp nguồn khác nhau). –

+0

Vâng nhưng. Tom đúng là bạn sẽ nhận được một đối tượng 'String' giống nhau, nhưng đó là hành vi cụ thể cho lớp String, và nó chỉ có thể bởi vì Strings không thay đổi được. Một ví dụ khác là 'int [] arr = {10, 20, 30};'. Tại chỗ mới. Nhưng thực sự là một, cú pháp khởi tạo chỉ là cú pháp để bạn không phải viết nó. –

Trả lời

43

Bởi vì bạn có thể làm điều này:

Superclass x = new Subclass(); 

Các loại tài liệu tham khảo có thể là một lớp cha của đối tượng thực tế được công bố, vì vậy bạn cần phải xác định cả hai. Ví dụ, bạn có thể làm:

List<String> stringList = new ArrayList<String>(); 

chương trình của bạn tương tác với các đối tượng mà thực hiện List, và bạn không quan tâm đến việc thực hiện,

+4

Để tăng cường hơn nữa nhận xét của Jim (đúng) - lý do bạn muốn sử dụng Superclass là vì bạn có thể lập trình cho giao diện. Bằng cách này, nếu một ArrayList là một lựa chọn tốt như một giao diện, nhưng sau đó, bạn tìm thấy một LinkedList là một lựa chọn tốt hơn, bạn có thể chuyển sang một LinkedList mà không phải thay đổi phần còn lại của ứng dụng của bạn. – JasCav

+1

JDK7 sẽ cho phép bạn viết 'Danh sách stringList = new ArrayList <>();'. Đó là một cải tiến nhỏ. –

+0

@Tom: Ah vâng, tôi đã nghe nói về điều đó - đó là về thời gian :-) –

0

Đầu tiên OddEven là loại, thứ hai là ví dụ.. Nó không cần thậm chí là OddEven, nó có thể là bất kỳ lớp con nào của OddEven. Nó không có nghĩa là bạn đã gõ nó hai lần. Bất kỳ IDE nào có các mẫu mã mà bạn chỉ phải nhập tên một lần.

+0

Cho dù bạn nhập nó hay IDE của bạn, nó vẫn đang được gõ. –

0

Khai báo đầu tiên là kiểu biến bạn muốn sử dụng trong phạm vi bạn có, trong trường hợp này là OddEven, khai báo thứ hai là hàm tạo để sử dụng cho việc khởi tạo (và trong trường hợp này khởi tạo) tham chiếu.

Bạn có thể đã nói INumberInstance = new OddEven(), trong đó INumberInstance là một số lớp mà OddEven có thể được truyền tới (ví dụ như một siêu OddEven).

0

Cách để tạo ra một đối tượng mới trong java là:

Class_name reference_variable = new Class_name(param_if_any); 

Nhưng lớp chuỗi là một ngoại lệ.

Bạn có thể tạo một đối tượng chuỗi mới như

String s = "abc"; 

hoặc

String s = new String("abc"); 
5

Lý do cho tên loại dường như không cần thiết là bạn đang thực hiện hai hoạt động riêng biệt, mỗi trong số đó đòi hỏi bạn phải chỉ định một loại.

Ở bên trái, bạn đang khai báo biến (vị trí lưu trữ) với một loại cụ thể.Ở bên phải, bạn đang tạo một đối tượng mới với một kiểu cụ thể. Các '=' ở giữa gây ra một tham chiếu đến đối tượng mới mà bạn tạo ra được đặt ở vị trí lưu trữ mà bạn đã tạo.

Các loại ở mỗi bên không nhất thiết phải giống nhau. Này, ví dụ, là mã quy phạm pháp luật:

Object number = new OddEven(); 

Lý do mà các chuỗi từ khóa chỉ xuất hiện một lần trong ví dụ thứ hai của bạn là kiểu String được ám chỉ ở phía bên tay phải vì "xxx" là một chuỗi liên tục . Nó chỉ đơn giản là viết tắt của:

String string = new String("xxx"); 
+0

Ooops ... có nghĩa là "Chuỗi chuỗi = chuỗi mới (" xxx ") trong dòng mã cuối cùng của tôi ở trên. – Steve

+0

@Steve: sửa nó cho bạn –

0

Ngoài những gì Jim nói, Java là ngôn ngữ được nhập tĩnh. Điều đó có nghĩa là mọi biến thể đều có một kiểu biết tại thời gian biên dịch.

Ví dụ:

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(); 
    } 
} 

trình biên dịch nhìn "a.foo()" và "b.foo()" và kiểm tra để thấy rằng một là loại A và A có một phương pháp gọi là " foo "không có đối số. Trình biên dịch thực hiện tương tự cho "b.foo()".

Nếu bạn có thể viết chính như thế này:

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(); 
    } 
} 

sau đó trình biên dịch không thể làm xác minh điều đó và nó sẽ phải xảy ra khi chạy.

0

Hãy suy nghĩ về 'số OddEven' như xác định đối tượng và 'OddEven mới();' làm đầy vật thể.

Tôi sẽ không đi sâu vào chi tiết về các lớp cha và lớp con vì người khác đã giải thích nó rồi.

0

Các nhà thiết kế của Java không để làm cho cú pháp thừa. Scala là một ngôn ngữ khác sử dụng JVM và nó cũng được nhập tĩnh. Scala sử dụng loại hội nghị để cắt giảm độ dài. Ví dụ, đây là một khai báo của một biến kiểu MyPair được gọi là x. MyPair kết hợp hai biến với nhau. Đó là một lớp học chung, vì vậy bạn có thể chỉ định các biến đầu tiên có kiểu Int và thứ hai kiểu String:

var x: MyPair[Int, String] = new MyPair[Int, String](1, "scala") 

Scala loại suy luận cho phép bạn loại bỏ các khai báo kiểu dư thừa:

var x = new MyPair[Int, String](1, "scala") 

Và Scala thậm chí suy luận loại dựa trên các đối số nhà xây dựng, vì vậy bạn có thể viết nó theo cách này:

var x = new MyPair(1, "scala") 
4

Khi bạn viết:

OddEven number = new OddEven(); 

Bạn thực sự làm hai việc: 1) bạn khai báo một biến number loại OddEven 2) bạn gán một tham chiếu đến một thể hiện mới của lớp OddEven. Nhưng vì một biến có thể chứa bất kỳ kiểu con nào của một kiểu, việc viết number = new OddEven(); sẽ không đủ để trình biên dịch biết loại thực của biến số number. Vì vậy, bạn phải khai báo nó quá.Java là ngôn ngữ được nhập mạnh mẽ, có nghĩa là mọi biến và mọi biểu thức đều có loại được biết tại thời gian biên dịch. Bạn có thể muốn đọc toàn bộ số Chapter 4. Types, Values, and Variables của Đặc tả Ngôn ngữ Java (JLS) để tìm hiểu thêm về điều này.

Bây giờ, khi bạn viết:

String str = "abc"; 

Mọi thứ một chút khác nhau. Các ký tự được kèm theo dấu ngoặc kép, "abc" tại đây, được gọi là chuỗi ký tự đã được tham chiếu đến một phiên bản String và luôn đề cập đến cùng một phiên bản của lớp String. Trích dẫn phần 3.10.5 String Literals của JLS:

Mỗi chuỗi chữ là một tài liệu tham khảo (§4.3) đến một instance (§4.3.1, §12.5) của lớp String(§4.3.3). String đối tượng có giá trị không đổi. Chuỗi literals-hay, tổng quát hơn, chuỗi đó là những giá trị của hằng số biểu (§15.28) -Bạn "thực tập nội trú" để chia sẻ độc đáo trường hợp, sử dụng phương pháp String.intern.

Vì vậy, String str = "abc"; chắc chắn không được chuyển đổi thành String str = new String("abc"); hoàn toàn không tương đương như tôi đã đọc trong một số nhận xét và câu trả lời. Chạy lớp sau:

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); 
    } 
} 

Tạo đầu ra dưới đây:

true 
false 

Và chứng tỏ rằng onetwo được tham chiếu đến các trường hợp tương tự nhưng mà abc là một tham chiếu đến khác dụ (ví dụ một thêm đối tượng không cần thiết đã được tạo).

Trên thực tế, sử dụng new String(String) là một cách hiệu quả để xây dựng chuỗi mới và chỉ nên được sử dụng để buộc một chuỗi sao chép vào một mảng ký tự cơ bản mới, như trong

String tiny = new String(monster.substring(10,20)) 
+0

Có một sự tinh tế để sử dụng' Chuỗi mới (Chuỗi) '; xem http : //stackoverflow.com/a/390854/8946. –

0

Khi bạn nói String name = "foo", nội Java trình biên dịch tạo ra một đối tượng String với giá trị "foo" và nó gán tham chiếu của nó cho biến số name. Vì vậy, ở đây thay vì tạo một đối tượng String mới, chúng ta đang gán một tham chiếu đến đối tượng String khác.

Btw, trình biên dịch sẽ tạo "foo" cho chúng tôi. Đầu tiên nó trông trong String Pool, nếu nó không tồn tại, chỉ sau đó nó tạo ra "foo". Nếu không, Compiler trả về một tham chiếu từ String pool. Đây là một số tối ưu hóa mà trình biên dịch Java thực hiện trong nội bộ.

String name = "foo" là simlar để OddEvenNumber oddEven = anotherOddEvenObject;

0

Hãy xem xét ví dụ sau,

Chúng ta có thể xác định loại đối tượng như sau,

List<String> abc; 

Trong method1(), nếu bạn muốn sử dụng array list phù hợp nhất với yêu cầu đó, sau đó chúng tôi có thể khởi tạo như sau,

abc = new ArrayList<String>(); 

Trong method2(), nếu bạn muốn sử dụng danh sách mảng liên kết mà phù hợp nhất cho nó yêu cầu thì chúng ta có thể nhanh chóng như như sau,

abc = new LinkedList<String>(); 

Vì vậy, ý tưởng là chúng ta có thể xác định loại " SuperClass "và khởi tạo với bất kỳ lớp con nào phù hợp với các yêu cầu khác nhau như" LinkedList "và" ArrayList "trong hoạt động thích hợp một cách linh hoạt.

Các vấn đề liên quan