138

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

4

15 回答 15

267

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.    

您可以通过首先确保不再需要 second 的旧值或将 second 的值分配给另一个指针来确保这一点。

first = second;
second = third; //OK

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

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

请注意,从语言的角度来看,将对象丢弃给垃圾收集器根本不是错误。这只是程序员需要注意的事情。同一个变量可以在不同的时间指向不同的对象,当没有指针引用它们时,旧值将被回收。但是如果程序的逻辑需要维护至少一个对象的引用,就会产生错误。

新手经常会犯以下错误。

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 中没有。

于 2009-11-17T16:48:59.127 回答
54

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

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

于 2009-11-17T16:36:48.573 回答
50

Java确实有指针。任何时候在 Java 中创建对象时,实际上都是在创建指向该对象的指针。然后可以将此指针设置为不同的对象或null,并且原始对象仍将存在(等待垃圾回收)。

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

如果您真的想获得低级,唯一的方法是使用Java Native Interface;即便如此,低级部分也必须用 C 或 C++ 完成。

于 2009-11-17T16:39:48.313 回答
12

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

于 2015-08-05T15:11:16.933 回答
11

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

于 2009-11-17T16:39:01.653 回答
9

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

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

于 2009-12-06T09:20:41.337 回答
5

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

于 2009-11-17T16:36:30.193 回答
2

不是真的,不。

Java没有指针。如果你真的想要,你可以尝试通过围绕反射之类的东西来模拟它们,但它会具有指针的所有复杂性而没有任何好处

Java 没有指针,因为它不需要它们。您希望从这个问题中得到什么样的答案,即您内心深处是希望您可以将它们用于某事还是只是出于好奇?

于 2009-11-17T16:36:52.453 回答
2

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

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

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

于 2009-11-17T16:39:19.100 回答
2

Java 引用类型与 C 指针不同,因为在 Java 中不能有指向指针的指针。

于 2015-07-12T00:15:56.307 回答
1

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

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

您始终可以通过创建数组并使用数组中的索引来模拟点。同样,这取决于您要完成的工作,这可能有用也可能没用。

于 2009-11-17T17:15:14.050 回答
1

来自Godfrey Nolan的《反编译Android》一书

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

于 2014-04-03T12:56:20.577 回答
0

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

但是,我确实希望 Java 可以让您通过引用传递文字值。沿线的东西

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

于 2010-01-27T03:19:56.583 回答
-1

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

于 2013-07-11T09:54:23.297 回答
-4

通过知道数组名称是指向第一个索引的指针,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] );
        
    }
}


于 2022-02-23T09:17:28.697 回答