V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
miaoxia
V2EX  ›  程序员

如何正确修改 Java 形参的引用?

  •  
  •   miaoxia · 2017-03-08 11:17:00 +08:00 · 2839 次点击
    这是一个创建于 2596 天前的主题,其中的信息可能已经有所发展或是发生改变。

    遇到一个题目:获取树的叶子节点并删除叶子节点

    这是我的代码:

    private List<Integer> getLeaves(TreeNode root, List<Integer> leaves) {
    	if(root == null){
    		return null;
    	}
    	if(root.left == null && root.right == null){
    		leaves.add(root.val);
    		// delete this node
    		root = null;
    //		root.val = -1;
    	} else {
    		getLeaves(root.left, leaves);
    		getLeaves(root.right, leaves);
    	}
    	return leaves;
    }
    

    跑完上面的代码,我发现叶子节点获取到了,但是没有被删除。 我把赋空注释掉,改为修改叶子节点的值,发现是可以修改的。

    我重新写了一个例子:

    TreeNode root = new TreeNode(1);
    TreeNode rootTemp = root;
    
    System.out.println("origin root : " + root);
    rootTemp.val = 2;
    System.out.println("after change rootTemp'val, root.val : " + root.val);
    rootTemp = null;
    System.out.println("after change rootTemp, root : " + root);
    rootTemp = new TreeNode(3);
    System.out.println("after change rootTemp, root : " + root);
    

    发现修改值和修改引用是两种操作。

    重新写了一个方法:

    System.out.println("origin root : " + root);
    changeReference(root);
    System.out.println("after reference, root : " + root);
    
    private void changeReference(TreeNode root) {
    	root = new TreeNode(3);
    }
    

    根据打印的结果,发现修改形参无法影响到实参 root 。

    那么如果一个方法中,形参是对象类型的。

    有办法修改 Java 形参的引用,来达到修改实参的目的吗?(比如重新 new 一个对象或者赋值为 null )

    9 条回复    2017-03-12 00:26:01 +08:00
    Allianzcortex
        1
    Allianzcortex  
       2017-03-08 11:25:20 +08:00 via iPhone
    Java 里只有 reference by value 这种说法~,新的函数里更改原来的值会影响,要不 linkedlist 里各种 dummy 就用不了了
    bombless
        2
    bombless  
       2017-03-08 11:33:32 +08:00
    你可以另外做个容器包一层,然后每次要实现这种效果就把东西扔容器里,再把容器传过去就好
    Accldent
        3
    Accldent  
       2017-03-08 11:44:20 +08:00   ❤️ 2
    一楼是想说 pass by value 吧

    形参只是实参的一个引用副本,修改值是通过同一个引用修改当然没问题,但是修改引用只是把当前栈帧上的本地变量给置空,不会对原栈帧的变量造成影响

    二楼的方法可以一试,或者你给 Node 提供一个 empty 方法以及 isEmpty 方法,以后不要用 null 来判断而用 isEmpty ,清空 node 可以调 empty(),如果希望 node 被回收就把引用断开
    domty
        4
    domty  
       2017-03-08 11:51:40 +08:00
    做不到, 3L 把原因说的很清楚了。

    你可以考虑在 TreeNode 对象里保存该结点的父结点和该结点在父节点的位置,来实现该结点在父节点的删除。
    21grams
        5
    21grams  
       2017-03-08 12:26:20 +08:00   ❤️ 1
    java 哪有什么形参实参
    gejun123456
        6
    gejun123456  
       2017-03-08 13:14:05 +08:00 via Android
    可以先获取叶子节点的父节点 然后 parent.left=null
    parent.right=null
    docted
        7
    docted  
       2017-03-08 16:05:49 +08:00
    changeReference(root);
    其实这个方法里边传进去的是个引用,但是并不是 root 本身,其实就是 root 的一个副本。引用可以理解为一个指针, root 本身和副本指向同一个地址,但你在函数里 root = new TreeNode(3);其实是讲那个副本指向了一个新地址,再修改肯定对原来的没影响。
    SoloCompany
        8
    SoloCompany  
       2017-03-08 22:46:44 +08:00
    java 没有指针也没有 & 符号

    另外,形参实参也不是这个概念吧
    Allianzcortex
        9
    Allianzcortex  
       2017-03-12 00:26:01 +08:00
    @Accldent 是,就是 pass by value ~顺便 @ 我一下哈,差点都没看见。
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   我们的愿景   ·   实用小工具   ·   972 人在线   最高记录 6543   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 26ms · UTC 20:21 · PVG 04:21 · LAX 13:21 · JFK 16:21
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.