it-swarm-vi.tech

Tại sao Java không cung cấp quá tải toán tử?

Đến từ C++ sang Java, câu hỏi chưa được trả lời rõ ràng là tại sao Java không bao gồm quá tải toán tử?

Không phải Complex a, b, c; a = b + c; đơn giản hơn nhiều so với Complex a, b, c; a = b.add(c); sao?

Có một lý do đã biết cho điều này, các đối số hợp lệ cho không cho phép quá tải toán tử không? Là lý do tùy tiện, hoặc mất thời gian?

375
rengolin

Giả sử bạn muốn ghi đè giá trị trước đó của đối tượng được gọi bởi a, thì một hàm thành viên sẽ phải được gọi.

Complex a, b, c;
// ...
a = b.add(c);

Trong C++, biểu thức này báo cho trình biên dịch tạo ba (3) đối tượng trên ngăn xếp, thực hiện phép cộng và sao chép giá trị kết quả từ đối tượng tạm thời vào đối tượng hiện có a.

Tuy nhiên, trong Java, operator= không thực hiện sao chép giá trị cho các loại tham chiếu và người dùng chỉ có thể tạo các loại tham chiếu mới, không phải các loại giá trị. Vì vậy, đối với loại do người dùng xác định có tên Complex, gán có nghĩa là sao chép tham chiếu đến giá trị hiện có.

Thay vào đó hãy xem xét:

b.set(1, 0); // initialize to real number '1'
a = b; 
b.set(2, 0);
assert( !a.equals(b) ); // this assertion will fail

Trong C++, điều này sao chép giá trị, do đó so sánh sẽ cho kết quả không bằng nhau. Trong Java, operator= thực hiện sao chép tham chiếu, vì vậy ab hiện đang đề cập đến cùng một giá trị. Kết quả là, so sánh sẽ tạo ra 'bằng', vì đối tượng sẽ so sánh bằng chính nó.

Sự khác biệt giữa các bản sao và tài liệu tham khảo chỉ làm tăng thêm sự nhầm lẫn của quá tải toán tử. Như @Sebastian đã đề cập, cả Java và C # đều phải xử lý riêng biệt giá trị và tham chiếu tham chiếu - operator+ có thể sẽ xử lý các giá trị và đối tượng, nhưng operator= đã được triển khai để xử lý các tham chiếu.

Trong C++, bạn chỉ nên xử lý một loại so sánh tại một thời điểm, vì vậy nó có thể ít gây nhầm lẫn hơn. Ví dụ: trên Complex, operator=operator== đều hoạt động trên các giá trị - sao chép giá trị và so sánh giá trị tương ứng.

17
Aaron

Có rất nhiều bài viết phàn nàn về quá tải nhà điều hành.

Tôi cảm thấy tôi phải làm rõ các khái niệm "quá tải toán tử", đưa ra một quan điểm thay thế cho khái niệm này.

Mã che giấu?

Lập luận này là một ngụy biện.

Obfuscating là có thể trong tất cả các ngôn ngữ ...

Thật dễ dàng để làm xáo trộn mã trong C hoặc Java thông qua các hàm/phương thức như trong C++ thông qua quá tải toán tử:

// C++
T operator + (const T & a, const T & b) // add ?
{
   T c ;
   c.value = a.value - b.value ; // subtract !!!
   return c ;
}

// Java
static T add (T a, T b) // add ?
{
   T c = new T() ;
   c.value = a.value - b.value ; // subtract !!!
   return c ;
}

/* C */
T add (T a, T b) /* add ? */
{
   T c ;
   c.value = a.value - b.value ; /* subtract !!! */
   return c ;
}

... Ngay cả trong các giao diện chuẩn của Java

Đối với một ví dụ khác, chúng ta hãy xem giao diện CloneableNAME_ trong Java:

Bạn có nghĩa vụ sao chép đối tượng thực hiện giao diện này. Nhưng bạn có thể nói dối. Và tạo ra một đối tượng khác nhau. Trên thực tế, giao diện này yếu đến mức bạn có thể trả lại một loại đối tượng khác hoàn toàn, chỉ để cho vui:

class MySincereHandShake implements Cloneable
{
    public Object clone()
    {
       return new MyVengefulKickInYourHead() ;
    }
}

