เป็นโมฆะวัตถุหรือไม่?


119

เป็นโมฆะObjectใน Java หรือไม่?


41
ไม่มันไม่ใช่และสำหรับผู้ที่สงสัยว่าทำไมคำถามเช่นนี้มีภาษาที่ null เป็นวัตถุอย่างเช่น Ruby
JRL

7
ในกาลาซึ่งจะพิถีพิถันมากเกี่ยวกับประเภทมีประเภทNull(เป็นลักษณะจริง) nullมีตัวอย่างเดียว
Carl Smotricz

1
@JRL: ด้วยความอยากรู้อยากเห็นฉันสงสัยว่ามันมีผลต่อการทำงานของ JRuby อย่างไร ... (ฉันไม่คุ้นเคยกับการใช้งานระดับนั้นมากพอที่จะรู้อย่างแน่นอน)
Benjamin Oakes

เพื่อเพิ่มความคิดเห็น @ JRL ของ - เทียบเท่าหยาบทับทิมจะnullเป็นnilซึ่งเป็นตัวอย่างของNilClass
เอเลียต Sykes

หรือ JavaScript ซึ่งnull instanceof Objectเป็นเท็จ แต่ผลตอบแทนtypeof(null) 'object'เป็นวัตถุในกรณีนั้นหรือไม่? ใครจะรู้.
ดอนฟัก

คำตอบ:


166

หาก null เป็น Object ก็จะสนับสนุนวิธีการjava.lang.Objectเช่นequals(). อย่างไรก็ตามนี่ไม่ใช่กรณี - การเรียกใช้เมธอดใด ๆ บนผลลัพธ์ null ใน a NullPointerException.

และนี่คือสิ่งที่ข้อกำหนดภาษา Javaกล่าวไว้ในหัวข้อนี้:

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

ฉันคิดว่าสิ่งนี้สามารถต้มให้เป็น "null is special" ได้


1
ดังนั้นวัตถุใน Java เป็นเพียงวัตถุถ้ามันเท่ากับหรือ java.lang.Objectsubclasses ในทางปฏิบัติ - ใช่ คุณไม่สามารถสร้างคลาสที่ไม่ใช่คลาสย่อยของ java.lang.Object ได้ แต่ฉันไม่เคยคิดเกี่ยวกับเรื่องนี้จากมุมมองเชิงปรัชญา
Andreas Dolk

อยากรู้อยากเห็นเอกสาร API สำหรับNullPointerExceptionพูดถึง» nullวัตถุ« ... :) แต่แล้วก็เป็นเรื่องปกติที่จะพูดถึง»พอยน์เตอร์ว่าง« ...
Lumi

คุณกล่าวว่า: "การอ้างอิงค่าว่างสามารถส่งไปยังประเภทการอ้างอิงใดก็ได้เสมอ" ดังนั้นเราสามารถคืนค่า null (typecasted-if allow) ในเมธอดที่มีประเภทการอ้างอิงอ็อบเจ็กต์ (return) ได้หรือไม่?
ศรีชาคราธา

1
@ ศรีศักรราช: ใช่เราทำได้! ซึ่งคุณสามารถค้นหาได้ง่ายขึ้นโดยการลองใช้รหัสมากกว่าการถามที่นี่
Michael Borgwardt

1
"การอ้างอิงค่าว่างเป็นค่าเดียวที่เป็นไปได้ของนิพจน์ประเภท null" ได้เวลาอ่านเอกสารข้อมูลจำเพาะ :)
sofs1

32

ตามที่ Java สเป็ค , nullเป็นชนิดที่สามารถกำหนดให้กับตัวแปรวัตถุ (เป็นค่าตามที่ระบุไว้ในความคิดเห็น) คุณไม่สามารถสร้างอินสแตนซ์หรือสร้างตัวแปรประเภทนี้ได้ แต่คุณต้องใช้ลิเทอรัลnullที่คอมไพเลอร์ให้มา


