如何在 Java 中使用指针?

我知道 Java 没有指针,但是我听说可以用指针创建 Java 程序,而且只有少数 Java 专家才能做到这一点。是真的吗?

485052 次浏览

从技术上讲,所有 Java 对象都是指针。不过,所有基元类型都是值。没有办法手动控制这些指针。Java 只是在内部使用引用传递。

由于 Java 没有指针数据类型,所以不可能在 Java 中使用指针。即使是少数的专家也不能在 java 中使用指针。

请参见: Java 语言环境中的最后一点

没有。

Java 没有指针。如果你想要的 真的,你可以尝试模仿他们的周围建立一些像反射,但它将有所有的指针的 复杂性没有任何的 福利

Java 没有指针,因为它不需要它们。你希望从这个问题中得到什么样的答案,也就是说,在内心深处,你希望用它们做些什么,还是仅仅出于好奇?

Java 没有像 C 那样的指针,但是它允许你在堆上创建由变量“引用”的新对象。缺少指针是为了阻止 Java 程序非法引用内存位置,同时也使得垃圾收集能够由 Java 虚拟机自动执行。

Java 中的所有对象都通过引用副本传递给函数,原语除外。

实际上,这意味着您发送的是指向原始对象的指针的副本,而不是对象本身的副本。

如果你想要一个例子来理解这一点,请留下评论。

Java 确实有指针。在 Java 中创建对象的任何时候,实际上都是在创建一个指向对象的指针; 这个指针可以设置为另一个对象或 null,而原始对象仍然存在(暂停垃圾回收)。

在 Java 中你不能做的是指针算法。你不能解引用一个特定的内存地址或增加一个指针。

如果您真的想要获得低级别,那么唯一的方法就是使用 Java本地接口; 即使这样,低级别的部分也必须用 C 或 C + + 完成。

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;

取消对 null 的引用:

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.

为了确保安全,可以首先确保不再需要原来的 second 值,或者为另一个指针指定 second 值。

first = second;
second = third; //OK

请注意,以其他方式(NULL、 new...)给 second 赋值同样是一个潜在的错误,可能导致丢失它所指向的对象。

当您调用 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
}
}

更新: 如注释中所示,必须注意 C 有指针算法。然而,我们在 Java 中没有这种功能。

正如其他人所说,简短的回答是“不”。

当然,您可以编写使用 Java 指针的 JNI 代码。这取决于你想要完成的事情,也许这会让你有所成就,也许不会。

您总是可以通过创建数组并使用数组中的索引来模拟点。同样,这取决于您试图完成的任务,它可能有用,也可能没用。

可以使用 Unsafe 类使用地址和指针。然而,顾名思义,这些方法是不安全的,通常是一个坏主意。不正确的使用可能导致 JVM 随机死亡(实际上在 C/C + + 中使用指针不正确也会导致同样的问题)

虽然您可能习惯于使用指针并认为自己需要它们(因为您不知道如何以其他方式编写代码) ,但是您会发现自己并不需要它们,而且这样做会更好。

你也可以有文字的指针。你必须自己实现它们。对于专家来说,这是相当基本的;)。使用 int/object/long/byte 数组,您就掌握了实现指针的基本知识。现在任何 int 值都可以是指向该数组 int []的指针。你可以递增指针,你可以递减指针,你可以乘以指针。您确实有指针算术! 这是实现1000个 int 属性类并具有应用于所有属性的泛型方法的唯一方法。您还可以使用 byte []数组代替 int []

然而我确实希望 Java 能够让你通过引用传递文字值

//(* 告诉你它是一个指针) Public void myMethod (int * intValue) ;

所有的 java 对象都是指针,因为保存地址的变量叫做指针,而对象保存地址,所以 object 是指针变量。

来自戈弗雷 · 诺兰的《反编译 Android 》一书

安全性规定 < strong > 指针不是 在 Java 中使用,因此黑客无法突破应用程序进入操作系统 没有指针意味着其他东西——在本例中是 JVM ——必须 负责分配和释放内存。内存泄漏也应该 成为过去的事情,或者理论上是这样的。一些应用写在 C 和 C + + 因为像筛子一样泄漏内存而臭名昭著,因为程序员 不要注意在适当的时候释放不需要的内存——不 任何读到这篇文章的人都会犯下这样的罪行,收集垃圾 还应该使程序员更有效率,减少花在 调试内存问题。

Java 引用类型不同于 C 指针,因为在 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 可以很容易地拥有指针。这就是为什么当我们把数组传递给函数时我们不写它的方括号。因为数组是引用


public class Main
{
public static void func ( int ptr1[] , int ptr2[] )
{
int temp;
temp = ptr1[0];
ptr1[0] = ptr2[0];
ptr2[0] = temp;
      

}
    

public static void main(String[] args) {
        

int x = 5;               int y = 8;
        

// in c language
//  int *p = &x;       int *q = &y;
        

        

//  in Java
int p[] = new int[1];
int q[] = new int[1];
        

p[0] = x;   // same as pointer
q[0] = y;   // same as pointer
        

func( p , q );  // passing address ( refrence )
        

System.out.println( "  After Swap " );
System.out.println( "x = "  + p[0] + "  " +  "y = " + q[0] );
        

}
}




你可以,但不是全部。您不能直接访问指针,但是您可以拥有指向同一位置的变量列表。几年前我偶然发现了一条路。

我不知道为什么,但是在 Java 中,当你将一个列表设置为等于另一个列表时,而不是复制所有的信息,就会产生一个指向原始列表的指针。我不确定它是否适用于所有形式的列表,但它适用于我迄今为止测试过的那些列表。我相信 arrayList 还有函数 clone () ,如果您想要一个合适的单独列表,它可以绕过这个问题。

Int []示例

public class Main {


public static void main(String[] args){


int[] alpha = new int[] {1,2,3};


int[] beta = alpha;
beta[0]=9;
beta[1]=9;
beta[2]=9;


System.out.println("alpha: " + alpha[0] + ", " + alpha[1] + ", " + alpha[2]);
System.out.println("-beta: " + beta[0] + ", " + beta[1] + ", " + beta[2]);
}
}

数组列表示例

import java.util.ArrayList;


public class Main {


public static void main(String[] args){


ArrayList<Integer> alpha = new ArrayList<>();
alpha.add(1);
alpha.add(2);
alpha.add(3);


ArrayList<Integer> beta = alpha;
beta.add(4);
beta.set(0, 5);


System.out.println("alpha: " + alpha.toString());
System.out.println("-beta: " + beta.toString());
}
}