Vì giao diện Cloneablecó thể bị lạm dụng/bị xáo trộn, nên nó có bị cấm trên cùng một lý do quá tải toán tử C++ không?

Chúng ta có thể quá tải phương thức toString() của lớp MyComplexNumberđể nó trả về giờ được xâu chuỗi trong ngày. Có nên cấm quá tải toString() không? Chúng ta có thể phá hoại MyComplexNumber.equals để nó trả về một giá trị ngẫu nhiên, sửa đổi các toán hạng ... vv, v.v.

Trong Java, như trong C++, hoặc bất kỳ ngôn ngữ nào, lập trình viên phải tôn trọng tối thiểu ngữ nghĩa khi viết mã. Điều này có nghĩa là triển khai hàm addbổ sung và phương thức triển khai Cloneablenhân bản và toán tử ++ so với gia số.

Cái gì đang xáo trộn?

Bây giờ chúng ta biết rằng mã có thể bị phá hoại ngay cả thông qua các phương thức Java nguyên sơ, chúng ta có thể tự hỏi về việc sử dụng thực sự của quá tải toán tử trong C++ không?

Ký hiệu rõ ràng và tự nhiên: phương pháp so với quá tải toán tử?

Chúng ta sẽ so sánh bên dưới, đối với các trường hợp khác nhau, mã "giống nhau" trong Java và C++, để có ý tưởng về kiểu mã hóa nào rõ ràng hơn.

So sánh tự nhiên:

// C++ comparison for built-ins and user-defined types
bool    isEqual          = A == B ;
bool    isNotEqual       = A != B ;
bool    isLesser         = A <  B ;
bool    isLesserOrEqual  = A <= B ;

// Java comparison for user-defined types
boolean isEqual          = A.equals(B) ;
boolean isNotEqual       = ! A.equals(B) ;
boolean isLesser         = A.comparesTo(B) < 0 ;
boolean isLesserOrEqual  = A.comparesTo(B) <= 0 ;

Xin lưu ý rằng A và B có thể thuộc bất kỳ loại nào trong C++, miễn là quá tải toán tử được cung cấp. Trong Java, khi A và B không phải là nguyên thủy, mã có thể trở nên rất khó hiểu, ngay cả đối với các đối tượng giống như nguyên thủy (BigInteger, v.v.) ...

Bộ truy cập mảng/container tự nhiên và đăng ký:

// C++ container accessors, more natural
value        = myArray[25] ;         // subscript operator
value        = myVector[25] ;        // subscript operator
value        = myString[25] ;        // subscript operator
value        = myMap["25"] ;         // subscript operator
myArray[25]  = value ;               // subscript operator
myVector[25] = value ;               // subscript operator
myString[25] = value ;               // subscript operator
myMap["25"]  = value ;               // subscript operator

// Java container accessors, each one has its special notation
value        = myArray[25] ;         // subscript operator
value        = myVector.get(25) ;    // method get
value        = myString.charAt(25) ; // method charAt
value        = myMap.get("25") ;     // method get
myArray[25]  = value ;               // subscript operator
myVector.set(25, value) ;            // method set
myMap.put("25", value) ;             // method put

Trong Java, chúng ta thấy rằng đối với mỗi container để làm điều tương tự (truy cập nội dung của nó thông qua một chỉ mục hoặc mã định danh), chúng ta có một cách khác nhau để làm điều đó, điều này gây nhầm lẫn.

Trong C++, mỗi container sử dụng cùng một cách để truy cập nội dung của nó, nhờ quá tải toán tử.

Thao tác tự nhiên tiên tiến

Các ví dụ bên dưới sử dụng một đối tượng Matrixname__, được tìm thấy bằng cách sử dụng các liên kết đầu tiên được tìm thấy trên Google cho " đối tượng ma trận Java " và " đối tượng ma trận c ++ ":

// C++ YMatrix matrix implementation on CodeProject
// http://www.codeproject.com/KB/architecture/ymatrix.aspx
// A, B, C, D, E, F are Matrix objects;
E =  A * (B / 2) ;
E += (A - B) * (C + D) ;
F =  E ;                  // deep copy of the matrix

