แอตทริบิวต์คงสุดท้ายส่วนตัวเทียบกับคุณลักษณะส่วนตัวสุดท้าย


305

ใน Java ความแตกต่างระหว่าง:

private final static int NUMBER = 10;

และ

private final int NUMBER = 10;

ทั้งสองprivateและfinalแตกต่างคือstaticคุณลักษณะ

มีอะไรดีกว่ากัน และทำไม?


62
private final static -> สร้างตัวแปรนี้เพียงครั้งเดียว ส่วนตัวสุดท้าย -> สร้างตัวแปรนี้สำหรับทุกวัตถุ ก่อนอื่นจะบันทึกหน่วยความจำไปเพื่อมัน
user1923551

4
final staticหมายความว่าตัวแปรนี้เป็นค่าคงที่และเชื่อมโยงกับคลาสเท่านั้นนั่นคือ "หนึ่งตัวแปรคงที่ต่อคลาส" ในขณะที่finalหมายถึง "หนึ่งตัวแปรคงที่ต่ออินสแตนซ์" เป็นผลให้คุณไม่สามารถใส่final staticตัวแปรในตัวสร้างคลาส 'เนื่องจากตัวสร้างที่เกี่ยวข้องในอินสแตนซ์ใหม่ (คุณสามารถลองด้วยตัวเองและจะได้รับข้อผิดพลาด)
LittleLittleQ

1
โดย "ไม่สามารถใส่ตัวแปรสแตติกสุดท้ายในคลาส 'คอนสตรัคเตอร์" ฉันหมายถึงว่าไม่สามารถเริ่มต้นfinal staticตัวแปรในคอนสตรัควิธีเดียวคือการใช้ initializer คงที่ :)
LittleLittleQ

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

คำตอบ:


309

โดยทั่วไปstaticหมายถึง "เชื่อมโยงกับประเภทตัวเองแทนที่จะเป็นอินสแตนซ์ของประเภท"

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

Test x = new Test();
Test y = new Test();
x.instanceVariable = 10;
y.instanceVariable = 20;
System.out.println(x.instanceVariable);

พิมพ์ออกมา 10: y.instanceVariableและx.instanceVariableแยกจากกันเพราะxและyอ้างถึงวัตถุต่าง ๆ

คุณสามารถอ้างถึงสมาชิกแบบสแตติกผ่านการอ้างอิงแม้ว่าจะเป็นความคิดที่ดีก็ตาม ถ้าเราทำ:

Test x = new Test();
Test y = new Test();
x.staticVariable = 10;
y.staticVariable = 20;
System.out.println(x.staticVariable);

ถ้าอย่างนั้นก็จะพิมพ์ออกมา 20 - มีเพียงหนึ่งตัวแปรไม่ใช่หนึ่งต่ออินสแตนซ์ มันจะชัดเจนขึ้นหากเขียนเป็น:

Test x = new Test();
Test y = new Test();
Test.staticVariable = 10;
Test.staticVariable = 20;
System.out.println(Test.staticVariable);

นั่นทำให้พฤติกรรมมีความชัดเจนมากขึ้น Modern IDEs มักจะแนะนำให้เปลี่ยนรายการที่สองเป็นรายการที่สาม

ไม่มีเหตุผลที่จะมีการประกาศแบบอินไลน์เริ่มต้นค่าเช่นต่อไปนี้เนื่องจากแต่ละอินสแตนซ์จะมีค่าของตัวเองNUMBERแต่มักจะมีค่าเดียวกันเสมอ (ไม่เปลี่ยนรูปและเริ่มต้นด้วยตัวอักษร) สิ่งนี้เหมือนกับที่จะมีfinal staticตัวแปรเพียงตัวเดียวสำหรับทุกอินสแตนซ์

private final int NUMBER = 10;

ดังนั้นหากไม่สามารถเปลี่ยนแปลงได้จะไม่มีจุดที่มีหนึ่งสำเนาต่อหนึ่งอินสแตนซ์

แต่มันสมเหตุสมผลถ้าถูกกำหนดค่าเริ่มต้นในตัวสร้างเช่นนี้:

// No initialization when is declared
private final int number;

public MyClass(int n) {
   // The variable can be assigned in the constructor, but then
   // not modified later.
   number = n;
}

ตอนนี้สำหรับอินสแตนซ์ของแต่ละMyClassเราสามารถมีค่าแตกต่างกัน numberแต่ที่ไม่เปลี่ยนรูปของ


