在编程中为所欲为[圣诞版]

众所周知,在Java中final String中的值是一成不变的。大家都知道String的+(拼接)运算会丢弃内存引用并在内存中重新开拓地址,事实上也确实如此。但final的变量真的是一成不变的吗?谨以此文打开程序员思路,跳出定式思维,希望本文会给你的程序员生涯带来新的思考。

一个简单的例子

这个例子很久远,早有前辈做过,但并不是所有的程序员都接触过。通常喜欢“猎奇”的程序员对此不会陌生。


import java.lang.reflect.Field;

public class ChangeFinalString {

    public static void main(String[] args) throws Exception {
        final String s = "12345: caiyongji";
        System.out.println(s);
        System.out.println("hashcode: " + s.hashCode());
        Field f = String.class.getDeclaredField("value");
        f.setAccessible(true);
        char[] value = (char[]) f.get(s);
        value[0] = (char) 20851;
        value[1] = (char) 27880;
        value[2] = (char) 20844;
        value[3] = (char) 20247;
        value[4] = (char) 21495;
        System.out.println(s);
        System.out.println("hashcode: " + s.hashCode());
    }
}

例子中,通过final初始化一个String,然后反射获取String类中名为value的Field,并重新赋值value。执行后,你会发现String的hashcode值没有变,String的值却变了。另外,你还会发现这几行简单代码的彩蛋。

得出结论

看!是不是觉得常规可以被打破,只要有足够的技巧就可以在编程中为所欲为?也许有些严谨的程序员会指出hashcode方法的实现依赖于JVM,并不能直接反映内存的情况。说实话,你甚至不需要记住本文的例子,我只是想打破你固有的思维模式。

然而,上面的并不是我想说的真正结论。

下面,才是“圣诞版”真正的意义。

也许有些人会觉得收获颇丰,我又掌握了一个面试问题的答案。没错,甚至像阿里、百度这样的国内巨头企业中,有一些面试官(注意是有一些),确实会问一些"final变量是不可变"这样的silly question. 他们钻研一门语言甚至知道所有具体实现的细节,甚至语言的bug。 但换个角度,在如此钻研的同时,你是否考虑了你的时间成本、女朋友以及后代?!

接口论

作为一个程序员,你是业务逻辑和代码实现的接口。没人在乎你怎么实现的业务,只在乎你的代码是否高效、准确、易用、易拓展(具体讲,比如多少ms返回结果,参数结构是否简单,是否容易添加新功能)。同理,你使用Java作为你实现业务逻辑的工具,你更可以选择Python、Node.js、Kotlin甚至Linux shell脚本,那么你是否要理解Java语言的所有实现?正如我在《如何成为10倍速的程序员》中所说的不要记忆。

我是在号召大家不求甚解吗?

是的。

反设计

如果把编程手段当成一种工具,无外乎语言、文档、框架,这些都可以当成是工具的一部分。不要试图用锤子打开螺丝钉,虽然你确实可以做到。但这是反设计的。就像这个例子一样,你可以通过reflect改变final,但说白了,这种技巧并没有什么用,它会给你带来很多麻烦,比如在拓展时、在java版本升级时考虑兼容性。

所以,在使用一种“工具”时,要尽量按照工具制造者的思维模式进行使用,所有这些所谓的“技巧”都是在反设计。



最后,专注、严谨、逻辑清晰是一个程序员的品质,但在技术迭代如此迅速的大背景下,在代码中追求极致是一个人类无法做到的(如果用掌握技巧的来衡量的话,你永远无法掌握所有技巧,并且,在技术迭代过程中,你原本掌握的技巧也在逐步淘汰。),别忘了你生活中的朋友、家人和你的爱好。

过完圣诞就是新的一年,祝所有的程序员朋友圣诞快乐(本文写于平安夜),同时在新的一年里开启程序员新的、不一样的人生。

时间: 2024-08-08 13:05:29

在编程中为所欲为[圣诞版]的相关文章

【浅墨Unity3D Shader编程】之五 圣诞夜篇: Unity中Shader的三种形态对比&混合操作合辑

本系列文章由@浅墨_毛星云 出品,转载请注明出处.  文章链接:http://hpw123.net/a/C__/kongzhitaichengxu/2014/1222/164.html 作者:毛星云(浅墨)    微博:http://weibo.com/u/1723155442 邮箱: [email protected] QQ交流群:330595914 更多文章尽在:http://www.hpw123.net 本文算是固定功能Shader的最后一篇,下一次更新应该就会开始讲解表面Shader,而

