ฉันรู้ว่า Java ไม่มีพอยน์เตอร์ แต่ฉันได้ยินมาว่าโปรแกรม Java สามารถสร้างได้ด้วยพอยน์เตอร์และสิ่งนี้สามารถทำได้โดยไม่กี่คนที่เป็นผู้เชี่ยวชาญใน java มันจริงหรอ?
ฉันรู้ว่า Java ไม่มีพอยน์เตอร์ แต่ฉันได้ยินมาว่าโปรแกรม Java สามารถสร้างได้ด้วยพอยน์เตอร์และสิ่งนี้สามารถทำได้โดยไม่กี่คนที่เป็นผู้เชี่ยวชาญใน java มันจริงหรอ?
คำตอบ:
อ็อบเจ็กต์ทั้งหมดใน Java เป็นข้อมูลอ้างอิงและคุณสามารถใช้เป็นตัวชี้ได้
abstract class Animal
{...
}
class Lion extends Animal
{...
}
class Tiger extends Animal
{
public Tiger() {...}
public void growl(){...}
}
Tiger first = null;
Tiger second = new Tiger();
Tiger third;
การอ้างอิงค่าว่าง:
first.growl(); // ERROR, first is null.
third.growl(); // ERROR, third has not been initialized.
ปัญหานามแฝง:
third = new Tiger();
first = third;
การสูญเสียเซลล์:
second = third; // Possible ERROR. The old value of second is lost.
คุณสามารถทำให้สิ่งนี้ปลอดภัยได้โดยการทำให้มั่นใจก่อนว่าไม่จำเป็นต้องใช้ค่าเก่าของวินาทีอีกต่อไปหรือกำหนดค่าของวินาทีให้กับตัวชี้อื่น
first = second;
second = third; //OK
โปรดสังเกตว่าการให้ค่าที่สองในรูปแบบอื่น (NULL, new ... ) เป็นเพียงข้อผิดพลาดที่อาจเกิดขึ้นได้และอาจส่งผลให้สูญเสียวัตถุที่ชี้ไป
ระบบ Java จะโยนข้อยกเว้น ( OutOfMemoryError
) เมื่อคุณเรียกใหม่และผู้จัดสรรไม่สามารถจัดสรรเซลล์ที่ร้องขอได้ สิ่งนี้หายากมากและมักเกิดจากการเรียกซ้ำแบบหนีไม่พ้น
โปรดทราบว่าจากมุมมองของภาษาการละทิ้งอ็อบเจ็กต์ไปยังตัวรวบรวมขยะไม่ใช่ข้อผิดพลาดเลย เป็นเพียงสิ่งที่ผู้เขียนโปรแกรมต้องพึงระวัง ตัวแปรเดียวกันสามารถชี้ไปยังวัตถุที่แตกต่างกันในเวลาที่ต่างกันและค่าเก่าจะถูกเรียกคืนเมื่อไม่มีตัวชี้อ้างอิงถึง แต่ถ้าตรรกะของโปรแกรมต้องการการรักษาอย่างน้อยหนึ่งการอ้างอิงไปยังวัตถุก็จะทำให้เกิดข้อผิดพลาด
สามเณรมักทำผิดต่อไปนี้
Tiger tony = new Tiger();
tony = third; // Error, the new object allocated above is reclaimed.
สิ่งที่คุณอาจจะพูดคือ:
Tiger tony = null;
tony = third; // OK.
การคัดเลือกนักแสดงที่ไม่เหมาะสม:
Lion leo = new Lion();
Tiger tony = (Tiger)leo; // Always illegal and caught by compiler.
Animal whatever = new Lion(); // Legal.
Tiger tony = (Tiger)whatever; // Illegal, just as in previous example.
Lion leo = (Lion)whatever; // Legal, object whatever really is a Lion.
ตัวชี้ใน C:
void main() {
int* x; // Allocate the pointers x and y
int* y; // (but not the pointees)
x = malloc(sizeof(int)); // Allocate an int pointee,
// and set x to point to it
*x = 42; // Dereference x to store 42 in its pointee
*y = 13; // CRASH -- y does not have a pointee yet
y = x; // Pointer assignment sets y to point to x's pointee
*y = 13; // Dereference y to store 13 in its (shared) pointee
}
พอยน์เตอร์ใน Java:
class IntObj {
public int value;
}
public class Binky() {
public static void main(String[] args) {
IntObj x; // Allocate the pointers x and y
IntObj y; // (but not the IntObj pointees)
x = new IntObj(); // Allocate an IntObj pointee
// and set x to point to it
x.value = 42; // Dereference x to store 42 in its pointee
y.value = 13; // CRASH -- y does not have a pointee yet
y = x; // Pointer assignment sets y to point to x's pointee
y.value = 13; // Deference y to store 13 in its (shared) pointee
}
}
UPDATE:ตามที่แนะนำในความคิดเห็นเราต้องทราบว่า C มีตัวชี้เลขคณิต อย่างไรก็ตามเราไม่มีสิ่งนั้นใน Java
Java มีพอยน์เตอร์ ทุกครั้งที่คุณสร้างวัตถุใน Java คุณกำลังสร้างตัวชี้ไปที่วัตถุ จากนั้นตัวชี้นี้สามารถตั้งค่าเป็นวัตถุอื่นหรือเป็นnull
และวัตถุดั้งเดิมจะยังคงมีอยู่ (รอการรวบรวมขยะ)
สิ่งที่คุณไม่สามารถทำได้ใน Java คือการคำนวณทางคณิตศาสตร์ของตัวชี้ คุณไม่สามารถยกเลิกการอ้างอิงที่อยู่หน่วยความจำเฉพาะหรือเพิ่มตัวชี้ได้
ถ้าคุณอยากที่จะได้รับในระดับต่ำเพียงวิธีเดียวที่จะทำคือกับJava อินเตอร์เฟสพื้นเมือง ; และถึงอย่างนั้นส่วนระดับต่ำจะต้องทำใน C หรือ C ++
เนื่องจาก Java ไม่มีชนิดข้อมูลตัวชี้จึงไม่สามารถใช้พอยน์เตอร์ใน Java ได้ แม้แต่ผู้เชี่ยวชาญเพียงไม่กี่คนก็ไม่สามารถใช้พอยน์เตอร์ใน java ได้
ดูจุดสุดท้ายใน: สภาพแวดล้อมภาษา Java
มีพอยน์เตอร์ใน Java แต่คุณไม่สามารถจัดการกับมันได้ใน C ++ หรือ C เมื่อคุณส่งผ่านอ็อบเจกต์คุณกำลังส่งพอยน์เตอร์ไปยังอ็อบเจ็กต์นั้น แต่ไม่ใช่ในความหมายเดียวกับใน C ++ ไม่สามารถยกเลิกการอ้างอิงวัตถุนั้นได้ หากคุณตั้งค่าโดยใช้ตัวเข้าถึงเนทีฟค่าจะเปลี่ยนไปเนื่องจาก Java รู้ตำแหน่งหน่วยความจำผ่านตัวชี้ แต่ตัวชี้ไม่เปลี่ยนรูป เมื่อคุณพยายามตั้งค่าตัวชี้ไปยังตำแหน่งใหม่คุณจะลงเอยด้วยอ็อบเจ็กต์โลคัลใหม่ที่มีชื่อเดียวกับอีกตัว วัตถุเดิมไม่มีการเปลี่ยนแปลง นี่คือโปรแกรมสั้น ๆ เพื่อแสดงให้เห็นถึงความแตกต่าง
import java.util.*;
import java.lang.*;
import java.io.*;
class Ideone {
public static void main(String[] args) throws java.lang.Exception {
System.out.println("Expected # = 0 1 2 2 1");
Cat c = new Cat();
c.setClaws(0);
System.out.println("Initial value is " + c.getClaws());
// prints 0 obviously
clawsAreOne(c);
System.out.println("Accessor changes value to " + c.getClaws());
// prints 1 because the value 'referenced' by the 'pointer' is changed using an accessor.
makeNewCat(c);
System.out.println("Final value is " + c.getClaws());
// prints 1 because the pointer is not changed to 'kitten'; that would be a reference pass.
}
public static void clawsAreOne(Cat kitty) {
kitty.setClaws(1);
}
public static void makeNewCat(Cat kitty) {
Cat kitten = new Cat();
kitten.setClaws(2);
kitty = kitten;
System.out.println("Value in makeNewCat scope of kitten " + kitten.getClaws());
//Prints 2. the value pointed to by 'kitten' is 2
System.out.println("Value in makeNewcat scope of kitty " + kitty.getClaws());
//Prints 2. The local copy is being used within the scope of this method.
}
}
class Cat {
private int claws;
public void setClaws(int i) {
claws = i;
}
public int getClaws() {
return claws;
}
}
สามารถรันได้ที่ Ideone.com
Java ไม่มีพอยน์เตอร์เหมือนที่ C มี แต่ช่วยให้คุณสร้างอ็อบเจ็กต์ใหม่บนฮีปซึ่งตัวแปร "อ้างอิง" การขาดพอยน์เตอร์คือการหยุดโปรแกรม Java ไม่ให้อ้างถึงตำแหน่งหน่วยความจำอย่างผิดกฎหมายและยังเปิดใช้งาน Garbage Collection โดยอัตโนมัติโดย Java Virtual Machine
คุณสามารถใช้ที่อยู่และตัวชี้โดยใช้คลาสที่ไม่ปลอดภัย อย่างไรก็ตามตามชื่อที่แนะนำวิธีการเหล่านี้ไม่ปลอดภัยและโดยทั่วไปเป็นความคิดที่ไม่ดี การใช้งานที่ไม่ถูกต้องอาจส่งผลให้ JVM ของคุณตายแบบสุ่ม (จริงๆแล้วปัญหาเดียวกันคือการใช้พอยน์เตอร์ไม่ถูกต้องใน C / C ++)
ในขณะที่คุณอาจคุ้นเคยกับตัวชี้และคิดว่าคุณต้องการ (เพราะคุณไม่รู้ว่าจะเขียนโค้ดด้วยวิธีอื่นอย่างไร) คุณจะพบว่าคุณทำไม่ได้และคุณจะดีกว่าสำหรับมัน
ในทางเทคนิควัตถุ Java ทั้งหมดเป็นพอยน์เตอร์ ประเภทดั้งเดิมทั้งหมดเป็นค่านิยม ไม่มีวิธีใดที่จะควบคุมตัวชี้เหล่านั้นด้วยตนเอง Java เพียงแค่ใช้ภายในโดยอ้างอิง
ไม่จริงไม่
Java ไม่มีพอยน์เตอร์ หากคุณต้องการจริงๆคุณสามารถลองเลียนแบบสิ่งเหล่านี้ได้โดยการสร้างสิ่งต่างๆเช่นภาพสะท้อน แต่มันจะมีความซับซ้อนของตัวชี้ทั้งหมดโดยไม่มีประโยชน์ใด ๆ
Java ไม่มีพอยน์เตอร์เพราะไม่ต้องการ คุณคาดหวังคำตอบแบบไหนจากคำถามนี้กล่าวคือลึก ๆ แล้วคุณหวังว่าคุณจะใช้คำตอบเหล่านี้เพื่ออะไรบางอย่างหรือเป็นเพียงความอยากรู้อยากเห็น?
อ็อบเจ็กต์ทั้งหมดใน java จะถูกส่งผ่านไปยังฟังก์ชันโดย Reference copy ยกเว้น primitives
หมายความว่าคุณกำลังส่งสำเนาของตัวชี้ไปยังวัตถุต้นฉบับแทนที่จะเป็นสำเนาของวัตถุนั้นเอง
กรุณาแสดงความคิดเห็นหากคุณต้องการตัวอย่างเพื่อทำความเข้าใจนี้
swap
ฟังก์ชันใน Java ซึ่งจะสลับสองวัตถุ
ชนิดการอ้างอิง Java ไม่เหมือนกับตัวชี้ C เนื่องจากคุณไม่มีตัวชี้ไปยังตัวชี้ใน Java
อย่างที่คนอื่นบอกคำตอบสั้น ๆ คือ "ไม่"
แน่นอนว่าคุณสามารถเขียนโค้ด JNI ที่เล่นกับพอยน์เตอร์ Java ได้ ขึ้นอยู่กับว่าคุณพยายามทำอะไรให้สำเร็จบางทีนั่นอาจจะทำให้คุณอยู่ที่ไหนสักแห่งและอาจจะไม่ทำ
คุณสามารถจำลองพอยต์ได้ตลอดเวลาโดยการสร้างอาร์เรย์และทำงานกับดัชนีในอาร์เรย์ อีกครั้งขึ้นอยู่กับสิ่งที่คุณพยายามทำสิ่งนั้นอาจเป็นประโยชน์หรือไม่ก็ได้
จากหนังสือชื่อ Decompiling Android โดย Godfrey Nolan
ความปลอดภัยกำหนดว่าพอยน์เตอร์ไม่ได้ใช้ใน Javaดังนั้นแฮกเกอร์จึงไม่สามารถแยกออกจากแอปพลิเคชันและเข้าสู่ระบบปฏิบัติการได้ ไม่มีพอยน์เตอร์หมายความว่าอย่างอื่น ---- ในกรณีนี้ JVM ---- ต้องดูแลการจัดสรรและการปลดปล่อยหน่วยความจำ การรั่วไหลของหน่วยความจำก็ควรจะกลายเป็นอดีตไปแล้วหรือไม่เช่นนั้นทฤษฎีก็ดำเนินไป แอปพลิเคชั่นบางตัวที่เขียนด้วยภาษา C และ C ++ มีชื่อเสียงในเรื่องการรั่วไหลของหน่วยความจำเช่นตะแกรงเนื่องจากโปรแกรมเมอร์ไม่ให้ความสำคัญกับการเพิ่มหน่วยความจำที่ไม่ต้องการในเวลาที่เหมาะสม - ไม่ใช่ว่าใครก็ตามที่อ่านสิ่งนี้จะมีความผิดในบาปดังกล่าว การเก็บขยะควรทำให้โปรแกรมเมอร์มีประสิทธิผลมากขึ้นโดยใช้เวลาน้อยลงในการแก้ไขปัญหาหน่วยความจำ
คุณสามารถมีคำแนะนำสำหรับตัวอักษรได้เช่นกัน คุณต้องดำเนินการด้วยตนเอง มันค่อนข้างพื้นฐานสำหรับผู้เชี่ยวชาญ;) ใช้อาร์เรย์ของ int / object / long / byte และ voila ที่คุณมีพื้นฐานในการใช้พอยน์เตอร์ ตอนนี้ค่า int ใด ๆ สามารถเป็นตัวชี้ไปยังอาร์เรย์ int [] ได้ คุณสามารถเพิ่มตัวชี้คุณสามารถลดตัวชี้คุณสามารถคูณตัวชี้ได้ คุณมีเลขคณิตตัวชี้แน่นอน! นั่นเป็นวิธีเดียวที่จะใช้คลาสแอตทริบิวต์ 1,000 int และมีวิธีการทั่วไปที่ใช้กับแอตทริบิวต์ทั้งหมด คุณยังสามารถใช้อาร์เรย์ไบต์ [] แทน int []
อย่างไรก็ตามฉันหวังว่า Java จะให้คุณส่งผ่านค่าตัวอักษรโดยการอ้างอิง บางสิ่งบางอย่างตามเส้น
//(* telling you it is a pointer)
public void myMethod(int* intValue);
วัตถุ java ทั้งหมดเป็นตัวชี้เนื่องจากตัวแปรที่เก็บแอดเดรสเรียกว่าพอยน์เตอร์และอ็อบเจ็กต์ถือแอดเดรสดังนั้นอ็อบเจ็กต์คือตัวแปรพอยน์เตอร์