2019年10月29日_java_3
考点1 序列化接口
要使对象具有序列化能力,则其类应该实现如下哪个接口( )。
- A java.io.Serializable
- B java.lang.Cloneable,
- C java.lang.CharSequence
- D java.lang.Comparable
展开/折叠
正确答案: A解析
java.io.Serializable接口是一个标志性接口,在接口内部没有定义任何属性与方法。只是用于标志此接口的实现类可以被序列化与反序列化。
java.lang.Cloneable接口是一个标志性接口,在接口内部没有定义任何属性与方法。以指示Object.clone()方法可以合法地对该类实例进行按字段复制。
java.lang.CharSequence接口对许多不同种类的char序列提供统一的只读访问接口。CharSequence是char值的一个可读序列。
java.lang.Comparable接口,此接口强制对实现它的每个类的对象进行整体排序,此序列被称为该类的自然排序
考点2 子类调用父类方法的方式
子类要调用继承自父类的方法,必须使用super关键字。
- A 正确
- B 错误
展开/折叠
正确答案: B解析
1、子类构造函数调用父类构造函数用super
2、子类重写父类方法后,若想调用父类中被重写的方法,用super
3、未被重写的方法可以直接调用。
考点3 泛型
以下说法错误的是()
- A 虚拟机中没有泛型,只有普通类和普通方法
- B 所有泛型类的类型参数在编译时都会被擦除
- C 创建泛型对象时请指明类型,让编译器尽早的做参数检查
- D 泛型的类型擦除机制意味着不能在运行时动态获取List
中T的实际类型
展开/折叠
正确答案: D解析
- Java泛型是使用擦除来实现的,这意味着当你在使用泛型时,任何具体的类型信息都被擦除了,你唯一知道的就是你在使用一个对象。因此
List<String>
和List<Integer>
在运行时实际上是相同的类型。这两种类型都被擦除成它们的“原生”类型,即List。 - 因此, 虚拟机中没有泛型,只有普通类和普通方法 。
- 不过还是可以通过反射获得泛型类T的实际类型
考点4 实例化子类对象时 优先调用子类重写的方法
以下代码执行的结果显示是多少( )?
1 | public class Demo { |
- A Sub.test() flag=1 Sub.Sub() flag=5
- B Sub.Sub() flag=5 Sub.test() flag=5
- C Sub.test() flag=0 Sub.Sub() flag=5
- D Super.test() flag=1 Sub.Sub() flag=5
展开/折叠
正确答案: A解析
在只想new Sub(5)的时候,父类先初始化了int flag = 1,然后执行父类的构造函数Super(),父类构造函数中执行的test()方法,因子类是重写了test()方法的,因此父类构造函数中的test()方法实际执行的是子类的test()方法,所以输出为Sub.test() flag=1,接着执行子类构造函数Sub(5) 将flag赋值为5,因此输出结果Sub.Sub() flag=5
重点在于要时刻记得子类重写父类方法,实例化子类对象,调用时会调用子类重写之后的方法
考点5 子类通过类名引用父类的静态成员,只会初始化父类,不会初始化子类
运行代码,输出的结果是()
1 | public class P { |
- A
P is init
123 - B
S is init
P is init
123 - C
P is init
S is init
123 - D
S is init
123
展开/折叠
正确答案: A解析
静态代码块在 类初始化的时候 执行S.abc
属于 被动引用 不会出发子类初始化
1.子类引用父类的静态字段,只会触发子类的加载、父类的初始化,不会导致子类初始化
2.通过数组定义来引用类,不会触发子类的初始化
3.常量在编译阶段会进行常量优化,将常量存入调用类的常量池中, 本质上并没有直接引用到定义常量的类,因此不会触发定义常量的类的初始化。
参考:《深入理解Java虚拟机》
这里有类主动引用和被动引用的demo:https://www.jianshu.com/p/3afa5d24bf71
考点6 String常量
关于下面的一段代码,以下哪些说法是正确的:
1 | public static void main(String[] args) { |
- A System.out.print(a == b)打印出来的是false
- B System.out.print(a == c)打印出来的是true
- C System.out.print(b == c)打印出来的是false
- D System.out.print(b == d)打印出来的是true
展开/折叠
正确答案: AD解析
a是运行时动态加载的,此时会在堆内存中生成一个myString字符串,指向堆内存字符串地址
b是编译时静态加载的,此时会在常量池中存放一个myString字符串,指向常量池字符串地址
A:a指向堆内存,b指向常量池,因此地址不相等,false
B:java有常量优化机制,c也指向常量池,且与b指向同一个,则a与c地址不相等,false;
C:b与c地址相等,true
D:d是c的副本,地址相同,所以b与d地址相等,true
考点7 系列化和反序列化
下列关于系列化和反序列化描述正确的是:
- A 序列化是将数据转为n个 byte序列的过程
- B 反序列化是将n个 byte转换为数据的过程
- C 将类型int转换为4 byte是反序列化过程
- D 将8个字节转换为long类型的数据为序列化过程
展开/折叠
正确答案: AB解析
序列化:将数据结构转换称为二进制数据流或者文本流的过程。序列化后的数据方便在网络上传输和在硬盘上存储。
反序列化:与序列化相反,是将二进制数据流或者文本流转换称为易于处理和阅读的数据结构的过程。
考点8 使线程释放锁资源
下列哪些操作会使线程释放锁资源?
- A sleep()
- B wait()
- C join()
- D yield()
展开/折叠
正确答案: BC解析
1.sleep会使当前线程睡眠指定时间,不释放锁
2.yield会使当前线程重回到可执行状态,等待cpu的调度,不释放锁
3.wait会使当前线程回到线程池中等待,释放锁,当被其他线程使用notify,notifyAll唤醒时进入可执行状态
4.当前线程调用 某线程.join()时会使当前线程等待某线程执行完毕再结束,底层调用了wait()方法的,wait()释放锁资源,故join也释放锁资源
考点9 类加载器
关于Java中的ClassLoader下面的哪些描述是错误的:( )
- A 默认情况下,Java应用启动过程涉及三个ClassLoader: Boostrap, Extension, System
- B 一般的情况不同ClassLoader装载的类是不相同的,但接口类例外,对于同一接口所有类装载器装载所获得的类是相同的
- C 类装载器需要保证类装载过程的线程安全
- D ClassLoader的loadClass在装载一个类时,如果该类不存在它将返回null
- E ClassLoader的父子结构中,默认装载采用了父优先
- F 所有ClassLoader装载的类都来自CLASSPATH环境指定的路径
展开/折叠
正确答案: BDF解析
A、java中类的加载有5个过程,加载、验证、准备、解析、初始化;这便是类加载的5个过程,而类加载器的任务是根据一个类的全限定名来读取此类的二进制字节流到JVM中,然后转换为一个与目标类对应的java.lang.Class对象实例,在虚拟机提供了3种类加载器,引导(Bootstrap)类加载器、扩展(Extension)类加载器、系统(System)类加载器(也称应用类加载器)。A正确
B、一个类,由不同的类加载器实例加载的话,会在方法区产生两个不同的类,彼此不可见,并且在堆中生成不同Class实例。所以B前面部分是正确的,后面接口的部分真的没有尝试过,等一个大佬的讲解吧;
C、类加载器是肯定要保证线程安全的;C正确
D、装载一个不存在的类的时候,因为采用的双亲加载模式,所以强制加载会直接报错,D错误
java.lang.SecurityException: Prohibited package name: java.lang
E、双亲委派模式是在Java 1.2后引入的,其工作原理的是,如果一个类加载器收到了类加载请求,它并不会自己先去加载,而是把这个请求委托给父类的加载器去执行,如果父类加载器还存在其父类加载器,则进一步向上委托,依次递归,请求最终将到达顶层的启动类加载器,如果父类加载器可以完成类加载任务,就成功返回,倘若父类加载器无法完成此加载任务,子加载器才会尝试自己去加载,这就是双亲委派模式,即每个儿子都很懒,每次有活就丢给父亲去干,直到父亲说这件事我也干不了时,儿子自己想办法去完成,所以默认是父装载,E正确
F、自定义类加载器实现 继承ClassLoader后重写了findClass方法加载指定路径上的class,F错误