先给出答案:
Java是值传递
参考链接:Java中是值传递和引用传递_java 是值传递,还是引用传递-CSDN博客
当传的是基本类型时,传的是值的拷贝,对拷贝变量的修改不影响原变量;
当传的是引用类型时,传的是引用地址的拷贝,但是拷贝的地址和真实地址指向的都是同一个真实数据,因此可以修改原变量中的值;
当传的是String类型时,虽然拷贝的也是引用地址,指向的是同一个数据,但是String的值不能被修改,因此无法修改原变量中的值。(后面说一下String为什么不可变)
当传的是数组时,传的是数组地址的拷贝,和上述的引用类型一样,都同一个数据。
思考原因:在做leetcode226翻转二叉树时突然把swap函数写成
swap(node.left,node.right);
public void swap(TreeNode left,TreeNode right){
TreeNode temp = left;
left = right;
right = temp;
} //并不能改变外面的A B
这样是不能改变node节点的左右值的。类似下图:(图来自参考链接)
并不能改变A和B真正的指向
把函数改成
swap(node);
public void swap(TreeNode root){
TreeNode temp = root.left;
root.left = root.right;
root.right = temp;
} //复制引用链接,和对象本身都指向堆,所以可以改变
有同学问,这不一样吗?
不一样的
第一个示例中虽然我们传递的是left
和right
对象的引用的副本,但在swap
方法中对left
和right
的重新赋值并不会影响原始的node
对象中的left
和right
属性。这是因为在Java中,方法参数是按值传递的,对于对象类型的参数,传递的是对象引用的副本。
当我们调用swap(node.left, node.right)
时,实际上是将node.left
和node.right
的引用传递给了left
和right
,而在swap
方法中对left
和right
的重新赋值只会影响方法内部的变量,不会影响原始的node
对象。(修改的是局部变量left和right而不是node.left和node.right)
如果想要在方法中交换node
对象的left
和right
属性,可以使用数组、集合或自定义对象等方式传递,或者通过返回值的方式来实现。这样可以在方法内部修改对象的属性,从而实现交换对象的目的。
在第二个示例中,swap
方法接受一个TreeNode
对象作为参数,然后在方法内部直接修改了node
对象的属性,实现了node.left
和node.right
的值的交换。这种方式会影响原始的node.left
和node.right
的值,因为传递的是对象的引用,对对象属性的修改会影响原始对象。(修改的是node的属性)
完整层序遍历代码
class Solution {
public TreeNode invertTree(TreeNode root) {
if(root==null) return null;
Deque<TreeNode> queue = new LinkedList<>();
queue.add(root);
while(!queue.isEmpty()){
int size = queue.size();
for(int i=0;i<size;i++){
TreeNode node = queue.poll();
swap(node);
if(node.left!=null) queue.add(node.left);
if(node.right!=null) queue.add(node.right);
}
}
return root;
}
public void swap(TreeNode root){
TreeNode temp = root.left;
root.left = root.right;
root.right = temp;
}
}
String 为什么不可变?
先看一下String的源码
public final class String
implements java.io.Serializable, Comparable<String>, CharSequence {
/** The value is used for character storage. */
private final char value[];
/** Cache the hash code for the string */
private int hash; // Default to 0
}
String内部是char型的数组,由final修饰,值不能被修改。
String类内部所有的字段都是被private修饰。而且String没有对外提供修改内部状态的方法,因此value数组不能改变。
所以,String是不可变的。
那String不可变有什么好处吗?(参考GPT的回答)
- 线程安全:由于String是不可变的,多个线程可以同时访问同一个String对象而无需担心数据被修改,从而提高了线程安全性。
- 缓存Hash值:由于String的不可变性,可以缓存String的hash值,HashMap通常使用Integer或者String作为Key,这样就不用重复计算hash值,提高了字符串的hash性能。
- 字符串池:由于String的不可变性,Java中的字符串池可以被实现,相同的字符串常量在内存中只有一份拷贝,节省了内存空间。