Java的一些细节语法(不定时更新。。。)
可信考试Java相关题目
-
ConcurrentHashMap
不允许key为null,但是HashMap
是可以的。TreeMap
key不支持null。 -
以下代码里面,请注意:
Integer a = 150; Integer b = 150; Integer c = 100; Integer d = 100; Integer e = new Integer(100); System.out.println(a == b); //false System.out.println(a == 150); //true 这种是真正的在对比值的大小 System.out.println(c == d); //true System.out.println(c == e); //false
-
Process
类有输出流,输入流,错误流。 -
关于nio里面
Buffer
的duplicate
方法:ByteBuffer buf = ByteBuffer.allocate(100); /** * duplicate函数的官方注释,并不是真正的复制。 * Creates a new byte buffer that shares this buffer's content. * * <p> The content of the new buffer will be that of this buffer. Changes * to this buffer's content will be visible in the new buffer, and vice * versa; the two buffers' position, limit, and mark values will be * independent. * */ ByteBuffer buf2 = buf.duplicate();
-
Java Stream
的数据源有容器,数组和I/O,Stream的中间操作(intermediate function)
并不会直接执行,只有遇到终端操作(terminal function)
才会开始执行。 -
在Java里面,
count = count++
,会导致count++没有效果,这个从字节码层面是可以解释的。0: iconst_0 1: istore_1 // 将0存入到参数1的位置 2: iload_1 //将参数1的位置,也就是0,读取到操作数栈 3: iinc 1, 1 //给参数1的位置的参数直接+1 6: istore_1 //将操作数栈顶,也就是0,存储在参数1的位置 7: getstatic #2 // Field java/lang/System.out:Ljava/io/PrintStream; 10: iload_1 //将参数1的位置,也就是0,读取到操作数栈 11: invokevirtual #3 // Method java/io/PrintStream.println:(I)V 14: return
相对的,
count = ++count
的字节码如下:0: iconst_0 1: istore_1 // 将0存入到参数1的位置 2: iinc 1, 1 // 将参数1的位置,也就是0,直接+1, 5: iload_1 // 读取参数1的位置,也就是1,放在操作数栈 6: istore_1 // 将操作数栈顶的值,也就是1,存储在参数1的位置 7: getstatic #2 // Field java/lang/System.out:Ljava/io/PrintStream; 10: iload_1 // 将参数1的位置,也就是1,读取到操作数1栈 11: invokevirtual #3 // Method java/io/PrintStream.println:(I)V 14: return
注意观察两段代码
iinc
前后的区别。 -
Java的栈帧包括:局部变量表,操作数,动态链接,方法返回地址(注意,不包含本地方法栈)
-
通过
DataSource
对象访问的驱动程序本身不会向DriverManager
注册,且其对象属性是可以进行更改的,如果服务器配置发生了变化,可以通过更新DataSource
来进行对应的适配。 -
关于Java里面的
<? extends Obj>
协变和<? super Obj>
逆变的详细解释:static class Parent{ } static class FirstChild extends Parent{ } static class SecondChild extends Parent{ } static class FirstGrandChild extends FirstChild{ } static class FirstGrand2Child extends FirstChild{ } static class SecondGrandChild extends SecondChild{ } static class SecondGrand2Child extends SecondChild{ } public static void main(String[] args) { //指定了上界 List<? extends FirstChild> parentList = new ArrayList<>(); List<FirstChild> firstChildList = new ArrayList<>(); firstChildList.add(new FirstGrandChild()); firstChildList.add(new FirstGrandChild()); //Parent没有继承FirstChild // parentList = new ArrayList<Parent>(); //这个是可以的,因为parentList表示该list存储了Parent或者其子类 parentList = firstChildList; //下面这个是不可以的,因为该list存储了Parent或者其子类,那么尝试添加FirstChild就会出错,因为继承了Parent的不仅有FirstChild还有SecondChild。 // 上面把List<FirstChild>赋值给List<? extends Parent>后,如果添加可以成功的话,那么根据Java泛型实现的方式,就可以添加SecondChild及其子类, // 这明显是违背Java的语法规则的,所以这种情况下只能添加null。这称之为协变 // parentList.add(new FirstChild()); //但是get是可以的,因为指定了上界,所以可以确定成员一定可以转换为FirstChild FirstChild c = parentList.get(0); //指定了下界 List<? super SecondChild> secondList = new ArrayList<>(); List<Parent> pList = new ArrayList<>(); secondList = pList; //不是SecondChild的父类 // secondGrandList = new ArrayList<SecondGrand2Child>(); //但是不同于协变,add是可以的,因为可以确定的是,secondList里面成员,一定可以转换成SecondChild或者其父类, // 所以这里的add操作是可以的,这叫做逆变。比如说下面的SecondGrandChild和SecondGrand2Child都是可以转换成SecondChild或者其父类的 secondList.add(new SecondGrandChild()); secondList.add(new SecondGrand2Child()); //相反的,get操作只能返回Object,因为SecondChild的父类不确定,因此无法确定一个具体的类型,但是Object又是所有类的父类, //因此,get返回的只能是Object对象 Object o = secondList.get(0); //这个操作是不可以的 // SecondChild child = secondList.get(0); }