เหตุใดคุณจึงไม่สามารถประกาศคลาสเป็นสแตติกใน Java


459

เหตุใดคุณจึงไม่สามารถประกาศคลาสเป็นสแตติกใน Java


72
Counter-คำถาม: สิ่งที่คุณจะคาดหวังว่าผลที่ออกมาจะเป็นถ้าคุณประกาศให้เป็นระดับระดับบนสุดจะเป็นstatic?
Joachim Sauer

3
ไม่ได้คุณไม่สามารถยกเว้นชั้นเรียนคงที่ แต่คุณต้องการทำอะไรกับสิ่งนั้น
manolowar

60
@Joachim Sauer: ดี C # ตีความstaticคลาสabstract finalเช่นพวกเขาไม่สามารถยกตัวอย่างและไม่สามารถขยายได้ ซึ่งหมายความว่าพวกเขาสามารถมีสมาชิกแบบคงที่เท่านั้นซึ่งมีประโยชน์สำหรับคลาสที่มีวิธีการช่วยเหลือเท่านั้น
bcat

30
@bcat นี่เป็นความจริงสำหรับ C # แต่คลาส java สามารถเป็นนามธรรมหรือสุดท้ายไม่ใช่ทั้งสองอย่าง เพื่อป้องกันไม่ให้คลาสอินสแตนซ์เราสามารถประกาศ Constructor ส่วนตัวได้
Lorenzo Polidori

7
@JoachimSauer ง่าย ๆ ฉันชอบที่จะบังคับให้สมาชิกทุกคนในชั้นเรียนคงที่ (อาจต้องประกาศด้วยวิธีหรือคุณสมบัติแต่ละอย่างด้วย)
hmartinezd

คำตอบ:


475

คลาสที่ซ้อนกันเท่านั้นที่สามารถเป็นแบบสแตติกได้ คุณสามารถใช้คลาสที่ซ้อนกันได้โดยไม่ต้องมีอินสแตนซ์ของคลาสภายนอก

class OuterClass{
    public static class StaticNestedClass{
    }

    public class InnerClass{
    }

    public InnerClass getAnInnerClass(){
        return new InnerClass();
    }

    //This method doesn't work
    public static InnerClass getAnInnerClassStatically(){
        return new InnerClass();
    }
}

class OtherClass{
    //Use of a static nested class:
    private OuterClass.StaticNestedClass staticNestedClass = new OuterClass.StaticNestedClass();

    //Doesn't work
    private OuterClass.InnerClass innerClass = new OuterClass.InnerClass();

    //Use of an inner class:
    private OuterClass outerclass= new OuterClass();
    private OuterClass.InnerClass innerClass2 = outerclass.getAnInnerClass();
    private OuterClass.InnerClass innerClass3 = outerclass.new InnerClass();
}

แหล่งข้อมูล:

ในหัวข้อเดียวกัน:


3
+1 แม้วลีแรกจะไม่ถูกต้อง ในขณะที่การสอนระบุว่า "คลาสที่ซ้อนกันแบบไม่คงที่จะเรียกว่าคลาสภายใน" (JLS: "คลาสภายในเป็นคลาสที่ซ้อนกันซึ่งไม่ได้ประกาศอย่างชัดเจนหรือโดยปริยาย")
user85421

74
คุณพูดถูก แต่ฉันไม่เห็นว่าสิ่งนี้ตอบคำถามได้อย่างไร
Joeri Hendrickx

2
@Carlos Heuberger คุณพูดถูกฉันอัปเดตโพสต์แล้ว @Joeri Hendrickx คำถามคือ "ทำไมคลาสไม่สามารถประกาศว่าเป็นแบบคงที่ .. ?" พวกเขาทำได้และ [อ่านโพสต์ของฉันที่นี่] มันเป็นคำอธิบายเกี่ยวกับการใช้คลาสแบบสแตติกและทำไมจึงต้องเป็นคลาสแบบซ้อน
Colin Hebert