java编程思想第四版中net.mindview.util包下载,及源码简单导入使用

在java编程思想第四版中需要使用net.mindview.util包,大家可以直接到http://www.mindviewinc.com/TIJ4/CodeInstructions.html 去下载,并按照所在页面的操作进行操作.当然也可以直接我下载下面的链接,下载的直接是JAR包,可以直接导入并使用: net.mindview.util包:百度网盘:点击下载  密码: ggpi java编程思想第四版源码:百度网盘:点击下载  密码: ur3e 下面我简单的介绍一下源码在Eclipse中的导

分享《Python核心编程(第3版)》《Python编程入门(第3版)》高清中英文版PDF+源代码

<Python核心编程(第3版)>经典<Python核心编程(第二版)>的全新升级版本,总共分为3部分.第1部分为讲解了Python的一些通用应用,包括正则表达式.网络编程.Internet客户端编程.多线程编程.GUI编程.数据库编程.Microsoft Office编程.扩展Python等内容.第2部分讲解了与Web开发相关的主题,包括Web客户端和服务器.CGI和WSGI相关的Web编程.Django Web框架.云计算.高级Web服务.第3部分则为一个补充/实验章节,包括文

编程中 word 所有属性

编程中 word 所有属性 word文档工程变量的 //合并单元格   table.Cell(2, 2).Merge(table.Cell(2, 3)); //单元格分离    object Rownum = 2;    object Columnnum = 2;    table.Cell(2, 2).Split(ref Rownum, ref Columnnum); //单元格对齐方式     WApp.Selection.Cells.VerticalAlignment =Microsoft

Java编程思想第四版读书笔记——第十三章 字符串

Java编程思想第四版读书笔记--第十三章 字符串 字符串的操作是计算机程序设计中最常见的行为. 关键词: StringBuilder ,StringBuffer,toString(),format转换,正则表达式, 1.不可变String String对象时不可变的.每当把String对象作为方法的参数时,都会复制一份引用.(其实就是对函数中参数列表中参数的操作不会影响外面的原参数) 如下: import static net.mindview.util.Print.*; public cla

编程中的正交原则

今天读到了<程序猿的修炼之道>关于"正交的优点"一节,突然间想起了一件事情. 关于当年參加飞思比赛的故事. 话说參加完这个比赛之后,最引以为豪的作品还是由我们队一路摸索建立起来的无线通信上位机调试技术(就姑且称之为技术吧),这项技术带来的优点是显而易见的,方便的查看各项执行数据为调整策略提供根据,方便的设置关键变量以尽快获取最佳执行參数.方便的检查各类传感器状态以确定其执行是否正常. 因此,我多次建议后来的师弟将这一成果沿用下去.并进行必要的改进. 在为他们提供的技术资料中

UNIX环境高级编程(第三版)关于apue.h的用法

UNIX环境高级编程(第三版)中的例子用到apue.h这个头文件,但是书里面写的地址已经不能访问. 经过一番查找之后,找到如下解决方案: 1.到www.apuebook.com上下载第2版的源码,也可以直接点这里. 2.下载后的源码,需要修改一下: 1.Make.defines.linux中第6行WKDIR=/home/sar/apue.2e更改为目录的绝对路径. 2.apue.2e/ipp/ipp.h中第122行中的status换为Status.(也可换为其他,但要与下面对应) 3.apue.

TCP/UDP编程中的问题汇总

TCP/UDP编程中的问题汇总 TCP和UDP发送大文件的问题. 答: 发送端: 发送时,先发送文件的名称及大小等信息. 然后,设置一个缓冲区的大小,假设为4K. 再循环读4K的文件内容,并发送,直到发送完成. 最后,再发送完成标记. 接收端: 接收到第一个包时,得到文件的大小等信息. 计算出要接收多少个包. 然后,循环接收包,并将接收到的数据写入到文件中. 直到,接收到的数据长度等于文件的大小. struct package { 文件标识 //GUID 偏移量 //001- 数据段 //Byt

深入剖析Java编程中的中文问题及建议最优解决方法

摘录自:http://fafeng.blogbus.com/logs/3062998.html http://www.blogbus.com/fafeng-logs/3063006.html 深入剖析Java编程中的中文问题及建议最优解决方法 说明:本文为作者原创,作者联系地址为:[email protected].由于Java编程中的中文问题是一个老生常谈的问题,在阅读了许多关于Java中文问题解决方法之后,结合作者的编程实践,我发现过去谈的许多方法都不能清晰地说明问题及解决问题,尤其是跨平台