2021年09月05日 java1

考点1:子类能访问父类的那些成员

C#、JAVA)扩展方法能访问被扩展对象的public成员

  • A 能
  • B 不能

解析

显示答案/隐藏答案正确答案: A

翻译一下,子类方法是否能够访问父类中的public成员。

考点2:构造方法

以下有关构造方法的说法,正确的是:()

  • A 一个类的构造方法可以有多个
  • B 构造方法在类定义时被调用
  • C 构造方法只能由对象中的其他方法调用
  • D 构造方法可以和类同名,也可以和类名不同

解析

显示答案/隐藏答案正确答案: A

A 一个类有多个构造方法便是重载的表现。重载参数列表不同。所以A是正确的。
B 构造方法是在对象创建时就被调用,用于初始化。
C 构造方法是给与之对应的对象进行初始化,初始化的动作只执行一次。
D 构造方法必须与所在类的名称同名。

B、构造器在对象被实例化的时候调用
C、构造方法不能由对象中的其他方法调用。都是new出来或者利用了反射。
D、构造方法必须与类同名,且没有返回值(不同于void)。

考点3:线程执行体run() 启动线程start()

以下哪个方法用于定义线程的执行体?

  • A start()
  • B init()
  • C run()
  • D synchronized()

解析

显示答案/隐藏答案正确答案: C

run()用于定义线程执行体,
start()用于启动线程

考点4:重载

对于同一类中的两个方法 , 在判断它们是不是重载方法时 , 肯定不考虑( )

  • A 参数个数
  • B 参数类型
  • C 返回值类型
  • D 参数顺序

解析

显示答案/隐藏答案正确答案: C

方法重写的注意事项:
构造方法不能被重写,不要问为什么?因为构造方法名必须和类名相同
private修饰的成员方法不能被重写
static修饰的方法不能被重写
final修饰的方法不能被重写
当子类重写了父类中的方法后,子类对象调用该方法时调用的是子类重写后的方法

子类的实例方法不能重写父类的静态方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
package extendstest;

public class Parent {
// 父类中的static方法
protected static void staticMethod() {
System.out.println("Static method in parent class");
}

// 父类中的非static方法
public void nonStaticMethod() {
System.out.println("Non static method in parent class");
}

// 父类中的final方法
protected final void finalMethod() {
System.out.println("Final method in parent class");
}
}

class Son extends Parent {
// 子类可以重写父类的protected 非static方法
@Override
public void nonStaticMethod() {
super.nonStaticMethod();
}

// 子类无法重写父类的static方法
@Override
public void staticMethod() {
System.out.println("Static method in parent class");
}

@Override
public final void finalMethod() {
System.out.println("Final method in son class");
}
}

子类的staticMethod方法报错如下:

Multiple markers at this line
    - This instance method cannot override the static method from Father
    - overrides extendstest.Father.canYouSeeStatic
    - The method canYouSeeStatic() of type Son must override or implement a supertype method

意思是子类的实例方法不能重写父类的静态方法

给子类中的staticMethod加上static修饰符:

    // 子类无法重写父类的static方法
    @Override
    public static void staticMethod() {
        System.out.println("Static method in parent class");
    }

还是不可以重写,报错如下:

The method staticMethod() of type Son must override or implement a supertype method

子类的finalMethod方法报错如下:

Multiple markers at this line
    - Cannot override the final method from Parent
    - overrides extendstest.Parent.finalMethod

可以定义与父类同名的Static方法

去掉子类的staticMethod()方法上面的@Override,则不会报错。
这不是重写,无法实现多态。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
package extendstest;

public class Parent {
// 父类中的static方法
protected static void staticMethod() {
System.out.println("Static method in parent class");
}

// 父类中的非static方法
public void nonStaticMethod() {
System.out.println("Non static method in parent class");
}

// 父类中的final方法
protected final void finalMethod() {
System.out.println("Final method in parent class");
}

public static void main(String[] args) {
Parent parent = new Son();
// 调用的还是父类的静态方法,不能实现多态
parent.staticMethod();
// 调用的是子类的方法,多态
parent.nonStaticMethod();
}
}