10
จนกว่า enums จะพร้อมใช้งานใน Java 5, static สุดท้ายเป็นวิธีปกติของการประกาศค่าคง
Vineet Reynolds

22
@Vineet: รอบชิงชนะเลิศแบบคงที่ยังคงมีวิธีการที่จะประกาศคงดั้งเดิมเว้นแต่คุณจะมีจำนวนที่ระบุของพวกเขา =)
Chii

@ Matthew: อาจเกิดขึ้น ไม่ใช่สำหรับค่าคงที่ แต่สำหรับค่าที่เกี่ยวข้องกับอินสแตนซ์บางส่วนที่มีเหตุผล ไม่ใช่ว่าฉันชอบซิงเกิลมากอยู่แล้ว
จอน Skeet

1
คำถามที่รุนแรง มันคุ้มค่าที่ใช้private finalมากกว่าprivate static finalที่จะบีบออก / เรียกคืนว่าหน่วยความจำเล็ก ๆ น้อย ๆ จากชั้นเรียน? สมมติว่าcalculatorอุปกรณ์ที่มี ram จำกัด แต่มีทรัพยากร CPU มากมาย
ชนะ Myo Htet

1
@WinMyoHtet: หากคุณใช้ฟิลด์คงที่มีเพียงหนึ่งในจำนวนทั้งหมด หากคุณใช้ฟิลด์อินสแตนซ์จะมีหนึ่งฟิลด์ต่ออินสแตนซ์ การใช้ฟิลด์สแตติกจะดีกว่าถ้าคุณไม่มีอินสแตนซ์ใด ๆ ซึ่งในกรณีนี้มันไร้ประโยชน์
Jon Skeet

38

สำหรับขั้นตอนสุดท้ายสามารถกำหนดค่าที่แตกต่างกันตอนรันไทม์เมื่อเริ่มต้น ตัวอย่างเช่น

Class Test{
  public final int a;
}

Test t1  = new Test();
t1.a = 10;
Test t2  = new Test();
t2.a = 20; //fixed

ดังนั้นแต่ละกรณีมีค่าที่แตกต่างกันของสนาม

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

Class TestStatic{
      public static final int a;
}

TestStatic t1  = new TestStatic();
t1.a = 10;
TestStatic t2  = new TestStatic();
t1.a = 20;   // ERROR, CAN'T BE ALTERED AFTER THE FIRST INITIALIZATION.

90
สิ่งนี้จะไม่คอมไพล์! ตัวแปรสุดท้ายจะต้องกำหนดค่าหรือมีค่าที่กำหนดไว้ในตัวสร้าง คำตอบนี้จะถูกต้องหากมีการกำหนด 2 constructors โดยแต่ละการกำหนด 'a' ให้กับค่าที่แตกต่างกัน
MattC

14
การยืนยันสิ่งนี้จะไม่รวบรวม ดังที่แสดงไว้ข้างต้นตัวแปรอินสแตนซ์สุดท้ายจะต้องมีอินสแตนซ์ก่อนที่ตัวสร้างจะเสร็จสิ้นและตัวแปรคลาสสุดท้ายจะต้องอินสแตนซ์ก่อนที่คลาสจะถูกสร้างขึ้น (คุณสามารถใช้บล็อกแบบคงที่) ทำไมเรื่องนี้ถึงมี upvotes มากมาย?
ฤดี Kershaw

ตามที่ MattC ชี้ให้เห็นคุณไม่สามารถกำหนดให้กับตัวแปรสุดท้ายหลังจากสร้างวัตถุนั้น - ในความเป็นจริงคุณไม่สามารถสร้างวัตถุโดยไม่ให้ค่ากับตัวแปรสุดท้าย ...
jamesdeath123

ในกรณีที่ใครก็ตามตกอยู่ในปัญหานี้โปรดทำตามคำตอบของ MattC
Faz

นี่คือสิ่งที่ฉันคิดว่า OP ขอให้ฉันลืมว่ารอบชิงชนะเลิศสามารถกำหนดค่าที่การเริ่มต้นถ้ามันไม่ได้ให้ไว้ที่การประกาศ
Salsero69

34

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

private static final int NUMBER = 10;

