การอ้างอิง Java แตกต่างจากตัวชี้ C อย่างไร


97

C มีพอยน์เตอร์และ Java มีสิ่งที่เรียกว่าการอ้างอิง พวกเขามีบางสิ่งที่เหมือนกันในแง่ที่ว่าพวกเขาทั้งหมดชี้ไปที่บางสิ่งบางอย่าง ฉันรู้ว่าพอยน์เตอร์ใน C เก็บที่อยู่ที่ชี้ไป การอ้างอิงเก็บที่อยู่ด้วยหรือไม่ พวกมันแตกต่างกันอย่างไรยกเว้นตัวชี้นั้นจะยืดหยุ่นและผิดพลาดได้ง่ายกว่ากัน?


10
หมายเหตุ C ++ ยังมีการอ้างอิงซึ่งแตกต่างจากพอยน์เตอร์หรือการอ้างอิง java
jk

@jk ฉันคิดว่ามันจะเหมือนกับใน Java ความแตกต่างคืออะไร?
Gnijuohz

17
การอ้างอิง C ++ นั้นไม่สามารถนำกลับมาใช้ใหม่ได้ (เช่นคุณไม่สามารถเปลี่ยนวัตถุที่กำหนด) และไม่สามารถยกเลิกได้ (เช่นคุณไม่สามารถอ้างอิงได้โดยไม่มีวัตถุเลย)
AProgrammer

@Gnijuohz กล่าวถึงสิ่งที่ @AProgrammer กล่าวอีกครั้ง: การfinalอ้างอิงใน Java เกือบเทียบเท่ากับการอ้างอิง C ++ เหตุผลที่พวกเขาไม่ได้ว่าเทียบเท่าอ้างอิง c ++ ยังเป็นไม่ nullable ในขณะที่finalการอ้างอิงใน Java เป็น nullable
Utku

คำตอบ:


142

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

คุณไม่สามารถใช้ตัวชี้ทางคณิตศาสตร์พร้อมการอ้างอิงได้ ความแตกต่างที่สำคัญที่สุดระหว่างตัวชี้ใน C และการอ้างอิงใน Java คือคุณไม่สามารถไปถึง (และปรับเปลี่ยน) ค่าพื้นฐานของการอ้างอิงใน Java กล่าวอีกนัยหนึ่ง: คุณไม่สามารถใช้เลขคณิตของตัวชี้ได้

ใน C คุณสามารถเพิ่มบางสิ่งลงในตัวชี้ (เช่นที่อยู่) หรือแทนที่บางสิ่งบางอย่างเพื่อชี้ไปยังสิ่งที่เป็น "ใกล้เคียง" หรือชี้ไปยังสถานที่ที่อยู่ในสถานที่ใดก็ได้

ใน Java การอ้างอิงชี้ไปที่สิ่งหนึ่งและสิ่งนั้นเท่านั้น คุณสามารถทำให้ตัวแปรมีการอ้างอิงที่แตกต่างกันแต่คุณไม่สามารถขอให้ชี้ไปที่ "สิ่งที่อยู่หลังสิ่งที่เป็นต้นฉบับ"

การอ้างอิงจะถูกพิมพ์อย่างยิ่ง แตกต่างก็คือว่าประเภทของการอ้างอิงเป็นมากการควบคุมอย่างเคร่งครัดมากขึ้นในชวากว่าชนิดของตัวชี้อยู่ในซีใน C คุณสามารถมีint*และโยนมันทิ้งไปchar*และเพียงแค่ re-ตีความหน่วยความจำที่ตำแหน่งนั้น การตีความอีกครั้งนั้นใช้ไม่ได้ใน Java: คุณสามารถตีความวัตถุที่ส่วนท้ายของการอ้างอิงเป็นสิ่งที่มันมีอยู่แล้ว (เช่นคุณสามารถส่งการObjectอ้างอิงไปยังStringการอ้างอิงได้ก็ต่อเมื่อวัตถุที่ชี้ไปนั้นเป็นจริงString)

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


18
+1 สำหรับยุทธ อย่าพึ่งพารายละเอียดการใช้งาน
CVn

