เหตุใด Java จึงไม่ให้ผู้ให้บริการโหลดมากเกินไป


406

มาจาก C ++ ถึง Java คำถามที่ไม่ได้รับคำตอบที่ชัดเจนคือทำไม Java จึงไม่รวมตัวดำเนินการมากเกินไป?

ไม่Complex a, b, c; a = b + c;ง่ายกว่านี้Complex a, b, c; a = b.add(c);หรือ

มีเหตุผลที่รู้จักกันในเรื่องนี้ข้อโต้แย้งที่ถูกต้องสำหรับการไม่อนุญาตให้ผู้ประกอบการมากเกินไป? เหตุผลโดยพลการหรือเสียเวลา?



1
@zzzz ฉันอ่านบทความนั้นลำบาก นี่แปลโดยอัตโนมัติหรือเป็นภาษาที่ 2 ของผู้เขียนเป็นภาษาอังกฤษหรือ ฉันพบว่าการสนทนาที่นี่สะอาดกว่ามาก

25
สำหรับคำถามที่ว่าไม่ได้สร้างสรรค์คำถามนี้ได้ให้บทสนทนาที่สร้างสรรค์ที่สุดเท่าที่ฉันเคยเห็นมา บางทีมันอาจเป็นตัวเลือกที่ดีกว่าสำหรับprogrammers.stackexchange.comแต่มีบางครั้งที่ฉันคิดว่า SO กำลังถูกไล่ออกจากวิชาที่กว้างขึ้น

@NNNMe เป็นเรื่องง่ายเพียงแค่แทรกaและthe - artlcles ที่หายไปนั้นเป็นของแถมที่คน ๆ นั้นไม่ใช่เจ้าของภาษาอังกฤษหรือเป็นโปรแกรมเมอร์ (หรือชอบผู้ชายคนนี้ทั้งสอง) เหตุผลที่โปรแกรมเมอร์เขียนบทความสามารถทำได้ ทำให้ความคิดเห็นสั้นลงและพอดีได้ง่ายขึ้นในพื้นที่ที่ให้ไว้ .. จากที่นั่นพวกเขาเพิ่งชินกับมัน ปัญหาของฉันอยู่กับเลย์เอาต์ฉันมักจะกดปุ่มไซต์นั้นในการค้นหาของ Google โชคดีที่มีส่วนต่อขยายโครเมี่ยมที่เรียกว่าชัดเจนว่าฟอร์แมตใหม่อ่านยาก
ycomp

1
ฉันไม่เห็นเหตุผลใด ๆ ว่าเหตุใด OP ถึงยอมรับคำตอบแรก คำตอบที่เขียนโดย @ stackoverflow.com/users/14089/paercebalยอดเยี่ยม มันควรจะได้รับการยอมรับ
Destructor

คำตอบ:


13

สมมติว่าคุณต้องการเขียนทับค่าก่อนหน้าของวัตถุที่อ้างถึงโดยaฟังก์ชันสมาชิกจะต้องถูกเรียกใช้

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

ใน C ++, การแสดงออกนี้จะบอกคอมไพเลอร์ที่จะสร้างสาม (3) วัตถุในกองดำเนินการนอกจากนี้และคัดลอกaค่าผลลัพธ์จากวัตถุชั่วคราวเป็นวัตถุที่มีอยู่

อย่างไรก็ตามใน Java operator=จะไม่ทำการคัดลอกค่าสำหรับประเภทการอ้างอิงและผู้ใช้สามารถสร้างประเภทการอ้างอิงใหม่ไม่ใช่ประเภทค่า ดังนั้นสำหรับประเภทที่ผู้ใช้กำหนดชื่อการComplexมอบหมายหมายถึงการคัดลอกการอ้างอิงไปยังค่าที่มีอยู่

พิจารณาแทน:

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

ใน C ++ นี่เป็นการคัดลอกค่าดังนั้นการเปรียบเทียบจะส่งผลไม่เท่ากัน ใน Java operator=ดำเนินการอ้างอิงการคัดลอกเพื่อให้aและbตอนนี้หมายถึงค่าเดียวกัน เป็นผลให้การเปรียบเทียบจะสร้าง 'เท่ากัน' เนื่องจากวัตถุจะเปรียบเทียบเท่ากับตัวเอง

ความแตกต่างระหว่างการคัดลอกและการอ้างอิงจะเพิ่มความสับสนของผู้ปฏิบัติงานมากเกินไป ดังที่ @Sebastian ได้กล่าวถึง Java และ C # ทั้งสองจะต้องจัดการกับค่าและความเท่าเทียมกันของการอ้างอิงแยกต่างหาก - operator+น่าจะจัดการกับค่าและวัตถุ แต่operator=มีการใช้งานแล้วเพื่อจัดการกับการอ้างอิง

ใน C ++ คุณควรจัดการกับการเปรียบเทียบครั้งละหนึ่งประเภทเท่านั้นดังนั้นจึงอาจทำให้สับสนน้อยลง ตัวอย่างเช่นในComplex, operator=และoperator==มีทั้งที่ทำงานเกี่ยวกับค่า - การคัดลอกค่านิยมและเปรียบเทียบค่าตามลำดับ


6
มันค่อนข้างง่ายจริงๆ ... แค่ทำเหมือนงูหลามและไม่มีภาระงานมากเกินไป
L̲̳o̲̳̳n̲̳̳g̲̳̳p̲̳o̲̳̳k̲̳̳e̲̳̳

225
คำตอบนี้ไม่ได้ตอบคำถามเลย คุณแค่พิณบนการใช้เครื่องหมายเท่ากับของ java หาก b + C ส่งคืนคอมเพล็กซ์ใหม่ดังนั้น a = b + c จะใช้ได้อย่างสมบูรณ์แบบและใช่ว่าจะอ่านง่ายกว่ามาก แม้ว่าคุณต้องการแก้ไข a ในสถานที่ a.set (b + c) เป็นตันที่อ่านง่ายกว่าโดยเฉพาะเมื่อเลขคณิตนั้นยิ่งกว่าเรื่องเล็กน้อย: a.set (a b + b c) / 5) หรือ a = a.multiply (b) .add (b.multiply (c)) แบ่งออก (5) ทางเลือกของคุณ ..
BT

24
หรือฉันเดา .. ไม่ใช่ตัวเลือกของคุณแล้วแต่กรณี
BT

