Joshua Bloch和Neal Gafter又为我们带来的7道谜题

本文来自CSDN博客,转载请标明出处:http://blog.csdn.net/pfpfpfpfpf/archive/2009/08/05/4414224.aspx

 

在2009年的JavaOne大会上,Joshua Bloch和Neal Gafter又为我们带来的7道谜题,看了感觉自己的java基础很不扎实。

1.Life's Persistent Questions

view plaincopy to clipboardprint?

public class SimpleQuestion {      
     
    static boolean yesOrNo(String s) {      
        s = s.toLowerCase();      
        if (s.equals("yes") || s.equals("y") || s.equals("t")) {      
            s = "true";      
        }      
        return Boolean.getBoolean(s);      
    }      
     
    public static void main(String[] args) {      
        System.out.println(yesOrNo("true") + " " + yesOrNo("Yes"));      
    }      
}    
public class SimpleQuestion {   
  
    static boolean yesOrNo(String s) {   
        s = s.toLowerCase();   
        if (s.equals("yes") || s.equals("y") || s.equals("t")) {   
            s = "true";   
        }   
        return Boolean.getBoolean(s);   
    }   
  
    public static void main(String[] args) {   
        System.out.println(yesOrNo("true") + " " + yesOrNo("Yes"));   
    }   
}  
 

 

问题:程序打印什么?

开始毫不犹豫的以为是true,结果试验了都是false。。。

google了一下

view plaincopy to clipboardprint?
String   aa   =   "aa";     
  System.setProperty(aa,"true");     
  boolean   isRMS   =   Boolean.getBoolean(aa);     
    boolean   isDW   =   Boolean.getBoolean("true");     
              System.out.println("isRMS="+isRMS);     
              System.out.println("isDW="+isDW);    
String   aa   =   "aa";  
  System.setProperty(aa,"true");  
  boolean   isRMS   =   Boolean.getBoolean(aa);  
    boolean   isDW   =   Boolean.getBoolean("true");  
              System.out.println("isRMS="+isRMS);  
              System.out.println("isDW="+isDW);  
 

 isRMS=true  
  isDW=false

结果是这个样子, public   static   boolean   getBoolean(String   name)当且仅当以参数命名的系统属性存在,且等于   "true"   字符串时,才返回   true。 如果没有以指定名称命名的属性或者指定名称为空或   null,则返回   false。

2.Instruments of Tortue
view plaincopy to clipboardprint?
import java.util.Arrays;     
import java.util.Collection;     
import java.util.HashSet;     
    
public class InstrumentedHashSet<E> extends HashSet<E> {     
    private int addCount = 0;     
    @Override    
    public boolean add(E e){     
        addCount++;     
        return super.add(e);     
    }     
    
    @Override    
    public boolean addAll(Collection<? extends E> c){     
        addCount += c.size();     
        return super.addAll(c);     
    }     
    
    public static void main(String[] args) {     
        InstrumentedHashSet<String> s = new InstrumentedHashSet<String>();     
        s.addAll(Arrays.asList("Accordion","Banjo","Kazoo"));     
        System.out.println(s.addCount);     
    }     
}   
import java.util.Arrays;  
import java.util.Collection;  
import java.util.HashSet;  
 
public class InstrumentedHashSet<E> extends HashSet<E> {  
    private int addCount = 0;  
    @Override 
    public boolean add(E e){  
        addCount++;  
        return super.add(e);  
    }  
 
    @Override 
    public boolean addAll(Collection<? extends E> c){  
        addCount += c.size();  
        return super.addAll(c);  
    }  
 
    public static void main(String[] args) {  
        InstrumentedHashSet<String> s = new InstrumentedHashSet<String>();  
        s.addAll(Arrays.asList("Accordion","Banjo","Kazoo"));  
        System.out.println(s.addCount);  
    }  
}    

问题:打印结果是什么?

应该是6,不要写3个,super.addAll()也是一个一个add()方法加进去的,所以add()方法也会再执行三次,一共是6次。

3.Iterator Titillator
view plaincopy to clipboardprint?
import java.util.Iterator;     
import java.util.NoSuchElementException;     
    
public abstract class AbstractIterator<T> implements Iterator<T> {     
    
    T next = nextElement();     
    
    public boolean hasNext() {     
        return next != null;     
    }     
    
    public T next() {     
        if (next == null) {     
            throw new NoSuchElementException();     
        }     
        T result = next;     
        next = nextElement();     
        return result;     
    }     
    
    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) {     
        for (Iterator<Character> i = test("OPS"); i.hasNext();) {     
            System.out.print(i.next());     
        }     
    }     
}   
import java.util.Iterator;  
import java.util.NoSuchElementException;  
 
public abstract class AbstractIterator<T> implements Iterator<T> {  
 
    T next = nextElement();  
 
    public boolean hasNext() {  
        return next != null;  
    }  
 
    public T next() {  
        if (next == null) {  
            throw new NoSuchElementException();  
        }  
        T result = next;  
        next = nextElement();  
        return result;  
    }  
 
    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) {  
        for (Iterator<Character> i = test("OPS"); i.hasNext();) {  
            System.out.print(i.next());  
        }  
    }  

  

问题:输出结果是什么?

初始化顺序的问题,nextElement();里面虽然执行了cursor++, 但是执行到cursor = 0把cursor的值又归零了,那么第一次next是保存了o,但是cursor的值仍然是0,第二次不是初始化了,不会执行cursor=0,所以cursor=1,next缺还是o。

4.Search for the One