2
+1 การรวบรวมขยะไม่สมควรได้รับการกล่าวถึงว่าเป็นตัวหนาหรือไม่ เป็นอีกวิธีหนึ่งที่ตัวชี้ C มีประสิทธิภาพมากกว่า แต่ก็อันตรายกว่า (ความเสี่ยงของการชี้ไปยังหน่วยความจำที่เป็นอิสระทำให้เกิดความเสียหายของหน่วยความจำ, ความเสี่ยงของการรั่วไหลของหน่วยความจำ)
MarkJ

ความแตกต่างระหว่างการอ้างอิงและพอยน์เตอร์ก็คือตัวชี้ใน C อาจถูกแปลงเป็นลำดับของตัวเลข (เช่นโดยใช้memcpyเพื่อย้ายหนึ่งไปสู่ ​​a char[]) และในทางกลับกัน หากตัวชี้ถูกแปลงเป็นลำดับของตัวเลขซึ่งถูกเก็บไว้ที่ใดที่หนึ่ง (อาจปรากฏบนหน้าจอและคัดลอกลงโดยตัวดำเนินการบนแผ่นกระดาษ) สำเนาทั้งหมดของตัวชี้ภายในคอมพิวเตอร์จะถูกทำลายและลำดับของตัวเลขนั้นจะถูกแปลง กลับไปที่พอยน์เตอร์ (บางทีหลังจากพิมพ์โดยโอเปอเรเตอร์) พอยน์เตอร์จะต้องชี้ไปที่สิ่งเดียวกันกับที่เคยทำมาก่อน โปรแกรมที่ ...
supercat

... แสดงตัวชี้เป็นตัวเลขจากนั้นแปลงตัวเลขที่ป้อนด้วยตนเองเป็นตัวชี้อาจเป็น "ความชั่วร้าย" แต่มันจะไม่เรียกใช้พฤติกรรมที่ไม่ได้กำหนดใด ๆ เว้นแต่ว่าผู้ปฏิบัติงานพิมพ์ตัวเลขที่ไม่ได้แสดงให้ถูกต้อง ตัวชี้ การรวบรวมขยะโดยทั่วไปนั้นเป็นไปไม่ได้ใน C แบบพกพาอย่างสมบูรณ์เพราะไม่มีวิธีที่คอมพิวเตอร์สามารถรู้ได้ว่าสำเนาของตัวชี้อาจมีอยู่ที่ไหนสักแห่งในจักรวาล
supercat

ตาม JLS, §4.3.1การอ้างอิงใน Java เป็นพอยน์เตอร์ดังนั้น "โดยปกติแล้วการอ้างอิง Java จะถูกนำไปใช้เป็นพอยน์เตอร์ แต่ไม่ได้กำหนดไว้โดยสเปค" เป็นเท็จ
Lew Bloch

8

การอ้างอิง C ++ แตกต่างกันอีกครั้ง

พวกเขาจะต้องเริ่มต้นได้และไม่สามารถเป็นโมฆะได้ (อย่างน้อยไม่ได้อยู่ในโปรแกรมที่มีรูปแบบที่ดี) และไม่สามารถทำการอ้างอิงซ้ำเพื่ออ้างอิงอย่างอื่นได้ การอ้างอิง C ++ นั้นคล้ายกับนามแฝงของวัตถุ

ข้อแตกต่างที่สำคัญอื่น ๆ ระหว่างตัวชี้และการอ้างอิง Java / C ++ คือคุณสามารถใช้ที่อยู่ของตัวชี้ที่คุณไม่สามารถเข้าถึงที่อยู่ของการอ้างอิงได้ (แน่นอนการอ้างอิง C ++ ไม่จำเป็นต้องมีอยู่จริงในฐานะวัตถุในหน่วยความจำเลย) ตัวชี้ไปยังตัวชี้ แต่ไม่ใช่การอ้างอิงถึงตัวอ้างอิง


4

ตัวชี้อ้างอิง Java และ C แตกต่างกันในสองจุด:

  1. ไม่มีตัวชี้คณิตศาสตร์สำหรับอดีต
  2. และคุณไม่สามารถสร้างการอ้างอิง Java กับสิ่งที่คุณต้องการคุณสามารถคัดลอกสิ่งที่บันทึกไว้ในที่ที่สามารถเข้าถึงได้ (ฟิลด์คงที่, ฟิลด์ของวัตถุ, ตัวแปรโลคอล) หรือส่งคืนโดยฟังก์ชันการร้องขอ (เช่น constructor-call) ซึ่งทั้งหมดอ้างถึง Java วัตถุ (ไม่เคยประเภทพื้นฐานเช่นการอ้างอิงchar, intและอื่น ๆ )