1
วิธีแก้ปัญหาที่ให้ไว้ที่นี่เป็นเรื่องดี ... แต่ฉันก็ยังสงสัยว่า y ppl ไม่ได้อธิบายอย่างมีเหตุผลว่าคลาสแบบคงที่ไม่สามารถทำได้ใน java..some OOPs คำอธิบายแนวคิดจะเป็นคำตอบที่ถูกต้อง ฉันกำลังรอมัน
Punith Raj

9
นั่นเป็นเรื่องจริง แต่คำถามที่คุณคิดมักจะแก้ไขตัวเองเมื่อคุณเริ่มถามตัวเองว่า "คลาสคงที่" จะเป็นอย่างไร ใน java องค์ประกอบแบบสแตติกหมายความว่าคุณสามารถเข้าถึง / เรียกใช้โดยไม่มีอินสแตนซ์ของคลาสที่ล้อมรอบ สิ่งที่อาจหมายถึงถ้าคุณใช้คำหลักกับชั้นเรียนเอง คุณตั้งใจทำอะไร คุณคาดหวังอะไร ตอนนี้คุณมีความคิดว่ามันจะเป็นอย่างไรฉันค่อนข้างแน่ใจว่ามันจะเป็น "ไม่เข้าท่าจริง ๆ " หรือจะเป็น "เรียกไกล" (มันจะทำให้รู้สึก แต่ท้ายที่สุดมันก็เป็นแค่ตัวเลือก ที่ทำขึ้นมา)
Colin Hebert

39

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


14
»คลาสระดับบนสุดเป็นค่าเริ่มต้นแบบคงที่«นี่คือคำตอบที่ดีที่สุด มันคงที่เพราะคุณไม่จำเป็นต้องมีอินสแตนซ์ของอะไรเลยที่จะอ้างถึง พวกเขาสามารถอ้างถึงได้จากทุกที่ พวกเขากำลังอยู่ในการจัดเก็บแบบคงที่ (เช่นเดียวกับในชั้นเก็บข้อมูล C) - ตามที่คนอื่น ๆ ได้กล่าวไว้ (Iain Elder ในความคิดเห็นต่อคำตอบอื่น) นักออกแบบภาษาสามารถอนุญาตให้ใช้staticคำหลักในระดับบนสุดเพื่อแสดงและบังคับใช้ว่าอาจมีเพียงสมาชิกแบบคงที่เท่านั้นและไม่ได้สร้างอินสแตนซ์ ที่อาจ แต่มีคนสับสนในขณะที่staticมีความหมายที่แตกต่างกันสำหรับชั้นเรียนที่ซ้อนกัน
Lumi

35

ดังนั้นฉันมางานปาร์ตี้ช้า แต่นี่คือสองเซ็นต์ของฉัน - เพิ่มปรัชญาในคำตอบของ Colin Hebert

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


1
ใช่. หากต้องการกล่าวอีกวิธีหนึ่งคลาสระดับบนสุดเป็นแบบคงที่โดยค่าเริ่มต้นดังนั้นจึงไม่จำเป็นต้องใช้คำหลัก
Warren Dew

1
ฉันจะเพิ่มสิ่งที่ Warren Dew พูดไว้ - "คลาสระดับบนสุดเป็นแบบสแตติกตามค่าเริ่มต้นเมื่อเข้าถึงสมาชิกแบบคงที่"
เด็กซ์เตอร์

1
คำตอบที่ไม่ถูกต้อง คำหลักใหม่เพื่อบังคับให้ทุกวิธีในคลาสให้เป็นแบบสแตติกและตัวสร้างส่วนตัวจะดี ฉันจะไม่ตั้งชื่อมันคงเพราะมันแค่สับสน
G_V