8
null คือประเภทและค่า
Joachim Sauer

5
nullชื่อเป็น "ตัวอย่าง" ของnullชนิดเห็นได้ชัด
strager

nullไม่ใช่ตัวแปร แต่เป็นลิเทอรัล
Gerold Broser

Re " nullเป็นประเภทที่สามารถกำหนดได้ ": 1) null(ในรหัส) เป็นลิเทอรัลว่างไม่ใช่ประเภท null 2) ประเภทไม่สามารถกำหนดให้กับตัวแปรใน Java โดยทั่วไปดูJLS 4.1: " มี [... ] ค่าข้อมูลสองชนิดที่สามารถจัดเก็บในตัวแปร [... ]: ค่าดั้งเดิม (§4.2) และค่าอ้างอิง (§4.3) " เป็นการอ้างอิงว่างที่สามารถกำหนดผ่านลิเทอรัลnullได้ ... ต่อ ...
Gerold Broser

3) ออบเจ็กต์ใน " ตัวแปรออบเจ็กต์ " เมื่อเทียบกับตัวแปรคลาสมักจะไม่อ้างถึงประเภท แต่หมายถึงอายุการใช้งาน เมื่อกล่าวถึงประเภทมักเรียกว่าตัวแปรของประเภทการอ้างอิงหรือเรียกสั้น ๆว่าตัวแปรอ้างอิง (ประเภท) ฉันทราบ 4 ประเภทใน Java API ที่แสดงตัวแปรอินสแตนซ์ / อ็อบเจ็กต์ (อาจมีมากกว่านั้น): อาร์เรย์ที่มีlengthคลาสย่อยของjava.awt.geom.Point2D.
Gerold Broser



12

Null คือการไม่มีวัตถุ


แต่ประเภท null สามารถกำหนดให้กับทุกประเภทการอ้างอิง
Tom Hawtin - แท

ไม่มี "ประเภทว่าง"; null เป็นค่าเฉพาะของนิพจน์ที่ไม่ใช่แบบดั้งเดิม (เช่นการอ้างอิงไม่มี "ประเภทการอ้างอิง" ใน Java สำหรับความเข้าใจของฉัน)
Tommy McGuire

3
Tommy: JLS 4.1: "นอกจากนี้ยังมีประเภท null พิเศษประเภทของนิพจน์ null ซึ่งไม่มีชื่อ"
Ken


12

JRL เขียนว่า:

ไม่มันไม่ใช่, ...

บ่อยครั้งขึ้นอยู่กับว่าคุณมองไปที่ใดคุณเชื่อใครมากกว่ากัน

ตาม JLS ที่ใช่ก็คือ โดยเฉพาะอย่างยิ่งถ้าคุณเปลี่ยนข้อความคำถามเป็น: " nullตัวอักษรเป็นประเภทObjectหรือไม่" นอกเหนือจากJLS 4.1 ที่ Michael Borgwardt อ้างถึงข้างต้น:

ดูJLS 3.10.7 :

ลิเทอรัล null เป็นประเภท null เสมอ

และJLS 4.10 :

ประเภทย่อยของประเภท T คือประเภท U ทุกประเภทโดย T เป็นซูเปอร์ไทป์ของ U และประเภท null

หรือJLS 4.10.2 :

ซูเปอร์ไทป์โดยตรงของประเภท null คือประเภทอ้างอิงทั้งหมดนอกเหนือจากประเภท null เอง

[Emphases โดยฉัน]

ตามคอมไพเลอร์ของ Eclipse 2019-09 ไม่ใช่ :

true.toString();  // Cannot invoke toString() on the primitive type boolean
null.toString();  // Cannot invoke toString() on the primitive type null

ตาม OpenJDKs 12.0.1 javac คือ :

true.toString();  // error: boolean cannot be dereferenced
null.toString();  // error: <null> cannot be dereferenced

