如何在Java中使用指针?

时间:2009-11-17 16:34:39

标签: java pointers unsafe

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

14 个答案:

答案 0 :(得分:231)

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.    

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

first = second;
second = third; //OK

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

当您调用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中没有这个。

答案 1 :(得分:42)

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

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

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

答案 2 :(得分:29)

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

另见最后一点:The Java Language Environment

答案 3 :(得分:8)

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

答案 4 :(得分:7)

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

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

答案 5 :(得分:7)

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上运行。

答案 6 :(得分:3)

java中的所有对象都通过引用副本传递给函数,但基元除外。

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

如果您想要一个例子来理解这一点,请发表评论。

答案 7 :(得分:2)

Java引用类型与C指针不同,因为您可以在Java中指向指针。

答案 8 :(得分:1)

从技术上讲,所有Java对象都是指针。但所有原始类型都是值。没有办法手动控制那些指针。 Java只是在内部使用pass-by-reference。

答案 9 :(得分:1)

不是,不。

Java没有指针。如果真的想要你可以尝试通过构建像反射之类的东西来模拟它们,但它会拥有所有复杂性的指针而没有的好处< /强>

Java没有指针,因为它不需要它们。你希望从这个问题中得到什么样的答案,也就是说,你希望你可以将它们用于某些事情,或者这只是好奇心吗?

答案 10 :(得分:1)

来自Godfrey Nolan的名为Decompiling Android的书

安全性要求指针不是 在Java中使用,因此黑客无法打破应用程序并进入操作 系统。没有指针意味着别的东西----在这种情况下,JVM ----必须 照顾分配和释放记忆。内存泄漏也应该 成为过去,或者理论如此。一些应用程序写在 因为程序员,C和C ++因为像筛子一样泄漏内存而臭名昭着 不要注意在适当的时候释放不必要的记忆----不是 任何阅读此内容的人都会犯这样的罪。垃圾收集 还应该让程序员更有效率,花更少的时间 调试内存问题。

答案 11 :(得分:0)

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

当然,您可以编写使用Java指针的JNI代码。根据你想要完成的事情,也许那会让你到达某个地方,也许它不会。

您总是可以通过创建数组并使用索引处理数组来模拟指针。同样,取决于您要完成的任务,可能会或可能没有用。

答案 12 :(得分:0)

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

但是我希望Java允许你通过引用传递文字值。一些事情

//(* telling you it is a pointer) public void myMethod(int* intValue);

答案 13 :(得分:-1)

所有java对象都是指针,因为保存地址的变量称为指针,对象保持address.so对象是指针变量。