@G_V แม้ว่าจาวาสามารถสร้างสัตว์ประหลาดได้ แต่ Java ก็เกือบจะหมดหนทางที่จะทำให้สิ่งโง่ ๆ สถิตยศาสตร์เป็นความคิดที่ไม่ดีโดยทั่วไปการเรียนแบบสแตติกนั้นแย่มาก (แย่กว่า singletons ซึ่งถือว่าเป็นรูปแบบการต่อต้าน) หลายคนไม่เข้าใจสิ่งนี้ดังนั้นการให้คำหลักมันจะเป็นความคิดที่แย่มาก แต่เราทำสิ่งเลวร้ายยาก ๆ และทิ้งไว้ที่นั้น โปรดทราบว่าไม่มีคำหลัก "ซิงเกิล" เช่นกัน และไม่มีคำหลักที่ให้บริการ สิ่งเหล่านี้ล้วนก่อให้เกิดรหัสที่ไม่ดี (แม้ว่าผู้คนยังคงใช้คุณสมบัติมากจน Java อาจสนับสนุนพวกเขาเช่นกัน)
Bill K

29

คลาสที่มี Constructor ส่วนตัวเป็นแบบสแตติก

ประกาศคลาสของคุณเช่นนี้:

public class eOAuth {

    private eOAuth(){}

    public final static int    ECodeOauthInvalidGrant = 0x1;
    public final static int    ECodeOauthUnknown       = 0x10;
    public static GetSomeStuff(){}

}

และคุณสามารถใช้โดยไม่มีการเริ่มต้น:

if (value == eOAuth.ECodeOauthInvalidGrant)
    eOAuth.GetSomeStuff();
...

3
มันไม่คงที่ แต่มีคุณสมบัติคงที่ หากคุณเขียน public int สุดท้าย ECodeOauthUnknown = 0x10; มันไม่คงที่อีกแล้ว
user1883212

9
ในกรณีที่ทุกคนสงสัยว่าสิ่งที่จะเกิดขึ้นที่นี่นี้ตรงกับคำนิยาม C # ของ "ระดับคงที่" - msdn.microsoft.com/en-us/library/79b3xss3%28v=vs.90%29.aspx กำหนดนิยาม Java ของ "คลาสคงที่" ทุกชั้นเรียนที่ไม่ใช่ภายในเป็นแบบคงที่ (ดูคำตอบพี่น้อง)
Calum

1
นอกเหนือจาก @ user1883212 ถูกต้องฉันยังพูดได้ว่าคำตอบนี้ทำให้ผู้อ่านสับสนว่าผู้สร้างส่วนตัวมีความสำคัญที่นี่ในขณะที่มันไม่สำคัญเลย
tlwhitec

