2010-01-08 8 views
8

Ok, vậy đây là câu hỏi ... là từ khóa mới lỗi thời?Các đối tượng mới có lỗi thời không?

Hãy xem xét trong C# (và java, tôi tin) có các quy tắc nghiêm ngặt cho các loại. Các lớp là các kiểu tham chiếu và chỉ có thể được tạo trên heap. Các loại POD được tạo trên ngăn xếp; nếu bạn muốn phân bổ chúng trên heap, bạn phải đóng chúng trong một kiểu đối tượng. Trong C#, structs là ngoại lệ, chúng có thể được tạo trên ngăn xếp hoặc đống.

Với những quy tắc này, chúng tôi có phải sử dụng từ khóa mới không? Nó sẽ không có ý nghĩa đối với ngôn ngữ để sử dụng chiến lược phân bổ phù hợp dựa trên loại?

Ví dụ, chúng tôi hiện đang phải viết:

SomeClassType x = new SomeClassType(); 

thay vì

SomeClassType x = SomeClassType(); 

hoặc thậm chí chỉ

SomeClassType x; 

Trình biên dịch sẽ căn cứ vào đó loại được tạo ra là một kiểu tham chiếu, tiếp tục và cấp phát bộ nhớ cho x trên heap.

Điều này áp dụng cho các ngôn ngữ khác như ruby, php và cộng sự. C/C++ cho phép lập trình viên kiểm soát nhiều hơn đối tượng nơi được tạo ra, vì vậy nó có lý do chính đáng để yêu cầu từ khóa mới.

new chỉ là một sự nắm giữ từ di sản dựa trên thập niên 60 và C của chúng tôi?

+0

Và đây không phải là cộng đồng wiki vì ...? –

+0

Tôi không biết. Bạn có nghĩ rằng nó nên được? –

+1

Đây là một câu hỏi hoàn toàn hợp lệ. Và một điều tốt nữa. Không cần CW. – bsneeze

Trả lời

18
SomeClassType x = SomeClassType(); 

trong trường hợp này SomeClassType() có thể là một phương pháp nằm ở một nơi khác, làm thế nào sẽ trình biên dịch biết nên gọi phương thức này hoặc tạo ra một lớp mới.

SomeClassType x; 

Điều này không phải là rất hữu ích, hầu hết mọi người khai báo các biến của họ như thế này và đôi khi điền chúng sau này khi cần. Vì vậy, nó sẽ không hữu ích để tạo một thể hiện trong bộ nhớ mỗi khi bạn khai báo một biến.

+0

Đúng, nhưng bạn không thể giải quyết vấn đề này bằng cách đặt nó thành null? –

+2

@flyfish: Không phải nếu bạn muốn nó không thay đổi (tức là'final' trong Java hoặc các ngôn ngữ khác tương đương), khi đó bạn không thể gán bất cứ thứ gì khác cho nó sau này. –

+1

nếu anh ta thiết lập để null như thế nào ông sẽ xây dựng sau này? –

5

Đối với người mới bắt đầu:

SomeClassType x; 

không được khởi tạo vì vậy không nhớ nên được phân bổ.

Ngoài ra, làm cách nào để bạn tránh các sự cố khi có phương thức có cùng tên với lớp học.

Giả sử bạn viết một số mã:

int World() { return 3; } 

int hello = World(); 

và mọi thứ đều tốt đẹp và vui vẻ.

Bây giờ bạn viết một Class mới sau:

class World 
{ 
    ... 
} 

Đột nhiên dòng int hello = World() của bạn là mơ hồ.

+1

* Đột nhiên dòng int hello = World() của bạn là mơ hồ. * Không phải ngôn ngữ động (như python) có thể xử lý kịch bản này rất tốt, một ngôn ngữ được biên dịch nên ném một lỗi (giống như khi bạn tạo một phương thức đã được xác định) – OscarRyz

+0

Với sức mạnh của sự phản chiếu, tôi không nghĩ rằng đây là một vấn đề. C# có thể xác định sự khác biệt giữa một loại và một thể hiện của loại có cùng tên (mặc dù nó không phải là một điều tốt để làm!). Mặc dù nó sẽ dễ dàng cho trình biên dịch để tăng chẩn đoán trong trường hợp này –

+0

@Stan, trong ví dụ của tôi World() chỉ là một hàm trả về một int, vì vậy nó hoàn toàn hợp lệ. – tster

0

Nếu bạn không có một hàm tạo tham số, điều này có thể trở nên xấu xí.

Nếu bạn có nhiều nhà thầu, điều này có thể trở nên thực sự xấu xí.

1

Tôi đã lập trình với Java trong một số năm và tôi chưa bao giờ quan tâm nếu đối tượng của tôi nằm trên đống hay chồng. Từ quan điểm đó, tất cả đều giống với tôi để nhập new hoặc không nhập.

Tôi đoán điều này sẽ phù hợp hơn với các ngôn ngữ khác.

Điều duy nhất tôi quan tâm là lớp học có các hoạt động phù hợp và các đối tượng của tôi được tạo đúng cách.

BTW, tôi sử dụng (hoặc thử) để sử dụng các từ khóa new duy nhất trong nhà máy merthod nên khách hàng của tôi trông như thế này anyway

SomeClasType x = SomeClasType.newInstance(); 

Xem: Effective Java Item:1

+1

Các đối tượng Java không bao giờ nằm ​​trong ngăn xếp. – tster

+2

Trên thực tế, Hotspot VM có thể phân bổ các đối tượng trên stack như là một tối ưu hóa nếu, sau khi phân tích thoát, nó xác định nó là cục bộ cho một phương thức. Hotspot rất thông minh với những thứ như vậy, mặc dù lập trình viên không bao giờ thực sự phải quan tâm. –

