透明思考@CSDN

思考着的程序员,程序员的思考

熊节ID:gigix
936939次访问,排名29好友0人,关注者11
gigix的文章
原创 361 篇
翻译 1 篇
转载 3 篇
评论 1822 篇
最近评论
shendl:public static AuthorizationService getInstance()

{

if(null == instance){

instance = new AuthorizationService();

}

return instanc……
lishali12345:你真的需要一直那些所谓的大师来摆弄吗?
我只是一个简单的读者而已,你总是拿一些所谓的名人大家的话来盖人,一个目的无非是想增加你自己说话的分量,其实你自己的话就压根没什么分量,基于对自己的不自信才会导致你在所有的文章中,开头以及结尾经常借大家之口来表达你要意淫的某些观点。
实在不忍心那些大家,经常就从你口之中说出来啊!
carry1002:你好,我是猎头公司carry,我们服务的对象主要是世界500强企业,现在有thougthtworks公司的职位机会,TW是敏捷方法领域的领头羊,有兴趣的朋友请和我联系,我的msn:carry.1@hotmail.com
zdonking:很好,感谢gigix前辈的经验分享。
zhouxz1026:不错!
蜂胶
蜂蜜
文章分类
收藏
    相册
    我的图片
    测试
    Arrays.asList("Rod", "Jane", "Freddy");(RSS)
    存档
    软件项目交易
    订阅我的博客
    XML聚合  FeedSky
    订阅到鲜果
    订阅到Google
    订阅到抓虾
    订阅到BlogLines
    订阅到Yahoo
    订阅到GouGou
    订阅到飞鸽
    订阅到Rojo
    订阅到newsgator
    订阅到netvibes

    原创 [Java细节]"hi there".equals("cheers !") == true收藏

    新一篇: “泛型Java”,一个美丽的hype | 旧一篇: AOP能做什么?

    不知道这个标题是否让读者产生一种想打我的冲动。至少今天我的主管被我用这个小把戏诧异了一把,当他看到"hi there".equals("cheers !") 的结果居然是true时,脸上的表情实在是可爱。

    OK,言归正传。System.out.println("hi there".equals("cheers !")); 这个看来再显然不过的句子,输出的结果居然是true。聪明的读者,你知道是为什么吗?如果一时还猜不出来,给你一点提示:

    1、Java语言规范规定,同一个程序中任何相同的字符串常量(literal string)都只是同一个String对象的不同引用,不论它们是否在同一个类、同一个包中。

    2、Java语言规范规定,由常量表达式计算得到的String对象将在编译期被求值,并在运行时被作为字符串常量对待;在运行时计算得到的String对象将是一个完全独立的新对象。

    如果你仍然不明就里,或者想知道这个把戏实现的细节,请看下面这篇来自artima的webLog——看看别人都在用blog写什么东西,再看看blogchina那帮人在用blog写什么东西,我都替他们害臊。

    ——————————————————

    Artima Weblogs
    "hi there".equals("cheers !") == true
    by Heinz Kabutz
    May 21, 2003
    Summary
    Java Strings are strange animals. They are all kept in one pen, especially the constant strings. This can lead to bizarre behaviour when we intentionally modify the innards of the constant strings through reflection. Join us, as we take apart one of Java's most prolific beasts.

    Whenever we used to ask our dad a question that he could not possibly have known the answer to (such as: what's the point of school, dad?) he would ask back: "How long is a piece of string?"

    Were he to ask me that now, I would explain to him that String is immutable (supposedly) and that it contains its length, all you have to do is ask the String how long it is. This you can do by calling length().

    OK, so the first thing we learn about Java is that String is immutable. It is like when we first learn about the stork that brings the babies? There are some things you are not supposed to know until you are older! Secrets so dangerous that merely knowing them would endanger the fibres of electrons pulsating through your Java Virtual Machine.

    So, are Strings immutable?

    Playing with your sanity - Strings

    Have a look at the following code:

    public class MindWarp {
      public static void main(String[] args) {
        System.out.println(
          "Romeo, Romeo, wherefore art thou oh Romero?");
      }
      private static final String OH_ROMEO =
        "Romeo, Romeo, wherefore art thou oh Romero?";
      private static final Warper warper = new Warper();
    }
    

    If we are told that the class Warper does not produce any visible output when you construct it, what is the output of this program? The most correct answer is, "you don't know, depends on what Warper does". Now THERE's a nice question for the Sun Certified Java Programmer Examination.

    In my case, running "java MindWarp" produces the following output

    C:> java MindWarp <ENTER>
    Stop this romance nonsense, or I'll be sick
    

    And here is the code for Warper:

    import java.lang.reflect.*;
    
    public class Warper {
      private static Field stringValue;
      static {
        // String has a private char [] called "value"
        // if it does not, find the char [] and assign it to value
        try {
          stringValue = String.class.getDeclaredField("value");
        } catch(NoSuchFieldException ex) {
          // safety net in case we are running on a VM with a
          // different name for the char array.
          Field[] all = String.class.getDeclaredFields();
          for (int i=0; stringValue == null && i<all.length; i++) {
            if (all[i].getType().equals(char[].class)) {
              stringValue = all[i];
            }
          }
        }
        if (stringValue != null) {
          stringValue.setAccessible(true); // make field public
        }
      }
      public Warper() {
        try {
          stringValue.set(
            "Romeo, Romeo, wherefore art thou oh Romero?",
            "Stop this romance nonsense, or I'll be sick".
              toCharArray());
          stringValue.set("hi there", "cheers !".toCharArray());
        } catch(IllegalAccessException ex) {} // shhh
      }
    }
    

    How is this possible? How can String manipulation in a completely different part of the program affect our class MindWarp?

    To understand that, we have to look under the hood of Java. In the language specification it says in ?3.10.5:

    "Each string literal is a reference (?4.3) to an instance (?4.3.1, ?12.5) of class String (?4.3.3). String objects have a constant value. String literals-or, more generally, strings that are the values of constant expressions (?15.28)-are "interned" so as to share unique instances, using the method String.intern."

    The usefulness of this is quite obvious, we will use less memory if we have two Strings which are equivalent pointing at the same object. We can also manually intern Strings by calling the intern() method.

    The language spec goes a bit further:

    1. Literal strings within the same class (?8) in the same package (?7) represent references to the same String object (?4.3.1).
    2. Literal strings within different classes in the same package represent references to the same String object.
    3. Literal strings within different classes in different packages likewise represent references to the same String object.
    4. Strings computed by constant expressions (?15.28) are computed at compile time and then treated as if they were literals.
    5. Strings computed at run time are newly created and therefore distinct.
    6. The result of explicitly interning a computed string is the same string as any pre-existing literal string with the same contents.

    This means that if a class in another package "fiddles" with an interned String, it can cause havoc in your program. Is this a good thing? (You don't need to answer ;-)

    Consider this example

    public class StringEquals {
    public static void main(String[] args) {
      System.out.println("hi there".equals("cheers !"));
    }
    private static final String greeting = "hi there";
    private static final Warper warper = new Warper();
    }
    

    Running this against the Warper produces a result of true, which is really weird, and in my opinion, quite mind-bending. Hey, you can SEE the values there right in front of you and they are clearly NOT equal!

    BTW, for simplicity, the Strings in my examples are exactly the same length, but you can change the length quite easily as well.

    Last example concerns the HashCode of String, which is now cached for performance reasons mentioned in "Java Idiom and Performance Guide", ISBN 0130142603. (Just for the record, I was never and am still not convinced that caching the String hash code in a wrapper object is a good idea, but caching it in String itself is almost acceptable, considering String literals.)

    public class CachingHashcode {
      public static void main(String[] args) {
        java.util.Map map = new java.util.HashMap();
        map.put("hi there", "You found the value");
        new Warper();
        System.out.println(map.get("hi there"));
        System.out.println(map);
      }
      private static final String greeting = "hi there";
    }
    

    The output under JDK 1.3 is:

    You found the value
    {cheers !=You found the value}
    

    Under JDK 1.2 it is

    null
    {cheers !=You found the value}
    

    This is because in the JDK 1.3 SUN is caching the hash code so if it once is calculated, it doesn't get recalculated, so if the value field changes, the hashcode stays the same.

    Imagine trying to debug this program where SOMEWHERE, one of your hackers has done a "workaround" by modifying a String literal. The thought scares me.

    The practical application of this blog? Let's face it, none.

    This is my first blog ever, I would be keen to hear what you thought of it?

    Talk Back!

    Have an opinion? Readers have already posted 24 comments about this weblog entry. Why not add yours?

    RSS Feed

    If you'd like to be notified whenever Heinz Kabutz adds a new entry to his weblog, subscribe to his RSS feed.

    About the Blogger

    Heinz Kabutz enjoys driving Java to the limits, and then a bit beyond. He has been programming in Java since 1997 on several very unimportant projects. During that time, he has picked up some horrifying tips on how you can get the most out of Java. These are published on his bi-monthly "The Java(tm) Specialists' Newsletter" (http://www.javaspecialists.co.za). It is not for the uninitiated :-) Heinz received a PhD in Computer Science from the University of CapeTown. He loves living in South Africa as it is both beautiful and interesting. Professionally, Heinz survives by writing Java code, insulting, ahem, consulting, and presenting courses on Java and Design Patterns.

    This weblog entry is Copyright © 2003 Heinz Kabutz. All rights reserved.

    发表于 @ 2003年05月30日 15:03:00|评论(loading...)|编辑

    新一篇: “泛型Java”,一个美丽的hype | 旧一篇: AOP能做什么?

    评论

    #ericmm 发表于2004-10-15 23:43:00  IP: 211.147.234.*
    其实可以包装一下,今天下午我就写了一个包装类,比较有趣

    public class EqualMaker{

    public static void makeEqual(String one,String two){
    //省掉了try
    Field values = one.getClass().getDeclaredField("value");
    values.setAccessible(true);

    values.set(one,two.toCharArray());
    }

    public static void main(String[] a){
    makeEqual("Eric","Amy ");
    System.out.println("Eric".equals("Amy ")):
    }
    }

    打印true,唯一的缺点就是两个string的长度要一样
    #错误 发表于2005-11-04 11:37:00  IP: 61.152.210.*
    我的输出怎么是false?
    public class Test
    {
    public static void main(String args[])
    {
    System.out.println ("hi there".equals("cheers !") );
    }
    }
    #Geordi 发表于2006-02-24 16:58:00  IP: 61.50.229.*
    我想抽你,楼主
    #高深 发表于2006-02-24 17:00:00  IP: 61.50.229.*
    不是我不明白。可能是你太高深!!!!!!
    #高深 发表于2006-02-24 17:00:00  IP: 61.50.229.*
    不是我不明白。可能是你太高深!!!!!!
    #longaway 发表于2006-02-25 11:06:00  IP: 221.219.195.*

    有意思。

    btw:
    那个 blogchina 不知道所谓何事?
    发表评论  


    当前用户设置只有注册用户才能发表评论。如果你没有登录,请点击登录
    Csdn Blog version 3.1a
    Copyright © 透明@CSDN