ในโลก. NET หากคลาสถูกทำเครื่องหมายทั้งนามธรรมและสุดท้าย (ผลของการstatic classประกาศใน C #) คอมไพเลอร์จะไม่ยอมให้โค้ดประกาศตัวแปรประเภทนั้นหรือใช้เป็นพารามิเตอร์ประเภททั่วไป การขาดคอนสตรัคเตอร์ที่สามารถเข้าถึงได้ในชั้นเรียนซึ่งอาจเป็นอินสแตนซ์หรือรับมรดกจะไม่ขัดขวางการประกาศตัวแปรประเภทนั้นหรือใช้เป็นพารามิเตอร์ประเภททั่วไป
supercat

คำตอบนี้ไม่ถูกต้องสมบูรณ์ คอนสตรัคส่วนตัวไม่เกี่ยวอะไรกับมัน รหัสเป็นเพียงตัวอย่างของคลาสที่ไม่มีอะไรนอกจากคุณลักษณะและวิธีการแบบคงที่ มันไม่มีส่วนเกี่ยวข้องกับคลาสแบบสแตติก
มาร์ควิสแห่ง Lorne

13

แน่นอนว่าพวกเขาทำได้ แต่มีเพียงคลาสซ้อนภายในเท่านั้น นั่นหมายความว่าอินสแตนซ์ของคลาสที่ซ้อนกันไม่ต้องการอินสแตนซ์ที่ล้อมรอบของคลาสภายนอก

แต่สำหรับชั้นเรียนระดับบนสุดนักออกแบบภาษาไม่สามารถคิดถึงสิ่งที่มีประโยชน์เกี่ยวกับคำหลักได้ดังนั้นจึงไม่ได้รับอนุญาต


+1 แม้วลีแรกจะไม่ถูกต้อง ตามที่ JLS ระบุ: "คลาสภายในเป็นคลาสที่ซ้อนกันซึ่งไม่ได้ประกาศแบบคงที่หรือโดยปริยาย" (เพียงแค่คำศัพท์ฉันรู้ ... )
user85421

7
แม้ว่าจะไม่สามารถประกาศคลาสระดับบนสุดได้staticแต่บางครั้งก็สมเหตุสมผล ตัวอย่างเช่นคลาสที่มีเมธอดตัวช่วยคงที่เท่านั้นที่ทำให้เข้าใจได้ง่าย แต่ภาษาจาวาไม่ได้ขัดขวางไม่ให้คุณทำเช่นนั้น คุณสามารถทำให้คลาสที่ไม่สามารถใช้งานได้ทันที (และ 'คงที่' ในทางปฏิบัติ) ไปยังคลาสอื่น ๆ โดยการประกาศตัวสร้างเริ่มต้นprivateซึ่งห้ามการสร้างอินสแตนซ์เนื่องจากไม่มีตัวสร้างที่มองเห็นได้
เลนซามูเอลแมคลีนผู้อาวุโส

12

คุณสามารถสร้างคลาสยูทิลิตี้ (ซึ่งไม่สามารถสร้างอินสแตนซ์ได้) โดยการประกาศประเภท enum โดยไม่มีอินสแตนซ์ นั่นคือคุณประกาศอย่างเจาะจงว่าไม่มีกรณีใด ๆ

public enum MyUtilities {;
   public static void myMethod();
}

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

5
@VisionarySoftwareSolutions สำหรับฉันความเฉพาะเจาะจงนี้บอกว่าไม่มีอินสแตนซ์ของคลาสนี้แทนที่จะทำให้ฉันไม่สามารถสร้างอินสแตนซ์ของคลาสได้โดยทางอ้อม
Peter Lawrey

8
public class Outer {
   public static class Inner {}
}

... มันสามารถประกาศคงที่ - ตราบใดที่มันเป็นสมาชิกระดับ

จาก JLS:

คลาสสมาชิกอาจเป็นแบบสแตติกซึ่งในกรณีนี้พวกเขาไม่สามารถเข้าถึงตัวแปรอินสแตนซ์ของคลาสที่ล้อมรอบ หรืออาจเป็นคลาสภายใน (inner8.1.3)

และที่นี่:

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

คำหลักแบบสแตติกจะไม่สมเหตุสมผลสำหรับคลาสระดับบนสุดเนื่องจากคลาสระดับบนไม่มีประเภทการล้อมรอบ


ถ้ามันไม่อยู่ข้างในทำไมเรียกมันว่าInner? Nestedคงจะเป็นทางเลือกที่สับสนน้อยกว่า
มาร์ควิสแห่ง Lorne

5

ตามที่อธิบายไว้ข้างต้นคลาสจะไม่คงที่จนกว่าจะเป็นสมาชิกของคลาสอื่น

หากคุณต้องการออกแบบคลาส "ซึ่งไม่สามารถมีได้หลายอินสแตนซ์" คุณอาจต้องการดูในรูปแบบการออกแบบ "ซิงเกิล"

ข้อมูลการเริ่มต้นซิงเกิลที่นี่

ข้อแม้:

หากคุณกำลังคิดที่จะใช้รูปแบบซิงเกิลต่อต้านด้วยพลังทั้งหมดของคุณ มันเป็นหนึ่งใน DesignPattern ที่ง่ายที่สุดที่จะเข้าใจอาจเป็นที่นิยมมากที่สุดและแน่นอนที่สุดในทางที่ผิด (ที่มา: JavaRanch ตามลิงค์ด้านบน)


4

นอกจากนี้วิธีการที่กำหนด Java เรียนภายในคงมีความหมายของการเรียนแบบคงที่ตามโลก C # อื่น[1] คลาสสแตติกเป็นคลาสที่มีเมธอดสแตติก (ฟังก์ชัน) เท่านั้นและมีไว้เพื่อสนับสนุนการโปรแกรมแบบโพรซีเดอร์ คลาสดังกล่าวไม่ใช่คลาสจริง ๆ ที่ผู้ใช้ของคลาสสนใจเฉพาะฟังก์ชันตัวช่วยเท่านั้นและไม่ได้สร้างอินสแตนซ์ของคลาส แม้ว่าคลาสสแตติกจะได้รับการสนับสนุนใน C # แต่ไม่มีการรองรับโดยตรงใน Java อย่างไรก็ตามคุณสามารถใช้ enums เพื่อเลียนแบบคลาส C # แบบคงที่ใน Java เพื่อให้ผู้ใช้ไม่สามารถสร้างอินสแตนซ์ของคลาสที่กำหนด (แม้จะใช้การสะท้อน) [2] :

public enum StaticClass2 {
    // Empty enum trick to avoid instance creation
    ; // this semi-colon is important

    public static boolean isEmpty(final String s) {
        return s == null || s.isEmpty();
    }
}

3

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

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

หากคุณเป็นเพียงการเปลี่ยนวัตถุทุกครั้งที่คุณเรียกใช้มันคืออะไรจุดของการสร้างมันได้หรือไม่

นั่นคือเหตุผลที่ Java กำจัดสแตติกสำหรับระดับบนสุด

อาจมีเหตุผลที่เป็นรูปธรรมมากขึ้น แต่สิ่งนี้สมเหตุสมผลมากสำหรับฉัน


3
คลาสภายในมีความสัมพันธ์กับคลาสนอกและนั่นคือเหตุผลที่พวกเขาสามารถคงที่ในขณะที่คุณมีวัตถุที่แตกต่างกันขึ้นอยู่กับ
user2626445

1
คุณหมายถึง 'นั่นคือเหตุผลที่พวกเขาไม่สามารถคงที่'
มาร์ควิสแห่ง Lorne

2

คลาสเท่านั้นที่สามารถเป็นแบบสแตติกได้ รหัสต่อไปนี้ใช้งานได้ดี:

public class whatever {
    static class innerclass {
    }
}

จุดของคลาสภายในคงที่คือพวกเขาไม่มีการอ้างอิงไปยังวัตถุชั้นนอก


1
'static Inner' เป็นข้อขัดแย้งในแง่ 'คงที่' และ 'ภายใน' เป็นลักษณะเฉพาะร่วมกัน คำที่คุณต้องการคือ 'ซ้อนกัน' ไม่ใช่ 'ภายใน'
มาร์ควิสแห่ง Lorne

1

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

public class StaticClass {

    static private int me = 3;
    public static void printHelloWorld() {
       System.out.println("Hello World");
    }



    public static void main(String[] args) {
        StaticClass.printHelloWorld();
        System.out.println(StaticClass.me);
    }
}

นั่นไม่ใช่คำจำกัดความของคลาสสแตติกหรือไม่? เราแค่ใช้ฟังก์ชั่นที่ถูกผูกไว้กับคลาส ระวังว่าในกรณีนี้เราสามารถใช้คลาสอื่นในที่ซ้อนกันได้ ดูนี่สิ:

class StaticClass1 {

    public static int yum = 4;

    static void  printHowAreYou() {
        System.out.println("How are you?");
    }
}

public class StaticClass {

    static int me = 3; 
    public static void printHelloWorld() {
       System.out.println("Hello World");
       StaticClass1.printHowAreYou();
       System.out.println(StaticClass1.yum);
    }



    public static void main(String[] args) {
        StaticClass.printHelloWorld();
        System.out.println(StaticClass.me);
    }
}

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

อย่าลืมสร้างนวกรรมิกส่วนตัวมิฉะนั้นคุณจะสามารถพูดได้new StaticClass()และนั่นก็ไม่สมเหตุสมผลนัก ด้วย Constructor ส่วนตัวมันจะไม่อนุญาตอินสแตนซ์ของมัน
grinch

1

หนึ่งสามารถดูPlatformUIใน Eclipse สำหรับคลาสที่มีวิธีการคงที่และตัวสร้างส่วนตัวด้วยตัวเองเป็นที่สิ้นสุด

public final class <class name>
{
   //static constants
   //static memebers
}

0

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

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