ทำไม? สิ่งนี้จะลดขนาดหน่วยความจำต่ออินสแตนซ์ มันอาจจะเป็นสิ่งที่ดีสำหรับแคชฮิต และมันก็สมเหตุสมผล: staticควรใช้กับสิ่งต่าง ๆ ที่ใช้ร่วมกันในทุก ๆ อินสแตนซ์ (aka วัตถุ) ที่เป็นประเภท (aka class)


ตัวแปรสแตติกจะถูกสร้างขึ้นที่รันไทม์เช่นกัน ดังนั้นคุณสามารถใช้ตัวแปรหรือวิธีการดังกล่าวก่อนที่วัตถุจะถูกสร้างขึ้น
bobby

13
โดยระเบียบการการเข้ารหัส Java ชื่อของตัวแปรสุดท้ายคงที่ควรเป็นตัวพิมพ์ใหญ่ทั้งหมด
starblue

@Martijn Courteaux, สถานการณ์เกี่ยวกับสถานการณ์ที่จะใช้คลาสหนึ่งครั้งตลอดช่วงอายุของแอป! private final intจะถูกลบออกจากหน่วยความจำเมื่ออินสแตนซ์จะถูก GC'ed ในขณะที่private static final intจะยังคงอยู่ในหน่วยความจำตลอดอายุการใช้งานของแอปนั้น คุณแนะนำอะไรในสถานการณ์ข้างต้น
MANN

@MANN: นี่คือทฤษฎีอย่างมาก ไม่มีสถานการณ์กรณีการใช้งานที่เป็นประโยชน์อย่างแท้จริงสำหรับเรื่องนั้น สิ่งนี้อาจเป็นประโยชน์หากคุณมี vars int จำนวน 50,000 ใบในชั้นเรียน แม้ในกรณีนี้สิ่งนี้จะช่วยประหยัดหน่วยความจำได้มากถึง 200kb เนื่องจากเรากำลังพูดถึง Java สิ่งนี้ดูเหมือนไม่เกี่ยวข้องทั้งหมด ในกรณีที่อุปกรณ์สำคัญของหน่วยความจำคอมไพเลอร์ C หรือ C ++ ที่เหมาะสมจะอินไลน์ค่าจำนวนเต็มเหล่านั้นเสมอทำให้ไม่จำเป็นต้องเพิ่มหน่วยความจำจนหมด
Martijn Courteaux

17

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


ตัวแปรอินสแตนซ์จะได้รับ gc'd เมื่อใดก็ตามที่การอ้างอิง / วัตถุทั้งหมดถึงมันตายใช่ไหม
Ruchir Baronia

อินสแตนซ์เป็น gc'd แต่สถิตเกี่ยวข้องกับคลาสไม่ใช่อินสแตนซ์ ตราบใดที่คลาสยังคงอยู่ในหน่วยความจำคุณจะสามารถอ้างถึงอินสแตนซ์และวิธีการคงที่สาธารณะ สิ่งเหล่านั้นจะไปสู่ ​​perm gen (หรืออะไรก็ตามที่เทียบเท่ากับ JDK 8) และไม่ใช่ gc'd
duffymo

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

13

การอ่านคำตอบฉันไม่พบการทดสอบจริง ๆ นี่คือ 2 เซ็นต์ของฉัน:

public class ConstTest
{

    private final int         value             = 10;
    private static final int  valueStatic       = 20;
    private final File        valueObject       = new File("");
    private static final File valueObjectStatic = new File("");

    public void printAddresses() {


        System.out.println("final int address " +
                ObjectUtils.identityToString(value));
        System.out.println("final static int address " +
                ObjectUtils.identityToString(valueStatic));
        System.out.println("final file address " + 
                ObjectUtils.identityToString(valueObject));
        System.out.println("final static file address " + 
                ObjectUtils.identityToString(valueObjectStatic));
    }


    public static void main(final String args[]) {


        final ConstTest firstObj = new ConstTest();
        final ConstTest sndObj = new ConstTest();

        firstObj.printAdresses();
        sndObj.printAdresses();
    }

}

ผลลัพธ์สำหรับวัตถุแรก:

final int address java.lang.Integer@6d9efb05
final static int address java.lang.Integer@60723d7c
final file address java.io.File@6c22c95b
final static file address java.io.File@5fd1acd3

ผลลัพธ์สำหรับวัตถุที่ 2:

final int address java.lang.Integer@6d9efb05
final static int address java.lang.Integer@60723d7c
final file address java.io.File@3ea981ca
final static file address java.io.File@5fd1acd3