9
ใน C ++ เทมเพลตนิพจน์จะช่วยแก้ปัญหาการคัดลอกเพิ่มเติม ไลบรารีทางคณิตศาสตร์ที่สำคัญมากใช้เทคนิคนี้ด้วยเหตุผลนี้ นอกจากนี้สิ่งนี้ไม่ได้ตอบคำถามเนื่องจาก a = b + c เป็นเพียงน้ำตาลประโยคสำหรับ a.foo (b.bar (c)) ซึ่งเป็นการสังเกตเบื้องต้นในคำถาม
Kaz Dragon

18
นี่ไม่ใช่คำตอบสำหรับคำถามที่ถาม นี่คือการคาดเดาของใครบางคนเกี่ยวกับความแตกต่างบางอย่างระหว่าง Java และ C ++
SChepurin

804

มีการโพสต์มากมายที่บ่นเกี่ยวกับการบรรทุกเกินพิกัด

ฉันรู้สึกว่าต้องอธิบายแนวคิด "โอเปอเรเตอร์การบรรทุกเกินพิกัด" เพื่อเสนอมุมมองทางเลือกในแนวคิดนี้

รหัสทำให้งง?

อาร์กิวเมนต์นี้เป็นความเข้าใจผิด

การทำให้งงเป็นไปได้ในทุกภาษา ...

มันเป็นเรื่องง่ายที่จะทำให้งงงวยรหัสใน C หรือ Java ผ่านฟังก์ชั่น / วิธีการที่มันเป็นใน C ++ ผ่านการดำเนินการเกินพิกัด:

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

... แม้จะอยู่ในอินเตอร์เฟสมาตรฐานของ Java

สำหรับตัวอย่างอื่นมาดูCloneableอินเตอร์เฟสใน Java:

คุณควรจะโคลนวัตถุที่ใช้อินเตอร์เฟซนี้ แต่คุณสามารถโกหก และสร้างวัตถุต่าง ๆ ในความเป็นจริงอินเทอร์เฟซนี้อ่อนแอดังนั้นคุณสามารถส่งคืนวัตถุชนิดอื่นพร้อมกันเพียงเพื่อความสนุก:

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

เนื่องจากCloneableอินเตอร์เฟซสามารถถูกใช้ในทางที่ผิด / obfuscated มันควรถูกแบนในบริเวณเดียวกันกับตัวดำเนินการ C + + เกินพิกัดที่ควรจะเป็น?

เราสามารถโอเวอร์โหลดtoString()เมธอดของMyComplexNumberคลาสเพื่อให้มันส่งคืนชั่วโมงที่ทำให้เป็นสตริงของวัน ควรtoString()ห้ามการบรรทุกเกินพิกัดเช่นกัน? เราสามารถก่อวินาศกรรมMyComplexNumber.equalsเพื่อให้มันคืนค่าแบบสุ่มแก้ไขตัวถูกดำเนินการ ... ฯลฯ ฯลฯ

ใน Java เช่นเดียวกับใน C ++ หรือภาษาใด ๆ โปรแกรมเมอร์ต้องเคารพความหมายขั้นต่ำเมื่อเขียนโค้ด ซึ่งหมายถึงการใช้งานaddฟังก์ชั่นที่เพิ่มและCloneableวิธีการใช้งานที่โคลนและ++ผู้ประกอบการกว่าการเพิ่มขึ้น

มีอะไรน่างงงวยอยู่แล้ว?

ตอนนี้เรารู้แล้วว่าโค้ดสามารถก่อวินาศกรรมได้แม้ผ่านวิธีการ Java แบบดั้งเดิมเราสามารถถามตัวเองเกี่ยวกับการใช้งานจริงของตัวดำเนินการโอเวอร์โหลดใน C ++ ได้หรือไม่

สัญลักษณที่ชัดเจนและเปนธรรมชาติ

เราจะเปรียบเทียบด้านล่างสำหรับกรณีที่แตกต่างกันรหัส "เดียวกัน" ใน Java และ C ++ เพื่อให้ทราบถึงรูปแบบการเข้ารหัสที่ชัดเจนยิ่งขึ้น

เปรียบเทียบธรรมชาติ:

// 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 ;

โปรดทราบว่า A และ B อาจเป็นประเภทใดก็ได้ใน C ++ ตราบใดที่มีการระบุตัวดำเนินการโอเวอร์โหลด ใน Java เมื่อ A และ B ไม่ใช่แบบดั้งเดิมรหัสอาจสับสนมากแม้สำหรับวัตถุที่เหมือนดั่งเดิม (BigInteger ฯลฯ ) ...

ตัวเข้าถึงอาร์เรย์ / คอนเทนเนอร์ตามธรรมชาติและตัวห้อย:

// 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

ใน Java เราเห็นว่าแต่ละคอนเทนเนอร์ทำสิ่งเดียวกัน (เข้าถึงเนื้อหาผ่านดัชนีหรือตัวระบุ) เรามีวิธีที่แตกต่างในการทำซึ่งทำให้เกิดความสับสน

ใน C ++ แต่ละคอนเทนเนอร์ใช้วิธีเดียวกันในการเข้าถึงเนื้อหาด้วยตัวดำเนินการที่มากเกินไป

การจัดการประเภทขั้นสูงตามธรรมชาติ

ตัวอย่างด้านล่างใช้ Matrixวัตถุซึ่งพบโดยใช้ลิงก์แรกที่พบใน Google สำหรับ " Java Matrix object " และ " C ++ Matrix object ":

// 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

และนี่ไม่ได้ จำกัด เฉพาะเมทริกซ์ BigIntegerและBigDecimalชั้นเรียนของ Java ต้องทนทุกข์ทรมานจากความสับสนฟุ่มเฟื่อยเดียวกันขณะที่เทียบเท่าใน C ++ เป็นเป็นที่ชัดเจนเป็นตัวชนิด

ตัววนซ้ำตามธรรมชาติ:

// 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

ฟังก์ชั่นธรรมชาติ:

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

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

การต่อข้อความ:

// 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") ;

ตกลงใน Java คุณสามารถใช้MyString = "Hello " + 25 + " World" ;... แต่รอสักครู่: นี่คือการใช้งานตัวดำเนินการมากเกินไปใช่ไหม? มันไม่ใช่การโกงหรอ ???

:-D

รหัสทั่วไป?

ตัวดำเนินการแก้ไขรหัสทั่วไปที่เหมือนกันควรจะสามารถใช้งานได้ทั้งสำหรับบิวด์อิน / ตัวดั้งเดิม (ซึ่งไม่มีส่วนต่อประสานใน Java), วัตถุมาตรฐาน (ซึ่งไม่สามารถมีอินเตอร์เฟสที่ถูกต้อง) และวัตถุที่ผู้ใช้กำหนด

ตัวอย่างเช่นการคำนวณค่าเฉลี่ยของสองค่าของประเภทใด ๆ :

// 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.

