เหตุใดจึงไม่สามารถแทนที่วิธีการแบบคงที่ได้
ถ้าเป็นไปได้โปรดใช้ตัวอย่าง
Parent p = new Child()
แล้วp.childOverriddenStaticMethod()
คอมไพเลอร์จะแก้ไขมันParent.childOverriddenStaticMethod()
โดยดูที่ประเภทการอ้างอิง
เหตุใดจึงไม่สามารถแทนที่วิธีการแบบคงที่ได้
ถ้าเป็นไปได้โปรดใช้ตัวอย่าง
Parent p = new Child()
แล้วp.childOverriddenStaticMethod()
คอมไพเลอร์จะแก้ไขมันParent.childOverriddenStaticMethod()
โดยดูที่ประเภทการอ้างอิง
คำตอบ:
การเอาชนะขึ้นอยู่กับการมีอินสแตนซ์ของคลาส ประเด็นของความแตกต่างคือคุณสามารถคลาสย่อยและวัตถุที่ใช้คลาสย่อยเหล่านั้นจะมีพฤติกรรมที่แตกต่างกันสำหรับวิธีการเดียวกันที่กำหนดไว้ในซูเปอร์คลาส (และแทนที่ในคลาสย่อย) วิธีการคงที่ไม่เกี่ยวข้องกับอินสแตนซ์ของคลาสใด ๆ ดังนั้นแนวคิดไม่สามารถใช้ได้
มีข้อควรพิจารณาสองประการในการขับเคลื่อนการออกแบบของ Java ที่ส่งผลกระทบต่อสิ่งนี้ สิ่งหนึ่งคือความกังวลเกี่ยวกับประสิทธิภาพ: มีการวิพากษ์วิจารณ์อย่างมากเกี่ยวกับเรื่องนี้ว่าสมอลล์ทอล์คช้าเกินไป (การรวบรวมขยะและการเรียก polymorphic เป็นส่วนหนึ่งของสิ่งนั้น) และผู้สร้างจาวามุ่งมั่นที่จะหลีกเลี่ยงสิ่งนั้น อีกประการหนึ่งคือการตัดสินใจว่ากลุ่มเป้าหมายสำหรับ Java คือนักพัฒนา C ++ การสร้างวิธีการแบบคงที่ทำงานในลักษณะที่พวกเขาได้รับประโยชน์จากความคุ้นเคยสำหรับโปรแกรมเมอร์ C ++ และยังรวดเร็วมากเพราะไม่จำเป็นต้องรอจนกระทั่งรันไทม์เพื่อหาวิธีที่จะเรียกใช้
objects
) อนุญาตให้ใช้วิธีการมากไป
obj.staticMethod()
) - ซึ่งได้รับอนุญาตและใช้ประเภทเวลารวบรวม เมื่อการเรียกแบบสแตติกอยู่ในวิธีที่ไม่คงที่ของคลาสวัตถุ "ปัจจุบัน" อาจเป็นชนิดที่ได้รับมาของคลาส - แต่วิธีการแบบคงที่ที่กำหนดไว้ในประเภทที่ได้รับจะไม่พิจารณา (พวกเขาอยู่ในประเภทเวลาทำงาน ลำดับชั้น)
ส่วนตัวฉันคิดว่านี่เป็นข้อบกพร่องในการออกแบบ Java ใช่ใช่ฉันเข้าใจว่าวิธีการที่ไม่คงที่แนบมากับอินสแตนซ์ในขณะที่วิธีการคงที่แนบมากับชั้นเรียน ฯลฯ ฯลฯ ยังคงพิจารณารหัสต่อไปนี้:
public class RegularEmployee {
private BigDecimal salary;
public void setSalary(BigDecimal salary) {
this.salary = salary;
}
public static BigDecimal getBonusMultiplier() {
return new BigDecimal(".02");
}
public BigDecimal calculateBonus() {
return salary.multiply(getBonusMultiplier());
}
/* ... presumably lots of other code ... */
}
public class SpecialEmployee extends RegularEmployee {
public static BigDecimal getBonusMultiplier() {
return new BigDecimal(".03");
}
}
รหัสนี้จะไม่ทำงานอย่างที่คุณคาดหวัง กล่าวคือ SpecialEmployee ได้รับโบนัส 2% เช่นเดียวกับพนักงานทั่วไป แต่ถ้าคุณลบ "static" s ดังนั้น SpecialEmployee จะได้รับโบนัส 3%
(เป็นที่ยอมรับ, ตัวอย่างนี้เป็นรูปแบบการเขียนโค้ดที่ไม่ดีในชีวิตจริงคุณอาจต้องการให้ตัวคูณโบนัสอยู่ในฐานข้อมูลมากกว่าที่จะเขียนโค้ดแบบยาก ๆ แต่นั่นเป็นเพียงเพราะฉันไม่ต้องการที่จะจมตัวอย่างด้วยจำนวนมาก ของรหัสที่ไม่เกี่ยวข้องไปยังจุด)
ดูเหมือนว่าเป็นไปได้สำหรับฉันที่คุณอาจต้องการทำให้ getBonusMultiplier คงที่ บางทีคุณอาจต้องการแสดงตัวคูณโบนัสสำหรับพนักงานทุกประเภทโดยไม่จำเป็นต้องมีอินสแตนซ์ของพนักงานในแต่ละหมวดหมู่ จุดประสงค์ของการค้นหาตัวอย่างเช่นอะไร จะเกิดอะไรขึ้นถ้าเรากำลังสร้างพนักงานประเภทใหม่และยังไม่มีพนักงานที่ได้รับมอบหมาย? นี่เป็นฟังก์ชั่นแบบคงที่ทางตรรกะ
แต่มันไม่ทำงาน
และใช่ฉันคิดได้หลายวิธีในการเขียนโค้ดด้านบนเพื่อให้มันทำงานได้ ประเด็นของฉันไม่ใช่ว่ามันจะสร้างปัญหาที่แก้ไม่ได้ แต่มันสร้างกับดักสำหรับโปรแกรมเมอร์ที่ไม่ระวังเพราะภาษานั้นไม่ทำงานอย่างที่คิด
บางทีถ้าฉันพยายามเขียนคอมไพเลอร์สำหรับภาษา OOP ฉันจะเห็นได้อย่างรวดเร็วว่าทำไมการใช้งานมันเพื่อที่ว่าฟังก์ชั่นแบบคงที่จะ overriden อาจเป็นเรื่องยากหรือเป็นไปไม่ได้
หรืออาจมีเหตุผลที่ดีว่าทำไม Java ทำงานในลักษณะนี้ ทุกคนสามารถชี้ให้เห็นถึงข้อได้เปรียบจากพฤติกรรมนี้หมวดหมู่ของปัญหาที่ทำให้ง่ายขึ้นได้หรือไม่ ฉันหมายถึงอย่าเพิ่งชี้ให้ฉันเห็นรายละเอียดภาษาจาวาและพูดว่า "ดูนี่เป็นเอกสารว่ามันทำงานอย่างไร" ฉันรู้แล้ว. แต่มีเหตุผลที่ดีว่าทำไมมันควรทำเช่นนี้? (นอกจากความชัดเจน "การทำให้งานถูกต้องยากเกินไป" ... )
ปรับปรุง
@VicKirk: ถ้าคุณหมายความว่านี่คือ "การออกแบบที่ไม่ดี" เพราะมันไม่เหมาะกับวิธีที่ Java จัดการกับสถิตยศาสตร์การตอบของฉันคือ "เอ่อแน่นอนว่า อย่างที่ฉันพูดไว้ในโพสต์ดั้งเดิมของฉันมันไม่ทำงาน แต่ถ้าคุณหมายถึงว่ามันเป็นการออกแบบที่ไม่ดีในแง่ที่ว่ามีบางอย่างผิดปกติกับภาษาที่ใช้งานได้นั่นคือการที่สถิตยศาสตร์สามารถแทนที่ได้เช่นเดียวกับฟังก์ชั่นเสมือนจริงซึ่งสิ่งนี้จะทำให้เกิดความคลุมเครือ ใช้อย่างมีประสิทธิภาพหรือบางอย่างฉันตอบว่า "ทำไม? มีอะไรผิดปกติกับแนวคิด"
ฉันคิดว่าตัวอย่างที่ฉันให้เป็นเรื่องธรรมดามากที่อยากทำ ฉันมีคลาสที่มีฟังก์ชั่นที่ไม่ได้ขึ้นอยู่กับข้อมูลอินสแตนซ์ใด ๆ และฉันอาจต้องการโทรหาอินสแตนซ์ที่เป็นอิสระจากเหตุผลรวมทั้งต้องการโทรจากภายในวิธีการอินสแตนซ์ เหตุใดจึงไม่ทำงาน ฉันพบกับสถานการณ์นี้หลายครั้งในช่วงหลายปีที่ผ่านมา ในทางปฏิบัติฉันได้รับมันโดยการทำให้ฟังก์ชั่นเสมือนจริงและจากนั้นสร้างวิธีการแบบคงที่ที่มีวัตถุประสงค์ในชีวิตเท่านั้นที่จะเป็นวิธีแบบคงที่ที่ผ่านการเรียกไปยังวิธีการเสมือนกับตัวอย่างบ้า ๆ บอ ๆ ดูเหมือนจะเป็นหนทางที่จะไปถึงที่นั่น
someStatic()
และ B ขยาย A แล้วB.someMethod()
ผูกกับเมธอดใน A หากฉันเพิ่มsomeStatic()
ใน B ในภายหลังรหัสการโทรยังคงเรียกใช้A.someStatic()
จนกว่าฉันจะคอมไพล์รหัสการโทรซ้ำ นอกจากนี้ยังทำให้ฉันประหลาดใจที่bInstance.someStatic()
ใช้ชนิดของ bInstance ที่ประกาศไม่ใช่ชนิดรันไทม์เนื่องจากมันผูกที่คอมไพล์ไม่ใช่ลิงก์ดังนั้นจึงA bInstance; ... bInstance.someStatic()
เรียกใช้ A.someStatic () ถ้ามีถ้า B.someStatic () อยู่
คำตอบสั้น ๆ คือ: เป็นไปได้ทั้งหมด แต่ Java ไม่ได้ทำ
นี่คือรหัสบางส่วนที่แสดงสถานะปัจจุบันของกิจการใน Java:
ไฟล์Base.java
:
package sp.trial;
public class Base {
static void printValue() {
System.out.println(" Called static Base method.");
}
void nonStatPrintValue() {
System.out.println(" Called non-static Base method.");
}
void nonLocalIndirectStatMethod() {
System.out.println(" Non-static calls overridden(?) static:");
System.out.print(" ");
this.printValue();
}
}
ไฟล์Child.java
:
package sp.trial;
public class Child extends Base {
static void printValue() {
System.out.println(" Called static Child method.");
}
void nonStatPrintValue() {
System.out.println(" Called non-static Child method.");
}
void localIndirectStatMethod() {
System.out.println(" Non-static calls own static:");
System.out.print(" ");
printValue();
}
public static void main(String[] args) {
System.out.println("Object: static type Base; runtime type Child:");
Base base = new Child();
base.printValue();
base.nonStatPrintValue();
System.out.println("Object: static type Child; runtime type Child:");
Child child = new Child();
child.printValue();
child.nonStatPrintValue();
System.out.println("Class: Child static call:");
Child.printValue();
System.out.println("Class: Base static call:");
Base.printValue();
System.out.println("Object: static/runtime type Child -- call static from non-static method of Child:");
child.localIndirectStatMethod();
System.out.println("Object: static/runtime type Child -- call static from non-static method of Base:");
child.nonLocalIndirectStatMethod();
}
}
หากคุณใช้งานสิ่งนี้ (ฉันทำบน Mac จาก Eclipse โดยใช้ Java 1.6) คุณจะได้รับ:
Object: static type Base; runtime type Child.
Called static Base method.
Called non-static Child method.
Object: static type Child; runtime type Child.
Called static Child method.
Called non-static Child method.
Class: Child static call.
Called static Child method.
Class: Base static call.
Called static Base method.
Object: static/runtime type Child -- call static from non-static method of Child.
Non-static calls own static.
Called static Child method.
Object: static/runtime type Child -- call static from non-static method of Base.
Non-static calls overridden(?) static.
Called static Base method.
ในกรณีนี้มีเพียงกรณีเดียวที่อาจเป็นเรื่องแปลกใจ (และเป็นคำถามที่เกี่ยวกับ) เป็นกรณีแรก
"ไม่ได้ใช้ชนิดเวลาทำงานเพื่อกำหนดวิธีการคงที่ที่เรียกว่าแม้ว่าจะถูกเรียกด้วยอินสแตนซ์ของวัตถุ ( obj.staticMethod()
)"
และกรณีสุดท้าย :
"เมื่อเรียกเมธอดสแตติกจากภายในเมธอดวัตถุของคลาสเมธอดสแตติกที่เลือกนั้นเป็นวิธีที่เข้าถึงได้จากคลาสนั้นและไม่ได้มาจากคลาสที่กำหนดประเภทเวลาทำงานของวัตถุ"
การเรียกแบบสแตติกได้รับการแก้ไขในเวลาคอมไพล์ขณะที่การเรียกเมธอดแบบไม่คงที่จะถูกแก้ไขในเวลาทำการ โปรดสังเกตว่าแม้ว่าวิธีการแบบสแตติกจะสืบทอด (จากพาเรนต์) แต่จะไม่ถูกแทนที่ (โดยลูก) นี่อาจแปลกใจถ้าคุณคาดหวังเป็นอย่างอื่น
การเรียกใช้เมธอดอ็อบเจ็กต์ได้รับการแก้ไขโดยใช้ชนิดรันไทม์ แต่การเรียกเมธอดแบบสแตติก ( คลาส ) ได้รับการแก้ไขโดยใช้ชนิดเวลาคอมไพล์ (ประกาศ)
ในการเปลี่ยนกฎเหล่านี้เพื่อให้การโทรครั้งสุดท้ายในตัวอย่างที่เรียกว่าการเรียกChild.printValue()
แบบคงที่จะต้องมีประเภทที่เวลาทำงานมากกว่าคอมไพเลอร์การแก้ไขการโทรในเวลารวบรวมที่มีคลาสที่ประกาศของวัตถุ (หรือ บริบท). การโทรแบบสแตติกสามารถใช้ลำดับชั้นชนิด (ไดนามิก) เพื่อแก้ไขการโทรเช่นเดียวกับการเรียกเมธอดวัตถุในวันนี้
สิ่งนี้จะเป็นไปได้อย่างง่ายดาย (ถ้าเราเปลี่ยน Java: -O) และไม่ได้ไร้เหตุผลอย่างไรก็ตามมันมีข้อควรพิจารณาที่น่าสนใจ
พิจารณาหลักคือการที่เราต้องตัดสินใจซึ่งเรียกวิธีแบบคงที่ควรทำเช่นนี้
ในขณะนี้ Java มี "การเล่นโวหาร" ในภาษาที่การobj.staticMethod()
โทรจะถูกแทนที่ด้วยการObjectClass.staticMethod()
โทร (ปกติจะมีคำเตือน) [ หมายเหตุ: ObjectClass
เป็นชนิดที่รวบรวมเวลาของobj
.] obj
เหล่านี้จะเป็นผู้สมัครที่ดีสำหรับการเอาชนะในลักษณะนี้เอาชนิดที่เวลาทำงานของ
ถ้าเราทำมันจะทำให้ร่างกายอ่านวิธีได้ยากขึ้น: การเรียกใช้สแตติกในคลาสพาเรนต์อาจมีการ"กำหนดเส้นทางใหม่" แบบไดนามิก เพื่อหลีกเลี่ยงปัญหานี้เราจะต้องเรียกใช้เมธอดสแตติกที่มีชื่อคลาส - และสิ่งนี้ทำให้การเรียกได้รับการแก้ไขอย่างชัดเจนมากขึ้นด้วยลำดับชั้นของประเภทเวลาคอมไพล์เวลา
วิธีการอื่น ๆ ของการเรียกวิธีคงมีความยุ่งยากมากขึ้น: this.staticMethod()
ควรจะหมายถึงเช่นเดียวกับการใช้ชนิดที่เวลาทำงานของobj.staticMethod()
this
อย่างไรก็ตามสิ่งนี้อาจทำให้เกิดอาการปวดหัวกับโปรแกรมที่มีอยู่ซึ่งเรียกวิธีการคงที่ (เห็นได้ชัดในท้องถิ่น) โดยไม่ต้องตกแต่ง (ซึ่งเทียบเท่ากับเนื้อหาthis.method()
)
ดังนั้นสิ่งที่เกี่ยวกับการโทรแบบไม่มีเครื่องตกแต่งstaticMethod()
? ฉันขอแนะนำให้พวกเขาทำเช่นเดียวกันกับวันนี้และใช้บริบทระดับท้องถิ่นเพื่อตัดสินใจว่าจะทำอย่างไร ความสับสนมิฉะนั้นจะเกิดขึ้นตามมา แน่นอนมันหมายความว่าmethod()
จะหมายถึงthis.method()
ว่าmethod
เป็นวิธีที่ไม่คงที่และThisClass.method()
ถ้าmethod
เป็นวิธีคงที่ นี่เป็นอีกแหล่งที่มาของความสับสน
ถ้าเราเปลี่ยนพฤติกรรมนี้ (และทำให้การโทรแบบคงที่อาจเกิดขึ้นแบบไดนามิกที่ไม่ใช่ท้องถิ่น) เราอาจจะต้องการที่จะทบทวนความหมายของfinal
, private
และprotected
เป็นบ่นเกี่ยวกับstatic
วิธีการของชั้นเรียน จากนั้นเราทุกคนจะต้องคุ้นเคยกับความจริงที่ว่าprivate static
และpublic final
วิธีการไม่ได้ถูกแทนที่และสามารถแก้ไขได้อย่างปลอดภัยในเวลารวบรวมและ "ปลอดภัย" เพื่ออ่านเป็นข้อมูลอ้างอิงในท้องถิ่น
ที่จริงเราผิด
แม้ว่า Java จะไม่อนุญาตให้คุณแทนที่วิธีแบบคงที่โดยค่าเริ่มต้นหากคุณดูเอกสารของคลาสและวิธีการเรียนใน Java อย่างละเอียดคุณยังคงสามารถหาวิธีจำลองแบบคงที่โดยแทนที่วิธีแก้ปัญหาต่อไปนี้:
import java.lang.reflect.InvocationTargetException;
import java.math.BigDecimal;
class RegularEmployee {
private BigDecimal salary = BigDecimal.ONE;
public void setSalary(BigDecimal salary) {
this.salary = salary;
}
public static BigDecimal getBonusMultiplier() {
return new BigDecimal(".02");
}
public BigDecimal calculateBonus() {
return salary.multiply(this.getBonusMultiplier());
}
public BigDecimal calculateOverridenBonus() {
try {
// System.out.println(this.getClass().getDeclaredMethod(
// "getBonusMultiplier").toString());
try {
return salary.multiply((BigDecimal) this.getClass()
.getDeclaredMethod("getBonusMultiplier").invoke(this));
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (IllegalArgumentException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}
} catch (NoSuchMethodException e) {
e.printStackTrace();
} catch (SecurityException e) {
e.printStackTrace();
}
return null;
}
// ... presumably lots of other code ...
}
final class SpecialEmployee extends RegularEmployee {
public static BigDecimal getBonusMultiplier() {
return new BigDecimal(".03");
}
}
public class StaticTestCoolMain {
static public void main(String[] args) {
RegularEmployee Alan = new RegularEmployee();
System.out.println(Alan.calculateBonus());
System.out.println(Alan.calculateOverridenBonus());
SpecialEmployee Bob = new SpecialEmployee();
System.out.println(Bob.calculateBonus());
System.out.println(Bob.calculateOverridenBonus());
}
}
ผลลัพธ์ที่ได้:
0.02
0.02
0.02
0.03
สิ่งที่เราพยายามทำสำเร็จ :)
แม้ว่าเราจะประกาศตัวแปรที่สามของ Carl เป็น RegularEmployee และมอบหมายให้เป็นอินสแตนซ์ของ SpecialEmployee เราจะยังคงมีการเรียกใช้ของวิธีการ CommonEmployee ในกรณีแรกและการเรียกของวิธี SpecialEmployee ในกรณีที่สอง
RegularEmployee Carl = new SpecialEmployee();
System.out.println(Carl.calculateBonus());
System.out.println(Carl.calculateOverridenBonus());
เพียงดูที่คอนโซลเอาต์พุต:
0.02
0.03
;)
วิธีการแบบคงที่จะถือว่าเป็นโลกโดย JVM มีไม่ผูกพันกับวัตถุเช่น
มันอาจเป็นไปได้ในแนวความคิดถ้าคุณสามารถเรียกวิธีการคงที่จากวัตถุคลาส (เช่นในภาษาเช่น Smalltalk) แต่มันไม่ได้เป็นกรณีใน Java
แก้ไข
คุณสามารถoverload static method ได้ แต่คุณไม่สามารถแทนที่เมธอดสแตติกได้เนื่องจากคลาสไม่มีวัตถุชั้นหนึ่ง คุณสามารถใช้การสะท้อนเพื่อรับคลาสของวัตถุในขณะใช้งาน แต่วัตถุที่คุณได้รับนั้นไม่ขนานกับลำดับชั้นของคลาส
class MyClass { ... }
class MySubClass extends MyClass { ... }
MyClass obj1 = new MyClass();
MySubClass obj2 = new MySubClass();
ob2 instanceof MyClass --> true
Class clazz1 = obj1.getClass();
Class clazz2 = obj2.getClass();
clazz2 instanceof clazz1 --> false
คุณสามารถสะท้อนการเรียนได้ แต่มันหยุดอยู่ตรงนั้น คุณไม่เรียกวิธีคงโดยใช้แต่ใช้clazz1.staticMethod()
MyClass.staticMethod()
วิธีการคงที่ไม่ผูกพันกับวัตถุและดังนั้นจึงไม่มีความคิดthis
หรือsuper
วิธีการคงที่ วิธีการคงที่เป็นฟังก์ชั่นระดับโลก; ผลที่ตามมาก็คือไม่มีความคิดของความหลากหลายและดังนั้นวิธีการเอาชนะไม่มีเหตุผล
แต่นี่อาจเป็นไปได้ถ้าMyClass
เป็นวัตถุในเวลาทำงานที่คุณเรียกใช้วิธีการเช่นเดียวกับใน Smalltalk (หรืออาจ JRuby เป็นหนึ่งความคิดเห็นแนะนำ แต่ฉันรู้ว่าไม่มีอะไรของ JRuby)
โอ้ใช่ ... อีกอย่าง คุณสามารถเรียกใช้วิธีการคงที่ผ่านวัตถุobj1.staticMethod()
แต่ที่น้ำตาล syntactic จริง ๆ สำหรับMyClass.staticMethod()
และควรหลีกเลี่ยง มันมักจะเพิ่มคำเตือนใน IDE ที่ทันสมัย ฉันไม่รู้ว่าทำไมพวกเขาจึงอนุญาตทางลัดนี้
clazz2 instanceof clazz1
อย่างถูกต้องคุณสามารถใช้แทนclass2.isAssignableFrom(clazz1)
ซึ่งฉันเชื่อว่าจะกลับมาจริงในตัวอย่างของคุณ
การแทนที่เมธอดนั้นเกิดขึ้นได้โดยการแจกจ่ายแบบไดนามิกซึ่งหมายความว่าชนิดของวัตถุที่ประกาศไม่ได้กำหนดพฤติกรรม แต่เป็นประเภทรันไทม์:
Animal lassie = new Dog();
lassie.speak(); // outputs "woof!"
Animal kermit = new Frog();
kermit.speak(); // outputs "ribbit!"
แม้ว่าทั้งสองlassie
และkermit
ถูกประกาศเป็นออบเจ็กต์ประเภทAnimal
พฤติกรรมของพวกเขา (เมธอด.speak()
) แตกต่างกันไปเนื่องจากการจัดส่งแบบไดนามิกจะผูกเฉพาะการเรียกเมธอด.speak()
ไปยังการใช้งาน ณ เวลารันไทม์ - ไม่ใช่ในเวลาคอมไพล์
ตอนนี้ที่นี่เป็นที่ที่static
คำหลักเริ่มมีเหตุผล: คำว่า "คงที่" เป็นคำตรงกันข้ามสำหรับ "ไดนามิก" ดังนั้นเหตุผลที่คุณไม่สามารถแทนที่เมธอดสแตติกได้เนื่องจากไม่มีการกระจายแบบไดนามิกในสมาชิกแบบสแตติก - เนื่องจากสแตติกหมายถึง "ไม่ไดนามิก" หากพวกเขาส่งแบบไดนามิก (และอาจจะเกิน) static
คำหลักก็จะไม่ทำให้รู้สึกอีกต่อไป
ใช่. จาวาช่วยให้วิธีการแบบคงที่เอาชนะและไม่มีทางทฤษฎีถ้าคุณแทนที่วิธีการแบบคงที่ใน Java แล้วมันจะรวบรวมและทำงานได้อย่างราบรื่น แต่มันจะสูญเสีย Polymorphism ซึ่งเป็นคุณสมบัติพื้นฐานของ Java คุณจะอ่านทุกที่ที่ไม่สามารถลองรวบรวมและใช้งานได้ คุณจะได้รับคำตอบ เช่นถ้าคุณมีคลาสสัตว์และวิธีการแบบคงที่กิน () และคุณแทนที่วิธีแบบคงที่ในคลาสย่อยให้เรียกว่าสุนัข จากนั้นเมื่อใดก็ตามที่คุณกำหนดวัตถุสุนัขให้กับการอ้างอิงสัตว์และเรียกกิน () ตามการกินของ Java Dog Dog () ควรได้รับการเรียก แต่ในสัตว์ที่เอาชนะการกินของสัตว์ () จะถูกเรียก
class Animal {
public static void eat() {
System.out.println("Animal Eating");
}
}
class Dog extends Animal{
public static void eat() {
System.out.println("Dog Eating");
}
}
class Test {
public static void main(String args[]) {
Animal obj= new Dog();//Dog object in animal
obj.eat(); //should call dog's eat but it didn't
}
}
Output Animal Eating
ตามหลักการ Polymorphism Dog Eating
ชวาออกควรจะเป็น
แต่ผลลัพธ์แตกต่างกันเนื่องจากการสนับสนุน Polymorphism Java ใช้การผูกปลายซึ่งหมายความว่าวิธีการที่เรียกว่าเฉพาะในเวลาทำงาน แต่ไม่ใช่ในกรณีของวิธีการคงที่ ในวิธีการคอมไพเลอร์วิธีการเรียกวิธีการที่รวบรวมเวลามากกว่าเวลาทำงานดังนั้นเราจึงได้รับวิธีการตามการอ้างอิงและไม่เป็นไปตามวัตถุการอ้างอิงที่มีที่เป็นเหตุผลว่าทำไมคุณสามารถพูดได้จริงว่ามันรองรับสถิตมากเกินไป 'T
การแทนที่จะถูกสงวนไว้สำหรับสมาชิกอินสแตนซ์เพื่อสนับสนุนพฤติกรรม polymorphic สมาชิกคลาสแบบสแตติกไม่ได้เป็นของอินสแตนซ์เฉพาะ แต่สมาชิกแบบคงที่อยู่ในชั้นเรียนและเนื่องจากการแทนที่ผลลัพธ์ไม่ได้รับการสนับสนุนเนื่องจากคลาสย่อยได้รับการป้องกันและสมาชิกอินสแตนซ์สาธารณะเท่านั้นและไม่ใช่สมาชิกแบบสแตติก คุณอาจต้องการกำหนด inerface และวิจัยโรงงานและ / หรือรูปแบบการออกแบบกลยุทธ์เพื่อประเมินแนวทางอื่น
ใน Java (และภาษา OOP หลายภาษา แต่ฉันไม่สามารถพูดได้ทั้งหมดและบางภาษาไม่มีสแตติกเลย) วิธีการทั้งหมดมีลายเซ็นคงที่ - พารามิเตอร์และประเภท ในวิธีการที่เสมือนพารามิเตอร์แรกบอกเป็นนัย ๆ : this
การอ้างอิงไปยังวัตถุเองและเมื่อเรียกจากภายในวัตถุคอมไพเลอร์เพิ่มโดยอัตโนมัติ
ไม่มีความแตกต่างสำหรับวิธีการคงที่ - พวกเขายังคงมีลายเซ็นคงที่ อย่างไรก็ตามด้วยการประกาศเมธอดสแตติกคุณได้ระบุไว้อย่างชัดเจนว่าคอมไพเลอร์ต้องไม่รวมพารามิเตอร์วัตถุโดยนัยที่จุดเริ่มต้นของลายเซ็นนั้น ดังนั้นรหัสอื่นใดที่เรียกสิ่งนี้ต้องไม่พยายามใส่การอ้างอิงไปยังวัตถุบนสแต็ก หากมันทำเช่นนั้นการดำเนินการของเมธอดจะไม่ทำงานเนื่องจากพารามิเตอร์จะอยู่ในตำแหน่งที่ไม่ถูกต้องและเลื่อนโดยหนึ่ง - บนสแต็ก
เพราะความแตกต่างนี้ระหว่างสอง; วิธีเสมือนมักจะมีการอ้างอิงไปยังวัตถุบริบท (เช่นthis
) ดังนั้นจึงเป็นไปได้ที่จะอ้างอิงสิ่งใดก็ตามภายในฮีปที่เป็นของอินสแตนซ์ของวัตถุนั้น แต่ด้วยวิธีการคงที่เนื่องจากไม่มีการอ้างอิงผ่านวิธีการนั้นไม่สามารถเข้าถึงตัวแปรวัตถุและวิธีการใด ๆ เนื่องจากไม่ทราบบริบท
หากคุณต้องการให้ Java เปลี่ยนนิยามเพื่อให้บริบทของวัตถุถูกส่งผ่านสำหรับทุกวิธีเป็นแบบสแตติกหรือเสมือนคุณจะมีเพียงเมธอดเสมือนเท่านั้น
ในขณะที่มีคนถามถึงความคิดเห็นของผู้ใช้ - เหตุผลและวัตถุประสงค์ของคุณสำหรับการต้องการใช้คุณสมบัตินี้คืออะไร?
ฉันไม่รู้จักรูบิทมากนักเนื่องจาก OP นี้ได้รับการกล่าวถึงฉันได้ทำการวิจัย ฉันเห็นว่าในคลาส Ruby เป็นวัตถุชนิดพิเศษจริงๆและหนึ่งสามารถสร้างวิธีการใหม่ (แม้แบบไดนามิก) คลาสเป็นวัตถุคลาสเต็มใน Ruby พวกเขาไม่ได้อยู่ใน Java นี่เป็นสิ่งที่คุณต้องยอมรับเมื่อทำงานกับ Java (หรือ C #) ภาษาเหล่านี้ไม่ใช่ภาษาไดนามิกแม้ว่า C # จะเพิ่มรูปแบบไดนามิกบางรูปแบบ ในความเป็นจริงทับทิมไม่มีวิธี "คงที่" เท่าที่ฉันสามารถหาได้ - ในกรณีนี้สิ่งเหล่านี้เป็นวิธีการในวัตถุชั้นเดียว จากนั้นคุณสามารถแทนที่ซิงเกิลตันนี้ด้วยคลาสใหม่และวิธีการในคลาสอ็อบเจ็กต์ก่อนหน้าจะเรียกคลาสที่กำหนดไว้ในคลาสใหม่ (ถูกต้อง?) ดังนั้นถ้าคุณเรียกวิธีการหนึ่งในบริบทของคลาสเดิมมันจะยังคงรันเฉพาะสถิตดั้งเดิมเท่านั้น แต่การเรียกใช้เมธอดในคลาสที่ได้รับจะเรียกเมธอดจากพาเรนต์หรือคลาสย่อย น่าสนใจและฉันเห็นคุณค่าในนั้น มันใช้รูปแบบความคิดที่แตกต่าง
เนื่องจากคุณกำลังทำงานใน Java คุณจะต้องปรับให้เข้ากับวิธีการทำสิ่งต่างๆ ทำไมพวกเขาทำเช่นนี้? อาจปรับปรุงประสิทธิภาพในเวลานั้นตามเทคโนโลยีและความเข้าใจที่มีอยู่ ภาษาคอมพิวเตอร์มีการพัฒนาอยู่ตลอดเวลา กลับไปไกลพอและไม่มีสิ่งเช่น OOP ในอนาคตจะมีแนวคิดใหม่อื่น ๆ
แก้ไข : หนึ่งความคิดเห็นอื่น ตอนนี้ฉันเห็นความแตกต่างและในขณะที่ฉันพัฒนา Java / C # ด้วยตนเองฉันสามารถเข้าใจว่าทำไมคำตอบที่คุณได้รับจากนักพัฒนา Java อาจสับสนถ้าคุณมาจากภาษาอย่าง Ruby static
วิธีการของJava ไม่เหมือนกับclass
วิธีของRuby นักพัฒนา Java จะมีเวลาทำความเข้าใจกับเรื่องนี้เช่นเดียวกับคนที่ทำงานด้วยภาษาอย่าง Ruby / Smalltalk ฉันเห็นได้ว่าสิ่งนี้จะทำให้เกิดความสับสนอย่างมากจากความจริงที่ว่า Java ยังใช้ "วิธีการเรียน" เป็นวิธีอื่นในการพูดคุยเกี่ยวกับวิธีการคงที่ แต่คำเดียวกันนี้ใช้ทับทิมต่างกัน Java ไม่มีวิธีการเรียนสไตล์ Ruby (ขออภัย); Ruby ไม่ได้มีวิธีการคงที่ของรูปแบบ Java ซึ่งเป็นจริงเพียงแค่ฟังก์ชั่นรูปแบบขั้นตอนเก่าที่พบใน C.
โดยวิธีการ - ขอบคุณสำหรับคำถาม! ฉันเรียนรู้สิ่งใหม่สำหรับฉันในวันนี้เกี่ยวกับวิธีการเรียน (สไตล์ทับทิม)
ดี ... คำตอบคือไม่ถ้าคุณคิดจากมุมมองของวิธี overriden ควรทำงานใน Java แต่คุณจะไม่ได้รับข้อผิดพลาดของคอมไพเลอร์หากคุณพยายามที่จะแทนที่วิธีคงที่ ซึ่งหมายความว่าหากคุณพยายามแทนที่ Java จะไม่หยุดคุณทำเช่นนั้น แต่แน่นอนคุณจะไม่ได้รับผลเช่นเดียวกับที่คุณได้รับสำหรับวิธีการไม่คงที่ การเอาชนะใน Java นั้นหมายถึงว่าวิธีการเฉพาะจะถูกเรียกตามชนิดเวลาทำงานของวัตถุและไม่ได้อยู่ในประเภทเวลารวบรวมของมัน (ซึ่งเป็นกรณีที่มีวิธีคงที่ overriden) โอเค ... เดาว่าทำไมพวกเขาถึงมีพฤติกรรมแปลก ๆ ? เนื่องจากเป็นวิธีการเรียนและด้วยเหตุนี้การเข้าถึงพวกเขาจึงได้รับการแก้ไขในช่วงเวลารวบรวมเท่านั้นโดยใช้ข้อมูลประเภทเวลารวบรวม
ตัวอย่าง : ลองมาดูกันว่าเกิดอะไรขึ้นถ้าเราพยายามเอาชนะเมธอดแบบสแตติก: -
class SuperClass {
// ......
public static void staticMethod() {
System.out.println("SuperClass: inside staticMethod");
}
// ......
}
public class SubClass extends SuperClass {
// ......
// overriding the static method
public static void staticMethod() {
System.out.println("SubClass: inside staticMethod");
}
// ......
public static void main(String[] args) {
// ......
SuperClass superClassWithSuperCons = new SuperClass();
SuperClass superClassWithSubCons = new SubClass();
SubClass subClassWithSubCons = new SubClass();
superClassWithSuperCons.staticMethod();
superClassWithSubCons.staticMethod();
subClassWithSubCons.staticMethod();
// ...
}
}
ผลลัพธ์ : -
SuperClass: inside staticMethod
SuperClass: inside staticMethod
SubClass: inside staticMethod
สังเกตเห็นบรรทัดที่สองของผลลัพธ์ มี staticMethod ที่ถูกกว่าบรรทัดนี้ควรจะเหมือนกันกับบรรทัดที่สามในขณะที่เรากำลังเรียก 'staticMethod ()' บนวัตถุประเภท Runtime เป็น 'SubClass' และไม่เป็น 'SuperClass' สิ่งนี้ยืนยันว่าวิธีการคงที่ได้รับการแก้ไขเสมอโดยใช้ข้อมูลประเภทเวลารวบรวมเท่านั้น
โดยทั่วไปแล้วมันไม่มีเหตุผลที่จะอนุญาตให้ 'แทนที่' ของวิธีการคงที่เนื่องจากไม่มีวิธีที่ดีในการพิจารณาว่าจะเรียกใช้งานที่ใดในรันไทม์ รับตัวอย่างพนักงานถ้าเราเรียก RegularEmployee.getBonusMultiplier () - ควรใช้วิธีการแบบไหน?
ในกรณีของ Java ใคร ๆ ก็สามารถจินตนาการนิยามภาษาที่เป็นไปได้ที่จะ 'แทนที่' วิธีการคงที่ตราบใดที่พวกเขาจะถูกเรียกผ่านวัตถุเช่น อย่างไรก็ตามทั้งหมดนี้จะทำคือการใช้วิธีการเรียนปกติอีกครั้งเพิ่มความซ้ำซ้อนในภาษาโดยไม่ต้องเพิ่มประโยชน์
โดยการเอาชนะเราสามารถสร้างลักษณะ polymorphic ขึ้นอยู่กับชนิดของวัตถุ วิธีการคงไม่มีความสัมพันธ์กับวัตถุ ดังนั้นจาวาไม่สามารถรองรับวิธีการคงที่ที่เอาชนะ
ฉันชอบและแสดงความคิดเห็นเป็นสองเท่าของ Jay ( https://stackoverflow.com/a/2223803/1517187 )
ฉันยอมรับว่านี่เป็นการออกแบบที่ไม่ดีของ Java
ภาษาอื่น ๆ อีกมากมายรองรับวิธีการคงที่ดังที่เราเห็นในความคิดเห็นก่อนหน้า ฉันรู้สึกว่า Jay มาที่ Java จาก Delphi เช่นฉัน
Delphi (Object Pascal) เป็นภาษาแรกที่ใช้ OOP
เห็นได้ชัดว่าหลายคนเคยมีประสบการณ์กับภาษานั้นมาตั้งแต่ก่อนหน้านี้เป็นภาษาเดียวที่เขียนผลิตภัณฑ์ GUI เชิงพาณิชย์ และ - ใช่เราทำได้ในวิธีการแทนที่ Delphi แบบคงที่ อันที่จริงวิธีการคงที่ใน Delphi เรียกว่า "วิธีการเรียน" ในขณะที่ Delphi มีแนวคิดที่แตกต่างกันของ "วิธีการ Delphi คงที่" ซึ่งเป็นวิธีการที่มีผลผูกพันก่อน ในการแทนที่วิธีการที่คุณต้องใช้การรวมล่าช้าให้ประกาศคำสั่ง "เสมือน" ดังนั้นมันจึงสะดวกและใช้งานง่ายและฉันคาดหวังสิ่งนี้ใน Java
มันจะทำอย่างไรดีเพื่อแทนที่วิธีคงที่ คุณไม่สามารถเรียกวิธีการคงที่ผ่านอินสแตนซ์
MyClass.static1()
MySubClass.static1() // If you overrode, you have to call it through MySubClass anyway.
แก้ไข: ดูเหมือนว่าผ่านการกำกับดูแลโชคร้ายในการออกแบบภาษาคุณสามารถเรียกวิธีการคงที่ผ่านอินสแตนซ์ โดยทั่วไปไม่มีใครทำอย่างนั้น ความผิดฉันเอง.
variable.staticMethod()
แทนClass.staticMethod()
ซึ่งเป็นตัวแปรที่มีประเภทการประกาศให้เป็นvariable
Class
ฉันเห็นด้วยว่ามันคือการออกแบบภาษาที่ไม่ดี
การเอาชนะใน Java นั้นหมายถึงว่าวิธีการเฉพาะนั้นจะถูกเรียกตามชนิด runtime ของวัตถุและไม่ได้อยู่ในประเภทเวลารวบรวมของมัน (ซึ่งเป็นกรณีที่มีวิธีคงที่แทนที่) เนื่องจากวิธีการแบบสแตติกเป็นวิธีการเรียนพวกเขาไม่ใช่วิธีการแบบอินสแตนซ์ดังนั้นพวกเขาจึงไม่มีอะไรเกี่ยวข้องกับความจริงที่การอ้างอิงชี้ไปที่วัตถุหรืออินสแตนซ์เนื่องจากเนื่องจากลักษณะของวิธีการแบบคงที่ คุณสามารถประกาศใหม่ในคลาสย่อย แต่คลาสย่อยนั้นไม่ทราบอะไรเกี่ยวกับวิธีการคงที่ของคลาสพาเรนต์เพราะอย่างที่ฉันบอกว่ามันเป็นคลาสเฉพาะที่คลาสนั้นถูกประกาศเท่านั้น การเข้าถึงพวกเขาโดยใช้การอ้างอิงวัตถุเป็นเพียงเสรีภาพพิเศษที่นักออกแบบของ Java และเราไม่ควรคิดที่จะหยุดการฝึกนั้นเมื่อพวกเขา จำกัด รายละเอียดและตัวอย่างเพิ่มเติม http://faisalbhagat.blogspot.com/2014/09/method-overriding-and-method-hiding.html
คุณจะได้รับพหุสัณฐานแบบไดนามิก เมื่อคุณพูดถึงวิธีการคงที่คำศัพท์ที่คุณพยายามใช้นั้นขัดแย้งกัน
คงที่พูด - เวลารวบรวมการเอาชนะถูกนำมาใช้สำหรับความแตกต่างแบบไดนามิก ทั้งสองอยู่ตรงกันข้ามกันในธรรมชาติและดังนั้นจึงไม่สามารถใช้ร่วมกัน
พฤติกรรมโพลีมอร์ฟิคแบบไดนามิกเกิดขึ้นเมื่อโปรแกรมเมอร์ใช้วัตถุและเข้าถึงวิธีการอินสแตนซ์ JRE จะแม็พวิธีอินสแตนซ์ที่ต่างกันของคลาสที่แตกต่างกันตามชนิดของวัตถุที่คุณใช้
เมื่อคุณพูดถึงวิธีการคงที่วิธีการคงที่เราจะเข้าถึงโดยใช้ชื่อชั้นเรียนซึ่งจะถูกเชื่อมโยงในเวลารวบรวมดังนั้นจึงไม่มีแนวคิดของการเชื่อมโยงวิธีการที่รันไทม์ด้วยวิธีการแบบคงที่ ดังนั้นคำว่า "แทนที่" วิธีการคงที่ตัวเองไม่ได้ทำให้ความหมายใด ๆ
หมายเหตุ: แม้ว่าคุณจะเข้าถึงวิธีการเรียนกับวัตถุ แต่คอมไพเลอร์ java ยังฉลาดพอที่จะค้นหาและจะทำการเชื่อมโยงแบบสแตติก
Box.createBox
ให้ความรู้สึกมากกว่าBoxFactory.createBox
และเป็นรูปแบบที่หลีกเลี่ยงไม่ได้เมื่อต้องการสร้างการตรวจสอบข้อผิดพลาดโดยไม่โยนข้อยกเว้น (ตัวสร้างไม่สามารถล้มเหลวพวกเขาสามารถฆ่ากระบวนการ / โยน ยกเว้น) ในขณะที่วิธีการคงสามารถกลับ null ในความล้มเหลวหรือแม้กระทั่งยอมรับการเรียกกลับประสบความสำเร็จ / ข้อผิดพลาดในการเขียนสิ่งที่ต้องการhastebin.com/codajahati.java
คำตอบของคำถามนี้ง่ายมากวิธีการหรือตัวแปรที่ทำเครื่องหมายเป็นสแตติกเป็นของคลาสเท่านั้นดังนั้นเมธอดสแตติกไม่สามารถสืบทอดในคลาสย่อยเนื่องจากเป็นของคลาสพิเศษเท่านั้น
ทางออกที่ง่าย: ใช้อินสแตนซ์เดี่ยว มันจะช่วยให้แทนที่และมรดก
ในระบบของฉันฉันมีชั้น SingletonsRegistry ซึ่งส่งคืนอินสแตนซ์สำหรับระดับที่ผ่าน หากไม่พบอินสแตนซ์จะถูกสร้างขึ้น
ชั้นเรียนภาษา Haxe:
package rflib.common.utils;
import haxe.ds.ObjectMap;
class SingletonsRegistry
{
public static var instances:Map<Class<Dynamic>, Dynamic>;
static function __init__()
{
StaticsInitializer.addCallback(SingletonsRegistry, function()
{
instances = null;
});
}
public static function getInstance(cls:Class<Dynamic>, ?args:Array<Dynamic>)
{
if (instances == null) {
instances = untyped new ObjectMap<Dynamic, Dynamic>();
}
if (!instances.exists(cls))
{
if (args == null) args = [];
instances.set(cls, Type.createInstance(cls, args));
}
return instances.get(cls);
}
public static function validate(inst:Dynamic, cls:Class<Dynamic>)
{
if (instances == null) return;
var inst2 = instances[cls];
if (inst2 != null && inst != inst2) throw "Can\'t create multiple instances of " + Type.getClassName(cls) + " - it's singleton!";
}
}
Singleton.get()
. รีจิสทรีเป็นค่าใช้จ่ายในการสร้างต้นแบบและจะขัดขวาง GC ในชั้นเรียน
วิธีการคงที่ตัวแปรบล็อกหรือระดับที่ซ้อนกันอยู่ในชั้นเรียนทั้งหมดมากกว่าวัตถุ
วิธีการใน Java ใช้ในการเปิดเผยพฤติกรรมของวัตถุ / คลาส ที่นี่เนื่องจากวิธีนี้เป็นแบบสแตติก (เช่นวิธีแบบสแตติกใช้เพื่อแสดงพฤติกรรมของคลาสเท่านั้น) การเปลี่ยน / ลบล้างพฤติกรรมของคลาสทั้งหมดจะเป็นการละเมิดปรากฏการณ์ของหนึ่งในเสาหลักพื้นฐานของการเขียนโปรแกรมเชิงวัตถุคือการทำงานร่วมกันในระดับสูง . (จำไว้ว่าตัวสร้างเป็นวิธีการพิเศษใน Java)
High Cohesion - คลาสหนึ่งควรมีเพียงหนึ่งบทบาท ตัวอย่างเช่น: คลาสรถยนต์ควรผลิตวัตถุรถยนต์เท่านั้นไม่ใช่จักรยานรถบรรทุกเครื่องบิน ฯลฯ แต่คลาสรถยนต์อาจมีคุณสมบัติบางอย่าง (พฤติกรรม) ที่เป็นของตัวเองเท่านั้น
ดังนั้นในขณะที่ออกแบบภาษาโปรแกรมจาวา ผู้ออกแบบภาษาคิดว่าจะอนุญาตให้ผู้พัฒนาเก็บพฤติกรรมบางอย่างของชั้นเรียนให้กับตัวเองเท่านั้นโดยการทำให้วิธีการคงที่ในธรรมชาติ
รหัสชิ้นด้านล่างพยายามแทนที่วิธีคงที่ แต่จะไม่พบข้อผิดพลาดในการรวบรวม
public class Vehicle {
static int VIN;
public static int getVehileNumber() {
return VIN;
}}
class Car extends Vehicle {
static int carNumber;
public static int getVehileNumber() {
return carNumber;
}}
นี้เป็นเพราะที่นี่เรายังไม่ได้เอาชนะวิธี แต่เราเป็นเพียงอีกครั้งประกาศมัน Java อนุญาตให้ประกาศใหม่ของวิธีการ (คงที่ / ไม่คงที่)
การลบคำหลักคงที่จากวิธี getVehileNumber () ของคลาสรถยนต์จะส่งผลให้เกิดข้อผิดพลาดในการรวบรวมเนื่องจากเราพยายามเปลี่ยนการทำงานของวิธีการคงที่ซึ่งเป็นของคลาสยานพาหนะเท่านั้น
นอกจากนี้หาก getVehileNumber () ถูกประกาศให้เป็นรหัสสุดท้ายแล้วจะไม่รวบรวมเนื่องจากคำหลักสุดท้ายจะ จำกัด โปรแกรมเมอร์จากการประกาศวิธีการใหม่
public static final int getVehileNumber() {
return VIN; }
โดยรวมแล้วนี่เป็นการออกแบบซอฟท์แวร์สำหรับที่ที่จะใช้วิธีการคงที่ ฉันชอบใช้วิธีการแบบสแตติกเพื่อดำเนินการบางอย่างโดยไม่ต้องสร้างอินสแตนซ์ของคลาส ประการที่สองเพื่อซ่อนพฤติกรรมของชั้นเรียนจากโลกภายนอก
นี่คือคำอธิบายง่ายๆ วิธีการคงที่เกี่ยวข้องกับคลาสในขณะที่วิธีการอินสแตนซ์ที่เกี่ยวข้องกับวัตถุเฉพาะ การแทนที่จะอนุญาตให้เรียกใช้งานวิธีการแทนที่ที่เกี่ยวข้องกับวัตถุนั้น ๆ ได้ ดังนั้นมันจึงตอบโต้ง่าย ๆ ที่จะแทนที่วิธีสแตติกซึ่งไม่ได้เกี่ยวข้องกับวัตถุ แต่เป็นคลาสเองในตอนแรก ดังนั้นวิธีการคงที่ไม่สามารถถูกแทนที่โดยขึ้นอยู่กับวัตถุที่เรียกมันมันจะถูกเชื่อมโยงกับคลาสที่มันถูกสร้างขึ้น
public abstract IBox createBox();
อินเทอร์เฟซภายใน IBox อย่างไร Box สามารถใช้ IBox เพื่อแทนที่ createBox และมีการสร้างผลลัพธ์วัตถุใน IBox ที่ถูกต้องมิฉะนั้นคืนค่า null คอนสตรัคเตอร์ไม่สามารถส่งคืน "ว่าง" ดังนั้นคุณจึงถูกบังคับให้ (1) ใช้ข้อยกเว้นทุกที่ (สิ่งที่เราทำตอนนี้) หรือ (2) สร้างคลาสโรงงานที่ทำในสิ่งที่ฉันพูดไว้ก่อนหน้านี้ ของ Java (ซึ่งเราทำด้วย) วิธีการที่ไม่ได้ใช้งานแบบคงที่แก้ปัญหานี้
ตอนนี้เห็นข้างต้นคำตอบที่ทุกคนรู้ว่าเราไม่สามารถแทนที่วิธีคงที่ แต่ไม่ควรเข้าใจผิดเกี่ยวกับแนวความคิดของการเข้าถึงวิธีการคงจากประเภทรอง
เราสามารถเข้าถึงวิธีสแตติกของคลาสซูเปอร์พร้อมการอ้างอิงคลาสย่อยหากวิธีสแตติกนี้ไม่ได้ถูกซ่อนโดยวิธีสแตติกใหม่ที่กำหนดในคลาสย่อย
ตัวอย่างเช่นดูรหัสด้านล่าง: -
public class StaticMethodsHiding {
public static void main(String[] args) {
SubClass.hello();
}
}
class SuperClass {
static void hello(){
System.out.println("SuperClass saying Hello");
}
}
class SubClass extends SuperClass {
// static void hello() {
// System.out.println("SubClass Hello");
// }
}
เอาท์พุท: -
SuperClass saying Hello
ดูJava oracle docsและค้นหาสิ่งที่คุณสามารถทำได้ในคลาสย่อยสำหรับรายละเอียดเกี่ยวกับการซ่อนเมธอดสแตติกในคลาสย่อย
ขอบคุณ
รหัสต่อไปนี้แสดงให้เห็นว่าเป็นไปได้:
class OverridenStaticMeth {
static void printValue() {
System.out.println("Overriden Meth");
}
}
public class OverrideStaticMeth extends OverridenStaticMeth {
static void printValue() {
System.out.println("Overriding Meth");
}
public static void main(String[] args) {
OverridenStaticMeth osm = new OverrideStaticMeth();
osm.printValue();
System.out.println("now, from main");
printValue();
}
}
osm
เป็นไม่ได้OverridenStaticMeth
OverrideStaticMeth