ทำไมตัวแปรอินเทอร์เฟซคงที่และครั้งสุดท้ายโดยค่าเริ่มต้น?


274

ทำไมตัวแปรอินเทอร์เฟซคงที่และครั้งสุดท้ายตามค่าเริ่มต้นใน Java?


41
คุณไม่ควรใส่ตัวแปรใด ๆ ในอินเทอร์เฟซ
cherouvim

34
เพราะอินเตอร์เฟสกำหนดสัญญาซึ่งสามารถนำไปใช้ได้หลายวิธี ค่าของตัวแปรคือการนำไปใช้
cherouvim

10
เราสามารถทำได้อย่างแน่นอนเมื่อเรารู้ว่าชั้นเรียนทั้งหมดที่ใช้อินเทอร์เฟซมีตัวแปรคงที่บางอย่าง (เช่นชื่อฟิลด์)
Aniket Thakur

เป็นความคิดที่ดีที่จะสร้างตัวแปรในคลาสเป็นอินสแตนซ์ของอินเทอร์เฟซที่คลาสใช้หรือไม่? ฉันเคยได้ยินเรื่องนี้มาก่อน
Doug Hauf

อินเทอร์เฟซใน java เป็นไปตามหลักการของกรดสุดท้ายเพราะการฟื้นฟูใน C. @cherouvim ประเภทของตัวแปรคือการใช้งานตัวแปรจะต้องประกาศโดยมีหรือไม่มีค่าและความหมายของตัวแปรเป็นค่า หากคุณเปลี่ยนค่าของตัวแปรไม่ใช่การปรับใช้ใหม่หมายถึงการกำหนดใหม่
กลัว

คำตอบ:


264

จากคำถามที่พบบ่อยการออกแบบอินเตอร์เฟส Java โดย Philip Shaw:

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

แหล่ง


39
โปรดทราบว่าคลาสนามธรรมไม่สามารถสร้างอินสแตนซ์ "ในสิทธิ์ของตนเอง" และไม่สามารถมีตัวแปรอินสแตนซ์ได้
macias

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

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

6
อินเทอร์เฟซไม่สามารถมีตัวแปรอินสแตนซ์เพื่อหลีกเลี่ยงการสืบทอดปัญหาสถานะหลายอย่าง ดูdocs.oracle.com/javase/tutorial/java/IandI/... คลาสไม่สามารถขยายได้มากกว่าหนึ่งคลาสเนื่องจากเหตุผลเดียวกัน
เดนิส

1
มีการแนะนำวิธีการเริ่มต้นอย่างไรและมีอินสแตนซ์ แต่ยังไม่รองรับตัวแปรอินสแตนซ์ ...
M.kazem Akhgary

41

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

ดังนั้นหากมีตัวแปรอินเตอร์เฟซก็จะคงที่โดยปริยายสุดท้ายและสาธารณะอย่างเห็นได้ชัด !!!


แน่นอนตัวแปรเช่นจะสามารถเข้าถึงได้ถ้าได้รับอนุญาตใน interfaceJava คลาสจะใช้อินเทอร์เฟซเพื่อประกาศตัวแปรอินสแตนซ์ (ตามที่ต้องการโดยอินเตอร์เฟส) มันคอนสตรัค (หรือวิธีอื่น ๆ ) ตั้งค่าตัวแปรอินสแตนซ์ เมื่ออินสแตนซ์ของคลาสนั้นอินสแตนซ์คุณจะสามารถเข้าถึงตัวแปรอินสแตนซ์ของมัน
pyrocrasty

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

36

สาธารณะ : สำหรับการเข้าถึงในทุกชั้นเรียนเช่นเดียวกับวิธีการที่มีอยู่ในอินเทอร์เฟซ

คงที่ : เนื่องจากอินเตอร์เฟสไม่สามารถมีวัตถุได้ interfaceName.variableName สามารถใช้เพื่ออ้างอิงหรือตัวแปรโดยตรงในคลาสที่นำไปใช้

ขั้นสุดท้าย : เพื่อทำให้พวกเขาคงที่ หาก 2 คลาสใช้อินเตอร์เฟสเดียวกันและคุณให้สิทธิ์ในการเปลี่ยนค่าทั้งสองค่าความขัดแย้งจะเกิดขึ้นในค่าปัจจุบันของ var ซึ่งเป็นสาเหตุที่อนุญาตให้เริ่มต้นได้เพียงครั้งเดียวเท่านั้น

นอกจากนี้ตัวดัดแปลงเหล่านี้ทั้งหมดจะมีนัยสำหรับอินเทอร์เฟซคุณไม่จำเป็นต้องระบุใด ๆ เลย


15