ในกรณีที่วงเล็บเหลี่ยมบ่งบอกว่าnullเป็นประเภทอื่นที่ไม่ใช่ชนิดดั้งเดิม และตามJLS 4.1 :

ภาษาการเขียนโปรแกรม Java มีสองประเภท ได้แก่ ประเภทดั้งเดิม (... ) และประเภทอ้างอิง (... )

ถ้าไม่ใช่อย่างนั้นก็เป็นอย่างอื่น


Claudiu เขียนว่า:

โมฆะเป็นสิ่งที่น่าเกลียด

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


Joachim Sauer เขียนว่า:

null คือประเภทและค่า

จริงๆแล้วมีสามรายการร่วมกับnull (ดูJLS 3.10.7 ด้วย ):

  1. (ที่ไม่มีชื่อเป็นอย่างอื่น) ประเภท null
  2. อักษรnull
  3. อ้างอิง nullค่า (โดยทั่วไปเรียกโดยย่อว่าค่า nullหรือค่าว่าง )

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

(2) ลิเทอรัลว่างอาจถูกจินตนาการว่าเป็นตัวแปรที่กำหนดเป็น:

JVM_global final null_type null = new null_type();

หมายเหตุด้วยJLS 3.9 :

บางครั้งถือว่าลำดับอักขระที่หลากหลายเป็นคำหลักไม่ถูกต้อง:


เกี่ยวกับ null instanceof <any type>

ด้วย JLS 4.10.2 ในใจ (“ ประเภท nullคือประเภทย่อยของทุกประเภท”) null instanceof <any type>ควรจะประเมินtrueเป็นหรือไม่? ตั้งแต่แรกเห็นใช่ แต่JLS 15.20.2ให้คำตอบเชิงลึก:

[... ] ผลลัพธ์ของตัวinstanceofดำเนินการคือtrueถ้าค่าของRelationalExpression ไม่ใช่null [... ] มิฉะนั้นผลที่ได้คือfalse

[Emphases โดยฉัน]

ถามตัวเองว่าอะไรสมเหตุสมผลกว่ากัน (จากมุมมองของโปรแกรมเมอร์แอปพลิเคชัน):

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

  • หรือให้trueดังนั้นจึงแจ้งให้เราทราบว่านิพจน์ประเมินเป็นการอ้างอิงพิเศษการอ้างอิงโมฆะการอ้างถึง "วัตถุ" เราไม่รู้ว่ามีอยู่หรือไม่และเป็นประเภทว่างพิเศษที่ไม่มีชื่อไม่เปิดเผย us แต่ผ่านลิเทอรัล nullเป็นประเภทย่อยของประเภทใด ๆ รวมถึงการสืบทอดหลายรายการและจะถูกละเว้นหรือไม่? ลองพิจารณาตัวอย่างที่เป็นประโยชน์เพิ่มเติม:

     class Car implements Vehicle {  
     ...
     Vehicle car = null;
     ...
     boolean b = car instanceof Car;  // True? There's not even an instance
     ...                              // which could be of type Car.

ซึ่งนำไปสู่:

เหตุใดจึงinstanceofไม่เป็นวิธีที่เหมาะสมในการพูดบางอย่างเกี่ยวกับnullObject-ness?

เรียกว่าinstanceofไม่ใช่sameorsubtypeofเลย นั่นหมายความว่าเรากำลังเปรียบเทียบประเภทของอินสแตนซ์กับประเภทไม่ใช่สองประเภท ตอนนี้nullหมายถึง:“ ไม่มีอินสแตนซ์” และหากไม่มีอินสแตนซ์ก็ไม่มีประเภทของอินสแตนซ์ falseมันเห็นได้ชัดว่าไม่มีอะไรเปรียบเทียบกับสิ่งที่ควรจะนำไปสู่การ

หรือในตัวอย่างโลกแห่งความเป็นจริงที่ "มากกว่า":

  • ฉันมีรูปแอปเปิ้ลขนาดเท่าจริง ( = ประเภทอ้างอิง ) อยู่ในมือพร้อมกับ» Big Apple « ( = ชื่อประเภทอ้างอิง ) เขียนอยู่
  • มีโต๊ะ ( = กอง ) อยู่ข้างหน้าฉัน
  • หากมีแอปเปิ้ล ( = อินสแตนซ์ ) บนโต๊ะแสดงว่ามีสายไฟ ( = อ้างอิง ) เชื่อมต่ออยู่
  • ฉันถือปลายอีกด้านของสายนี้ไว้ในมือ ( = ตัวแปรอ้างอิง )
  • ฉันติดตามแอปเปิ้ลตามสายและเปรียบเทียบกับรูปภาพของฉัน ( = instanceof )
  • หากแอปเปิ้ลมีขนาดเท่ากันหรือใหญ่กว่ารูปภาพข้อความ» Big Apple «ใช้กับมัน ( = จริง )
  • ถ้ามันเล็กกว่าแสดงว่าไม่ใช่ ( = false )
  • หากไม่มีแอปเปิ้ลอยู่บนโต๊ะ (= ไม่มีอินสแตนซ์ ) และด้วยเหตุนี้จึงไม่มีสายไฟ ( = null ) การเขียนก็ใช้ไม่ได้เช่นกัน ( = false ) เพราะ: ไม่มีแอปเปิ้ลเป็นแอปเปิ้ลลูกใหญ่? ไม่มันไม่ใช่.


ดังที่ Michael กล่าวสรุป: "null is special" แน่นอน


2
Apple และ null? คุณไม่กลัวคดีความ? :)
GáborLipták