การอภิปรายผู้ปฏิบัติงานมากไป

ตอนนี้เราได้เห็นการเปรียบเทียบที่เป็นธรรมระหว่างรหัส C ++ โดยใช้ตัวดำเนินการโอเวอร์โหลดและรหัสเดียวกันใน Java ตอนนี้เราสามารถพูดถึง "ตัวดำเนินการเกินพิกัด" เป็นแนวคิด

ผู้ประกอบการเกินพิกัดที่มีอยู่ตั้งแต่ก่อนคอมพิวเตอร์

แม้ภายนอกของวิทยาศาสตร์คอมพิวเตอร์ที่มีการดำเนินงานมาก: ตัวอย่างเช่นในวิชาคณิตศาสตร์ประกอบการชอบ+, -, *ฯลฯ มีมากเกินไป

อันที่จริงความหมายของ+, -, *ฯลฯ การเปลี่ยนแปลงขึ้นอยู่กับชนิดของตัวถูกดำเนินการที่ (numerics เวกเตอร์, ฟังก์ชั่นคลื่นควอนตัม, การฝึกอบรม ฯลฯ )

พวกเราส่วนใหญ่ซึ่งเป็นส่วนหนึ่งของหลักสูตรวิทยาศาสตร์ของเราได้เรียนรู้ความสำคัญหลายประการสำหรับผู้ประกอบการขึ้นอยู่กับประเภทของตัวถูกดำเนินการ เราพบว่าพวกเขาสับสนพวกเขา?

ผู้ประกอบการมากไปขึ้นอยู่กับตัวถูกดำเนินการ

นี่เป็นส่วนที่สำคัญที่สุดของการบรรทุกเกินพิกัด: เช่นเดียวกับในคณิตศาสตร์หรือในฟิสิกส์การดำเนินการขึ้นอยู่กับประเภทของตัวถูกดำเนินการ

ดังนั้นรู้ประเภทของตัวถูกดำเนินการและคุณจะรู้ผลของการดำเนินการ

แม้แต่ C และ Java ก็ยังมีผู้ให้บริการโหลดมากเกินไป

ใน C พฤติกรรมที่แท้จริงของผู้ปฏิบัติงานจะเปลี่ยนไปตามตัวถูกดำเนินการ ตัวอย่างเช่นการเพิ่มสองจำนวนเต็มแตกต่างจากการเพิ่มสองคู่หรือแม้กระทั่งหนึ่งจำนวนเต็มและหนึ่งคู่ มีแม้กระทั่งโดเมนเลขคณิตทั้งตัวชี้ (โดยไม่ต้องร่ายคุณสามารถเพิ่มจำนวนเต็มให้กับตัวชี้ แต่คุณไม่สามารถเพิ่มสองพอยน์เตอร์ ... )

ใน Java ไม่มีตัวชี้ทางคณิตศาสตร์ แต่บางคนยังพบว่าการต่อสตริงโดยไม่มีตัว+ดำเนินการจะไร้สาระมากพอที่จะพิสูจน์ข้อยกเว้นใน "โอเปอเรเตอร์การบรรทุกเกินพิกัดเป็นความชั่วร้าย"

เป็นเพียงแค่คุณในฐานะ C (สำหรับเหตุผลทางประวัติศาสตร์) หรือ Java (สำหรับเหตุผลส่วนตัวดูด้านล่าง) coder คุณไม่สามารถให้บริการของคุณเอง

ใน C ++ ตัวดำเนินการมากไปไม่ใช่ตัวเลือก ...

ใน C ++ การโอเวอร์โหลดของผู้ประกอบการสำหรับประเภทในตัวเป็นไปไม่ได้ (และนี่เป็นสิ่งที่ดี) แต่ประเภทที่ผู้ใช้กำหนดเองสามารถมีตัวดำเนินการที่ผู้ใช้กำหนดเองมากเกินไป

ดังที่ได้กล่าวไปแล้วก่อนหน้านี้ใน C ++ และในทางตรงกันข้ามกับ Java ประเภทผู้ใช้จะไม่ถือว่าเป็นพลเมืองชั้นสองของภาษาเมื่อเทียบกับประเภทในตัว ดังนั้นหากประเภทในตัวมีตัวดำเนินการประเภทผู้ใช้ก็ควรจะมีเช่นกัน

ความจริงก็คือเหมือนtoString(), clone(), equals()วิธีการสำหรับ Java ( เช่นกึ่งมาตรฐานเหมือน ), C ++ มากไปประกอบเป็นส่วนหนึ่งมากจาก C ++ ที่จะกลายเป็นธรรมชาติเป็นผู้ประกอบการเดิม C หรือก่อน Java วิธีการที่กล่าวถึง

เมื่อรวมกับการเขียนโปรแกรมแม่แบบการใช้งานมากเกินไปกลายเป็นรูปแบบการออกแบบที่รู้จักกันดี ในความเป็นจริงคุณไม่สามารถไปไกลได้ใน STL โดยไม่ต้องใช้โอเปอเรเตอร์ที่โอเวอร์โหลดและโอเปอร์เรเตอร์สำหรับคลาสของคุณเอง

... แต่ไม่ควรถูกทำร้าย

การบรรทุกเกินพิกัดของผู้ประกอบการควรพยายามเคารพความหมายของผู้ปฏิบัติงาน อย่าลบใน+โอเปอเรเตอร์ (เช่น "ห้ามลบในaddฟังก์ชั่น" หรือ "คืนอึในcloneเมธอด")

การบรรทุกมากเกินไปอาจเป็นอันตรายได้เพราะอาจทำให้เกิดความคลุมเครือ ดังนั้นจึงควรสำรองไว้สำหรับกรณีที่กำหนดไว้อย่างดี สำหรับ&&และ||ไม่เคยเกินพวกเขาจนกว่าคุณจะรู้ว่าสิ่งที่คุณกำลังทำเพราะคุณจะสูญเสียการประเมินการลัดวงจรที่ผู้ประกอบการพื้นเมือง&&และ||เพลิดเพลิน

ดังนั้น ... ตกลง ... แล้วทำไมมันเป็นไปไม่ได้ใน Java?

เพราะ James Gosling พูดอย่างนั้น:

ฉันออกจากการใช้งานเกินกำลังเป็นทางเลือกที่ค่อนข้างเป็นส่วนตัวเพราะฉันเห็นคนจำนวนมากเกินไปใช้มันใน C ++

เจมส์กอสลิง ที่มา: http://www.gotw.ca/publications/c_family_interview.htm

โปรดเปรียบเทียบข้อความของ Gosling ด้านบนกับ Stroustrup ด้านล่าง:

การตัดสินใจในการออกแบบ C ++ หลายอย่างนั้นทำให้พวกเขาไม่ชอบที่จะบังคับให้คนทำสิ่งต่าง ๆ โดยเฉพาะ [... ] บ่อยครั้งที่ฉันถูกล่อลวงให้ทำสิ่งที่ฉันไม่ชอบด้วยตัวเองฉันไม่ได้ทำเช่นนั้นเพราะฉันไม่คิดว่า สิทธิที่จะบังคับให้มุมมองของฉันกับคนอื่น ๆ

Bjarne Stroustrup ที่มา: การออกแบบและวิวัฒนาการของ C ++ (พื้นหลังทั่วไป 1.3)

ผู้ประกอบการที่มากไปจะได้ประโยชน์จาก Java หรือไม่

วัตถุบางอย่างจะได้รับประโยชน์อย่างมากจากการบรรทุกเกินพิกัด (คอนกรีตหรือชนิดตัวเลขเช่น BigDecimal จำนวนเชิงซ้อนเมทริกซ์ภาชนะบรรจุตัววนซ้ำตัวเปรียบเทียบตัวแยกวิเคราะห์ ฯลฯ )

ใน C ++ คุณสามารถได้รับประโยชน์จากผลประโยชน์นี้เนื่องจากความอ่อนน้อมถ่อมตนของ Stroustrup ใน Java คุณเพียงแค่เมาเพราะตัวเลือกของ Goslingเลือกส่วนบุคคล

สามารถเพิ่มลงใน Java ได้หรือไม่

เหตุผลที่ไม่เพิ่มตัวดำเนินการมากเกินไปใน Java อาจเป็นการรวมตัวกันของการเมืองภายในการแพ้ต่อคุณสมบัติความไม่ไว้วางใจของนักพัฒนา เวลาที่จะเขียนข้อมูลจำเพาะที่ถูกต้อง ฯลฯ

ดังนั้นอย่ากลั้นหายใจรอคุณสมบัตินี้ ...

แต่พวกเขาทำใน C # !!!

ใช่...

แม้ว่าสิ่งนี้จะห่างไกลจากความแตกต่างเพียงอย่างเดียวระหว่างสองภาษา แต่สิ่งนี้ไม่เคยทำให้ฉันผิดหวัง

เห็นได้ชัดว่า C # folks ด้วย"ทุกดั้งเดิมคือstructและstructมาจากวัตถุ"ทำให้ถูกต้องตั้งแต่ครั้งแรก

และพวกเขาทำมันในภาษาอื่น ๆ !!!

แม้จะมี FUD ทั้งหมดกับการใช้งานเกินพิกัดที่กำหนดไว้แล้วภาษาต่อไปนี้รองรับ: Scala , Dart , Python , F # , C # , D , Algol 68 , Smalltalk , Groovy , Perl 6 , C ++, ทับทิม , Haskell , MATLAB , Eiffel , Lua , Clojure , Fortran 90 , Swift , Ada , Delphi 2005 ...

ภาษาจำนวนมากที่มีปรัชญา (และบางครั้งก็เป็นปฏิปักษ์) ที่แตกต่างกันมากมาย

อาหารสมอง...


50
นี่คือคำตอบที่ยอดเยี่ยม ฉันไม่เห็นด้วยกับมัน แต่มันก็ยังเป็นคำตอบที่ยอดเยี่ยม ฉันคิดว่าปัญหาที่เป็นไปได้ด้วยการโอเวอร์โหลดที่ไม่ดีเกินกว่าค่าของการโอเวอร์โหลดที่ดี
Douglas Leeder

69
@ ดักลาส Leeder: ขอบคุณ! ผู้ประกอบการมากไปเหมือน OOP ครั้งแรกที่คุณเรียนรู้ที่จะทำคุณเขียนมากไปทุกหนทุกแห่งเหมือนที่คุณใส่คลาสพื้นฐานและการสืบทอดทุกที่ (เช่นหวานประชด Java API) แต่สิ่งนี้ผ่านไปอย่างรวดเร็วและคุณก็ชื่นชมความเป็นไปได้ตลอดเวลาที่ไม่ได้ใช้ ประสบการณ์ 10 ปี + ของฉันเองเกี่ยวกับ C ++ คือจำนวนโอเวอร์โหลดที่ไม่ดีที่ฉันเห็นทั้งในโค้ดและโค้ดจากโคเดอร์อื่น ๆ นั้นต่ำมากฉันเชื่อว่าฉันสามารถนับมันได้ด้วยมือเดียว และนี่เป็นจำนวนที่น้อยกว่าจำนวนของบั๊กโดยรวมที่มี sprintf, strcat, memset และ buffer มากเกินไป
paercebal

11
@ ดักลาส Leeder: ฉันเชื่อว่าหลังจากพูดคุยเกี่ยวกับเรื่องนั้นในคำถาม SO อื่น ๆ ช่องว่างระหว่าง "คนรัก" และ "เกลียดชัง" ของผู้ประกอบการเกินพิกัดอาจเกิดจากความแตกต่างในวิธีการของรหัส: "เกลียด" เป็นฟังก์ชั่นอื่น ๆ อีกมากมาย คือสิ่งที่สำคัญ "หมายถึงพวกเขาคาดหวังว่าฟังก์ชั่นจะทำสิ่งหนึ่งและสิ่งเดียวเท่านั้น ดังนั้นผู้ประกอบการควรทำงานตามที่ออกแบบโดยภาษา "คู่รัก" เป็นเรื่องเกี่ยวกับ "วัตถุควรประพฤติตน" ซึ่งหมายความว่าพวกเขายอมรับได้ง่ายขึ้นว่าฟังก์ชั่น (และตัวดำเนินการ) สามารถเปลี่ยนพฤติกรรมได้ตามประเภทของพารามิเตอร์
paercebal

103
คำตอบมหากาพย์ หนึ่งใน debunks ที่ผ่านการรับรองมากที่สุดที่ฉันเคยอ่าน
Sebastian Mach

7
@MaartenBodewes: ตัวอย่างทั้งหมดที่ฉันเขียนไว้ด้านบนและสิ่งที่รบกวนจิตใจคุณคือ"ในฐานะนักพัฒนาคุณจะเมาเพราะความเป็นส่วนตัวของ Gosling" ? กรุณาเขียนคำตอบของคุณเองปกป้อง"นักพัฒนาคุณมีความโง่ให้คนอัจฉริยะตัดสินใจสำหรับสิ่งที่คุณต้องการ"มุม การสนทนานี้ไม่ได้มีวัตถุประสงค์
paercebal

44

