#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,
char
,int
等基本类型) 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
评论
注意C ++还具有与指针或Java参考不同的参考@jk。我以为和Java一样,有什么区别?
C ++引用不可重新绑定(即您不能更改指定的对象)并且不能为空(即您不能有效地使它们完全不引用任何对象)。
@Gnijuohz改写@AProgrammer所说的话:Java中的最终参考几乎等同于C ++参考。它们不完全相等的原因是,C ++引用另外不能为空,而Java中的最终引用也可以为空。