view plaincopy to clipboardprint?
import java.util.ArrayList;     
import java.util.Collections;     
import java.util.Comparator;     
import java.util.List;     
    
    
public class Searching {     
    public static void main(String[] args) {     
        String[] strings = { "0", "1", "2", "3", "4", "5"};     
    
        List<Integer> integers = new ArrayList<Integer>();     
        for(String s : strings){     
            integers.add(Integer.valueOf(s));     
        }     
    
        System.out.println(Collections.binarySearch(integers, 1,cmp));     
    }     
    
    static Comparator<Integer> cmp = new Comparator<Integer>(){     
        public int compare(Integer i,Integer j){     
            return i<j?-1:(i==j?0:1);     
        }     
    };     
}   
import java.util.ArrayList;  
import java.util.Collections;  
import java.util.Comparator;  
import java.util.List;  
 
 
public class Searching {  
    public static void main(String[] args) {  
        String[] strings = { "0", "1", "2", "3", "4", "5"};  
 
        List<Integer> integers = new ArrayList<Integer>();  
        for(String s : strings){  
            integers.add(Integer.valueOf(s));  
        }  
 
        System.out.println(Collections.binarySearch(integers, 1,cmp));  
    }  
 
    static Comparator<Integer> cmp = new Comparator<Integer>(){  
        public int compare(Integer i,Integer j){  
            return i<j?-1:(i==j?0:1);  
        }  
    };  

 

问题:打印结果是什么?

-2,Integer类型比较时,并不是比较int型的数值,而是比较引用的内存地址,明显就不一样了。

5.Cogito Ergo Sum
view plaincopy to clipboardprint?
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;     
        storeInMap();     
    }     
    
    private void storeInMap() {     
        map.put(val, this);     
    }     
    
    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);     
    }     
}   
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;  
        storeInMap();  
    }  
 
    private void storeInMap() {  
        map.put(val, this);  
    }  
 
    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);  
    }  

 
 

问题:打印结果是什么?

需要注意的是静态变量,也就是类变量,在类的preparation阶段进行赋值,此时都是赋默认的初值,并不是自己定义的初值,比如int型0,引用型null等,后面会进入Resolution阶段,然后才是初始化( Initialization),这个阶段会执行static初始化,把变量初始化为你指定的值。

6.Thread Friendly

  view plaincopy to clipboardprint?
public class ThreadFriendly {     
    ThreadLocal<Value> threadLocalPart = new ThreadLocal<Value>();     
    class Value{     
        final int i;     
        Value(int i){     
            this.i = i;     
        }     
    }     
         
    ThreadFriendly  setThreadVal(int i){     
        threadLocalPart.set(new Value(i));     
        return this;     
    }     
         
    int getThreadVal(){     
        return threadLocalPart.get().i;     
    }     
         
    public static void main(String[] args) {     
        int sum = 0;     
        for(int i = -500000;i<=500000;i++){     
            sum+= new ThreadFriendly ().setThreadVal(i).getThreadVal();     
        }     
        System.out.println(sum);     
    }     
}   
public class ThreadFriendly {  
    ThreadLocal<Value> threadLocalPart = new ThreadLocal<Value>();  
    class Value{  
        final int i;  
        Value(int i){  
            this.i = i;  
        }  
    }  
      
    ThreadFriendly  setThreadVal(int i){  
        threadLocalPart.set(new Value(i));  
        return this;  
    }  
      
    int getThreadVal(){  
        return threadLocalPart.get().i;  
    }  
      
    public static void main(String[] args) {  
        int sum = 0;  
        for(int i = -500000;i<=500000;i++){  
            sum+= new ThreadFriendly ().setThreadVal(i).getThreadVal();  
        }  
        System.out.println(sum);  
    }  

 

问题:打印结果是什么?

报错

Exception in thread "main" java.lang.OutOfMemoryError: Java heap space

这个不会了,转别人的分析

/**

其实这个细说起来还是很复杂的,需要理解ThreadLocal的原理和弱引用的相关知识。因为内部类对象存在一个指向外部类(包含内部类的类)ThreadFriendly对象的引用,而ThreadFriendly对象又存在到ThreadLocal对象的引用,导致Thread中ThreadLocal.ThreadLocalMap inheritableThreadLocals 中的key一直是强引用,无法释放,最终导致内存溢出。

     解决方法:


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

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

*/

7.When Words Collide
  view plaincopy to clipboardprint?
public class test {     
    public static void main(String[] args) {     
        System.out.println(     
            Words.FIRST + " " + Words.SECOND + " " + Words.THIRD     
        );     
    }     
}     
    
public class Words{     
    public static final String FIRST = "the";     
    public static final String SECOND = null;    
    public static final String THIRD = "set";     
}   
public class test {  
    public static void main(String[] args) {  
        System.out.println(  
            Words.FIRST + " " + Words.SECOND + " " + Words.THIRD  
        );  
    }  
}  
 
public class Words{  
    public static final String FIRST = "the";  
    public static final String SECOND = null; 
    public static final String THIRD = "set";  

 

编译PrintWords.java文件。
修改Words.java文件为
view plaincopy to clipboardprint?
public class Words{     
    public static final String FIRST = "physics";     
    public static final String SECOND = "chemistry";     
    public static final String THIRD = "biology";     
}    
public class Words{  
    public static final String FIRST = "physics";  
    public static final String SECOND = "chemistry";  
    public static final String THIRD = "biology";  
}   

问题:再次编译运行PrintWords.java,打印结果是什么?

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

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

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值