最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

一文淺析Java中的值傳遞

 更新時間:2023年08月01日 08:56:00   作者:HuskySir  
今天在解決一個問題時,程序總是不能輸出正確值,分析邏輯思路沒問題后,發(fā)現(xiàn)原來是由于函數(shù)傳遞導(dǎo)致了這個情況,下面我們就來看看Java中的值傳遞到底是什么情況吧

LeetCode 113

問題:給你二叉樹的根節(jié)點root和一個整數(shù)目標(biāo)和targetSum,找出所有 從根節(jié)點到葉子節(jié)點 路徑總和等于給定目標(biāo)和的路徑。

示例

輸入:root = [5,4,8,11,null,13,4,7,2,null,null,5,1], targetSum = 22

輸出:[[5,4,11,2],[5,8,4,5]]

我的代碼如下

class Solution {
    public void traversal(TreeNode root, int count, List<List<Integer>> res, List<Integer> path) {
        path.add(root.val);
        if (root.left == null && root.right == null) {
            if (count - root.val == 0) {
                res.add(path);
            }
            return;
        }
?
        if (root.left != null) {
            traversal(root.left, count - root.val, res, path);
            path.remove(path.size() - 1);
        }
        if (root.right != null) {
            traversal(root.right, count - root.val, res, path);
            path.remove(path.size() - 1);
        }
    }
?
    public List<List<Integer>> pathSum(TreeNode root, int targetSum) {
        List<List<Integer>> res = new ArrayList<>();
        List<Integer> path = new ArrayList<>();
        if (root == null) return res;
        traversal(root, targetSum, res, path);
?
        return res;
    }
}

該題的思路是采用遞歸,traversal函數(shù)內(nèi)root是當(dāng)前樹的根節(jié)點,count是目標(biāo)值,res是存儲結(jié)果,path是路徑。該代碼對于示例的輸入輸出為

輸入:root = [5,4,8,11,null,13,4,7,2,null,null,5,1], targetSum = 22

輸出:[[5],[5]]

經(jīng)過排查最終問題在于代碼中的add方法

原代碼部分內(nèi)容為

if (root.left == null && root.right == null) {
    if (count - root.val == 0) {
        res.add(path);
    }
    return;
}

該部分內(nèi)容需要改為

if (root.left == null && root.right == null) {
    if (count - root.val == 0) {
        res.add(new ArrayList(path));
    }
    return;
}

此時所有代碼對于示例的輸入輸出為

輸入:root = [5,4,8,11,null,13,4,7,2,null,null,5,1], targetSum = 22

輸出:[[5,4,11,2],[5,8,4,5]]

在java中,存在8大基本數(shù)據(jù)類型,且均有對應(yīng)的包裝類

數(shù)據(jù)類型占用位數(shù)默認(rèn)值包裝類
byte(字節(jié)型)80Byte
short(短整型)160Short
int(整型)320Integer
long(長整型)640.0lLong
float(浮點型)320.0fFloat
double(雙精度浮點型)640.0dDouble
char(字符型)16"/u0000"Character
boolean(布爾型)1falseBoolean

在java中,函數(shù)傳遞只有值傳遞,是指在調(diào)用函數(shù)時,將實際參數(shù)復(fù)制一份傳遞給函數(shù),這樣在函數(shù)中修改參數(shù)(形參)時,不會影響到實際參數(shù)。

基本數(shù)據(jù)類型的值傳遞

測試類

public class TestClass {
    public static void test(int value) {
        value = 2;
        System.out.println("形參value的值:" + value);
    }
?
    public static void main(String[] args) {
        int value = 1;
        System.out.println("調(diào)用函數(shù)前value的值:" + value);
        test(value);
        System.out.println("調(diào)用函數(shù)后value的值:" + value);
    }
}

結(jié)果為

調(diào)用函數(shù)前value的值:1
形參value的值:2
調(diào)用函數(shù)后value的值:1

結(jié)論:可以看到,int類型的value初始為1,調(diào)用函數(shù)后,value仍然為1,基本數(shù)據(jù)類型在函數(shù)中修改參數(shù)(形參)時不會影響到實參的值。

引用數(shù)據(jù)類型的值傳遞

類TreeNode

public class TreeNode {
    int val;
    TreeNode left;
    TreeNode right;
?
    TreeNode() {
    }
?
    TreeNode(int val) {
        this.val = val;
    }
?
    TreeNode(int val, TreeNode left, TreeNode right) {
        this.val = val;
        this.left = left;
        this.right = right;
    }
}

