值传递还是址传递,Java中使用final作为参数的修饰的感想

背景

最近在项目里经常看到有的小伙伴喜欢在参数里面加上final关键字,平常也没怎么注意,偶然几天有空仔细看了一下,觉得十分有意思。所以记录下来,一方面是给自己多一些加深回忆的素材,另一方面也是希望能给与我有相同疑惑的同学有个参考。当然这个本身可能是比较基础的问题,但是多换个角度看也蛮有意思的

final关键字在Java中的应用场景其实也还是蛮多的,其中最出名的地方,应该就是继承的时候不允许继承吧。然后还有很多的场景就是final static来定义一些常量吧。当然,还有一个比较有意思的场景,就是今天我们的主角,在传参时使用final关键字。

比如这样:

public void doThings(final Object inputParam)

这里不由得联想到了当年刚学C++中,一个很有意思又很容易混淆的概念,参数时按址传递还是按值传递的呢?当然在Java中因为取消了 * 和 & 这些容易混淆的关键字,但是如果在传递参数时不注意的话,还是很容易造成一些不容易发现的错误的。那么就想从使用final关键词上来在看看Java有趣的传参机制。


为什么在传参中加上final

首先,我觉得还是给出一个大概的结论吧:

  1. int、char这些基础类型来说,可以认为就是按值传递的(在函数中对其的修改不会影响到参数本身来源的值得改变)。当然String这个类型会比较特殊,在于虽然本身是一个基础类型,但是它同时又是一个对象,有一些列Object中继承的方法。(这里和String在内存中具体处理有关系,因为我们实际操作的是String其实是一个对象,而真实的字串值是存在于静态区,并非是String本身,这一点和装箱类型的Integer之类的有点相似。具体有兴趣的同学可以参考一下Java中内存结构,如内存模型的一个图 谜之音:凑不要脸的! 我:是啊,我就是,怎么了(捂脸)

  2. 对于对象来说,按照按值传递来处理,基本上也是没有问题的,而且能够简化问题本身。

  3. 但是(终于等到这个词了,据说是中国人最讨厌的两个字之一(捂脸)),在Java中其实也是可以直接改变参数对象的值的,只要你加上final关键字之后编译器不报错的话,而且这很好的弥补了有时我们返回值只有一个时的尴尬。

那么,这是为啥呢,我们就来看看final关键字吧~其实就final本身来说,还是比较好理解的,简单的可以认为final就代表着不能改变的意思。可以发现,不管是final在修饰变量,或者修饰方法,或者修饰类的时候,其实都最最终意味着不可改变的意思。
乍一听,感觉有点玄乎,不可改变为啥修饰了参数之后反而使得参数值本身可以改变了呢?其实这里和Java本身的机制有关,因为传递的是参数并非参数本身,而是参数本身的一个引用的复制。这也就是很多文章将这里的传递和赋值号联系起来的原因。具体可以参考这些文章,写的挺好的:

所以参考下图,我们可以发现,其实参数值的变化,是因为我们在内部可以通过引用来修改到参数值本身,但是其本质仍然是一个引用,而final定义的不可改变,是引用的不可改变,也就是引用本身是不能改变的(即不能指向其它对象!)

参数传递

所以引用的不可改变就表示了我们始终只能修改最初开始所指向的值本身,而不会因为修改成中间可能指向了其它值得引用本身。这里可能有点难以理解,我们可以通过以下代码来加强理解一下:

public class AnPoJo {

    public int a = 1;
    
    @Override
    public String toString() {
        return String.valueOf(a);
    }
}


public class Application {

    public static void main(String[] args) {
        AnPoJo pojo = new AnPoJo();
        
        modify1(pojo);
        System.out.println("modify1: "+ pojo);
        modify2(pojo);
        System.out.println("modify2: " + pojo);     
    }
    
    private static AnPoJo modify1(AnPoJo pojo){
        pojo = new AnPoJo();
        pojo.a = 2;
        return pojo;
    } 
    
    private static AnPoJo modify2(AnPoJo pojo){
        pojo.a = 2;
        return pojo;
    }
}

打印结果如下:

modify1: 1
modify2: 2

由此可见,其实只要引用本身不变化,是可以成功达到想要修改参数值的效果的。因此这里如果使用final关键字来标记想要直接改变参数值的方法是一个非常好的编程习惯,杜绝了疏忽可能导致的错误。例如可以这样来修改方法modify1,通过编译器就能很容易的检测到错误点:

private static AnPoJo modify1(final AnPoJo pojo){
    pojo = new AnPoJo();    // compile error
    pojo.a = 2;
    return pojo;
} 

结语

其实有很多非常好的编程技巧,看似平淡无奇,但是仔细思考起来还是蛮有意思的一件事,能从中体会到优秀代码中对语言本身的理解和把握。除了本例之外,还有诸如其它一些例子,如: if(true==isValid())

当然由于知识结构所限,也有一个学习的过程,如果有所错误或者遗漏,欢迎大家指正补充~
并在此给出一个简单的结论:

  1. 如果不清楚到底是传值还是传址,Java中就全部当做传值处理就ok(除了部分特殊场景外,也不会有什么不足)
  2. 如果一定要改变参数值本身,一定要加final关键字!

enjoy~

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 213,558评论 6 492
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,002评论 3 387
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 159,036评论 0 349
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,024评论 1 285
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,144评论 6 385
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,255评论 1 292
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,295评论 3 412
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,068评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,478评论 1 305
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,789评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,965评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,649评论 4 336
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,267评论 3 318
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,982评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,223评论 1 267
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,800评论 2 365
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,847评论 2 351

推荐阅读更多精彩内容

  • 1. Java基础部分 基础部分的顺序:基本语法,类相关的语法,内部类的语法,继承相关的语法,异常的语法,线程的语...
    子非鱼_t_阅读 31,605评论 18 399
  • Spring Cloud为开发人员提供了快速构建分布式系统中一些常见模式的工具(例如配置管理,服务发现,断路器,智...
    卡卡罗2017阅读 134,644评论 18 139
  • 前言 人生苦多,快来 Kotlin ,快速学习Kotlin! 什么是Kotlin? Kotlin 是种静态类型编程...
    任半生嚣狂阅读 26,179评论 9 118
  • 一:java概述:1,JDK:Java Development Kit,java的开发和运行环境,java的开发工...
    ZaneInTheSun阅读 2,642评论 0 11
  • 当人生面临重大困难或者磨难,最容易难住人的就是钱,钱支配着你的一切欲望,钱驱使着你的一切行为,虽然如此,钱也是最能...
    HJoanna阅读 292评论 0 0