// Java JAMA matrix implementation (seriously...)
// http://math.nist.gov/javanumerics/jama/doc/
// A, B, C, D, E, F are Matrix objects;
E = A.times(B.times(0.5)) ;
E.plusEquals(A.minus(B).times(C.plus(D))) ;
F = E.copy() ;            // deep copy of the matrix

Và điều này không giới hạn trong ma trận. Các lớp BigIntegerBigDecimalcủa Java chịu cùng độ dài khó hiểu, trong khi các loại tương đương của chúng trong C++ rõ ràng như các loại tích hợp.

Lặp đi lặp lại tự nhiên:

// C++ Random Access iterators
++it ;                  // move to the next item
--it ;                  // move to the previous item
it += 5 ;               // move to the next 5th item (random access)
value = *it ;           // gets the value of the current item
*it = 3.1415 ;          // sets the value 3.1415 to the current item
(*it).foo() ;           // call method foo() of the current item

// Java ListIterator<E> "bi-directional" iterators
value = it.next() ;     // move to the next item & return the value
value = it.previous() ; // move to the previous item & return the value
it.set(3.1415) ;        // sets the value 3.1415 to the current item

Functor tự nhiên:

// C++ Functors
myFunctorObject("Hello World", 42) ;

// Java Functors ???
myFunctorObject.execute("Hello World", 42) ;

Nối văn bản:

// C++ stream handling (with the << operator)
                    stringStream   << "Hello " << 25 << " World" ;
                    fileStream     << "Hello " << 25 << " World" ;
                    outputStream   << "Hello " << 25 << " World" ;
                    networkStream  << "Hello " << 25 << " World" ;
anythingThatOverloadsShiftOperator << "Hello " << 25 << " World" ;

// Java concatenation
myStringBuffer.append("Hello ").append(25).append(" World") ;

Ok, trong Java bạn có thể sử dụng MyString = "Hello " + 25 + " World" ; quá ... Nhưng, đợi một chút: Đây là quá tải toán tử, phải không? Không phải là gian lận sao?

: -D

Mã chung?

Các toán hạng sửa đổi mã chung giống nhau phải có thể sử dụng được cho cả các hàm dựng sẵn/nguyên thủy (không có giao diện trong Java), các đối tượng tiêu chuẩn (không thể có giao diện phù hợp) và các đối tượng do người dùng định nghĩa.

Ví dụ: tính giá trị trung bình của hai giá trị của các loại tùy ý:

// C++ primitive/advanced types
template<typename T>
T getAverage(const T & p_lhs, const T & p_rhs)
{
   return (p_lhs + p_rhs) / 2 ;
}

int     intValue     = getAverage(25, 42) ;
double  doubleValue  = getAverage(25.25, 42.42) ;
complex complexValue = getAverage(cA, cB) ; // cA, cB are complex
Matrix  matrixValue  = getAverage(mA, mB) ; // mA, mB are Matrix

// Java primitive/advanced types
// It won't really work in Java, even with generics. Sorry.

Thảo luận về quá tải toán tử

Bây giờ chúng ta đã thấy các so sánh công bằng giữa mã C++ khi sử dụng nạp chồng toán tử và cùng mã trong Java, bây giờ chúng ta có thể thảo luận về "quá tải toán tử" như là một khái niệm.

Quá tải toán tử tồn tại từ trước khi máy tính

Ngay cả ngoài khoa học máy tính, có quá tải toán tử: Ví dụ, trong toán học, các toán tử như +, -, *, v.v. bị quá tải.

Thật vậy, việc biểu thị +, -, *, v.v. thay đổi tùy thuộc vào các loại toán hạng (số, vectơ, hàm sóng lượng tử, ma trận, v.v.).

Hầu hết chúng ta, như một phần của các khóa học khoa học, đã học được nhiều ý nghĩa cho các toán tử, tùy thuộc vào các loại toán hạng. Chúng tôi đã tìm thấy chúng khó hiểu, họ?

Quá tải toán tử phụ thuộc vào toán hạng của nó

Đây là phần quan trọng nhất của quá tải toán tử: Giống như trong toán học hoặc trong vật lý, phép toán phụ thuộc vào các kiểu toán hạng của nó.

Vì vậy, biết loại toán hạng, và bạn sẽ biết hiệu quả của hoạt động.

Ngay cả C và Java cũng có quá tải toán tử (mã hóa cứng)