สรุป:

อย่างที่ฉันคิดว่า java สร้างความแตกต่างระหว่างดั้งเดิมและประเภทอื่น ๆ ประเภทดั้งเดิมใน Java มักจะ "แคช" เหมือนกันสำหรับตัวอักษรสตริง (ไม่ใช่วัตถุ String ใหม่) ดังนั้นจึงไม่แตกต่างกันระหว่างสมาชิกแบบคงที่และไม่คงที่สมาชิก

อย่างไรก็ตามมีการทำซ้ำหน่วยความจำสำหรับสมาชิกที่ไม่คงที่หากพวกเขาไม่ใช่ตัวอย่างของประเภทดั้งเดิม

การเปลี่ยนค่าของ valueStatic เป็น 10 จะยิ่งเพิ่มมากขึ้นเนื่องจาก Java จะให้ที่อยู่เดียวกันกับตัวแปร int สองตัว


2
Autoboxing ของ 'int' -> จำนวนเต็มทำให้เกิดความสับสนที่นี่ คุณเห็นว่าการ autoboxing ของค่า int (เล็ก) บางค่าจะนำไปสู่วัตถุจำนวนเต็มตัวเดียวกัน
dkneller

@StackHola @dkneller แท้จริงแล้วการ autoboxing เป็นรายละเอียดที่สำคัญมากที่เกิดขึ้นที่นี่ ObjectUtils.identityToString(Object)ลายเซ็นคือ (นอกจากนี้ Java ไม่มีการส่งต่อโดยอ้างอิงใด ๆ ) การทดสอบที่มีประโยชน์จริงคือการจัดสรรวัตถุสองรายการและเปลี่ยนค่าของpublic final int FOO = 10ตัวแปรโดยใช้การสะท้อน Java ในวิธีที่บังคับ จากนั้นตรวจสอบว่าวัตถุอื่นมีการเปลี่ยนแปลงค่าหรือไม่
Martijn Courteaux

11

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

ลองพิจารณาตัวอย่างต่อไปนี้:

public class TestClass {
    private final static double NUMBER = Math.random();

    public TestClass () {
        System.out.println(NUMBER);
    }
}

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

อย่างไรก็ตามเมื่อลองตัวอย่างต่อไปนี้แทน:

public class TestClass {
    private final double NUMBER = Math.random();

    public TestClass () {
        System.out.println(NUMBER);
    }
}

การสร้างสามอินสแตนซ์ของ TestClass จะพิมพ์ค่าสุ่มต่าง ๆ สามค่าเนื่องจากแต่ละอินสแตนซ์มีค่าคงที่ที่สร้างขึ้นแบบสุ่ม

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


2

จอนกล่าวแล้วว่าตัวแปรคงที่หรือที่เรียกว่าตัวแปรคลาสเป็นตัวแปรที่มีอยู่ในอินสแตนซ์ของคลาส

ฉันพบตัวอย่างของสิ่งนี้ที่นี่ :

public class StaticVariable
{
  static int noOfInstances;
  StaticVariable()
  {
    noOfInstances++;
  }
  public static void main(String[] args)
  {
    StaticVariable sv1 = new StaticVariable();
    System.out.println("No. of instances for sv1 : " + sv1.noOfInstances);

    StaticVariable sv2 = new StaticVariable();
    System.out.println("No. of instances for sv1 : "  + sv1.noOfInstances);
    System.out.println("No. of instances for st2 : "  + sv2.noOfInstances);

    StaticVariable sv3 = new StaticVariable();
    System.out.println("No. of instances for sv1 : "  + sv1.noOfInstances);
    System.out.println("No. of instances for sv2 : "  + sv2.noOfInstances);
    System.out.println("No. of instances for sv3 : "  + sv3.noOfInstances);
  }
}

ผลลัพธ์ของโปรแกรมได้รับด้านล่าง:

ดังที่เราเห็นในตัวอย่างนี้แต่ละวัตถุมีสำเนาของตัวแปรคลาส

C:\java>java StaticVariable
No. of instances for sv1 : 1
No. of instances for sv1 : 2
No. of instances for st2 : 2
No. of instances for sv1 : 3
No. of instances for sv2 : 3
No. of instances for sv3 : 3

2