( นี่ไม่ใช่คำตอบเชิงปรัชญา แต่เป็นคำตอบเชิงปฏิบัติมากกว่า ) ข้อกำหนดสำหรับstaticตัวดัดแปลงนั้นชัดเจนซึ่งผู้อื่นได้ตอบแล้ว โดยทั่วไปตั้งแต่การเชื่อมต่อที่ไม่สามารถ instantiated วิธีเดียวที่จะเข้าถึงเขตข้อมูลที่มีเพื่อให้ข้อมูลชั้นเรียน static-

เหตุผลที่อยู่เบื้องหลังinterfaceเขตข้อมูลกลายเป็นโดยอัตโนมัติfinal(คงที่) คือการป้องกันการใช้งานที่แตกต่างกันโดยไม่ตั้งใจเปลี่ยนค่าของตัวแปรอินเตอร์เฟสซึ่งอาจส่งผลกระทบต่อพฤติกรรมของการใช้งานอื่น ๆ โดยไม่ได้ตั้งใจ ลองนึกภาพสถานการณ์ด้านล่างที่interfaceทรัพย์สินไม่ได้เป็นfinalJava อย่างชัดเจน:

public interface Actionable {
    public static boolean isActionable = false;

    public void performAction();
}

public NuclearAction implements Actionable {

    public void performAction() {
        // Code that depends on isActionable variable
        if (isActionable) {
            // Launch nuclear weapon!!!
        }
    }
}

ทีนี้ลองคิดดูสิว่าจะเกิดอะไรขึ้นถ้าคลาสอื่นที่ปรับActionableเปลี่ยนสถานะของตัวแปรอินเตอร์เฟส:

public CleanAction implements Actionable  {

    public void performAction() {
        // Code that can alter isActionable state since it is not constant
        isActionable = true;
    }
}

หากคลาสเหล่านี้ถูกโหลดภายใน JVM เดียวโดย classloader ดังนั้นพฤติกรรมของNuclearActionสามารถได้รับผลกระทบจากคลาสอื่นCleanActionเมื่อperformAction()มีการเรียกใช้หลังจากCleanActionที่มีการดำเนินการ (ในเธรดเดียวกันหรืออย่างอื่น) ซึ่งในกรณีนี้อาจเป็นหายนะ (ความหมายนั่นคือ)

เนื่องจากเราไม่ทราบว่าการนำไปปฏิบัติแต่ละครั้งinterfaceจะใช้ตัวแปรเหล่านี้finalอย่างไร


9

เนื่องจากสิ่งอื่นเป็นส่วนหนึ่งของการนำไปใช้และอินเตอร์เฟสไม่สามารถมีการนำไปใช้งานได้


1
ถ้าเช่นนั้นอะไรคือเหตุผลของการตัดสินใจครั้งสุดท้าย
Jothi

7
เพื่อระบุว่ามันคงที่ Java ไม่มีคำหลัก const คงสุดท้ายคือวิธีที่คุณประกาศค่าคงที่
Amir Afghanani

5
ตั้งแต่ Java 8 พวกเขาสามารถมีการใช้งาน แต่ก็ขอแนะนำอย่างยิ่งที่จะไม่ใช้มันหากคุณไม่ต้องการความเข้ากันได้ backwarts :)
codepleb

6
public interface A{
    int x=65;
}
public interface B{
    int x=66;
}
public class D implements A,B {
    public static void main(String[] a){
        System.out.println(x); // which x?
    }
}

นี่คือทางออก

System.out.println(A.x); // done

ฉันคิดว่ามันเป็นเหตุผลหนึ่งที่ตัวแปรอินเตอร์เฟซคงที่

อย่าประกาศตัวแปรภายในส่วนต่อประสาน


3
ในความเป็นจริงโดยไม่ต้องสเปค "ขวาน" มันจะไม่ได้รวบรวม" ดังนั้นจึงมีความปลอดภัยจริงที่จะใช้ตัวแปร (ซึ่งโดยปริยายจะคงที่สาธารณะสุดท้าย) ในอินเตอร์เฟซ.
มาร์โก

ฉันไม่เห็นด้วยกับคำตอบในขณะที่ @Marco บอกว่าจะไม่ได้รวบรวม ฉันไม่พบข้อเสียอื่นใด ๆ ในตอนนี้บางทีคุณอาจไม่เห็นว่าเขียนไว้static finalก่อนหน้าตัวแปรที่เป็นแบบสแตติกและสุดท้าย
Micer

5

คงที่ - เพราะอินเตอร์เฟซไม่สามารถมีตัวอย่างใด ๆ และสุดท้าย - เพราะเราไม่จำเป็นต้องเปลี่ยน


15
"เราไม่ต้องการ" == "เราไม่ได้รับอนุญาต" อย่าผสมความหมาย
peterh - Reinstate Monica

3

เพราะ:

Static : เนื่องจากเราไม่สามารถมีวัตถุของอินเตอร์เฟสได้ดังนั้นเราจึงควรหลีกเลี่ยงการใช้ตัวแปรระดับสมาชิก Object และควรใช้ตัวแปรระดับ class เช่น static

Final : เพื่อให้เราไม่ควรมีค่าที่ไม่ชัดเจนสำหรับตัวแปร (ปัญหาเพชร - การสืบทอดหลายอย่าง)

และเป็นไปตามเอกสารประกอบการติดต่อเป็นสัญญาและไม่ดำเนินการ

การอ้างอิง: คำตอบของ Abhishek Jain เกี่ยวกับโควต้า


2

Java ไม่อนุญาตให้ใช้ตัวแปรเชิงนามธรรมและ / หรือคำจำกัดความของตัวสร้างในอินเตอร์เฟส การแก้ไข: เพียงแค่วางคลาสนามธรรมระหว่างอินเทอร์เฟซของคุณและการใช้งานของคุณซึ่งจะขยายคลาสนามธรรมเช่นนั้น:

 public interface IMyClass {

     void methodA();
     String methodB();
     Integer methodC();

 }

 public abstract class myAbstractClass implements IMyClass {
     protected String varA, varB;

     //Constructor
     myAbstractClass(String varA, String varB) {
         this.varA = varA;
         this.varB = VarB;
     }

     //Implement (some) interface methods here or leave them for the concrete class
     protected void methodA() {
         //Do something
     }

     //Add additional methods here which must be implemented in the concrete class
     protected abstract Long methodD();

     //Write some completely new methods which can be used by all subclasses
     protected Float methodE() {
         return 42.0;
     }

 }

 public class myConcreteClass extends myAbstractClass {

     //Constructor must now be implemented!
     myClass(String varA, String varB) {
         super(varA, varB);
     }

     //All non-private variables from the abstract class are available here
     //All methods not implemented in the abstract class must be implemented here

 }

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

(คำหลัก "ป้องกัน" หมายความว่าเฉพาะคลาสที่ขยายเท่านั้นที่สามารถเข้าถึงวิธีการและตัวแปรเหล่านี้ได้)

สไปโร


1

อินเทอร์เฟซคือสัญญาระหว่างสองฝ่ายที่ไม่แปรเปลี่ยนแกะสลักในหิน ดูออกแบบโดยสัญญา


1

อินเตอร์เฟส: บริการตามความต้องการของระบบ

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

สาธารณะ:มันเกิดขึ้นบางครั้งอินเทอร์เฟซที่อาจวางไว้ในแพคเกจอื่น ๆ ดังนั้นจึงจำเป็นต้องเข้าถึงตัวแปรจากที่ใดก็ได้ในโครงการ

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

final:สมมติว่าหนึ่งอินเตอร์เฟสใช้หลายคลาสและคลาสทั้งหมดพยายามเข้าถึงและอัพเดตตัวแปรอินเตอร์เฟส ดังนั้นจึงนำไปสู่การเปลี่ยนแปลงข้อมูลที่ไม่สอดคล้องและส่งผลกระทบต่อคลาสอื่น ๆ ทุกคลาส ดังนั้นจึงจำเป็นต้องประกาศตัวปรับปรุงการเข้าถึงด้วยขั้นตอนสุดท้าย


0

ในJavaอินเทอร์เฟซไม่อนุญาตให้คุณประกาศตัวแปรอินสแตนซ์ใด ๆ การใช้ตัวแปรที่ประกาศในอินเตอร์เฟสเป็นตัวแปรอินสแตนซ์จะส่งคืนข้อผิดพลาดในเวลาคอมไพล์

คุณสามารถประกาศตัวแปรคงที่โดยใช้static finalซึ่งแตกต่างจากตัวแปรอินสแตนซ์


นี่เป็นสิ่งที่ผิดธรรมดา คอมไพเลอร์จะไม่บ่นถ้าคุณทำให้มันเป็นส่วนตัวหรือได้รับการคุ้มครอง ภายใต้ฝากระโปรงดังที่คนอื่นพูดถึงแล้ว และฉันคิดว่ามันชัดเจนว่าทำไม เนื่องจากอินเทอร์เฟซหมายถึงการกำหนดพฤติกรรมไม่ใช่สถานะ
Mikayil Abdullayev

0

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


0

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


0

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

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

ฉันพยายามใส่แบบคงที่หรือไม่สร้างความแตกต่างเลย รหัสดังต่อไปนี้:

public interface Addable {
    static int count = 6;

    public int add(int i);

}

public class Impl implements Addable {

    @Override
    public int add(int i) {
        return i+count;
    }
}

public class Test {

    public static void main(String... args) {
        Impl impl = new Impl();

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