James Gosling เปรียบการออกแบบ Java ดังต่อไปนี้:

"มีหลักการนี้เกี่ยวกับการเคลื่อนย้ายเมื่อคุณย้ายจากอพาร์ทเมนต์หนึ่งไปยังอพาร์ทเมนต์อื่นการทดลองที่น่าสนใจคือการบรรจุอพาร์ทเมนต์ของคุณและใส่ทุกอย่างลงในกล่อง กำลังทำอาหารมื้อแรกของคุณและคุณกำลังดึงอะไรบางอย่างออกมาจากกล่องหลังจากนั้นประมาณหนึ่งเดือนคุณก็เคยคิดว่าสิ่งใดในชีวิตที่คุณต้องการจริง ๆ แล้วคุณก็เอาส่วนที่เหลือ อะไร - ลืมไปว่าคุณชอบมันมากแค่ไหนและมันยอดเยี่ยมแค่ไหนและคุณก็ทิ้งมันไปได้มันวิเศษมากที่ทำให้ชีวิตของคุณง่ายขึ้นและคุณสามารถใช้หลักการนั้นกับปัญหาการออกแบบทุกประเภทได้ เจ๋งหรือแค่เพราะน่าสนใจ "

คุณสามารถอ่านบริบทของคำพูดได้ที่นี่

โดยทั่วไปการบรรทุกเกินพิกัดนั้นยอดเยี่ยมสำหรับคลาสที่มีรูปแบบของจุดสกุลเงินหรือจำนวนเชิงซ้อน แต่หลังจากนั้นคุณก็เริ่มหมดตัวอย่างรวดเร็ว

ปัจจัยอีกประการหนึ่งคือการใช้งานคุณลักษณะใน C ++ โดยนักพัฒนาซอฟต์แวร์มากเกินไปเช่น '&&', '||', ผู้ดำเนินการส่งและแน่นอน 'ใหม่' ความซับซ้อนที่เกิดจากการรวมสิ่งนี้กับการผ่านค่าและข้อยกเว้นได้รับการกล่าวถึงในหนังสือC ++ชั้นยอด


6
คุณสามารถให้รหัสตัวอย่างของ "ความซับซ้อนของการใช้งานเกินพิกัดรวมกับรหัสผ่านและค่ายกเว้น" ได้หรือไม่ แม้จะมีการเล่นกับภาษาไม่กี่ปีและการเป็นเจ้าของและการอ่านหนังสือที่มีประสิทธิภาพ / ยอดเยี่ยมทั้งหมดใน C ++ ฉันก็ไม่เข้าใจว่าคุณหมายถึงอะไร
paercebal

60
สิ่งที่ได้ผลสำหรับ James Gosling จะไม่ทำงานสำหรับทุกคน เขาเป็นคนที่สั้นอย่างไม่น่าเชื่อในการคาดการณ์การทดลองบรรจุหีบห่อ "น่าสนใจ" ของเขาเพื่อหมายถึง "ทิ้งทุกสิ่งในโลกที่ฉันไม่ต้องการออกไป เห็นได้ชัดว่าเขาไม่รู้ว่าฉันต้องการหรือใช้อะไร
BT

49
@BT: ส่วนใหญ่ enlightning เป็นมุมมองที่ลูกห่านเมื่อเทียบกับมุมมอง Stroustrup Many C++ design decisions have their roots in my dislike for forcing people to do things in some particular way [...] Often, I was tempted to outlaw a feature I personally disliked, I refrained from doing so because I did not think I had the right to force my views on others. (B. Stroustrup)ในปัญหานี้:
paercebal

29
@ ซอฟต์แวร์ Monkey: "C ++, ประจานอย่างกว้างขวางกับคนอื่น ๆ , Java, ชอบอย่างกว้างขวาง" นี่คือการตลาด hype โปรดจำไว้ว่า C ++ เติบโตขึ้นเพียงอย่างเดียวในขณะที่ Java (และ. NET) ทำกำไรจากการตลาดควาญ ดูเหมือนจะไม่แปลกเลยที่ "ภาษาที่คนนิยมใช้กันอย่างแพร่หลาย" จาวา จำกัด อยู่ที่แอปพลิเคชันเซิร์ฟเวอร์ในขณะที่ "ประจบประแจงอย่างกว้างขวาง" (อาจเป็นเพราะนักพัฒนาและผู้จัดการ Java ต้องการลดต้นทุนการผลิตโค้ด) C ++ ไปจากที่สูงมาก - เซิร์ฟเวอร์ประสิทธิภาพให้กับเกมประสิทธิภาพสูงหรือไม่ [... ]
paercebal

16
@Hassan: แต่ละภาษามีแฮ็กข้อมูลทั่วไปของ Java เป็นหนึ่งในตัวอย่างที่ยอดเยี่ยมของสิ่งนั้น ตอนนี้เกี่ยวกับI'd like them to go have a look at some C++ code out there that is hideously put together with weird hacks and "exceptional" features of the language: โปรแกรมเมอร์ที่ไม่ดีจะเขียนรหัสไม่ดีไม่ว่าภาษาใด เพียงลองเลียนแบบ "รหัสผ่านอ้างอิง" สำหรับพารามิเตอร์ฟังก์ชันใน Java เพื่อให้มีแนวคิด ฉันเห็นรหัสแล้วและหัวเราะอย่างหนักจนเจ็บปวด นี่คือสิ่งที่ Gosling ไม่ได้ใช้ดังนั้นจำเป็นต้องมีแฮ็กที่น่ากลัวใน Java แต่ก็มีอยู่จริงโดยไม่มีค่าใช้จ่ายทั้งใน C # และ C ++
paercebal

22

ลองใช้ Boost.Units: ลิงก์ข้อความ

มันให้การวิเคราะห์มิติศูนย์ค่าใช้จ่ายผ่านการบรรทุกเกินพิกัด สิ่งนี้จะมีความชัดเจนมากขึ้น

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

จะเอาท์พุท "พลังงาน = 4 J" ที่ถูกต้อง


1
"วิธีการที่ซับซ้อนหากการบำรุงรักษาและรหัสนี้ทำให้งงงวยที่ไหน?
Mooing Duck

13

นักออกแบบ Java ตัดสินใจว่าการใช้งานเกินกำลังเป็นปัญหามากกว่าที่ควรจะเป็น เรียบง่ายเหมือนที่

ในภาษาที่ตัวแปรออบเจคต์ทุกตัวเป็นตัวอ้างอิงจริงการดำเนินการมากไปของตัวดำเนินการจะได้รับอันตรายเพิ่มเติมจากการที่ไม่สมเหตุผลกับโปรแกรมเมอร์ C ++ อย่างน้อยที่สุด เปรียบเทียบสถานการณ์กับ C # 's == โอเปอเรเตอร์การบรรทุกเกินพิกัดและObject.EqualsและObject.ReferenceEquals(หรือสิ่งที่เรียกว่า)