class Son extends Parent {
// 子类可以重写父类的protected 非static方法
@Override
public void nonStaticMethod() {
System.out.println("Static method in Son class");
}

// 子类无法重写父类的static方法
// @Override
// 子类可以定义与父类相同的静态方法
public static void staticMethod() {
System.out.println("Static method in Son class");
}

}

运行效果:

1
2
Static method in parent class
Static method in Son class

重写描述的是子类实例方法和父类实例方法的关系

static定义的方法时类方法,通过类名调用。
上面的parent.staticMethod();调用实际上还是类名.staticMethod();
也就是Parent.staticMethod();.所以不会去调用Son类中的同名方法。
如果非要调用子类的同名静态方法的话,需要改成:Son.staticMethod()

static方法如何实现”多态”

使用子类来调用覆盖的static方法,如果子类中有该静态方法,则执行子类的静态方法。
如果子类没有该静态方法,则去父类中查找静态方法,如果有则执行父类的静态方法:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
package extendstest;

public class Parent {
// 父类中的static方法
protected static void staticMethod() {
System.out.println("Static method in parent class");
}

// 父类中的非static方法
public void nonStaticMethod() {
System.out.println("Non static method in parent class");
}

// 父类中的final方法
protected final void finalMethod() {
System.out.println("Final method in parent class");
}

public static void main(String[] args) {
Son son = new Son();
Parent parent = son;
// 调用的还是父类的静态方法,不能实现多态
parent.staticMethod();
// 调用的是子类的方法,多态
parent.nonStaticMethod();
// 调用子类的静态方法,如果子类定义了该静态方法,
// 则调用子类的,如果没有则去父类中查找
// son.staticMethod();
Son.staticMethod();
}
}

class Son extends Parent {
// 子类可以重写父类的protected 非static方法
@Override
public void nonStaticMethod() {
System.out.println("Static method in Son class");
}

// 子类无法重写父类的static方法
// @Override
// 子类可以定义与父类相同的静态方法
public static void staticMethod() {
System.out.println("Static method in Son class");
}

}

运行效果:

1
2
3
Static method in parent class
Static method in Son class
Static method in Son class

此时Son类中重写了父类的静态方法,调用的是重写后的。
如果把Son类中的staticMethod方法注释掉。:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
package extendstest;

public class Parent {
// 父类中的static方法
protected static void staticMethod() {
System.out.println("Static method in parent class");
}

// 父类中的非static方法
public void nonStaticMethod() {
System.out.println("Non static method in parent class");
}

// 父类中的final方法
protected final void finalMethod() {
System.out.println("Final method in parent class");
}

public static void main(String[] args) {
Son son = new Son();
Parent parent = son;
// 调用的还是父类的静态方法,不能实现多态
parent.staticMethod();
// 调用的是子类的方法,多态
parent.nonStaticMethod();
// 调用子类的静态方法,如果子类定义了该静态方法,
// 则调用子类的,如果没有则去父类中查找
// son.staticMethod();
Son.staticMethod();
}
}

class Son extends Parent {
// 子类可以重写父类的protected 非static方法
@Override
public void nonStaticMethod() {
System.out.println("Static method in Son class");
}

// // 子类无法重写父类的static方法
// // @Override
// // 子类可以定义与父类相同的静态方法
// public static void staticMethod() {
// System.out.println("Static method in Son class");
// }
}

运行效果:

1
2
3
Static method in parent class
Static method in Son class
Static method in parent class

可以看到,此时调用了从父类继承得到的静态方法。

static方法可以被继承 可以被覆盖 不能被重写

重写,说的是根据运行时的对象类型来决定调用哪个方法,而不是编译时类型。

因为无法使用@Override修饰,所以不是重写。

