Java 中的引用如何工作?
How do references in Java work?
当我们向链表的头部插入节点时,可以使用如下代码:
Node oldfirst = first;
first = new Node();
first.item = "not";
first.next = oldfirst;
而Node的定义如下,
private class Node
{
Item item;
Node next;
}
我的问题是因为在java中,对象变量是引用,那么oldfirst和first应该总是指向同一个节点。如果是这样,它就不能将节点插入到头部。我哪里错了?
我在解题时也找到了这样的代码"merge two sorted lists":
/**
* Definition for singly-linked list.
* public class ListNode {
* int val;
* ListNode next;
* ListNode(int x) {
* val = x;
* next = null;
* }
* }
*/
public class Solution {
public ListNode mergeTwoLists(ListNode l1, ListNode l2) {
ListNode p1 = l1;
ListNode p2 = l2;
ListNode fakeHead = new ListNode(0);
ListNode p = fakeHead;
while(p1 != null && p2 != null){
if(p1.val <= p2.val){
p.next = p1;
p1 = p1.next;
}else{
p.next = p2;
p2 = p2.next;
}
p = p.next;
}
if(p1 != null)
p.next = p1;
if(p2 != null)
p.next = p2;
return fakeHead.next;
}
}
上面代码中,p是dummyHead的引用,所以当returns,p变了,dummyHead.nex还是合并后的表头吗?
谢谢!
引用本身就是变量,它们只是指向内存中的一个地址。
在你的例子中,oldFirst 和 first 是指向同一个对象的不同引用,这就是为什么当你设置 first 指向其他东西,oldFirst 不受影响,因为它是不同的引用,实际上它是 a copy 的 first 引用,但不是同一个引用。
如果还不明白看'int'数据类型,可以有int a = 10;和 int b = 10;两个整数 "point" 都是同一个整数,当您将 a 设置为等于 12 时,b 不受影响,引用以相同的方式工作。
在 C# 中,您可以通过引用和值将引用传递给函数(在 java 中不能通过引用传递)。所以如果你有一个函数:
void Foo(ref SomeType x); // pass by reference
在函数 Foo 的范围内,您将拥有传递给该函数的相同内容,因此如果您将 x 重置为指向其他内容,您将更改内容你传入了这个函数。
但是如果你这样写:
void Foo(SomeType x);
然后 x 将按值传递,这意味着 x 将是您传递给函数 Foo 的引用的副本,如果您将其重置为指向其他内容,它不会影响您传递给该函数的引用。
这将解释:
Node oldfirst = first; // oldFirst points to the same node as first
first = new Node(); // first now points to a new node.
// oldFirst stays pointing to the original first node
first.item = "not"; // update the item of the new first node
first.next = oldFirst; // .next of the new node points to the old original first node
所以这段代码在列表的开头插入了一个新节点。
当我们向链表的头部插入节点时,可以使用如下代码:
Node oldfirst = first;
first = new Node();
first.item = "not";
first.next = oldfirst;
而Node的定义如下,
private class Node
{
Item item;
Node next;
}
我的问题是因为在java中,对象变量是引用,那么oldfirst和first应该总是指向同一个节点。如果是这样,它就不能将节点插入到头部。我哪里错了?
我在解题时也找到了这样的代码"merge two sorted lists":
/**
* Definition for singly-linked list.
* public class ListNode {
* int val;
* ListNode next;
* ListNode(int x) {
* val = x;
* next = null;
* }
* }
*/
public class Solution {
public ListNode mergeTwoLists(ListNode l1, ListNode l2) {
ListNode p1 = l1;
ListNode p2 = l2;
ListNode fakeHead = new ListNode(0);
ListNode p = fakeHead;
while(p1 != null && p2 != null){
if(p1.val <= p2.val){
p.next = p1;
p1 = p1.next;
}else{
p.next = p2;
p2 = p2.next;
}
p = p.next;
}
if(p1 != null)
p.next = p1;
if(p2 != null)
p.next = p2;
return fakeHead.next;
}
}
上面代码中,p是dummyHead的引用,所以当returns,p变了,dummyHead.nex还是合并后的表头吗?
谢谢!
引用本身就是变量,它们只是指向内存中的一个地址。
在你的例子中,oldFirst 和 first 是指向同一个对象的不同引用,这就是为什么当你设置 first 指向其他东西,oldFirst 不受影响,因为它是不同的引用,实际上它是 a copy 的 first 引用,但不是同一个引用。
如果还不明白看'int'数据类型,可以有int a = 10;和 int b = 10;两个整数 "point" 都是同一个整数,当您将 a 设置为等于 12 时,b 不受影响,引用以相同的方式工作。
在 C# 中,您可以通过引用和值将引用传递给函数(在 java 中不能通过引用传递)。所以如果你有一个函数:
void Foo(ref SomeType x); // pass by reference
在函数 Foo 的范围内,您将拥有传递给该函数的相同内容,因此如果您将 x 重置为指向其他内容,您将更改内容你传入了这个函数。
但是如果你这样写:
void Foo(SomeType x);
然后 x 将按值传递,这意味着 x 将是您传递给函数 Foo 的引用的副本,如果您将其重置为指向其他内容,它不会影响您传递给该函数的引用。
这将解释:
Node oldfirst = first; // oldFirst points to the same node as first
first = new Node(); // first now points to a new node.
// oldFirst stays pointing to the original first node
first.item = "not"; // update the item of the new first node
first.next = oldFirst; // .next of the new node points to the old original first node
所以这段代码在列表的开头插入了一个新节点。