8

Groovyมีผู้ให้บริการโหลดมากเกินไปและทำงานใน JVM หากคุณไม่สนใจเรื่องประสิทธิภาพ (ซึ่งเล็กลงทุกวัน) มันเป็นไปโดยอัตโนมัติตามชื่อเมธอด เช่น '+' เรียกวิธีการ 'บวก (อาร์กิวเมนต์)'


4
ฉันขอให้ทุกภาษาที่มีไวยากรณ์หนักที่มีการใช้งานเกินพิกัดจะใช้เทคนิคนั้น ฉันไม่เคยเข้าใจว่าทำไมพวกเขาต้องคิดค้นวิธีการตั้งชื่อและค้นหาแบบพิเศษ Stroustrup ไม่ได้กล่าวถึงตัวเลือกใด ๆ ใน D & EC ++ ทีม C # ใช้แนวทางที่ถูกต้องพร้อมกับไวยากรณ์ Linq ( where ...กลายเป็น.Where(i => ... ) ถ้าเพียง แต่พวกเขาต้องการทำเช่นเดียวกันกับตัวดำเนินการทางคณิตศาสตร์หลายสิ่งจะง่ายขึ้นและมีประสิทธิภาพมากขึ้น Java มีข้อดีของกระดานชนวนที่สะอาดและสามารถได้รับสิทธินี้ (แม้ว่าด้วยเหตุผลทางศาสนามันก็อาจจะไม่เคย)
Daniel Earwicker

@DanielEarwicker ฉันมักจะตั้งข้อสังเกตว่าเมื่อมีความขัดแย้งที่ซับซ้อนที่ผู้คนจะติดแท็กแรงจูงใจสำหรับทั้งสองด้านว่าเป็น "ศาสนา" ในธรรมชาติ

@ noah ฉันสามารถอยู่กับเซตย่อยของตัวดำเนินการโอเวอร์โหลดเช่นนี้โดยมีเงื่อนไขว่ามีแท็กพิเศษสำหรับชื่อวิธีการที่ทำให้พวกเขาแตกต่างกันทางสายตา บางสิ่งบางอย่างเช่นการกำหนดวิธี __plus () สำหรับการใช้งาน "+" OL และอยู่ไกลเกินความจำเป็นในการโหลดสิ่งต่าง ๆ เช่นการปลดเปลื้องและแม้แต่การห้อยแถวลำดับ สิ่งที่ฉันไม่เต็มใจที่จะอยู่ด้วยคือวิธีที่ C ++ และ C # เห็นว่าเหมาะสมที่จะนำไปใช้

2
ไม่ใช่คำตอบ มีหลายภาษาที่ทำงานบน VM การใช้งานมากเกินไปไม่ควรเป็นเหตุผลที่ดีในการเปลี่ยนภาษา
Maarten Bodewes

6

ฉันคิดว่านี่อาจเป็นตัวเลือกการออกแบบที่ใส่ใจเพื่อบังคับให้นักพัฒนาสร้างฟังก์ชั่นที่ชื่อมีการสื่อสารความตั้งใจของพวกเขาอย่างชัดเจน ในนักพัฒนา C ++ จะโอเวอร์โหลดโอเปอเรเตอร์ที่มีฟังก์ชั่นซึ่งมักจะไม่เกี่ยวข้องกับลักษณะที่ยอมรับกันโดยทั่วไปของโอเปอเรเตอร์ที่กำหนดทำให้แทบจะเป็นไปไม่ได้เลยที่จะกำหนดว่าโค้ดใดบ้าง


14
In C++ developers would overload operators with functionality that would often have no relation to the commonly accepted nature of the given operator: นี่เป็นการยืนยันที่ไร้ค่า ฉันเป็นนักพัฒนา C ++ มืออาชีพมาตั้งแต่ 12 ปีและฉันไม่ค่อยพบปัญหานี้ ในความเป็นจริงข้อผิดพลาดและข้อผิดพลาดการออกแบบส่วนใหญ่ที่ฉันเห็นใน C ++ อยู่ในรหัส C-style ( void *, ปลดเปลื้อง, ฯลฯ )
paercebal

6
-1 ตัวแปรทุกตัวที่คุณกำหนดเป็นสัญลักษณ์เช่นเดียวกับสัญลักษณ์ตัวดำเนินการทางคณิตศาสตร์ ไม่ว่าคุณจะใช้วลีเพื่อตั้งชื่อตัวแปรคำเดียวหรือตัวอักษรเดียวก็คือการตัดสินใจของคุณ (หรือทีมของคุณ) ใครจะพูดในสิ่งที่มีความหมายและสิ่งที่ไม่? คำตอบคือคุณโปรแกรมเมอร์ ภายในคณิตศาสตร์บริสุทธิ์การคูณระหว่างเมทริกซ์หมายถึงบางสิ่งที่แตกต่างจากการคูณระหว่างตัวเลขสองตัวในคณิตศาสตร์ขั้นพื้นฐาน แต่เราใช้สัญลักษณ์เดียวกันสำหรับการคูณทั้งสองแบบ
วิศวกร

2
@ paercebal: การยืนยันนั้นถูกต้อง คุณไม่ต้องมองไกลกว่า IOstreams เพื่อที่จะเห็นมันในทางปฏิบัติ โชคดีที่นักพัฒนาส่วนใหญ่มีความระมัดระวังในการประดิษฐ์ซีแมนทิกส์ใหม่สำหรับผู้ให้บริการปัจจุบัน
Ben Voigt

5
@BenVoigt: [... ] และฉันไม่ได้พูดถึงความจริงที่ว่าaddฟังก์ชั่นนั้นอาจถูกนำไปใช้ในทางที่ผิดจริงๆ (เช่นการคูณหรือการรับ mutex) ... การละเมิดที่กล่าวถึงโดย user14128 ไม่ได้ จำกัด อยู่ที่ผู้ประกอบการ แต่ มีความกลัวทางพยาธิวิทยาบางอย่างเกี่ยวกับการใช้งานเกินพิกัดที่ฉันเชื่อว่ามาจากวันก่อนหน้าของ C กับ C ++ ความกลัวที่ไม่ได้แก้ไขใน Java แต่โชคดีที่ไม่ได้เข้าสู่ C # ... ในที่สุดการเคารพความหมาย และการเขียนฟังก์ชั่น / ผู้ปฏิบัติงานอย่างชัดเจนเป็นหน้าที่ของผู้พัฒนา ไม่ใช่ภาษา
paercebal