ใครบางคนเขียนว่าอ้างอิงพิมพ์อย่างยิ่งเพราะคุณไม่สามารถบังคับให้รวบรวมเพื่อรักษาเป็นint* นอกเหนือจากข้อเท็จจริงที่ว่าการแปลงเฉพาะนั้นปลอดภัยจริง ๆไม่มีความหลากหลายใน C ดังนั้นการเปรียบเทียบจึงไม่ใช่การเริ่มต้น แน่นอนว่า Java นั้นพิมพ์ได้มากกว่า C ไม่ใช่ว่าเป็นคุณสมบัติของ C pointers และ Java Reference คุณต้องใช้ JNI ในการทำลายความปลอดภัยของประเภท (นอกเหนือจากข้อ จำกัด ทั่วไป) แม้ใน C คุณต้องบังคับคอมไพเลอร์char*

ใครบางคนเขียนว่าอ้างอิง Java อาจจะนำมาใช้เป็นตัวชี้ C ซึ่งผมบอกว่าแน่ใจว่าพวกเขาเป็นอย่างเคร่งครัดที่มีประสิทธิภาพน้อยลงในเครื่อง 32Bit พวกเขามักจะมี JVM หากจะดำเนินการใน C แม้ว่าบนเครื่อง64 บิตพวกเขาจะถูกบีบอัดโดยทั่วไปวัตถุ - ตัวชี้ ("บีบอัด OOPs") เพื่อประหยัดพื้นที่และแบนด์วิดธ์
อย่างไรก็ตามพอยน์เตอร์ C เหล่านั้นไม่จำเป็นต้องเทียบเท่ากับที่อยู่ฮาร์ดแวร์แม้ว่าโดยทั่วไปแล้ว (> 99% ของการนำไปใช้งาน) นั้นมีเหตุผลด้านประสิทธิภาพ
ในที่สุดนั่นคือรายละเอียดการใช้งานที่ไม่ได้สัมผัสกับโปรแกรมเมอร์


-1

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

พิจารณาจาวาโค้ดต่อไปนี้

public static void changeRValue(StringBuffer sb){
    sb = new StringBuffer("helllllo"); /*attempt to assign the reference
                                        to a new object*/
}
public static void main(String[] args) {
    StringBuffer sb = new StringBuffer("hi");     //Create a new string buffer
    changeRValue(sb);                             //Call changeRValue
    System.out.println(sb.toString());            //Prints "hi" not "hello"
}

ตอนนี้ให้พิจารณาตัวชี้ใน c ++:

void func(Dog* dog){
    *dog = Dog("hello world"); //Change the value of dog to a new object
}

int main(int argc, const char * argv[]) {
    Dog dog1("hi");                            //Create a dog object
    func(&dog1);                               //pass the address of dog
    cout << dog1.name;                         //Prints "hello world" not hi.
    return 0;
}

ฉันคิดว่าฉันอาจจะเพิ่มว่ามันสามารถเห็นได้คล้ายกับสุนัข
ตัวผู้

2
คุณสามารถปรับเปลี่ยนวัตถุชี้ไปที่ใน Java ได้อย่างง่ายดายเช่นเดียวกับใน C ++ คุณเพียงแค่ต้องมีการเข้าถึงสมาชิกที่เหมาะสม วัตถุ Java ไม่มีตัวดำเนินการที่ได้รับมอบหมายเนื่องจาก Java ไม่รองรับตัวดำเนินการที่ผู้ใช้กำหนดมากเกินไปดังนั้นคุณจึงไม่สามารถใช้โอเปอเรเตอร์ที่โหลดมากเกินไปได้ การขาดจาวานั้นไม่มีส่วนเกี่ยวข้องกับความจริงที่ว่าการอ้างอิง Java เหมือนกับพอยน์เตอร์ C ++ ซึ่งเป็นตัวชี้ทางคณิตศาสตร์
Deduplicator
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.