Trong C, hành vi thực của toán tử sẽ thay đổi theo toán hạng của nó. Ví dụ: thêm hai số nguyên khác với việc thêm hai số nhân, hoặc thậm chí một số nguyên và một số nguyên. Thậm chí còn có toàn bộ miền số học con trỏ (không cần truyền, bạn có thể thêm vào con trỏ một số nguyên, nhưng bạn không thể thêm hai con trỏ ...).

Trong Java, không có số học con trỏ, nhưng ai đó vẫn tìm thấy nối chuỗi mà không có toán tử + sẽ đủ lố bịch để biện minh cho một ngoại lệ trong tín hiệu "quá tải toán tử là xấu".

Chỉ là bạn, với tư cách là C (vì lý do lịch sử) hoặc Java (cho lý do cá nhân, xem bên dưới) coder, bạn không thể cung cấp của riêng bạn.

Trong C++, quá tải toán tử không phải là tùy chọn ...

Trong C++, quá tải toán tử cho các kiểu dựng sẵn là không thể (và đây là một điều tốt), nhưng đã xác định người dùng loại có thể có đã xác định người dùng Vận hành quá tải.

Như đã nói trước đó, trong C++ và ngược lại với Java, các kiểu người dùng không được coi là công dân hạng hai của ngôn ngữ, khi so sánh với các loại tích hợp. Vì vậy, nếu các loại tích hợp có toán tử, các loại người dùng cũng có thể có chúng.

Sự thật là, giống như các phương thức toString(), clone(), equals() dành cho Java (tức là gần giống như tiêu chuẩn), Quá tải toán tử C++ là một phần của C++ đến mức nó trở nên tự nhiên như các toán tử C gốc hoặc các phương thức Java đã đề cập trước đó.

Kết hợp với lập trình mẫu, quá tải toán tử trở thành một mẫu thiết kế nổi tiếng. Trong thực tế, bạn không thể đi rất xa trong STL mà không sử dụng các toán tử quá tải và các toán tử quá tải cho lớp của riêng bạn.

... nhưng nó không nên bị lạm dụng

Quá tải toán tử nên cố gắng tôn trọng ngữ nghĩa của toán tử. Không được trừ trong toán tử + (như trong "không trừ trong hàm addname__" hoặc "trả về crap trong phương thức clonename__").

Quá tải diễn viên có thể rất nguy hiểm vì chúng có thể dẫn đến sự mơ hồ. Vì vậy, họ thực sự nên được dành riêng cho các trường hợp được xác định rõ. Đối với &&||, đừng bao giờ làm quá tải chúng trừ khi bạn thực sự biết bạn đang làm gì, vì bạn sẽ mất đánh giá ngắn mạch mà các nhà khai thác gốc &&|| thưởng thức.

Vậy ... Ok ... Vậy tại sao Java không thể?

Bởi vì James Gosling đã nói như vậy:

Tôi rời khỏi quá tải toán tử như là một lựa chọn khá cá nhân bởi vì tôi đã thấy quá nhiều người lạm dụng nó trong C++.

James Gosling. Nguồn: http://www.gotw.ca/publications/c_family_interview.htmlm

Vui lòng so sánh văn bản của Gosling ở trên với Stroustrup dưới đây:

Nhiều quyết định thiết kế C++ bắt nguồn từ việc tôi không thích ép buộc mọi người thực hiện mọi thứ theo một cách đặc biệt nào đó [...] Thông thường, tôi bị cám dỗ để vi phạm một tính năng mà cá nhân tôi không thích, tôi đã từ chối vì tôi Tôi không nghĩ mình có quyền ép buộc quan điểm của mình về người khác.

Bjarne Stroustrup. Nguồn: Sự khao khát và tiến hóa của C++ (Nền tảng chung 1.3)

Toán tử quá tải sẽ có lợi cho Java?

Một số đối tượng sẽ được hưởng lợi rất nhiều từ quá tải toán tử (các loại cụ thể hoặc số, như BigDecimal, số phức, ma trận, container, iterator, bộ so sánh, bộ phân tích cú pháp, v.v.).

Trong C++, bạn có thể kiếm lợi từ lợi ích này nhờ sự khiêm tốn của Stroustrup. Trong Java, bạn chỉ đơn giản là say sưa vì của Gosling lựa chọn cá nhân.

