C有指针,Java有所谓的引用。从某种意义上说,它们有共同点,即它们都指向某个事物。我知道C中的指针存储它们指向的地址。参考也存储地址吗?除了指针更灵活,更容易出错以外,它们又有何不同?

评论

注意C ++还具有与指针或Java参考不同的参考

@jk。我以为和Java一样,有什么区别?

C ++引用不可重新绑定(即您不能更改指定的对象)并且不能为空(即您不能有效地使它们完全不引用任何对象)。

@Gnijuohz改写@AProgrammer所说的话:Java中的最终参考几乎等同于C ++参考。它们不完全相等的原因是,C ++引用另外不能为空,而Java中的最终引用也可以为空。

#1 楼

引用可以通过存储地址来实现。通常,Java引用将被实现为指针,但这不是规范所必需的。他们可能正在使用附加的间接层,以更轻松地进行垃圾收集。但是最后,它将(几乎总是)归结为涉及(Java样式)引用实现的(C样式)指针。

您不能对引用进行指针算术运算。 C语言中的指针与Java语言中的引用之间最重要的区别是,您实际上无法获取(和操纵)Java语言中的引用的基础值。换句话说:您不能执行指针算术。

在C语言中,您可以向指针(即地址)添加某些内容,或者减去某些内容以指向“附近”的东西或指向位置在任何地方都可以。

在Java中,引用指向一个事物,而该事物仅指向该事物。您可以使变量具有不同的引用,但不能仅仅要求它指向“原始事物之后的事物”。

引用是强类型的。另一个区别是,Java中的引用类型比C中的指针类型受到更严格的控制。在C中,您可以拥有一个int*并将其强制转换为char*,然后只需重新解释该位置的内存即可。这种重新解释在Java中不起作用:您只能将引用另一端的对象解释为已经存在的对象(即,仅当指向的对象实际上是一个对象时,才可以将Object引用强制转换为String引用)。 String)。

这些差异使C指针更强大,但也更危险。这两种可能性(指针算术和重新解释所指向的值)都为C增加了灵活性,并且是该语言某些功能的源泉。但是它们也是问题的主要根源,因为如果使用不当,它们很容易破坏代码建立的假设。而且很容易错误使用它们。

评论


+1。不要依赖实施细节。

–用户
2012年3月28日在9:52

+1垃圾收集是否值得一提?这是C指针功能更强大但也更危险的另一种方式(悬空指针指向释放的内存有导致内存损坏,内存泄漏的风险)

– MarkJ
13年8月14日在11:07



引用和指针之间的另一个区别是C中的指针可以转换为数字序列(例如,通过使用memcpy将其移动到char []中),反之亦然。如果将指针转换为存储在某个位置的数字序列(可能在屏幕上显示并由操作员在纸条上向下复制),则计算机内的指针的所有副本都会被破坏,并且该数字序列将被转换回到一个指针(可能是在操作员输入之后),该指针仍必须指向之前所做的相同操作。一个程序...

–超级猫
2014年1月8日19:22

...将指针显示为数字,然后将手动输入的数字转换为指针,可能是“邪恶的”,但是除非操作员键入了未显示以形成有效数字的数字,否则它不会调用任何未定义的行为指针。因此,在完全可移植的C语言中不可能进行通用垃圾回收,因为计算机无法知道宇宙中某处是否存在指针的副本。

–超级猫
2014年1月8日19:24

根据JLS,第4.3.1节,Java中的引用是指针,因此“通常Java引用将实现为指针,但这不是规范所必需的。”是假的。

–Lew Bloch
17年5月11日在17:40

#2 楼

C ++引用又一次不同。

它们必须被初始化并且不能为null(至少在格式正确的程序中不能为空),并且不能被重新引用其他内容。 C ++引用更像是对象的别名。

指针与Java / C ++引用之间的另一个重要区别是,您可以获取指针的地址,而不能访问引用的地址(实际上,C ++引用实际上根本不需要作为内存中的对象存在),因此您可以拥有一个指向指针的指针,但没有指向引用的引用

#3 楼

Java引用和C指针有两点完全不同:


前者没有指针算法。
您不能为所需的内容创建Java引用,您可以仅复制那些保存在可访问的位置(静态字段,对象字段,局部变量)或由函数调用(如构造函数调用)返回的那些对象,因此它们均引用Java对象(绝不引用诸如reference,charint等基本类型) on)。

有人写道,引用是强类型的,因为您不能强迫编译器将int*视为char*
除了特定转换实际上是安全的事实之外, C中没有多态性,因此比较是一个入门。
当然,Java比C具有更强的类型,这并不是C指针与Java引用的功能,您需要使用JNI来打破类型安全性(除了忽略通用限制),但是即使在C语言中,您也必须强制执行

有人写道,Java引用可以实现为C指针,我敢肯定,由于JVM是用C实现的,因此它们在功能上通常不那么强大,通常在32Bit机器上。尽管在64位计算机上,它们通常是压缩的普通对象指针(“压缩的OOP”)以节省空间和带宽。
无论如何,这些C指针也不必等于硬件地址,即使它们通常( > 99%的实现)是出于性能方面的考虑。
最后,这是实现细节,程序员不知道。

#4 楼

它们略有不同。在Java中,引用的副本被复制到被调用函数的堆栈中,指向与调用函数相同的对象,并允许您操纵该对象。但是,您不能更改调用函数所引用的对象。

请考虑以下Java代码

public static void changeRValue(StringBuffer sb){
    sb = new StringBuffer("helllllo"); /*attempt to assign the reference
                                        to a new object*/
}
public static void main(String[] args) {
    StringBuffer sb = new StringBuffer("hi");     //Create a new string buffer
    changeRValue(sb);                             //Call changeRValue
    System.out.println(sb.toString());            //Prints "hi" not "hello"
}


现在考虑使用c ++中的指针:

void func(Dog* dog){
    *dog = Dog("hello world"); //Change the value of dog to a new object
}

int main(int argc, const char * argv[]) {
    Dog dog1("hi");                            //Create a dog object
    func(&dog1);                               //pass the address of dog
    cout << dog1.name;                         //Prints "hello world" not hi.
    return 0;
}


评论


我以为我可以补充一点,它可以被视为类似于const Dog *

–拉面
15年8月20日在14:32

您可以像使用C ++一样轻松地在Java中修改指向对象。您只需要访问合适的成员即可。 Java对象没有赋值运算符,因为Java不支持用户定义的运算符重载,因此您不能使用重载的运算符。 Java的缺乏与Java引用与使用指针算术的C ++指针相同的事实无关。

–重复数据删除器
15年8月20日在20:31