• Java小细节


    Java小细节,把遇到的小问题汇集到这里,不定期持续更新~~

    ①下面的程序打印结果是什么?

    public class TestMain1 {
        public static void main(String[] args) {
            Integer i1 = 127;
            Integer i2 = 127;
            System.out.println(i1==i2);
            
            Integer i3 = 128;
            Integer i4 = 128;
            System.out.println(i3==i4);
            
            Integer i5 = 127;
            Integer i6 = new Integer(127);
            System.out.println(i5==i6);
            
            Integer i7 = 128;
            Integer i8 = new Integer(128);
            System.out.println(i7==i8);
        }
    }

    运行一下,得到的结果是:true  false  false   false

    第3、4打印出false比较好理解,因为是new的不同对象。但是第1、2打印的结果为什么不一样呢?

    这是因为:Integer的缓存做了处理。看看Integer的valueOf方法就明白了:

    public static Integer valueOf(int i) {
        final int offset = 128;
        if (i >= -128 && i <= 127) { // must cache
            return IntegerCache.cache[i + offset];
        }
        return new Integer(i);
    }

    就是说-128~127之间的数据,返回的是同一个对象。所以i1==i2 i3!=i4

    Java的解释是:....this method is likely to yield significantly better space and time performance by caching frequently requested values...

    ②下面这段程序能正常运行吗?

    import java.util.Arrays;
    import java.util.List;
    
    
    public class TestMain2 {
        public static void main(String[] args) {
            String[] array= new String[5];
            for (int i = 0; i < array.length; i++) {
                array[i] = String.valueOf(i);
            }
            
            List<String> list = Arrays.asList(array); 
            
            list.add("test");
        }
    
    }

    答案是不能,会抛出java.lang.UnsupportedOperationException异常

    解析:Arrays.asList方法得到的list是一个静态的内部类

    private static class ArrayList<E> extends AbstractList<E> implements RandomAccess, java.io.Serializable

    而这个ArrayList并没有覆写父类的add方法,所以上面的代码会调用AbstractList中的add方法。

    而AbstractList中的add方法是这个样子的:

    public boolean add(E o) {
        add(size(), o);
        return true;
    }
    
    public void add(int index, E element) {
        throw new UnsupportedOperationException();
    }

    所以,执行到list.add("test");就会抛出异常。

    ③遍历集合的同时删除元素

     昨天看同事写的代码中出现的代码,是在是匪夷所思,一个多年Java经验的人写出来的啊~~

     除开具体的业务逻辑,大概是下面这个样子

        
        public static void main(String[] args) {
            List<String> testList = new ArrayList<String>();
            testList.add("one");
            testList.add("two");
            testList.add("three");
    for (String string : testList) { System.out.println(string); if (string.equals("one")) { testList.remove(string); } } }

    先说明一下,for-each循环会被编译器转换成Iterator来进行。上面的代码会出现什么问题呢?抛出java.util.ConcurrentModificationException,

    看看源码即知:

        public E next() {
                checkForComodification();
            try {
            E next = get(cursor);
            lastRet = cursor++;
            return next;
            } catch(IndexOutOfBoundsException e) {
            checkForComodification();
            throw new NoSuchElementException();
            }
        }

    在AbstractList中实现了next方法,在取得下一个之前进行检查,checkForComodification源码如下:

    final void checkForComodification() {
            if (modCount != expectedModCount)
            throw new ConcurrentModificationException();
    }
    modCount:表示该集合对象结构被修改的次数,add或者remove,都会让modCount++
    expectedModCount:表示期待的modCount值,用来判断在遍历过程中集合是否被修改过。

    回到正题,上面的代码执行remove之后,modCount==4,而expectedModCount==3

    在取得下一个next的时候,会抛出异常。(是的,你没看错,是remove之后,并不是remove的同时抛出的异常)

    不过,这样的代码,并不总是抛出ConcurrentModificationException,看看下面的代码:

        
        public static void main(String[] args) {
            List<String> testList = new ArrayList<String>();
            testList.add("one");
            testList.add("two");
            //testList.add("three");
    
            for (String string : testList) {
                System.out.println(string);
                if (string.equals("one")) {
                    testList.remove(string);
                }
            }
        }
        

    这个代码和上面的只有一行只差,他不会抛出ConcurrentModificationException异常,但是不会打印出two,你知道为什么吗?

    答案其实在上面也提到了,在取得下一个next的时候,会抛出异常。(是的,你没看错,是remove之后,并不是remove的同时抛出的异常)

    删除“one”之后,size变成1,就不会有下一次遍历,即使modCount==3,而expectedModCount==2,异常也不会触发。

    不管怎么说,上面的删除方式是错误的,那么正确的该怎么写呢?用Iterator的remove方法

        
        public static void main(String[] args) {
            List<String> testList = new ArrayList<String>();
            testList.add("one");
            testList.add("two");
            testList.add("three");
    
            Iterator<String> it = testList.iterator();
            while (it.hasNext()) {
                String temp = it.next();
                System.out.println(temp);
                if (temp.equals("one")) {
                    it.remove();
                }
            }
        }
        
  • 相关阅读:
    VMware 克隆linux后找不到eth0(学习hadoop,所以想快速搭建一个集群)
    Qt之窗体透明 (三种不同的方法和效果)
    Qt之获取本机网络信息(MAC, IP等等,很全)
    Qt之图形(Source和Dest相互覆盖的取舍,真的很方便)
    Qt之QSpacerItem(控件之间的间距不尽相同,可以借助QSpacerItem来设置,并且还可以对QSpacerItem设置QSizePolicy)
    IoC在ASP.NET Web API中的应用
    ASP.NET MVC应用程序展示RDLC报表
    Ninject 在 Winform、 Asp.net MVC中连络EntityFramework的应用
    Apworks框架实战(三):单元测试与持续集成
    总体介绍ASP.NET Web API下Controller的激活与释放流程
  • 原文地址:https://www.cnblogs.com/yejg1212/p/3064922.html
Copyright © 2020-2023  润新知