Nó có thể được thêm vào Java?

Các lý do không thêm quá tải toán tử trong Java có thể là sự pha trộn của chính trị nội bộ, dị ứng với tính năng, mất lòng tin của các nhà phát triển (bạn biết, những kẻ phá hoại dường như ám ảnh Java các nhóm ...), khả năng tương thích với các JVM trước đó, thời gian để viết một đặc tả chính xác, v.v.

Vì vậy, đừng nín thở chờ đợi tính năng này ...

Nhưng họ làm điều đó trong C # !!!

Ừ ...

Mặc dù đây không phải là sự khác biệt duy nhất giữa hai ngôn ngữ, nhưng ngôn ngữ này không bao giờ làm tôi buồn cười.

Rõ ràng, những người C #, với họ "mọi nguyên thủy là một structvà một structxuất phát từ Object", có nó ngay lần thử đầu tiên.

Và họ làm điều đó trong các ngôn ngữ khác !!!

Mặc dù tất cả FUD chống lại quá tải toán tử được xác định đã sử dụng, các ngôn ngữ sau hỗ trợ nó: Scala , Dart , Python , F # =, C # , D , ALGOL 68 , Smalltalk , Groovy , Perl 6 , C++, Ruby , Haskell , MATLAB , Eiffel , Lua , Clojure , Fortran 9 , Swift , Ada , Delphi 2005 ...

Rất nhiều ngôn ngữ, với rất nhiều triết lý khác nhau (và đôi khi đối lập), và tất cả chúng đều đồng ý về điểm đó.

Thức ăn cho suy nghĩ ...

760
paercebal

James Gosling thích thiết kế Java như sau:

"Có nguyên tắc này về việc di chuyển, khi bạn chuyển từ căn hộ này sang căn hộ khác. Một thử nghiệm thú vị là đóng gói căn hộ của bạn và đặt mọi thứ vào hộp, sau đó chuyển sang căn hộ tiếp theo và không giải nén bất cứ thứ gì cho đến khi bạn cần. Vì vậy, bạn ' Đang làm bữa ăn đầu tiên của bạn, và bạn đang lấy thứ gì đó ra khỏi hộp. Sau một tháng, bạn đã sử dụng nó để tìm ra những thứ trong cuộc sống mà bạn thực sự cần, và sau đó bạn lấy phần còn lại của công cụ - quên đi bạn thích nó hay nó tuyệt đến mức nào - và bạn chỉ cần vứt nó đi. Thật đáng kinh ngạc khi nó đơn giản hóa cuộc sống của bạn và bạn có thể sử dụng nguyên tắc đó trong tất cả các loại vấn đề thiết kế: không làm mọi thứ chỉ vì chúng Thật tuyệt hoặc chỉ vì chúng thú vị. "

Bạn có thể đọc bối cảnh của trích dẫn ở đây

Về cơ bản, quá tải toán tử là tuyệt vời cho một lớp mô hình một số loại điểm, tiền tệ hoặc số phức. Nhưng sau đó bạn bắt đầu chạy ra khỏi các ví dụ nhanh.

Một yếu tố khác là sự lạm dụng tính năng trong C++ bởi các nhà phát triển làm quá tải các toán tử như '&&', '||', các toán tử cast và tất nhiên là 'mới'. Sự phức tạp do kết hợp điều này với việc vượt qua giá trị và các ngoại lệ được đề cập rất rõ trong C++ cuốn sách.

39
Garth Gilmour

Kiểm tra Boost.Units: liên kết văn bản

Nó cung cấp phân tích thứ nguyên không chi phí thông qua quá tải toán tử. Điều này có thể rõ ràng hơn bao nhiêu?

quantity<force>     F = 2.0*newton;
quantity<length>    dx = 2.0*meter;
quantity<energy>    E = F * dx;
std::cout << "Energy = " << E << endl;

thực sự sẽ tạo ra "Năng lượng = 4 J" là chính xác.

20
user15793

Các nhà thiết kế Java đã quyết định rằng quá tải toán tử là rắc rối hơn giá trị của nó. Đơn giản như vậy.

