Java刷题笔记9

T1 又是类内执行顺序

image-20231017201429605

类中的静态部分,从上到下运行,先遇见谁执行谁;
所以先执行publicstaticTest t1 =new Test();

在new Test()的过程中已经执行了一次静态成员函数的初始化了,所以接着往下执行,关于static的运行是类的事,实例化的过程中不管他,所以接着输出了A

再找到静态块static,这里输出B

最后在main方法中,重复了一次实例化的过程,输出A

T2 自动转型

image-20231017203231893被final修饰的变量是常量,这里的b6=b4+b5可以看成是b6=10;在编译时就已经变为b6=10了

而b1和b2是byte类型,java中进行计算时候将他们提升为int类型,再进行计算,b1+b2计算后已经是int类型,赋值给b3,b3是byte类型,类型不匹配,编译不会通过,需要进行强制转换。

Java中的byte,short,char进行计算时都会提升为int类型。

T3 类的构造&继承&实例化

Test.main()函数执行后的输出是( )

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
class Test {
public static void main(String[] args) {
System.out.println(new B().getValue());
}
static class A {
protected int value;
public A (int v) {
setValue(v);
}
public void setValue(int value) {
this.value= value;
}
public int getValue() {
try {
value ++;
return value;
} finally {
this.setValue(value);
System.out.println(value);
}
}
}
static class B extends A {
public B () {
super(5);
setValue(getValue()- 3);
}
public void setValue(int value) {
super.setValue(2 * value);
}
}
}

A 6 7 7

B 22 34 17

C 22 74 74

D 11 17 34

第一个数值

  1. new B()构造B类实例对象,进入B类的构造方法,B类构造方法的第一行代码用super(5)调用了父类带有参数的构造函数,父类的构造函数又调用了setValue()方法,但值得注意的是,子类中的方法覆盖父类的方法以后,由于向上转型,父类调用的方法实际上是子类的。那么这里的setValue(v);调用了B类的setValue()方法,而B类中setValue()方法又使用super关键字调用了父类的setValue()方法,将B实例的value值设置为2 x 5 = 10。那么到这里,B类的构造函数中第一行代码super(5)执行完毕,程序继续向下执行进入setValue(getValue()- 3);代码块。

  2. 这里先执行getValue()方法,但因为B类中并没有重写该方法,这里需要调用父类的getValue()方法。进入A类getValue()方法,首先是value++,那么此时B的成员变量value值由 10变为11,程序继续向下执行,将11作为返回值,但此处要注意的一点是,在Try catch finally**体系当中,在return之前始终会执行finally里面的代码,如果finally里面有return,则数据跟随finally改变。如果没有return,则原数据不跟随finally里改变的数据改变。那么进入finally代码块,由于此时正在初始化的是B类的一个对象(运行时多态),因此调用B类的setValue()方法。B类的setValue()方法中使用super*关键字调用了父类的setValue()方法,将原有的value2,即11 x 2 = 22,继续向下进行System.out.println(value);输出第一个数值22。随后,A类的getValue()方法将之前暂存的value=11返回。

第二个数值

  1. 拿到getValue()方法返回值之后程序继续运行,此处代码变为setValue(11- 3);根据和之前相同的流程,B类成员变量value的值变为16。程序运行到此处,new B()执行完毕。

  2. 回到main函数中,实例化的B类对象调用getValue()方法,B类中并没有重写该方法,需要调用父类的getValue()方法。getValue()方法第一行代码value++将B的成员变量value值变为17,此时执行到return代码,将value=17暂存,等待finally代码块运行完毕后返回。

  3. 此处finally代码块执行流程和之前相同,这里不再赘述。那么执行完this.setValue(value);后,value值变为2 x 17 = 34。继续向下进行System.out.println(value);输出第二个数值34,return刚刚暂存的value=17。

第三个数值

回到main函数,将刚刚返回的值输出,就得到了第三个数值17。

综上所述,本题正确答案为B。

T4 异常发现时机

image-20231019231950987

img

编译时能被发现的是必须加上try catch的异常,这些异常在编译时可以被发现,如果异常编译时不一定发生,如除以0异常,指针为空异常。

T5 集合的线程安全

image-20231019232131480

基本上我们平常用到的都是非线程安全的集合类,因为要使线程安全,是要加锁来实现的,势必造成性能降低。如hashset、hashmap、arraylist、linkedlist、treemap、treeset、stringbulider等。

像stringbuffer、vector、hashtable这些都是专用于多线程的,再者以concurrent(意为:同时发生的)为前缀的集合类大多是线程安全的。

作者:72%
链接:https://www.nowcoder.com/exam/test/75216289/submission?pid=53805751
来源:牛客网

T6 字符串split方法

image-20231019235522396

String split 这个方法默认返回一个数组, 如果没有找到分隔符, 会把整个字符串当成一个长度为1的字符串数组返回到结果, 所以此处结果就是1

T7 线程创建方式

创建线程对象两种方式:

  1. 继承Thread类,重载run方法
  2. 实现Runnable接口,实现run方法