3
@ jbo5112: ตัวอย่าง: cout << f() || g(); วงเล็บไม่ทำให้ชัดเจนขึ้น แต่จะแก้ไขให้ถูกต้อง และผู้ประกอบการเปลี่ยนบิตไม่ได้ถูกทารุณกรรมพวกเขาก็ไม่จำเป็น เป็นเพราะเหตุใดcout << (5&3) << endl;ดีกว่าcout.fmt(5&3)(endl);? การใช้โอเปอเรเตอร์การเรียกใช้ฟังก์ชันกับตัวแปรสมาชิก functor จะเป็นการออกแบบที่ดีกว่าสำหรับการสตรีมมากกว่าการนำเสนอโอเปอเรเตอร์ bitwise เพียงเพราะว่า glyph ดูดี แต่สิ่งนี้อยู่ไกลจากสิ่งเดียวที่ผิดกับลำธาร
Ben Voigt

5

คุณสามารถถ่ายภาพตัวเองด้วยการเดินเท้าของผู้ปฏิบัติงานมากไป มันเหมือนกับคนพอยน์เตอร์ที่ทำผิดพลาดโง่ ๆ กับพวกเขาดังนั้นจึงตัดสินใจเอากรรไกรออกไป

อย่างน้อยฉันก็คิดว่านั่นเป็นเหตุผล ฉันอยู่ข้างคุณแล้ว :)



2
นั่นเป็นวิธีคิดที่แย่มาก คุณสามารถยิงตัวเองด้วยการเดินเท้าเราค่อนข้างลดมือลงดังนั้นคุณจะไม่สามารถทำได้ และแน่นอนเราคิดว่าคุณเป็นคนงี่เง่าที่จะยิงตัวเอง
ntj

5

บางคนบอกว่าตัวดำเนินการมากเกินไปใน Java จะนำไปสู่ ​​obsfuscation คนเหล่านั้นเคยหยุดดูจาวาโค้ดบางตัวที่ทำคณิตศาสตร์พื้นฐานเช่นการเพิ่มมูลค่าทางการเงินโดยใช้เปอร์เซ็นต์ BigDecimal หรือไม่? .... การใช้คำฟุ่มเฟื่อยของการออกกำลังกายดังกล่าวกลายเป็นของตัวเองของ obsfuscation กระแทกแดกดันการเพิ่มผู้ประกอบการมากไปยังจาวาจะช่วยให้เราสามารถสร้างระดับสกุลเงินของเราซึ่งจะทำให้รหัสทางคณิตศาสตร์ดังกล่าวสง่างามและเรียบง่าย (น้อย obsfuscated)


4

การกล่าวว่าตัวดำเนินการมากเกินไปนำไปสู่ข้อผิดพลาดเชิงตรรกะของประเภทที่ตัวดำเนินการที่ไม่ตรงกับตรรกะการดำเนินงานมันก็เหมือนไม่มีอะไรพูด ข้อผิดพลาดประเภทเดียวกันจะเกิดขึ้นหากชื่อฟังก์ชั่นไม่เหมาะสมสำหรับตรรกะการดำเนินการ - ดังนั้นอะไรคือทางออก: ลดความสามารถในการใช้ฟังก์ชัน! นี่คือคำตอบที่ตลก - "ไม่เหมาะสมสำหรับตรรกะการดำเนินงาน", ชื่อพารามิเตอร์ทุกตัว, ทุกคลาส, ฟังก์ชั่นหรืออะไรก็ตามที่ไม่เหมาะสมในเชิงตรรกะ ฉันคิดว่าตัวเลือกนี้ควรมีให้ในภาษาโปรแกรมที่น่าเชื่อถือและผู้ที่คิดว่าไม่ปลอดภัย - เฮ้ไม่มีทั้งคู่บอกว่าคุณต้องใช้มัน ให้ใช้ C # พวกเขาหลบเลี่ยงพอยน์เตอร์ แต่เดี๋ยวก่อน - มีคำสั่ง 'รหัสที่ไม่ปลอดภัย' - โปรแกรมตามที่คุณต้องการโดยความเสี่ยงของคุณเอง


4

ในทางเทคนิคมีการใช้งานตัวดำเนินการมากเกินไปในทุกภาษาการเขียนโปรแกรมที่สามารถจัดการกับตัวเลขประเภทต่าง ๆ เช่นจำนวนเต็มและจำนวนจริง คำอธิบาย: คำว่าการใช้งานมากเกินไปหมายถึงมีการปรับใช้หลายอย่างสำหรับหนึ่งฟังก์ชันเท่านั้น ในภาษาการเขียนโปรแกรมส่วนใหญ่มีการใช้งานที่แตกต่างกันสำหรับโอเปอเรเตอร์ + หนึ่งรายการสำหรับจำนวนเต็มหนึ่งรายการสำหรับ reals ซึ่งเรียกว่าโอเปอเรเตอร์การบรรทุกเกินพิกัด

ตอนนี้หลายคนพบว่ามันแปลกที่ Java มีตัวดำเนินการบรรทุกเกินพิกัดสำหรับตัวดำเนินการ + สำหรับการเพิ่มสตริงเข้าด้วยกันและจากจุดยืนทางคณิตศาสตร์นี้จะแปลกแน่นอน แต่เห็นได้จากมุมมองของนักพัฒนาภาษาโปรแกรมไม่มีอะไรผิด สำหรับโอเปอเรเตอร์ + สำหรับคลาสอื่นเช่นสตริง อย่างไรก็ตามคนส่วนใหญ่ยอมรับว่าเมื่อคุณเพิ่ม builtin overloading สำหรับ + ​​สำหรับ String แล้วโดยทั่วไปก็เป็นความคิดที่ดีที่จะให้ฟังก์ชั่นนี้สำหรับนักพัฒนาเช่นกัน

ไม่เห็นด้วยอย่างสมบูรณ์กับการเข้าใจผิดที่ผู้ประกอบการใช้งานเกินพิกัดทำให้งงงวยรหัสเนื่องจากจะเหลือสำหรับนักพัฒนาในการตัดสินใจ นี่ไร้เดียงสาที่จะคิดและพูดตามตรงแล้วมันค่อนข้างเก่า

+1 สำหรับการเพิ่มโอเปอเรเตอร์การโหลดใน Java 8


