一些经典面试题的思考与解析

这里把遇到的一些面试题拿来分析分析,因为如果不仔细想,很容易得出错的答案。

一、对象引用

public class Test10 {

	static StringBuilder a = new StringBuilder("A");
	static StringBuilder b = new StringBuilder("B");

	public static void main(String[] s) {
		op(a, b);
		System.out.println(a + "," + b);
	}

	static void op(StringBuilder x, StringBuilder y) {
		x.append(y);
		y = x;
		//assert y == Test10.a; 此断言表明y也指向了a

	}
}
    这段code输出多少,AB,AB吗,错了?前面定义的a和b变量,它们是对象“A”和“B”的引用。op方法把a,b当参数给x,y,相当于x和y也指向了对象A、B。一个对象可以被多次引用 。x.append(y)让对象A变成了AB,y=x让y放弃引用对象B,重新指向a原先的对象,即现在的“AB”,所以变量b是没有改变的,对象B也没有变化,所以a +"," +b自然就是AB,B。引用类型的变量传递的是对象在heap中的地址,只要持有对象的地址,就可以对object进行修改。

    另外说一个assert的用法。assert condition; 这里condition是一个必须为真(true)的表达式。如果表达式的结果为true,那么断言为真,并且无任何行动。如果表达式为false,则断言失败,则会抛出一个AssertionError对象。要想让断言起效用,即让断言语句在运行时确实检查,在运行含有assert的程序时,必须指定-ea选项。在Eclipse开发环境中,运行时,我们必须配置运行时的选项"Run",在Arguments页面中的"VM Arguments" 中填入-ea选项。才能让断言在运行时起作用。


二、Integer缓存

public class Test 
{ 
  public static void main(String[] args) 
  { 
    int a = 1000, b = 1000; 
    System.out.println(a == b); 

    Integer c = 1000, d = 1000; 
    System.out.println(c == d); 

    Integer e = 100, f = 100; 
    System.out.println(e == f); 
  } 
} 
结果是什么呢?trure 、false 、true。 The Java Language Specification, 3rd Edition 写道:

为了节省内存,对于下列包装对象的两个实例,当它们的基本值相同时,他们进行==时总是true:
 Boolean
 Byte
 Character, \u0000 - \u007f(7f是十进制的127)
 Integer, -128 — 127

Integer类源码中有以下片段:

/**
     * Cache to support the object identity semantics of autoboxing for values between 
     * -128 and 127 (inclusive) as required by JLS.
     *
     * The cache is initialized on first usage. During VM initialization the
     * getAndRemoveCacheProperties method may be used to get and remove any system
     * properites that configure the cache size. At this time, the size of the
     * cache may be controlled by the vm option -XX:AutoBoxCacheMax=<size>.
     */

    // value of java.lang.Integer.IntegerCache.high property (obtained during VM init)
    private static String integerCacheHighPropValue;

    static void getAndRemoveCacheProperties() {
        if (!sun.misc.VM.isBooted()) {
            Properties props = System.getProperties();
            integerCacheHighPropValue =
                (String)props.remove("java.lang.Integer.IntegerCache.high");
            if (integerCacheHighPropValue != null)
                System.setProperties(props);  // remove from system props
        }
    }

    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() {}
    }

    /**
     * Returns a <tt>Integer</tt> instance representing the specified
     * <tt>int</tt> value.
     * If a new <tt>Integer</tt> instance is not required, this method
     * should generally be used in preference to the constructor
     * {@link #Integer(int)}, as this method is likely to yield
     * significantly better space and time performance by caching
     * frequently requested values.
     *
     * @param  i an <code>int</code> value.
     * @return a <tt>Integer</tt> instance representing <tt>i</tt>.
     * @since  1.5
     */
    public static Integer valueOf(int i) {
        if(i >= -128 && i <= IntegerCache.high)
            return IntegerCache.cache[i + 128];
        else
            return new Integer(i);
    }

这儿的IntegerCache有一个静态的Integer数组,在类加载时就将-128 到 127 的Integer对象创建了,并保存在cache数组中,一旦程序调用valueOf 方法,如果i的值是在-128 到 127 之间就直接在cache缓存数组中去取Integer对象。

再看其它的包装器:

  • Boolean:(全部缓存)
  • Byte:(全部缓存)
  • Character(<= 127缓存)
  • Short(-128 — 127缓存)
  • Long(-128 — 127缓存)
  • Float(没有缓存)
  • Doulbe(没有缓存)

同样对于垃圾回收器来说:

Integer i = 100;   
i = null;//will not make any object available for GC at all.
这里的代码不会有对象符合垃圾回收器的条件,这儿的i虽然被赋予null,但它之前指向的是cache中的Integer对象,而cache没有被赋null,所以Integer(100)这个对象还是存在。

而如果i大于127或小于-128则它所指向的对象将符合垃圾回收的条件:

Integer i = 10000;   
i = null;//will make the newly created Integer object available for GC.
以上引用自 java Integer类的缓存

我们还可以引申出其他的思考。

Integer a = new Integer(0);
Integer b = new Integer(0);
system.out.println(a==b); // false

 这里不是直接 = 0,而是 = new Integer(0); 对于Integer(包装)类型,用==比较时,虽然拆箱后的值都一样,但毕竟比较的是heap中的地址,两个new的地址显然不是一样的, 

故a==b是false。

Integer a = new Integer(0);
Integer b = new Integer(0);
a++;b++;system.out.println(a==b); //true

 a++时a拆成int计算后值还在-128和127之间,所以return了IntegerCache[]中的对应值,b++后也是相同道理,所以它俩都共同指向IntegerCache,true了。 




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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值