9

ไม่มันไม่ใช่ตัวอย่างของคลาสหรือคลาส เป็นการอ้างอิงถึงความว่างเปล่า

แก้ไข : ยังไม่ได้อ่านข้อมูลจำเพาะดังนั้นข้างต้นอาจไม่ถูกต้อง 100%


5

ตามที่อธิบายไว้ในบทที่4.1 ประเภทของประเภทและค่าของข้อกำหนดภาษา Java null คือประเภทที่มีค่าเดียวการอ้างอิงแบบ null (และแสดงด้วยลิเทอรัลnull):

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

คุณอาจต้องการอ่านเกี่ยวกับNull Object Pattern (ที่ฉันไม่แนะนำ) แม้ว่า ดูC2 WikiหรือWikipediaสำหรับข้อมูลเพิ่มเติมเกี่ยวกับรูปแบบนี้


5

ไม่แม้ว่าจะเป็นแบบนั้น แต่ก็ไม่มีประโยชน์เนื่องจากไม่มีวิธีการหรือฟิลด์ใด ๆ


4

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


3
ในความเป็นจริงnull instanceof <anytype>จะกลับfalseด้วย
Bombe

4

ตามที่Java Spec ,

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


4

Java จัดการกับวัตถุผ่านการอ้างอิง Null คือรายละเอียด OO-ness ของ Java เนื่องจากมันทำให้คุณต่ำกว่าระดับ OO ไม่ใช่ไม่ใช่วัตถุ แต่เป็น VALUE ของข้อมูลอ้างอิง และไม่มีส่วนเกี่ยวข้องกับกระบวนทัศน์ของวัตถุ แต่เกี่ยวข้องกับการต่อท่อของ Java ที่เปิดใช้งานวัตถุ


3

เป็นโมฆะอินสแตนซ์ของjava.lang.Object? เลขที่

เป็นโมฆะวัตถุหรือไม่? ขึ้นอยู่กับคำจำกัดความของ " is "


2
Object foo = null;
System.out.println(foo.toString()); 

รายการบรรทัดแรกnullสามารถกำหนดให้พิมพ์Objectได้ แต่บรรทัดที่สองจะแสดงให้เห็นว่าไม่ใช่อย่างแน่นอนObjectและในที่สุดก็ได้ผลลัพธ์เป็นไฟล์java.lang.NullPointerException


1

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


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