关于Java的坑问题来源于占小狼公众号今天发的几个问题

今天看公众号的时候,看到占小狼公众号有篇文章叫Java中的坑,然后就点进去看了,我先罗列一下问题:

第一个坑:

Set<Integer> set = new HashSet<>();
for (int i = 0; i < 100; i++) {
     set.add(i);
     set.remove(i-1);
 }
 System.out.println(set.size());

第二个坑:

package com.example.demo.chapter3;

import java.util.HashSet;
import java.util.Set;

public class Test {
    public static void main(String[] args) {
        Set<Short> set = new HashSet<>();
        for (short i = 0; i < 100; i++) {
            set.add(i);
            set.remove(i-1);
        }
        System.out.println(set.size());
    }
}

上面两个坑,问你输出结果是什么?

第三个坑:

package com.example.demo.chapter3;

public class TestTwo {
    public static void main(String[] args) {
        Object i = 1 == 1? new Integer(3):new Double(1);
        System.out.println(i);
    }
}

第4个坑:

Map<Long,String> map = new HashMap<>();
map.put(1L,"1111");
map.put(2L,"2222");
map.put(3L,"3333");
long[] ids = ArrayUtils.toPrimitive((Long[]) map.keySet().toArray());

其中ArrayUtils.javacommons-lang3.jar中的一个工具类,你只需要在你的pom.xml中添加下面的依赖就可以:

 <dependency>
     <groupId>org.apache.commons</groupId>
     <artifactId>commons-lang3</artifactId>
     <version>3.9</version>
 </dependency>

结果抛出了异常:

Exception in thread "main" java.lang.ClassCastException: [Ljava.lang.Object; cannot be cast to [Ljava.lang.Long;
	at com.example.demo.chapter3.ExceptionTest.main(ExceptionTest.java:14)

第一个坑的答案是:1
为什么是1,原因在于remove方法,setremove方法源码如下所示:

/**
     * Removes the specified element from this set if it is present
     * (optional operation).  More formally, removes an element <tt>e</tt>
     * such that
     * <tt>(o==null&nbsp;?&nbsp;e==null&nbsp;:&nbsp;o.equals(e))</tt>, if
     * this set contains such an element.  Returns <tt>true</tt> if this set
     * contained the element (or equivalently, if this set changed as a
     * result of the call).  (This set will not contain the element once the
     * call returns.)
     *
     * @param o object to be removed from this set, if present
     * @return <tt>true</tt> if this set contained the specified element
     * @throws ClassCastException if the type of the specified element
     *         is incompatible with this set
     * (<a href="Collection.html#optional-restrictions">optional</a>)
     * @throws NullPointerException if the specified element is null and this
     *         set does not permit null elements
     * (<a href="Collection.html#optional-restrictions">optional</a>)
     * @throws UnsupportedOperationException if the <tt>remove</tt> operation
     *         is not supported by this set
     */
    boolean remove(Object o);
  • 该方法的参数是一个对象Object类型
  • 从set集合中移除某个具体的元素

坑1的答案和解析

从第一个坑的代码可以看到,当i=0的时候,同时向set集合中添加0元素,然后移除-1元素;依次类推,那么当i=1的时候,set集合中只有1,0元素会被移除掉,所以最后就只剩下一个元素99。

需要注意的是remove的参数,在不同类中存在重载方法,有的参数是下标索引,有的是元素对象,所以调用不同的方法传入不同的参数,得到的结果也是不同的。

坑2的答案和解析

第二个与第一个不同之处便是,数据类型是Short,但是这个结果就不一样的,最后打印出来的结果是100,为什么会这样子?同一段代码,只是数据类型的改变,导致最后的结果不一样。

在这里插入图片描述
上图是第二个坑的字节码文件,直接使用javap -c 类名的方式得到了该文件的字节码文件,它在set集合中装入的是Short类型的数据,但是remove的时候,它却是removeInteger对象,因为ShortInteger类型都重写了Object类的equals方法,所以在remove的时候作比较,最后得到的结果就是falseset集合中的元素都没有被移除掉。

   public boolean equals(Object obj) {
        if (obj instanceof Integer) {
            return value == ((Integer)obj).intValue();
        }
        return false;
    }
 public boolean equals(Object obj) {
        if (obj instanceof Short) {
            return value == ((Short)obj).shortValue();
        }
        return false;
    }

第三个坑的答案与解析

答案是3.0,不是你想的3。
这个原因我也是通过字节码看出来的,因为前面是一个恒真的条件,然后使用了三目运算符,本来应该返回new Integer(3)的结果3,但是实际却返回了3.0,问题的本质在于三目运算符存在隐式的类型转换。所以返回了3.0。字节码如下:

在这里插入图片描述
需要注意的是里面有个i2f,表示将int类型转为float类型,关于这些指令是什么意思,可以去字节码指令列表去对照看每个指令的意思JVM 虚拟机字节码指令表

第四个坑的答案与解析

/**
     * Returns an array containing all of the elements in this set; the
     * runtime type of the returned array is that of the specified array.
     * If the set fits in the specified array, it is returned therein.
     * Otherwise, a new array is allocated with the runtime type of the
     * specified array and the size of this set.
     *
     * <p>If this set fits in the specified array with room to spare
     * (i.e., the array has more elements than this set), the element in
     * the array immediately following the end of the set is set to
     * <tt>null</tt>.  (This is useful in determining the length of this
     * set <i>only</i> if the caller knows that this set does not contain
     * any null elements.)
     *
     * <p>If this set makes any guarantees as to what order its elements
     * are returned by its iterator, this method must return the elements
     * in the same order.
     *
     * <p>Like the {@link #toArray()} method, this method acts as bridge between
     * array-based and collection-based APIs.  Further, this method allows
     * precise control over the runtime type of the output array, and may,
     * under certain circumstances, be used to save allocation costs.
     *
     * <p>Suppose <tt>x</tt> is a set known to contain only strings.
     * The following code can be used to dump the set into a newly allocated
     * array of <tt>String</tt>:
     *
     * <pre>
     *     String[] y = x.toArray(new String[0]);</pre>
     *
     * Note that <tt>toArray(new Object[0])</tt> is identical in function to
     * <tt>toArray()</tt>.
     *
     * @param a the array into which the elements of this set are to be
     *        stored, if it is big enough; otherwise, a new array of the same
     *        runtime type is allocated for this purpose.
     * @return an array containing all the elements in this set
     * @throws ArrayStoreException if the runtime type of the specified array
     *         is not a supertype of the runtime type of every element in this
     *         set
     * @throws NullPointerException if the specified array is null
     */
    <T> T[] toArray(T[] a);

在这里插入图片描述

发布了453 篇原创文章 · 获赞 539 · 访问量 156万+

猜你喜欢

转载自blog.csdn.net/u012934325/article/details/95002140