Trong một ngôn ngữ mà mọi biến đối tượng thực sự là một tham chiếu, quá tải toán tử sẽ có thêm nguy cơ là khá phi logic - ít nhất là đối với một lập trình viên C++. So sánh tình huống với quá tải toán tử = # của C # và Object.EqualsObject.ReferenceEquals (hoặc bất cứ điều gì nó được gọi).

11
Sebastian Redl

Groovy có quá tải toán tử và chạy trong JVM. Nếu bạn không quan tâm đến hiệu suất (sẽ trở nên nhỏ hơn mỗi ngày). Nó tự động dựa trên tên phương thức. ví dụ: '+' gọi phương thức 'cộng (đối số)'.

8
noah

Tôi nghĩ rằng đây có thể là một lựa chọn thiết kế có ý thức để buộc các nhà phát triển tạo ra các chức năng có tên rõ ràng truyền đạt ý định của họ. Trong C++, các nhà phát triển sẽ quá tải các toán tử với chức năng thường không liên quan đến bản chất thường được chấp nhận của toán tử đã cho, khiến cho việc xác định một đoạn mã làm gì mà không nhìn vào định nghĩa của toán tử là gần như không thể.

6
user14128

Vâng, bạn thực sự có thể tự bắn vào chân mình với quá tải toán tử. Nó giống như với con trỏ, mọi người phạm sai lầm ngu ngốc với họ và vì vậy nó đã quyết định lấy cái kéo đi.

Ít nhất tôi nghĩ đó là lý do . Dù sao tôi cũng đứng về phía bạn. :)

5
Sarien

Về mặt kỹ thuật, có quá tải toán tử trong mọi ngôn ngữ lập trình có thể xử lý các loại số khác nhau, ví dụ: số nguyên và số thực. Giải thích: Thuật ngữ quá tải có nghĩa là chỉ đơn giản là có một vài triển khai cho một chức năng. Trong hầu hết các ngôn ngữ lập trình, các triển khai khác nhau được cung cấp cho toán tử +, một cho số nguyên, một cho số thực, đây được gọi là nạp chồng toán tử.

Bây giờ, nhiều người thấy lạ khi Java có quá tải toán tử cho toán tử + để thêm các chuỗi lại với nhau và theo quan điểm toán học thì điều này thực sự lạ, nhưng nhìn từ quan điểm của nhà phát triển ngôn ngữ lập trình, không có gì sai khi thêm quá trình toán tử dựng sẵn cho toán tử + cho các lớp khác, vd Chuỗi. Tuy nhiên, hầu hết mọi người đồng ý rằng một khi bạn thêm nạp chồng cho + cho Chuỗi, thì nói chung cũng là một ý tưởng tốt để cung cấp chức năng này cho nhà phát triển.

Một sự hoàn toàn không đồng ý với sai lầm rằng toán tử quá tải mã làm xáo trộn, vì điều này được để lại cho nhà phát triển quyết định. Điều này là ngây thơ để suy nghĩ, và thành thật mà nói, nó đang già đi.

+1 để thêm quá tải toán tử trong Java 8.

4
Olai

Nói rằng quá tải toán tử dẫn đến các lỗi logic loại mà toán tử không khớp với logic hoạt động, nó giống như không nói gì. Loại lỗi tương tự sẽ xảy ra nếu tên hàm không phù hợp với logic hoạt động - vậy giải pháp là gì: giảm khả năng sử dụng chức năng!? Đây là một câu trả lời hài hước - "Không phù hợp với logic hoạt động", mọi tên tham số, mọi lớp, chức năng hoặc bất cứ điều gì có thể không phù hợp về mặt logic . không an toàn - hey không có cả hai nói rằng bạn phải sử dụng nó. Hãy lấy C #. Họ rủ rê con trỏ nhưng hey - có tuyên bố 'mã không an toàn' - lập trình theo ý bạn có thể tự chịu rủi ro.

4
Kvant

Một số người nói rằng quá tải toán tử trong Java sẽ dẫn đến sự ám ảnh. Có bao giờ những người đó dừng lại để xem một số mã Java đang thực hiện một số phép toán cơ bản như tăng giá trị tài chính theo tỷ lệ phần trăm khi sử dụng BigDecimal? .... tính dài dòng của một bài tập như vậy trở thành minh chứng cho sự ám ảnh của chính nó. Trớ trêu thay, việc thêm quá tải toán tử vào Java sẽ cho phép chúng ta tạo lớp Tiền tệ của riêng mình, điều này sẽ làm cho mã toán học đó trở nên thanh lịch và đơn giản (ít bị ám ảnh hơn).

