如何在Java中使用指针?

102 java pointers unsafe

我知道Java没有指针,但我听说Java程序可以用指针创建,这可以由少数java专家完成.这是真的吗?

Saj*_*ani 236

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;
Run Code Online (Sandbox Code Playgroud)

取消引用null:

first.growl();  // ERROR, first is null.    
third.growl(); // ERROR, third has not been initialized.
Run Code Online (Sandbox Code Playgroud)

别名问题:

third = new Tiger();
first = third;
Run Code Online (Sandbox Code Playgroud)

丢失细胞:

second = third; // Possible ERROR. The old value of second is lost.    
Run Code Online (Sandbox Code Playgroud)

您可以通过首先确保不再需要旧值second或将另一个指针指定为second的值来使此安全.

first = second;
second = third; //OK
Run Code Online (Sandbox Code Playgroud)

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

OutOfMemoryError当您调用new并且分配器无法分配所请求的单元时,Java系统将抛出异常().这是非常罕见的,通常是由于失控递归造成的.

请注意,从语言的角度来看,将对象放弃到垃圾收集器根本不是错误.这只是程序员需要注意的事情.相同的变量可以在不同的时间指向不同的对象,并且当没有指针引用它们时将回收旧的值.但是如果程序的逻辑需要至少保持一个对象的引用,它将导致错误.

新手经常会出现以下错误.

Tiger tony = new Tiger();
tony = third; // Error, the new object allocated above is reclaimed. 
Run Code Online (Sandbox Code Playgroud)

你可能想说的是:

Tiger tony = null;
tony = third; // OK.
Run Code Online (Sandbox Code Playgroud)

铸造不当:

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.
Run Code Online (Sandbox Code Playgroud)

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
}
Run Code Online (Sandbox Code Playgroud)

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
    }
} 
Run Code Online (Sandbox Code Playgroud)

更新:如评论中所建议的那样,必须注意C有指针算术.但是,我们在Java中没有这个.

  • 很好的答案,但你没有解决一个关键的区别:C有指针算术.(幸运的是)你不能用Java做到这一点. (14认同)
  • 我讨厌对任何答案进行投票,特别是一个流行的答案,但Java没有指针,你根本不能使用像指针一样的引用.有些事情你只能使用实际指针 - 例如,你可以获取或设置过程数据空间中的任何字节.你根本无法用Java做到这一点.非常糟糕的是,这里的很多人似乎都不明白指针究竟是什么,imho,现在我将脱下我的傻瓜肥皂盒,希望你原谅我的小爆发. (8认同)
  • 我觉得你的意思很遗憾.为什么你认为java不支持指针运算是好的? (4认同)
  • @Danger第一行答案"Java中的所有对象都是引用,你可以像指针一样使用它们." 这是可以提供的最佳答案.如果唯一的答案是"不,java没有指针." 那个回答本来是没有用的.这个答案改为陈述你可以做什么. (4认同)
  • @ user3462295因为人们似乎认为一般民众难以使用它,并且只能通过编写忍者编写编译器或设备驱动程序来理解. (2认同)

Mic*_*ers 42

Java确实有指针.无论何时用Java创建对象,实际上都是在创建指向对象的指针; 然后可以将此指针设置为不同的对象或null,并且原始对象仍将存在(挂起的垃圾收集).

你不能用Java做的是指针算术.您不能取消引用特定的内存地址或增加指针.

如果你真的想要获得低级别,那么唯一的方法就是使用Java Native Interface ; 即使这样,低级部分也必须用C或C++完成.

  • Java根本没有指针,简单明了,我不能为我的生活理解为什么这么多答案都说明了不正确的信息.这是StackOverlfow的人!计算机科学中指针的定义是(你可以谷歌这样):"在计算机科学中,指针是一种编程语言对象,其值指的是(或"指向")存储在计算机内存中其它地方的另一个值它的地址." Java中的引用不是指针.Java需要运行垃圾收集,如果你有一个真正的指针,那就错了! (7认同)
  • @Danger指针是包含内存地址的一段数据.Java是两件让人忘记的事情.它是一种语言和平台.很多人不会说.NET是一种语言,我们需要记住,说"Java没有指针"可能会产生误导,因为平台当然拥有并使用指针.程序员无法通过Java语言访问这些指针,但它们确实存在于运行时中.语言中的引用存在于运行时中的实际指针之上. (3认同)
  • @Danger这是真的,但我认为在这些情况下区分平台和语言很重要,因为我知道当我第一次开始像你这样的声明时会让我感到困惑。 (2认同)

For*_*ega 31

由于Java没有指针数据类型,因此无法在Java中使用指针.即便是少数专家也无法在java中使用指针.

另请参阅最后一点:Java语言环境

  • 这里为数不多的正确答案之一几乎没有任何赞成? (3认同)

Zub*_*air 10

Java没有像C这样的指针,但它确实允许您在堆上创建由变量"引用"的新对象.缺少指针是阻止Java程序非法引用内存位置,并且还允许Java虚拟机自动执行垃圾收集.


kin*_*005 8

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;
    }
}
Run Code Online (Sandbox Code Playgroud)

这可以在Ideone.com上运行.


Pet*_*rey 7

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

虽然你可能习惯了指针,并认为你需要它们(因为你不知道如何编码任何其他方式),你会发现你没有,你会更好.

  • 指针非常强大且有用.在许多情况下,没有指针(Java)会使代码效率降低.仅仅因为人们不喜欢使用指针并不意味着语言应该排除它们.我不应该有步枪,因为其他人(比如军队)用他们来杀人吗? (8认同)
  • 我在过去40年中编写的大部分代码都不可能在Java中实现,因为Java缺乏核心的低级功能. (2认同)

Poi*_*ter 5

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