+1

@Joe M: Yeap, đó là lý do tại sao chúng tôi phải đánh dấu là biến cuối cùng mà chúng tôi muốn truy cập từ các lớp bên trong. Nhưng đó là công việc biên dịch. – OscarRyz

16

phương pháp thứ ba của bạn sẽ không hoạt động, vì đôi khi chúng ta muốn định nghĩa một đối tượng của một kiểu và gán nó cho một biến kiểu khác. Ví dụ:

Stream strm = new NetworkStream(); 

Tôi muốn loại luồng (có thể truyền vào đâu đó), nhưng nội bộ tôi muốn loại NetworkStream.

Cũng nhiều lần tôi có thể tạo một đối tượng mới trong khi gọi một phương thức:

myobj.Foo(new NetworkStream()); 

làm điều đó theo cách này:

myobj.Foo(NetworkStream()); 

là rất khó hiểu. Tôi đang tạo một đối tượng hay gọi một phương thức khi tôi nói NetworkStream()?

+0

Điểm tốt. Tôi đã không cố gắng để trang trải tất cả các trường hợp sử dụng ở đây. Chỉ là một câu hỏi chung. –

+0

mục đích của việc này là gì? chỉ cần làm 'NetworkStream strm = new NetworkStream();' – tster

+0

Vâng, Stream strm = new NetworkStream() là một ví dụ xấu ... đây có lẽ là một ví dụ tốt hơn: Luồng [] streams = new Stream [2]; luồng [0] = new NetworkStream(); luồng [1] = new FileStream(); Xin lỗi vì định dạng crappy, tôi không thể tìm ra cách định dạng mã trong hộp nhận xét này. –

3

Vì lý do hiệu suất, điều này có thể là một ý tưởng tồi. Ví dụ, nếu bạn muốn có x là một tham chiếu cho một đối tượng đã được tạo, nó sẽ là một sự lãng phí bộ nhớ và thời gian xử lý để tạo ra một đối tượng mới sau đó ngay lập tức vứt bỏ nó.

6

Nếu bạn chỉ có thể viết SomeClassType x; và tự động khởi chạy, điều đó sẽ không cho phép các nhà thầu có bất kỳ thông số nào. Không phải mọi SomeClassType sẽ có một hàm tạo tham số; làm thế nào trình biên dịch sẽ biết những gì các đối số để cung cấp?

public class Repository 
{ 
    private IDbConnection connection; 

    public Repository(IDbConnection connection) 
    { 
     if (connection == null) 
     { 
      throw new ArgumentNullException("connection"); 
     } 
     this.connection = connection; 
    } 
} 

Làm thế nào bạn sẽ nhanh chóng đối tượng này chỉ với Repository rep;? Nó đòi hỏi một đối tượng phụ thuộc để hoạt động đúng.

Chưa kể, bạn có thể muốn viết mã như vậy:

Dictionary<int, SomeClass> instances = GetInstancesFromSomewhere(); 
SomeClass instance; 
if (instances.TryGetValue(1, out instance)) 
{ 
    // Do something 
} 

có bạn thực sự muốn nó tự động khởi tạo cho bạn?

Nếu bạn vừa viết SomeClassType x = SomeClassType() thì điều này không phân biệt giữa một hàm tạo và một phương thức trong phạm vi.

Tổng quát hơn:

Tôi nghĩ rằng có một sự hiểu lầm cơ bản của những gì từ khóa new là cho.Thực tế là các loại giá trị được phân bổ trên ngăn xếp và các loại "tham chiếu" được phân bổ trên đống là chi tiết triển khai . Từ khóa new là một phần của đặc điểm . Là một lập trình viên, bạn không quan tâm đến việc nó có được phân bổ trên heap hay stack (phần lớn thời gian) hay không, nhưng bạn cần phải chỉ định cách đối tượng được khởi tạo.

Có nhiều loại có giá trị khác của initializers quá, chẳng hạn như:

int[] values = { 1, 2, 3, 4 }; 

Thì đấy, một khởi với không new. Trong trường hợp này trình biên dịch đủ thông minh để tìm ra cho bạn bởi vì bạn đã cung cấp một biểu thức nghĩa đen định nghĩa toàn bộ đối tượng.

Vì vậy, tôi đoán "câu trả lời" của tôi là, đừng lo lắng về nơi đối tượng tồn tại trong trí nhớ; sử dụng từ khóa new như được dự định, làm trình khởi tạo đối tượng cho các đối tượng yêu cầu khởi tạo.

2

Sẽ không hợp lý đối với ngôn ngữ để sử dụng phân bổ thích hợp chiến lược dựa trên loại này?

Đó chính là điều mà trình biên dịch C#/thời gian chạy đã thực hiện. Từ khóa new chỉ là cú pháp để xây dựng một đối tượng theo bất kỳ cách nào có ý nghĩa đối với đối tượng đó.

Xóa từ khóa new sẽ làm cho nó ít rõ ràng hơn là một hàm tạo đang được gọi. Đối với một ví dụ tương tự, hãy xem xét out thông số:

myDictionary.TryGetValue(key, out val); 

Trình biên dịch đã biết rằng val là một out. Nếu bạn không nói như vậy, nó than phiền. Nhưng nó làm cho mã dễ đọc hơn để có nó nói.

Ít nhất, đó là sự biện minh - trong các IDE hiện đại, những thứ này có thể được tìm thấy và đánh dấu theo những cách khác ngoài văn bản được chèn vào thực tế.

Mới chỉ là điểm dừng từ sốvà di sản dựa trên C của chúng tôi?

Chắc chắn là không. C không có từ khóa new.