3
Volksman

Giả sử Java là ngôn ngữ triển khai thì a, b và c sẽ là các tham chiếu đến kiểu Complex với các giá trị ban đầu là null. Ngoài ra, giả sử rằng Complex là bất biến như được đề cập BigInteger và tương tự bất biến BigDecimal , tôi nghĩ bạn có nghĩa như sau, khi bạn gán tham chiếu cho Complex được trả về từ việc thêm b và c, và không so sánh tài liệu tham khảo này với a.

Không phải là:

Complex a, b, c; a = b + c;

much đơn giản hơn:

Complex a, b, c; a = b.add(c);
2
David Schlosnagle

Đôi khi thật tuyệt khi có quá tải toán tử, các lớp bạn bè và nhiều kế thừa.

Tuy nhiên tôi vẫn nghĩ rằng đó là một quyết định tốt. Nếu Java có quá tải toán tử thì chúng ta không bao giờ có thể chắc chắn về ý nghĩa của toán tử mà không xem qua mã nguồn. Hiện tại điều đó là không cần thiết. Và tôi nghĩ rằng ví dụ của bạn về việc sử dụng các phương thức thay vì quá tải toán tử cũng khá dễ đọc. Nếu bạn muốn làm cho mọi thứ rõ ràng hơn, bạn luôn có thể thêm một nhận xét trên các tuyên bố lông.

// a = b + c
Complex a, b, c; a = b.add(c);
1
user14070

Các lựa chọn thay thế cho Hỗ trợ gốc của quá tải toán tử Java

Vì Java không có quá tải toán tử, nên đây là một số lựa chọn thay thế bạn có thể xem xét:

  1. Sử dụng ngôn ngữ khác. Cả GroovyScala có quá tải toán tử và dựa trên Java.
  2. Sử dụng Java-oo , một plugin cho phép quá tải toán tử trong Java. Lưu ý rằng nó KHÔNG độc lập với nền tảng. Ngoài ra, nó có nhiều vấn đề và không tương thích với các bản phát hành mới nhất của Java (tức là Java 10). ( Nguồn StackOverflow gốc )
  3. Sử dụng JNI , Giao diện gốc Java hoặc các lựa chọn thay thế. Điều này cho phép bạn viết các phương thức C hoặc C++ (có thể là các phương thức khác?) Để sử dụng trong Java. Tất nhiên điều này cũng KHÔNG độc lập với nền tảng.

Nếu bất cứ ai biết về người khác, xin vui lòng bình luận, và tôi sẽ thêm nó vào danh sách này.

0
gagarwa

Đây không phải là một lý do tốt để không cho phép nó mà là một lý do thực tế:

Mọi người không phải lúc nào cũng sử dụng nó có trách nhiệm. Nhìn vào ví dụ này từ thư viện thư viện Python:

>>> IP()
<IP |>
>>> IP()/TCP()
<IP frag=0 proto=TCP |<TCP |>>
>>> Ether()/IP()/TCP()
<Ether type=0x800 |<IP frag=0 proto=TCP |<TCP |>>>
>>> IP()/TCP()/"GET / HTTP/1.0\r\n\r\n"
<IP frag=0 proto=TCP |<TCP |<Raw load='GET / HTTP/1.0\r\n\r\n' |>>>
>>> Ether()/IP()/IP()/UDP()
<Ether type=0x800 |<IP frag=0 proto=IP |<IP frag=0 proto=UDP |<UDP |>>>>
>>> IP(proto=55)/TCP()
<IP frag=0 proto=55 |<TCP |>>

Đây là lời giải thích:

Toán tử/đã được sử dụng làm toán tử thành phần giữa hai các lớp. Khi làm như vậy, lớp dưới có thể có một hoặc nhiều mặc định các trường quá tải theo lớp trên. (Bạn vẫn Có thể đưa ra giá trị bạn muốn). Một chuỗi có thể được sử dụng như một lớp thô.

0
Sarien