`
deepinmind
  • 浏览: 449047 次
  • 性别: Icon_minigender_1
  • 来自: 北京
博客专栏
1dc14e59-7bdf-33ab-841a-02d087aed982
Java函数式编程
浏览量:41367
社区版块
存档分类
最新评论

Java中如何颠倒"是非"

阅读更多
我们先来看一段代码:

public static void  main(String[] args)  {
         if(Boolean.valueOf("true") == false)
            System.out.println("true == false");
} 


你觉得这段代码的输出是什么?1. 什么也没有。 2. true == false.  3. 这可不好说。

选1的都是好孩子,直接选3的就请不要往下看了。选2的,只能说,你们太配合了。

其实这是源于stackoverflow很久前的一个帖子,前几天和同事正好聊起到。在我的机器上,这段代码是输出true== false的,这是因为我没把代码粘贴全,其实完整的代码是这样的:


import java.lang.reflect.Field;
import java.lang.reflect.Modifier; 

public class Test {

    static {
        try {
            Field f = Boolean.class.getDeclaredField("TRUE");

            Field modifiersField = Field.class.getDeclaredField("modifiers");
            modifiersField.setAccessible(true);
            modifiersField.setInt(f, f.getModifiers() & ~Modifier.FINAL);

            f.setAccessible(true);
            f.set(Boolean.class, Boolean.FALSE);

        }
        catch(Exception ex) {}
    }

    public static void  main(String[] args)  {

        if(Boolean.valueOf("true") == false)
            System.out.println("true == false");

    }
} 





Boolean类内部有这么两个静态成员变量:


    /**
     * The <code>Boolean</code> object corresponding to the primitive
     * value <code>true</code>.
     */
    public static final Boolean TRUE = new Boolean(true);

    /**
     * The <code>Boolean</code> object corresponding to the primitive
     * value <code>false</code>.
     */
    public static final Boolean FALSE = new Boolean(false); 


当调用Boolean.valueOf()或者触发编译器的自动装箱的时候,都会用到这两个变量。上面的代码里我们就是通过反射将其中的那个TRUE修改成了new Boolean(false),因此能会输出"true==false”。注意这个字段是final类型的,所以简单的.setAccessible(true);它可不吃这一套,因此后面会将它的修饰符改成非final的: modifiersField.setInt(f, f.getModifiers() & ~Modifier.FINAL);这里稍微有点饶,这个修饰符是在TRUE对应的这个静态成员变量的Field实例(Boolean.class.getDeclaredField("TRUE"))的一个叫modifier的字段里(Field.class.getDeclaredField("modifiers");)。

当然,如果你看到你的员工写出Boolean.valueOf("true") == false这样的语句的话,你估计第一反应就是把他给炒了。但是有的情况就不那么容易发现了。我们经常会把数据序列化成XML或者JSON的格式,当然我们同样也需要将它们进行反序列化。

假设有这么一段JSON:


{  "deepinmind" : true }

你可以用fastjson之类的对它进行反序列化,


    public static void  main(String[] args)  {

           JSONObject json = (JSONObject)JSON.parse("{ \"deepinmind\" : true }") ;
           System.out.println("deepinmind: "+json.getBoolean("deepinmind")); 

    } 


结果是:

deepinmind: false



因为fastjson会把解析后的值存到一个map里,这样的话就正好触发了自动装箱。在不知不觉中,你的结果已经被修改了。


当然能做的远不止这些,比如下面这段代码:

public class Test {

    static {
        try {
        Field modifiersField = Field.class.getDeclaredField("modifiers");
        modifiersField.setAccessible(true);
        
        Class<?> cls = Class.forName("java.lang.Integer$IntegerCache")  ;
        Field f =  cls.getDeclaredField("cache");
        f.setAccessible(true);

        modifiersField.setInt(f, f.getModifiers() & ~Modifier.FINAL);

        Integer[] array = (Integer[])f.get(cls);
        array[128+21] = new Integer(22);

        }
        catch(Exception ex) {}
    }

    public static void  main(String[] args)  {

                System.out.format("3 * 7 = %d", 21);

    }
}




3 * 7 = 22

看吧,再也不用管什么三七二十一了。

这是因为Integer会把-128~127之间的整型缓存起来,自动装箱的时候会优先使用缓存的这些对象。而System.out.format后面是个变长参数,这会触发int类型的自动装箱。前面之所以加了128是因为cache数组的前128位存的是负数:


private static class IntegerCache {
        static final int high;
        static final Integer cache[];

        static {
            final int low = -128;

            // high value may be configured by property
            int h = 127;
            if (integerCacheHighPropValue != null) {
                // Use Long.decode here to avoid invoking methods that
                // require Integer's autoboxing cache to be initialized
                int i = Long.decode(integerCacheHighPropValue).intValue();
                i = Math.max(i, 127);
                // Maximum array size is Integer.MAX_VALUE
                h = Math.min(i, Integer.MAX_VALUE - -low);
            }
            high = h;

            cache = new Integer[(high - low) + 1];
            int j = low;
            for(int k = 0; k < cache.length; k++)
                cache[k] = new Integer(j++);
        }

        private IntegerCache() {}
    } 



想得到这个输出,你除了可以修改IntegerCache外,还可以自己写一个PrintStream,把System.out给替换掉,这样你想输出什么就能输出什么了。不过这个也得用到反射,因为System.out是final类型的。


当然了,权当娱乐,可千万不要这么写代码。如果它让你感到害怕,你可以看下这个讨论,了解下如何把这个功能给屏蔽掉。

原创文章转载请注明出处:http://it.deepinmind.com

7
2
分享到:
评论
8 楼 Night舞夜 2014-06-16  
deepinmind 写道
Night舞夜 写道
我想说我机器上毛都没输出.Boolean.valueOf("true")输出的是true, 难道这还与机器有关?


你是运行我粘贴的第二段代码吗?

我只运行了这个Boolean.valueOf("true")
7 楼 deepinmind 2014-04-04  
Night舞夜 写道
我想说我机器上毛都没输出.Boolean.valueOf("true")输出的是true, 难道这还与机器有关?


你是运行我粘贴的第二段代码吗?
6 楼 Night舞夜 2014-04-04  
我想说我机器上毛都没输出.Boolean.valueOf("true")输出的是true, 难道这还与机器有关?
5 楼 deepinmind 2014-04-03  
与天争锋 写道
第一段代码 表示完全神马都木有输出。楼上是说。。。多了一个括号


哦还真是 我以为说第二段呢。。眼真尖,哈哈
4 楼 与天争锋 2014-04-03  
第一段代码 表示完全神马都木有输出。楼上是说。。。多了一个括号
3 楼 deepinmind 2014-04-03  
LazyDonkey 写道
true == false的那段代码会编译错误的


?没有啊,我都是运行过的
2 楼 LazyDonkey 2014-04-03  
true == false的那段代码会编译错误的
1 楼 jiiming 2014-04-02  

相关推荐

    java 中文字转为英文

    java 中文字转为英文java 中文字转为英文java 中文字转为英文

    Java 中文入门学习手册合集[chm版]

    第一章 Java语言的产生及其特点 第二章 Java程序开发与运行环境 第三章 Java程序设计基础 第四章 Java应用程序的基本框架 第五章 Java的类 第六章 Java图形用户接口 第七章 多线程 第八章 Java的"异常" 第九...

    java中文排序,数字字母汉字排序

    首先,我们需要理解Java中的排序机制。Java集合框架中的`List`接口提供了一个`sort(Comparator&lt;? super E&gt; comparator)`方法,可以接受一个比较器(Comparator)来定义自定义的排序规则。默认情况下,Java使用自然...

    JAVA_API1.6文档(中文)

    java.security.interfaces 提供的接口用于生成 RSA Laboratory Technical Note PKCS#1 中定义的 RSA(Rivest、Shamir 和 Adleman AsymmetricCipher 算法)密钥,以及 NIST 的 FIPS-186 中定义的 DSA(数字签名算法)...

    Java API文档 中文网页版

    在Java中,API主要由Sun Microsystems(现为Oracle公司)维护,是Java平台的核心组成部分。它包括了Java标准库中的各种类库,如集合框架、输入/输出流、网络编程、多线程、图形用户界面(GUI)等。 Java API文档...

    java中文帮助文档

    java中文帮助文档java中文帮助文档java中文帮助文档java中文帮助文档java中文帮助文档java中文帮助文档java中文帮助文档java中文帮助文档java中文帮助文档

    Head First Java 中文高清版pdf

    除此之外,书中的案例涵盖了集合框架,包括ArrayList、LinkedList、HashMap等,这些都是Java开发中不可或缺的数据结构。此外,还会介绍泛型、枚举和注解,这些都是现代Java编程中的重要元素。 最后,书籍还讲解了...

    ElasticSearch Java API 中文文档

    3. **依赖(Dependency)**: 介绍了如何在Java项目中添加ElasticSearch Java API依赖,特别是推荐使用与ElasticSearch版本号一致的transport版本号。这是使用ElasticSearch Java API前的必要配置。 4. **Java客户端...

    java jdk 8 帮助文档 中文 文档 chm 谷歌翻译

    JDK1.8 API 中文谷歌翻译版 java帮助文档 JDK API java 帮助文档 谷歌翻译 JDK1.8 API 中文 谷歌翻译版 java帮助文档 Java最新帮助文档 本帮助文档是使用谷歌翻译,非人工翻译。准确性不能保证,请与英文版配合使用 ...

    java 实现国际化 中英文语言切换

    在这个主题中,我们将深入探讨如何使用Java和JSP进行语言切换,以满足用户对中英文显示的需求。 1. **Java 国际化基础** Java 提供了 `java.util.Locale` 类来表示不同的语言环境,如英文(`en`)和中文(`zh`)。...

    java源码包---java 源码 大量 实例

     Java 3DMenu 界面源码,有人说用到游戏中不错,其实平时我信编写Java应用程序时候也能用到吧,不一定非要局限于游戏吧,RES、SRC资源都有,都在压缩包内。 Java zip压缩包查看程序源码 1个目标文件 摘要:Java源码...

    《kettle中调用java类》示例代码

    在标题《kettle中调用java类》示例代码中,我们关注的是如何在Kettle的转换或作业中嵌入Java代码,以实现更复杂的数据处理逻辑。 首先,Kettle支持两种方式来调用Java类:使用“Java Class”步骤和使用“Execute ...

    java中main方法发送httpPost请求

    首先,Java中发送HTTP POST请求通常会用到`HttpURLConnection`类或者第三方库如Apache HttpClient或OkHttp。下面我们将主要使用`HttpURLConnection`来演示,因为它内置在JDK中,无需额外引入依赖。 1. **创建HTTP...

    Java 面经手册·小傅哥.pdf

    当你仔细阅读书籍时,会发现Java中有大量的数学知识,包括:扰动函数、负载因子、拉链寻址、开放寻址、斐波那契(Fibonacci)散列法还有黄金分割点的使用等等。 适合人群 1. 具备一定编程基础,工作1-3年的研发...

    Java OCR 图像智能字符识别技术,可识别中文

    Java OCR(Optical Character Recognition,光学字符识别)技术是一种计算机视觉领域的应用,它能将图像中的文字转换成可编辑的文本格式。这项技术在各种场景下都有广泛应用,比如文档扫描、车牌识别、发票处理等。...

    java朗读中文字符串.zip

    在Java中,这种功能通常依赖于Java的Text-to-Speech API,也就是Java Speech API (JSAPI) 的一部分,特别是`javax.speech`和`edu.speech`这两个包中的类。 Java Text-to-Speech (TTS) 是一项将文本数据转化为可听见...

    JAVA API官方中文版手册chm文件文档

    JAVA API官方文档中文版软件包 java.applet java.awt java.awt.color java.awt.datatransfer java.awt.dnd java.awt.event java.awt.font java.awt.geom java.awt.im java.awt.im.spi java.awt.image ...

    JAVA中license控制实现示例.doc

    JAVA中license控制实现示例 在 Java 中,license 控制是指通过生成和验证数字签名来控制软件的使用权限。这种方法广泛应用于 J2EE 应用中,特别是在系统购买的早期,提供有限制的 license 文件对系统进行限制。 在...

    java 图片旋转、翻转、镜像处理

    首先,我们需要了解Java中用于处理图像的主要类库:Java Advanced Imaging (JAI) 和 Java 2D API。虽然JAI提供了更强大的图像处理功能,但Java 2D API通常更易于理解和使用,尤其对于简单的图像操作如旋转、翻转和...

    JAVA8API-官方文档下载-中文版

    2. **Nashorn JavaScript引擎**: 提供了在Java中执行JavaScript代码的能力,便于混合编程。 3. **并行数组操作**: `java.util.parallel`包提供了并行版本的数组操作,如`Arrays.parallelSort()`。 4. **集合工厂...

Global site tag (gtag.js) - Google Analytics