对于静态方法,我们不应该尝试去重写,而且调用时应该以类进行调用,而不是对象进行调用。

问 static方法可以被重写吗?

答,static方法可以被子类继承,子类可以覆盖继承到的static方法。但是这不叫重写。
因为如果你在同名的static方法上写上@Override注解,编译器会报错。

重写是为了实现多态,多态是在运行的时候根据对象的类型来调用方法的。
如果使用了静态方法,那么在编译期间,就知道调用的是那个静态方法了,这不符合多态的定义。

https://www.jianshu.com/p/df43f5500ea3
静态方法从程序开始运行后就已经分配了内存,也就是说已经写死了。所有引用到该方法的对象(父类的对象也好子类的对象也好)所指向的都是同一块内存中的数据,也就是该静态方法。子类中如果定义了相同名称的静态方法,并不会重写,而应该是在内存中又分配了一块给子类的静态方法,没有重写这一说

考点5:不懂的点:JVM

off-heap是指那种内存()

  • A JVM GC能管理的内存
  • B JVM进程管理的内存
  • C 在JVM老年代内存区
  • D 在JVM新生代内存

解析

显示答案/隐藏答案正确答案: B

堆外内存

off-heap叫做堆外内存,将你的对象从堆中脱离出来序列化,然后存储在一大块内存中,这就像它存储到磁盘上一样,但它仍然在RAM中。
对象在这种状态下不能直接使用,它们必须首先反序列化,也不受垃圾收集。
序列化和反序列化将会影响部分性能(所以可以考虑使用FST-serialization)使用堆外内存能够降低GC导致的暂停。
堆外内存不受垃圾收集器管理,也不属于老年代,新生代。

堆外内存意味着把内存对象分配在Java虚拟机的堆以外的内存,这些内存直接受操作系统管理(而不是虚拟机)不属于老年代和新生代。

JVM GC回收堆和方法区,排除法选择 B

这样做的结果就是能保持一个较小的堆,以减少垃圾收集对应用的影响。

使用堆外内存能够降低GC导致的暂停。

堆外内存,它和内存池一样,也能缩短垃圾回收时间,但是它适用的对象和内存池完全相反。
内存池往往适用于生命期较短的可变对象,而生命期中等或较长的对象,正是堆外内存要解决的。

堆外内存的特点

https://blog.csdn.net/universe_ant/article/details/52145450
堆外内存有以下特点:

  • 对于大内存有良好的伸缩性
  • 对垃圾回收停顿的改善可以明显感觉到
  • 在进程间可以共享,减少虚拟机间的复制

当然堆外内存也有它自己的问题,

  • 最大的问题就是你的数据结构变得不那么直观,如果数据结构比较复杂,就要对它进行串行化(serialization),而串行化本身也会影响性能。
  • 另一个问题是由于你可以使用更大的内存,你可能开始担心虚拟内存(即硬盘)的速度对你的影响了。

1)程序计数器

几乎不占有内存。用于取下一条执行的指令。

2)堆

所有通过new创建的对象的内存都在堆中分配,其大小可以通过-Xmx和-Xms来控制。
堆被划分为新生代和旧生代,
新生代又被进一步划分为Eden和Survivor区,最后Survivor由FromSpace和ToSpace组成,结构图如下所示:

新生代。新建的对象都是用新生代分配内存,Eden空间不足的时候,会把存活的对象转移到Survivor中,新生代大小可以由-Xmn来控制,也可以用-XX:SurvivorRatio来控制Eden和Survivor的比例旧生代。用于存放新生代中经过多次垃圾回收仍然存活的对象。

3)栈

每个线程执行每个方法的时候都会在栈中申请一个栈帧,每个栈帧包括局部变量区和操作数栈,用于存放此次方法调用过程中的临时变量、参数和中间结果。

4)本地方法栈

用于支持native方法的执行,存储了每个native方法调用的状态

5)方法区

