ฟิลด์คงที่บนการอ้างอิง null ใน Java


119

staticสมาชิก ( staticฟิลด์หรือstaticวิธีการ) ใน Java เชื่อมโยงกับคลาสตามลำดับแทนที่จะเป็นอ็อบเจ็กต์ของคลาสนี้ รหัสต่อไปนี้พยายามเข้าถึงฟิลด์แบบคงที่ในการnullอ้างอิง

public class Main
{
    private static final int value = 10;

    public Main getNull()
    {
        return null;
    }

    public static void main(String[] args)
    {
        Main main=new Main();
        System.out.println("value = "+main.getNull().value);
    }
}

แม้ว่าmain.getNull()ผลตอบแทนจะทำงานและการแสดงnull value = 10รหัสนี้ทำงานอย่างไร?



4
Main main = null; main.getNull().valueเพื่อความสนุกสนานให้ลอง
Marko Topolnik

1
สิ่งนี้ทำให้ฉันนึกถึงnew Thread[]{}[-1].sleep(10);ตำแหน่งที่ sleep () เป็นวิธีการคงที่ สิ่งนี้เคยประสบความสำเร็จใน Java เวอร์ชันเก่าบางรุ่น
hertzsprung

คำตอบ:


93

ลักษณะการทำงานนั้นระบุไว้ในข้อกำหนดภาษา Java :

การอ้างอิง null อาจถูกใช้เพื่อเข้าถึงตัวแปรคลาส (คงที่) โดยไม่ก่อให้เกิดข้อยกเว้น

ในรายละเอียดเพิ่มเติมการประเมินภาคสนามแบบคงที่เช่นPrimary.staticFieldงานดังต่อไปนี้ (เน้นของฉัน) - ในกรณีของคุณPrimary = main.getNull():

  • การแสดงออกประถมศึกษาได้รับการประเมินและผลที่ได้จะถูกยกเลิก [ ... ]
  • ถ้าฟิลด์นั้นเป็นฟิลด์สุดท้ายที่ไม่ว่างผลลัพธ์จะเป็นค่าของตัวแปรคลาสที่ระบุในคลาสหรืออินเทอร์เฟซที่เป็นประเภทของนิพจน์หลัก [ ... ]

5
หากใครมีข้อมูลว่าเหตุใดจึงเลือกตัวเลือกนี้ก็น่าสนใจ

6
@JonofAllTrades ฉันคิดว่าสิ่งนี้ชัดเจน: มีเหตุผลที่จะไม่ทิ้งข้อยกเว้นใด ๆ เมื่อเรียกใช้การอ้างอิงที่เป็นโมฆะเพราะมันไม่สำคัญเนื่องจากเมธอดเป็นแบบคงที่
Malcolm

13
@JonofAllTrades: คำถามที่แท้จริงคือเหตุใดจึงมีการเลือกอนุญาตให้สมาชิกแบบคงที่เรียกว่าอินสแตนซ์ ... สำหรับฉันดูเหมือนว่าจะทำให้เกิดความสับสนและรหัสที่อ่านได้น้อยลง
Falanwe

2
@Falanwe: เห็นด้วยและเป็นโครงสร้างที่ฉันไม่ต้องการแม้ว่าส่วนใหญ่ฉันจะทำงานใน. NET โดยที่ไม่ได้รับอนุญาต ฉันเดาว่าคุณอาจต้องการเรียกวิธีการคงที่ที่เหมาะสมของคลาสย่อยเมื่อคุณได้รับการอ้างอิงถึงคลาสแม่

8
@Falanwe สิ่งนี้ได้รับอนุญาต แต่จะเพิ่มคำเตือนใน Eclipse: "ฟิลด์คงที่ Main.value ควรเข้าถึงแบบคงที่" อย่างน้อยพวกเราที่จู้จี้จุกจิกเกี่ยวกับคำเตือน (เช่นฉัน) จะหลีกเลี่ยงรหัสดังกล่าว
Artyom

19

เนื่องจากอย่างที่คุณกล่าวว่าฟิลด์แบบคงที่จะไม่เชื่อมโยงกับอินสแตนซ์

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

main.getNull(); 
Main.value

7
ฉันจะเรียกมันว่าน้ำตาลวากยสัมพันธ์เหมือนขี้เลื่อยหิน;)
Stephen Swensen

3

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

Main main = null;
System.out.println(main.value);

มันจะพิมพ์ค่าของค่าตัวแปรคงที่เนื่องจากในเวลาคอมไพล์มันจะถูกแปลงเป็น

System.out.println(Main.value);

พิสูจน์:

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


3
  1. การเข้าถึงstaticสมาชิกด้วยชื่อคลาสนั้นถูกกฎหมาย แต่ไม่มีการเขียนว่าstaticสมาชิกไม่สามารถเข้าถึงสมาชิกโดยใช้ตัวแปรอ้างอิงอ็อบเจ็กต์ มันทำงานตรงนี้

  2. nullตัวแปรอ้างอิงวัตถุที่ได้รับอนุญาตในการเข้าถึงstaticตัวแปรระดับโดยไม่ต้องขว้างปายกเว้นอย่างใดอย่างหนึ่งที่รวบรวมหรือเวลาทำงาน


2

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

โปรดดูลิงค์ด้านล่างสำหรับรายละเอียดเพิ่มเติม

http://docs.oracle.com/javase/tutorial/java/javaOO/classvars.html

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