測試類1

public class TestClass {
    public static void test(TreeNode node) {
        node.val = 2;
        System.out.println("形參node的val值:" + node.val);
    }
?
    public static void main(String[] args) {
        TreeNode node = new TreeNode(1);
        System.out.println("調(diào)用函數(shù)前node的val值:" + node.val);
        test(node);
        System.out.println("調(diào)用函數(shù)后node的val值:" + node.val);
    }
}

結(jié)果為

調(diào)用函數(shù)前node的val值:1
形參node的val值:2
調(diào)用函數(shù)后node的val值:2

結(jié)論:可以看到,TreeNode類型的node對象的val值初始為1,調(diào)用函數(shù)后,node對象的val值被修改為2,引用數(shù)據(jù)類型在函數(shù)中修改參數(shù)(形參)時影響到了實參的值。

現(xiàn)在看另一個示例

測試類2

public class TestClass {
    public static void test(TreeNode node) {
        node = new TreeNode(2);
        System.out.println("形參node的val值:" + node.val);
    }
?
    public static void main(String[] args) {
        TreeNode node = new TreeNode(1);
        System.out.println("調(diào)用函數(shù)前node的val值:" + node.val);
        test(node);
        System.out.println("調(diào)用函數(shù)后node的val值:" + node.val);
    }
}

結(jié)果為

調(diào)用函數(shù)前node的val值:1
形參node的val值:2
調(diào)用函數(shù)后node的val值:1

結(jié)論:可以看到,TreeNode類型的node對象的val值初始為1,調(diào)用函數(shù)后,node對象的val值仍然為1,引用數(shù)據(jù)類型在函數(shù)中修改參數(shù)(形參)時未影響到實參的值。

那么,為什么會出現(xiàn)這種問題呢?

首先,在JAVA中,函數(shù)傳遞都是采用值傳遞,實際參數(shù)都會被復(fù)制一份給到函數(shù)的形式參數(shù),所以形式參數(shù)的變化不會影響到實際參數(shù),基本數(shù)據(jù)類型的值傳遞示例可以發(fā)現(xiàn)這個性質(zhì)。但引用數(shù)據(jù)類型的值傳遞為什么會出現(xiàn)修改形式參數(shù)的值有時會影響到實際參數(shù),而有時又不會影響到實際參數(shù)呢?其實引用數(shù)據(jù)類型傳遞的內(nèi)容也會被復(fù)制一份給到函數(shù)的形式參數(shù),這個內(nèi)容類似C++中的地址,示例中的node對象存儲于堆中,雖然形參與實參是兩份內(nèi)容,但內(nèi)容值相同,都指向堆中相同的對象,故測試類1在函數(shù)內(nèi)修改對象值時,函數(shù)外查看時會發(fā)現(xiàn)對象值已被修改。測試類2在函數(shù)內(nèi)重新構(gòu)造了一個對象node,在堆中申請了一個新對象(新對象與原對象val值不相同),讓形參指向這個對象,所以不會影響到原對象node的值。測試類1與測試類2的區(qū)別在于引用數(shù)據(jù)類型的指向?qū)ο蟀l(fā)生了變化。

以下代碼可驗證上述分析

測試類1

public class TestClass {
    public static void test(TreeNode node) {
        System.out.println("test:node" + node);
        node.val = 2;
        System.out.println("test:node" + node);
        System.out.println("形參node的val值:" + node.val);
    }
?
    public static void main(String[] args) {
        TreeNode node = new TreeNode(1);
        System.out.println("調(diào)用函數(shù)前node的val值:" + node.val);
        System.out.println("main node:" + node);
        test(node);
        System.out.println("調(diào)用函數(shù)后node的val值:" + node.val);
        System.out.println("main node:" + node);
    }
}

結(jié)果為

調(diào)用函數(shù)前node的val值:1
main node:TreeNode@1540e19d
test:nodeTreeNode@1540e19d
test:nodeTreeNode@1540e19d
形參node的val值:2
調(diào)用函數(shù)后node的val值:2
main node:TreeNode@1540e19d

測試類2

public class TestClass {
    public static void test(TreeNode node) {
        System.out.println("test:node" + node);
        node = new TreeNode(2);
        System.out.println("test:node" + node);
        System.out.println("形參node的val值:" + node.val);
    }
?
    public static void main(String[] args) {
        TreeNode node = new TreeNode(1);
        System.out.println("調(diào)用函數(shù)前node的val值:" + node.val);
        System.out.println("main node:" + node);
        test(node);
        System.out.println("調(diào)用函數(shù)后node的val值:" + node.val);
        System.out.println("main node:" + node);
    }
}

