我在使用C很长一段时间后回到Java并且已经陷入了一个简单的概念。我开始编写一个基本的BST实现来恢复我的方向,并且认为我理解了Java的值传递值参数传递(是的,我知道甚至对象引用都是通过值传递的,这是一种非常常见的误解)。
我递归地实现了添加功能,如下面的代码所示,但是我发现如果我实际上没有返回节点值,它就不起作用。我已经注释掉了不起作用的线条,并用可用于比较的线条替换它们。
我的想法是,因为实际根节点的引用副本正被传递给add函数,所以每个函数调用中完成的更改都是在内存中的实际对象上完成的,所以如果我添加一个节点到左或右分支,应保留。
我感到非常尴尬,因为我知道我必须在这里遗漏一些非常简单的东西,但阅读java参数传递似乎让我想知道为什么我错了。谢谢您的帮助。
public class BinaryTree {
TreeNode root;
public BinaryTree(){
root = null;
}
void add(int item){
root = add(root,item);
//add(root,item);
}
//public void TreeNode add(TreeNode node, int item){
public TreeNode add(TreeNode node, int item){
if(node == null){
node = new TreeNode(item);
} else if(item <= node.getItem()){
node.setLeft(add(node.getLeft(),item));
//add(node.getLeft(),item);
} else if(item > node.getItem()){
node.setRight(add(node.getRight(),item));
//add(node.getRight(),item);
}
return node;
//return;
}
static void printTree(BinaryTree tree){
printTree(tree.root);
}
static void printTree(TreeNode node){
if(node == null){
System.out.println("Tree Empty");
return;
}
if(node.getLeft() != null)
printTree(node.getLeft());
if(node.getRight() != null){
System.out.print(node.getItem()+ ", ");
printTree(node.getRight());
} else {
System.out.print(node.getItem()+ ", ");
}
return;
}
public static void main(String args[]){
BinaryTree tree1 = new BinaryTree();
tree1.add(10);
tree1.add(3);
tree1.add(5);
printTree(tree1);
}
}`
答案 0 :(得分:1)
这是因为在你的void add
方法中,你将root设置为等于TreeNode add
的结果,所以你必须返回一些东西,否则root将为null。例如,让我们将第一个元素添加到BST。运行TreeNode add
方法后,必须返回一些内容,因为最终会在root
方法中将其分配给void add
。这里有一个概述,如果你不返回任何东西会发生什么。
void add(10) gets executed
root = add(root, 10)
TreeNode add(root, 10) gets executed
if(node == null) evaluates to true
node = new TreeNode(10); // this is where java being pass by value matters
您认为root实际上正在更改为新的TreeNode对象,其项值为10.但是,这不会发生。而是每当调用接受参数的方法时,指针就会指向这些参数中的对象。因此,调用TreeNode add(root, 10)
会创建指向root
的指针。此指针名为node
,因此当您在此处的最后一行中更改node
时,它会更改指针node
指向的内容,而root
保持不变。如果你没有返回node
,那么你对这个刚刚创建的新TreeNode对象的引用一无所知,所以它最终会在Java的垃圾收集中丢失。