谜题解析

题目接http://zangxt.iteye.com/blog/435711

说明:这篇博文是我自己分析和整理的,题目来源和解析参考http://developers.sun.com/learning/javaoneonline/sessions/2009/pdf/TS-5186.pdf

,版权归原作者所有。

 

1.读文档,看Boolean.getBoolean()这个方法的功能就能解决。

    多读文档,很多接口可能并不是按我们想象的方式工作。

2.答案是6.

    多态带来的问题。

public boolean addAll(Collection<? extends E> c){
        addCount
+= c.size();
       
return super.addAll(c);
    }
     我们看父类中的代码:

public boolean addAll(Collection<? extends E> c) { boolean modified = false; Iterator<? extends E> e = c.iterator(); while (e.hasNext()) { if (add(e.next())) modified = true; } return modified; }

 

    父类的addAll()方法调用了add(),由于多态,这里调用的是子类的add()方法,也就是

public boolean add(E e){
        addCount
++;
       
return super.add(e);
    }
   又对addCount进行了加1操作。

 

组合优于继承,在继承API中的类时先明确这些类是否适合继承。

3.结果是OOPS。

    多输出了一个O,这个倒是容易发现问题。这个也是和初始化顺序相关的,一般建议在构造方法中不要调用可能被覆盖的方法,但是像这种T next = nextElement();调用我们可能会不小心。执行这句话的时候,子类的构造方法及初始化语句尚未执行。nextElement();里面虽然执行了cursor++, 但是当流程执行到子类的初始化语句时cursor = 0把cursor++的效果弄没了。所以,我们可以将cursor = 0去掉来暂时性的解决问题。当然,原作者给出了更好的方案:

 改正后的代码:

import java.util.Iterator; import java.util.NoSuchElementException; public abstract class AbstractIterator<T> implements Iterator<T> { T cachedNext; boolean hasCachedNext; public boolean hasNext() { if (!hasCachedNext) { cachedNext = nextElement(); } hasCachedNext = true; return cachedNext != null; } public T next() { if (!hasNext()) { throw new NoSuchElementException(); } hasCachedNext = false; return cachedNext; } public void remove() { throw new UnsupportedOperationException(); } protected abstract T nextElement(); private static Iterator<Character> test(final String s) { return new AbstractIterator<Character>() { private int cursor = 0; protected Character nextElement() { return cursor == s.length() ? null : s.charAt(cursor++); } }; } public static void main(String[] args) { Iterator<Character> i = test("OPS"); for (; i.hasNext();) { System.out.print(i.next()); } } }

 

      关于构造方法的调用顺序和初始化顺序,可以参考《Thinking In Java》或者自己写个简单的程序单步调试一下。

4.结果是-2.

问题出在:

return i<j?-1:(i==j?0:1);
两个Integer,用==判断容易出问题。

这句话可以修改为

return i<j?-1:(i>j?1:0);

     说明:对于包装类型,进行大于或者小于比较时,会进行拆箱操作,所以比较的就是封装的数的内容。但是使用==和!=进行比较时,比较的是引用的值。

    在《Java Puzzlers》一书中,作者也有类似的例子。比如,要求给出两个变量声明,使循环成为死循环。

while(i>=j && j>=i && i!=j){

}

     答案可以是:

Integer i = new Integer(1);
Integer j = new Integer(1);

 

5.这个是相对容易的,不过要对枚举的原理和java在类加载以及创建对象时的初始化顺序非常熟悉才行。可以结合下面两篇进行理解:

http://blog.csdn.net/ZangXT/archive/2008/10/29/3174741.aspx

http://blog.csdn.net/ZangXT/archive/2008/10/31/3196244.aspx

 

解决方案:

 

import java.util.LinkedHashMap; import java.util.Map; public enum RomanNumeral { I(1), V(5), X(10), L(50), C(100), D(500), M(1000); private static Map<Integer, RomanNumeral> map = new LinkedHashMap<Integer, RomanNumeral>(); public final int val; RomanNumeral(int val) { this.val = val; } static { for (RomanNumeral r : RomanNumeral.values()) { map.put(r.val, r); } } public static RomanNumeral fromInt(int val) { return map.get(val); } public static void main(String[] args) { int sum = 0; for (int i = 0; i < 1000; i++) { if (fromInt(i) != null) { sum += i; } } System.out.println(sum); } }

 

 

6.抛出异常,Exception in thread "main" java.lang.OutOfMemoryError: Java heap space

   

     其实这个细说起来还是很复杂的,需要理解ThreadLocal的原理和弱引用的相关知识。因为内部类对象存在一个指向外部类(包含内部类的类)ThreadFriendly对象的引用,而ThreadFriendly对象又存在到ThreadLocal对象的引用,导致Thread中ThreadLocal.ThreadLocalMap inheritableThreadLocals 中的key一直是强引用,无法释放,最终导致内存溢出。在开头给出的链接中,原作者的pdf里面有引用示意图,比较直观,有兴趣的可以下载看看。

     解决方法:

 

static class Value{
       
final int i;
        Value(
int i){
           
this.i = i;
        }
    }

 

     当然,也可以static ThreadLocal<Value> threadLocalPart = new ThreadLocal<Value>();

7.因为null的存在会导致Words类的加载,所以输出是:

the chemistry set

 

    关于常量折叠,可以参考:

http://blog.csdn.net/ZangXT/archive/2008/12/13/3511697.aspx

 

    这里需要注意的是,null并不是常量,将PrintWords.java编译之后,Words.FIRST,Words.THIRD都直接用"the"和"set"替换了,它们没有对Words类型的引用。但Words.SECOND 仍然保留对Words.SECOND的引用。

这可以通过分析javap -verbose反汇编class文件得到证实。

    重编译Words.java文件之后,PrintWords.java中进行输出时,读取Words.SECOND时要去加载Words类。导致输出结果是the chemistry set。(因为the 和 set已经编译为字符串常量,不会引用Words类的内容)

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值