結(jié)果為

調(diào)用函數(shù)前node的val值:1
main node:TreeNode@1540e19d
test:nodeTreeNode@1540e19d
test:nodeTreeNode@677327b6
形參node的val值:2
調(diào)用函數(shù)后node的val值:1
main node:TreeNode@1540e19d

對于測試類1,形參和實參都是指向相同的對象,所以利用形參修改對象的值,實參指向的對象的值發(fā)生改變。對于測試類2,形參在函數(shù)開始和實參指向相同的對象,讓其指向新的對象后,實參指向的對象的值不會發(fā)生改變。簡要說,測試類1形參復(fù)制了實參的地址,修改了地址對應(yīng)的對象值,但并未修改地址值,測試類2形參復(fù)制了實參的地址,并修改了地址值,但并未修改原地址值對應(yīng)的對象值。

有了目前的結(jié)論,可以理解為什么res.add()函數(shù)內(nèi)path修改為new ArrayList(path)就可代碼運行成功。因為我的path類型為List<Integer>,為引用數(shù)據(jù)類型,且path的值一直在發(fā)生變化。隨著遞歸代碼的運行,path的值發(fā)生變化,res內(nèi)最初的List<Integer>值會發(fā)生變化(就是path的值)。但將path修改為new ArrayList(path)后,是在堆中新構(gòu)造了對象,并指向該對象,原對象的變化不會影響到該對象的值,那么res內(nèi)List<Integer>值就不會發(fā)生變化。

listList.add()方法直接傳入list1

import java.util.ArrayList;
import java.util.List;
?
public class TestClass {
    public static void main(String[] args) {
        List<List<Integer>> listList = new ArrayList<>();
        List<Integer> list1 = new ArrayList<>();
        list1.add(1);
        listList.add(list1);  //直接add list1
        List<Integer> list2 = new ArrayList<>();
        list2.add(2);
        listList.add(list2);
        System.out.println("list1改變前");
        for (List<Integer> l : listList) {
            for (Integer i : l) {
                System.out.println(i);
            }
            System.out.println("---");
        }
        list1.set(0, 2);    //將list1的0號元素改為2
        System.out.println("list1改變后");
        for (List<Integer> l : listList) {
            for (Integer i : l) {
                System.out.println(i);
            }
            System.out.println("---");
        }
    }
}

結(jié)果為

list1改變前
1
---
2
---
list1改變后
2
---
2
---

listList.add()方法重新構(gòu)造新對象(內(nèi)容與list1相同)

import java.util.ArrayList;
import java.util.List;
?
public class TestClass {
    public static void main(String[] args) {
        List<List<Integer>> listList = new ArrayList<>();
        List<Integer> list1 = new ArrayList<>();
        list1.add(1);
        listList.add(new ArrayList<>(list1)); //構(gòu)造新對象 再調(diào)用add
        List<Integer> list2 = new ArrayList<>();
        list2.add(2);
        listList.add(list2);
        System.out.println("list1改變前");
        for (List<Integer> l : listList) {
            for (Integer i : l) {
                System.out.println(i);
            }
            System.out.println("---");
        }
        list1.set(0, 2);    //將list1的0號元素改為2
        System.out.println("list1改變后");
        for (List<Integer> l : listList) {
            for (Integer i : l) {
                System.out.println(i);
            }
            System.out.println("---");
        }
    }
}

結(jié)果為

list1改變前
1
---
2
---
list1改變后
1
---
2
---