存放了要加载的类信息、静态变量、final类型的常量、属性和方法信息。
JVM用永久代(PermanetGeneration)来存放方法区,(在JDK的HotSpot虚拟机中,可以认为方法区就是永久代,但是在其他类型的虚拟机中,没有永久代的概念,有关信息可以看周志明的书)可通过-XX:PermSize和-XX:MaxPermSize来指定最小值和最大值。

考点6:异常处理机制

java关于异常处理机制的叙述哪些正确

  • A catch部分捕捉到异常情况时,才会执行finally部分
  • B 当try区段的程序发生异常时,才会执行catch区段的程序
  • C 在try区段不论程序是否发生异常及捕获到异常,都会执行finally部分
  • D 以上都是

解析

显示答案/隐藏答案正确答案: BC

finally不执行情况

try块执行时,finally表示总是执行。但是

  1. 在try中调用System.exit(0),强制退出了程序,finally块不执行。
  2. 在进入try块前,出现了异常,此时try没有执行,finally块不执行。

考点7:面向对象三大特性

面向对象的程序设计语言具有()等共同特性。

  • A 封装性
  • B 多态性
  • C 简单性
  • D 复杂性
  • E 继承性

解析

显示答案/隐藏答案正确答案: ABE

面向对象OOP三大特性:

  • 继承
  • 封装
  • 多态

准确来说,基于对象和面向对象是有区别的。
基于对象是封装和继承
面向对象是封装、继承和多态
详见 https://blog.csdn.net/jiaruitao777/article/details/99098027

考点8:IO流 字符流字节流

下面哪个流类不属于面向字符的流()

  • A BufferedWriter
  • B FileInputStream
  • C ObjectInputStream
  • D InputStreamReader

解析

显示答案/隐藏答案正确答案: BC

既然是字符流,那么一般是reader和writer结尾。
Stream结尾的是字节,Reader结尾的是字符

面向字符的输入流类都是Reader的子类,

面向字符的输出流都是类 Writer 的子类

考点9:堆存放对象 栈存放程序

程序中常采用变量表示数据,变量具有名、地址、值、作用域、生存期等属性。关于变量的叙述,()是正确的。

  • A 根据作用域规则,在函数中定义的变量只能在函数中引用
  • B 在函数中定义的变量,其生存期为整个程序执行期间
  • C 在函数中定义的变量不能与其所在函数的形参同名
  • D 在函数中定义的变量,其存储单元在内存的栈区

解析

显示答案/隐藏答案正确答案: ACD

这里主要说明D为什么是对的

首先说明栈内存和堆内存里存放的是什么

  • 栈内存中存放函数中定义的一些基本类型的变量和对象的引用变量;
  • 堆内存中存放new创建的对象和数组。

简单的来说,堆主要是用来存放对象的,栈主要是用来执行程序的

这么做是因为

  • 栈的存取速度快,栈数据可以共享,但是栈中的数据大小和生存期必须确定,缺乏灵活性中存放一些基本类型的对象和对象句柄
  • 堆是操作系统分配给自己内存,由于从操作系统管理的内存分配,所以再分配和销毁时都需要占用时间,因此用堆的效率非常低,但是优点在于编译器不需要指导从堆里分配多少存储控件,也不需要知道存储的数据要再堆里停留多长事件,因此用堆保存数据时会得到更大的灵活性

参考链接:https://blog.csdn.net/wangbo1998/article/details/80379016

D选项不太严谨,如果定义的是引用类型变量,且没有通过逃逸分析,则可能会被分配到堆中,逃逸分析是jdk1.8默认开启的

D选项我给大家说明一下,我觉得题出的不严谨,如果方法中有引用类型的变量,那么存储是在堆中,引用在栈中

考点10:身份证号的正则表达式