จากการทดสอบที่ฉันทำตัวแปรสแตติกสุดท้ายนั้นไม่เหมือนกับตัวแปรสุดท้าย (ไม่คงที่)! ตัวแปรสุดท้าย (ไม่คงที่) สามารถแตกต่างจากวัตถุไปยังวัตถุ !!! แต่นั่นก็ต่อเมื่อการเริ่มต้นถูกสร้างขึ้นภายใน Constructor! (ถ้ามันไม่ได้เริ่มต้นจากตัวสร้างมันก็เป็นเพียงความทรงจำของเสียเพราะมันสร้างตัวแปรสุดท้ายสำหรับทุกวัตถุที่สร้างขึ้นที่ไม่สามารถเปลี่ยนแปลงได้)

ตัวอย่างเช่น:

class A
{
    final int f;
    static final int sf = 5;

    A(int num)
    {
        this.f = num;
    }

    void show()
    {
        System.out.printf("About Object: %s\n Final: %d\n Static Final: %d\n\n", this.toString(), this.f, sf);
    }

    public static void main(String[] args)
    {
        A ob1 = new A(14);
        ob1.show();

        A ob2 = new A(21);
        ob2.show();

    }
}

สิ่งที่ปรากฏบนหน้าจอคือ:

เกี่ยวกับ Object: A @ addbf1 Final: 14 Static Final: 5

เกี่ยวกับ Object: A @ 530daa Final: 21 Static Final: 5

นิรนามนักศึกษาชั้นปีที่ 1 ด้านไอทีกรีซ