到此這篇關(guān)于一文淺析Java中的值傳遞的文章就介紹到這了,更多相關(guān)Java值傳遞內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • MyBatis中批量插入的三個關(guān)鍵優(yōu)化技巧與避坑指南

    MyBatis中批量插入的三個關(guān)鍵優(yōu)化技巧與避坑指南

    這篇文章主要為大家詳細(xì)介紹了MyBatis中批量插入的三個關(guān)鍵優(yōu)化技巧與避坑指南,文中的示例代碼講解詳細(xì),感興趣的小伙伴可以跟隨小編一起學(xué)習(xí)一下
    2026-01-01
  • 一文詳解如何配置MyBatis實現(xiàn)打印可執(zhí)行的SQL語句

    一文詳解如何配置MyBatis實現(xiàn)打印可執(zhí)行的SQL語句

    在MyBatis中,動態(tài)SQL是一個強(qiáng)大的特性,允許我們在XML映射文件或注解中編寫條件語句,根據(jù)運行時的參數(shù)來決定SQL的具體執(zhí)行內(nèi)容,這篇文章主要給大家介紹了關(guān)于如何配置MyBatis實現(xiàn)打印可執(zhí)行的SQL語句的相關(guān)資料,需要的朋友可以參考下
    2024-08-08
  • 詳解 Java靜態(tài)代理

    詳解 Java靜態(tài)代理

    這篇文章主要介紹了 Java靜態(tài)代理的相關(guān)資料,幫助大家更好的理解和學(xué)習(xí)Java代理的知識,感興趣的朋友可以了解下
    2020-08-08
  • 使用Java快速將Web中表格轉(zhuǎn)換成Excel的方法

    使用Java快速將Web中表格轉(zhuǎn)換成Excel的方法

    在平時做系統(tǒng)項目時,經(jīng)常會需要做導(dǎo)出功能,下面這篇文章主要給大家介紹了關(guān)于使用Java快速將Web中表格轉(zhuǎn)換成Excel的相關(guān)資料,需要的朋友可以參考下
    2023-06-06
  • Java后綴數(shù)組之求sa數(shù)組的實例代碼

    Java后綴數(shù)組之求sa數(shù)組的實例代碼

    后綴數(shù)組就是一個字符串所有后綴大小排序后的一個集合,然后我們根據(jù)后綴數(shù)組的一些性質(zhì)就可以實現(xiàn)各種需求。這篇文章主要介紹了Java后綴數(shù)組-求sa數(shù)組,需要的朋友可以參考下
    2018-04-04
  • springboot如何重定向外部網(wǎng)頁

    springboot如何重定向外部網(wǎng)頁

    這篇文章主要介紹了springboot如何重定向外部網(wǎng)頁,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2022-11-11
  • 在CentOS系統(tǒng)上安裝Java?JDK?8簡單步驟

    在CentOS系統(tǒng)上安裝Java?JDK?8簡單步驟

    最近購買一臺新的云服務(wù)器,用于開發(fā)學(xué)習(xí)使用,因此需要安裝很多的組件,下面這篇文章主要給大家介紹了關(guān)于在CentOS系統(tǒng)上安裝Java?JDK8的簡單步驟,需要的朋友可以參考下
    2023-12-12
  • Java使用easyExcel實現(xiàn)Excel文件解析

    Java使用easyExcel實現(xiàn)Excel文件解析

    這篇文章主要為大家詳細(xì)介紹了Java如何使用easyExcel實現(xiàn)Excel文件解析,文中的示例代碼講解詳細(xì),感興趣的小伙伴可以跟隨小編一起學(xué)習(xí)一下
    2025-02-02
  • PowerJob的AliOssService工作流程源碼解讀

    PowerJob的AliOssService工作流程源碼解讀

    這篇文章主要介紹了PowerJob的AliOssServiceg工作流程源碼解讀,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2024-01-01
  • minio分布式文件管理方式

    minio分布式文件管理方式

    文章介紹了MinIO作為分布式存儲系統(tǒng),支持大文件存儲與數(shù)據(jù)恢復(fù),通過Docker部署并配置多副本存儲,同時涵蓋圖片/視頻上傳、斷點續(xù)傳、格式轉(zhuǎn)換(如AVI轉(zhuǎn)MP4)及xxl-job分布式任務(wù)調(diào)度,強(qiáng)調(diào)樂觀鎖機(jī)制和補(bǔ)償機(jī)制確保任務(wù)可靠性與數(shù)據(jù)一致性
    2025-08-08

最新評論

南阳市| 平昌县| 华阴市| 易门县| 万载县| 徐闻县| 丰顺县| 古交市| 呼图壁县| 响水县| 松阳县| 新巴尔虎右旗| 石河子市| 拉萨市| 柳州市| 日土县| 普安县| 威海市| 胶南市| 偏关县| 长寿区| 阜阳市| 财经| 滦南县| 汕头市| 宁阳县| 沙雅县| 洛宁县| 洪泽县| 神农架林区| 韶关市| 和静县| 永康市| 大新县| 香河县| 仲巴县| 农安县| 蒙阴县| 秦皇岛市| 青州市| 巴塘县|