多选题
关于身份证号,以下正确的正则表达式为( )

  • A isIDCard=/^[1-9]\d{7}((0\d)|(1[0-2]))(([0|1|2]\d)|3[0-1])\d{3}$/;
  • B isIDCard=/^[1-9]\d{7}((9\d)|(1[0-2]))(([0|1|2]\d)|3[9-1])\d{3}$/;
  • C isIDCard=/^[1-9]\d{5}[1-9]\d{3}((0\d)|(1[0-2]))(([0|1|2]\d)|3[0-1])\d{4}$/;
  • D isIDCard=/^[1-9]\d{5}[1-9]\d{3}((9\d)|(1[9-2]))(([0|1|2]\d)|3[9-1])\d{4}$/;

解析

显示答案/隐藏答案正确答案: AC

身份证构成

15位身份证的构成:六位出生地区码+六位出身日期码+三位顺序码
18位身份证的构成:六位出生地区码+八位出生日期码+三位顺序码+一位校验码

A选项
^[1-9]\d{7}((0\d)|(1[0-2]))(([0|1|2]\d)|3[0-1])\d{3}$

  • [1-9]\d{7},有8位,其中前六位是地址码,后两位是年份,00~99年。
  • ((0\d)|(1[0-2])),有两位,表示月份,第一个括号范围位0009,第二个括号的范围位1012,综合得到00~12,符合月份的定义。
  • (([0|1|2]\d)|3[0-1]),有两位,表示日期,第一个括号的范围位0009或者1019或者2029,第2个括号的范围位3031,综合得到00~31,符合月份的定义。这个其实也不严谨,例如2月份,只有28天,或29天。
  • \d{3}有三位,表示顺序码

B选项
^[1-9]\d{7}((9\d)|(1[0-2]))(([0|1|2]\d)|3[9-1])\d{3}$

  • [1-9]\d{7},有8位,其中前六位是地址码,后两位是年份,00~99年。
  • ((9\d)|(1[0-2])),有两位,表示月份,第一个括号的范围位90~99,一年只有12个月份,没有90月份,更没有99月份,B选项排除。

C选项的
^[1-9]\d{5}[1-9]\d{3}((0\d)|(1[0-2]))(([0|1|2]\d)|3[0-1])\d{4}$

  • [1-9]\d{5}这六位,表示六位出生地码,
    • ^[1-9]\d{5}[1-9]\d{3}((0\d)|(1[0-2]))(([0|1|2]\d)|3[0-1])\d{4}$
  • [1-9]\d{3}这四位,表示年
    • ^[1-9]\d{5}[1-9]\d{3}((0\d)|(1[0-2]))(([0|1|2]\d)|3[0-1])\d{4}$
  • ((0\d)|(1[0-2]))这两位表示,月份,从第一个括号匹配00~09。第二个括号匹配10~12
    • ^[1-9]\d{5}[1-9]\d{3}((0\d)|(1[0-2]))(([0|1|2]\d)|3[0-1])\d{4}$
    • 所以月份共计匹配范围:00~12符合月份00~12的定义。
  • (([0|1|2]\d)|3[0-1])这两位表示日期,第一个括号匹配0009,1019,2029。第二个括号匹配3031。
    • ^[1-9]\d{5}[1-9]\d{3}((0\d)|(1[0-2]))(([0|1|2]\d)|3[0-1])\d{4}$
    • 所以日期总计匹配范围:00~31,符合日期的定义。
  • \d{4},表示匹配三位顺序吗+一位校验码。校验码有字母,这里显然不能完全匹配,勉强认为校验码都是数字吧。
    • ^[1-9]\d{5}[1-9]\d{3}((0\d)|(1[0-2]))(([0|1|2]\d)|3[0-1])\d{4}$

D选项
^[1-9]\d{5}[1-9]\d{3}((9\d)|(1[9-2]))(([0|1|2]\d)|3[9-1])\d{4}$

  • [1-9]\d{5},六位地址码
  • [1-9]\d{3},四位年,1000~9999
  • ((9\d)|(1[9-2])),表示月份,9\d的范围位90~99,一年最多有12个月,没有90个月,更没有99个月。所以D选项错误。