นี่ไม่ใช่คำตอบ :(
Sanjaya Pandey

2

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

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

ในการแสดงวิธีใช้ค่าต่าง ๆ ในอินสแตนซ์ให้ตรวจสอบรหัสนี้:

public class JustFinalAttr {
  public final int Number;

  public JustFinalAttr(int a){
    Number=a;
  }
}

...System.out.println(new JustFinalAttr(4).Number);

ฉันมีลิงค์สำหรับเปรียบเทียบอย่างละเอียดที่นี่ ฉันขอโทษพวกนี้มีการกลั่นกรองฉันเดา
BlondCode

ลิงค์กลับมา บรรณาธิการได้นำออกมาเป็นตายแล้ว ดูเหมือนว่าจะมีชีวิตอยู่ในขณะนี้
Erick G. Hagstrom

2

นี่คือสองเซ็นต์ของฉัน:

final           String CENT_1 = new Random().nextInt(2) == 0 ? "HEADS" : "TAILS";
final   static  String CENT_2 = new Random().nextInt(2) == 0 ? "HEADS" : "TAILS";

ตัวอย่าง:

package test;

public class Test {

    final long OBJECT_ID = new Random().nextLong();
    final static long CLASSS_ID = new Random().nextLong();

    public static void main(String[] args) {
        Test[] test = new Test[5];
        for (int i = 0; i < test.length; i++){
            test[i] = new Test();
            System.out.println("Class id: "+test[i].CLASSS_ID);//<- Always the same value
            System.out.println("Object id: "+test[i].OBJECT_ID);//<- Always different
        }
    }
}

กุญแจสำคัญคือตัวแปรและฟังก์ชั่นสามารถคืนค่าที่แตกต่างกันดังนั้นตัวแปรสุดท้ายจึงสามารถกำหนดด้วยค่าที่แตกต่างกัน


คุณช่วยอธิบายได้อย่างละเอียดว่าอะไรดีกว่าและเพราะอะไร
แดเนียล

2

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

public class City {

    // base price that is always same for all objects[For all cities].
    private static double iphone_base_price = 10000;

    // this is total price = iphone_base_price+iphone_diff;
    private double iphone_citi_price;

    // extra price added to iphone_base_price. It is constant per city. Every
    // city has its own difference defined,
    private final double iphone_diff;

    private String cityName = "";

    // static final will be accessible everywhere within the class but cant be
    // changed once initialized.
    private static final String countryName = "India";

    public City(String cityName, double iphone_diff) {
        super();
        this.iphone_diff = iphone_diff;
        iphone_citi_price = iphone_base_price + iphone_diff;
        this.cityName = cityName;

    }

    /**
     * get phone price
     * 
     * @return
     */
    private double getPrice() {

        return iphone_citi_price;
    }

    /**
     * Get city name
     * 
     * @return
     */
    private String getCityName() {

        return cityName;
    }

    public static void main(String[] args) {

        // 300 is the
        City newyork = new City("Newyork", 300);
        System.out.println(newyork.getPrice() + "  " + newyork.getCityName());

        City california = new City("California", 800);
        System.out.println(california.getPrice() + "  " + california.getCityName());

        // We cant write below statement as a final variable can not be
        // reassigned
        // california.iphone_diff=1000; //************************

        // base price is defined for a class and not per instances.
        // For any number of object creation, static variable's value would be the same
        // for all instances until and unless changed.
        // Also it is accessible anywhere inside a class.
        iphone_base_price = 9000;

        City delhi = new City("delhi", 400);
        System.out.println(delhi.getPrice() + "  " + delhi.getCityName());

        City moscow = new City("delhi", 500);
        System.out.println(moscow.getPrice() + "  " + moscow.getCityName());

        // Here countryName is accessible as it is static but we can not change it as it is final as well. 
        //Something are meant to be accessible with no permission to modify it. 
        //Try un-commenting below statements
        System.out.println(countryName);

        // countryName="INDIA";
        // System.out.println(countryName);

    }

}

1

น้อยมากและคงที่

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

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


1

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


1

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

ค่าตัวแปรสุดท้ายส่วนตัวจะเหมือนค่าคงที่ต่อวัตถุ

คุณสามารถอ้างถึง java.lang.String หรือค้นหาตัวอย่างด้านล่าง

public final class Foo
{

    private final int i;
    private static final int j=20;

    public Foo(int val){
        this.i=val;
    }

    public static void main(String[] args) {
        Foo foo1= new Foo(10);

        Foo foo2= new Foo(40);

        System.out.println(foo1.i);
        System.out.println(foo2.i);
        System.out.println(check.j);
    }
}

// ขาออก

10
40
20

0

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


0

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

อย่างไรก็ตามคุณสามารถทำให้ตัวแปรเป็นแบบสาธารณะได้ในขณะนี้เนื่องจากไม่มีใครสามารถแก้ไขได้เช่นเดียวกับ "System.out" ซึ่งขึ้นอยู่กับความตั้งใจของคุณและสิ่งที่คุณต้องการบรรลุ


1
วิธีการแบบคงที่ไม่จำเป็นต้องใช้ในการเข้าถึงตัวแปรแบบคงที่ - ฉันคิดว่าคุณกำลังคิดว่า "การเข้าถึงตัวแปรอินสแตนซ์จากวิธีการแบบคงที่" (ไม่อนุญาต)
ataulm

0

ให้บอกว่าถ้าคลาสจะไม่มีมากกว่าหนึ่งอินสแตนซ์แล้วอันไหนจะใช้หน่วยความจำเพิ่มเติม:

ส่วนตัวคง int สุดท้าย ID = 250; หรือ int ID สุดท้ายส่วนตัว = 250;

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


1
โปรดอย่าทำซ้ำคำตอบอื่น ๆ ที่กล่าวถึงแล้ว
ผู้ใช้ที่ไม่รู้จัก

0

ตัวแปรสแตติกเป็นของคลาส (ซึ่งหมายความว่าวัตถุทั้งหมดแชร์ตัวแปรนั้น) ตัวแปรไม่คงที่เป็นของแต่ละวัตถุ

public class ExperimentFinal {

private final int a;
private static final int b = 999; 

public ExperimentFinal(int a) {
    super();
    this.a = a;
}
public int getA() {
    return a;
}
public int getB() {
    return b;
}
public void print(int a, int b) {
    System.out.println("final int: " + a + " \nstatic final int: " + b);
}
public static void main(String[] args) {
    ExperimentFinal test = new ExperimentFinal(9);
    test.print(test.getA(), test.getB());
} }

ดังที่คุณเห็นตัวอย่างด้านบนสำหรับ "final int" เราสามารถกำหนดตัวแปรของเราสำหรับแต่ละอินสแตนซ์ (object) ของคลาสอย่างไรก็ตามสำหรับ "static final int" เราควรกำหนดตัวแปรในคลาส (ตัวแปรสแตติกเป็นของคลาส )


0

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


0

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


-1

สิ่งนี้อาจช่วยได้

public class LengthDemo {
public static void main(String[] args) {
    Rectangle box = new Rectangle();
    System.out.println("Sending the value 10.0 "
            + "to the setLength method.");
    box.setLength(10.0);
    System.out.println("Done.");
    }
}

1
แน่ใจหรือเปล่าว่าคำตอบสำหรับคำถามนี้?
mikus

-2

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

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