การใช้ Java +เพื่อเชื่อมต่อสิ่งที่ string-ish นั้นน่าเกลียดน่าดูมาก IMHO ดังที่ overloading /ใน C และ FORTRAN สำหรับการหารทั้งหมดและบางส่วน ใน Pascal หลายรุ่นการใช้ตัวดำเนินการทางคณิตศาสตร์ในประเภทตัวเลขใด ๆ จะให้ผลลัพธ์ที่เป็นตัวเลขเทียบเท่ากับการส่งตัวถูกดำเนินการถึงRealแม้ว่าผลลัพธ์ที่อาจไม่ใช่ตัวเลขทั้งหมดต้องป้อนผ่านTruncหรือRoundก่อนที่พวกเขาจะสามารถกำหนดให้เป็นจำนวนเต็ม
supercat

2

สมมติว่า Java เป็นภาษาที่ใช้งานแล้ว a, b และ c ทั้งหมดจะอ้างอิงถึงการพิมพ์คอมเพล็กซ์ที่มีค่าเริ่มต้นเป็นโมฆะ นอกจากนี้สมมติว่า Complex ไม่มีการเปลี่ยนแปลงตามBigInteger ที่กล่าวถึงและBigDecimal ที่ไม่เปลี่ยนรูปแบบที่คล้ายกันฉันคิดว่าคุณหมายถึงสิ่งต่อไปนี้เนื่องจากคุณกำหนดการอ้างอิงไปยัง Complex ที่ส่งคืนจากการเพิ่ม b และ c และไม่เปรียบเทียบการอ้างอิงนี้กับ

ไม่ใช่:

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

มากง่ายกว่า:

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

2
ฉัน ;) เท่ากับสามารถหมายถึงทั้งการมอบหมายหรือการเปรียบเทียบ แต่ = คือการมอบหมายเสมอและ == เป็นการเปรียบเทียบเสมอ ชื่อสามารถแนะนำแหล่งที่มาของข้อผิดพลาดขนาดใหญ่ได้

1

บางครั้งมันจะดีถ้ามีโอเปอเรเตอร์การบรรทุกเกินพิกัดคลาสเพื่อนและการสืบทอดหลายรายการ

อย่างไรก็ตามฉันยังคิดว่ามันเป็นการตัดสินใจที่ดี หาก Java มีการใช้งานตัวดำเนินการมากเกินไปเราก็ไม่อาจมั่นใจได้ถึงความหมายของตัวดำเนินการโดยไม่ต้องดูซอร์สโค้ด ในปัจจุบันที่ไม่จำเป็น และฉันคิดว่าตัวอย่างของคุณในการใช้วิธีการแทนการใช้งานมากเกินไปก็สามารถอ่านได้เช่นกัน หากคุณต้องการทำให้สิ่งต่าง ๆ ชัดเจนยิ่งขึ้นคุณสามารถเพิ่มความคิดเห็นข้างบนคำสั่งขน

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

12
แน่นอนดังที่กล่าวไว้ที่อื่นคุณไม่สามารถมั่นใจได้ในความหมายของฟังก์ชั่นการเพิ่มเช่นกัน
Eclipse

จริงฉันยังรู้สึกสบายใจที่รู้ว่าอย่างน้อยผู้ปฏิบัติงานของฉันได้รับการเข้ารหัสอย่างหนัก แน่นอนว่าการมีคุณสมบัติและการใช้งานอย่างสมเหตุสมผลจะทำให้เราดีขึ้นเท่านั้น ปัญหาคือว่ามันยากที่จะรู้ว่ามีคนใช้พวกเขาอย่างสมเหตุสมผล และคุณเห็นด้วยกับคำจำกัดความของความสมเหตุสมผล :-)

1
ความคิดเห็นที่เพิ่มเข้ามาเพื่อให้ความกระจ่างแก่โค้ดคือสิ่งที่รหัสจะมีลักษณะเป็นภาษาที่รองรับการใช้งานมากเกินไป นอกจากนี้ความจริงที่แสดงความคิดเห็นเขียนในแง่ของผู้ประกอบการปฏิเสธความขัดแย้งของคุณเพื่อดำเนินการมากเกินไป
Aluan Haddad

0

นี่ไม่ใช่เหตุผลที่ดีที่จะไม่อนุญาต แต่เป็นสิ่งที่ใช้งานได้จริง:

ผู้คนมักจะไม่ใช้มันอย่างรับผิดชอบ ดูตัวอย่างนี้จาก scapy ไลบรารี่ของ 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 |>>

นี่คือคำอธิบาย:

/ โอเปอเรเตอร์ถูกใช้เป็นตัวดำเนินการจัดองค์ประกอบระหว่างสองเลเยอร์ เมื่อทำเช่นนั้นเลเยอร์ที่ต่ำกว่าสามารถมีฟิลด์ค่าเริ่มต้นหนึ่งฟิลด์หรือมากกว่านั้นได้โอเวอร์โหลดตามเลเยอร์ด้านบน (คุณยังสามารถให้คุณค่าที่คุณต้องการ) สตริงสามารถใช้เป็นเลเยอร์ดิบ


0

ทางเลือกในการรองรับ Native ของ Java Operator Overloading

เนื่องจาก Java ไม่มีการใช้งานตัวดำเนินการมากเกินไปนี่เป็นทางเลือกบางประการที่คุณสามารถดูได้:

  1. ใช้ภาษาอื่น ทั้งGroovyและScalaมีผู้ให้บริการมากไปและขึ้นอยู่กับ Java
  2. ใช้java-ooซึ่งเป็นปลั๊กอินที่ช่วยให้ผู้ให้บริการโหลดมากเกินไปใน Java โปรดทราบว่ามันไม่ได้เป็นแพลตฟอร์มอิสระ นอกจากนี้ยังมีปัญหามากมายและไม่สามารถใช้งานร่วมกับ Java รุ่นล่าสุด (เช่น Java 10) ( ต้นฉบับแหล่ง StackOverflow )
  3. ใช้JNI , Java Native Interface หรือทางเลือก สิ่งนี้อนุญาตให้คุณเขียนเมธอด C หรือ C ++ (อาจเป็นอื่นหรือไม่?) เพื่อใช้ใน Java แน่นอนว่านี่ไม่ใช่แพลตฟอร์มอิสระ

หากใครรู้ของผู้อื่นโปรดแสดงความคิดเห็นและฉันจะเพิ่มไปยังรายการนี้


0

ในขณะที่ภาษา Java ไม่รองรับการโหลดเกินตัวดำเนินการโดยตรงคุณสามารถใช้ปลั๊กอินคอมไพเลอร์ Manifoldในโครงการ Java ใด ๆ เพื่อเปิดใช้งาน รองรับ Java 8 - 13 (เวอร์ชัน Java ปัจจุบัน) และได้รับการสนับสนุนอย่างเต็มที่ใน IntelliJ IDEA

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.