2021年08月09日 java

考点1:基本类型的表示范围 float小数初始化 long整数初始化

以下的变量定义语句中,合法的是()

  • A byte=128
  • B boolean=null
  • C long a=123L
  • D double=0.9239d

解析

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

byte能表示的范围[-128,127]
boolean的取值只能是true或 false
整数默认是int类型,如果要转为long类型,需要在整数后面加上L
小数默认类型是double,如果要转为float类型,需要在小数后面加上字母F

考点2:final类 String

有以下代码片段:

1
2
3
String str1="hello";
String str2="he"+ new String("llo");
System.out.println(str1==str2);

请问输出的结果是:

  • A true
  • B 都不对
  • C null
  • D false

解析

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

这里的str1指的是方法区中的字符串常量池中的“hello”,编译时期就知道的

String是fina1类,这意味着String不能被继承,在Java中被final修饰的类是不允许被继承的,并且final类的成员方法都默认是final方法.
String类底层是char数组来保存字符串的。

字符串常量池

在class件中有一部分用来存储编译期间生成的字面常量以及符号引用,这部分做class文件常量池

在运行期间对应着方法区的运行时常量池

借鉴之前关于 Stringi拼接的一个总结:1、常量和常量拼接,结果在常量池中且常를池中不存在相同内容的常量。2、只要有一个变星,结果就在堆中。3、如果拼接的结果调用了
tem()方法,返回值会在常量池中。补充一点,还有fna修饰时,拼接也会在常量池中.

考点3:try catch finally

能单独和finally语句一起使用的块是( )

  • A try
  • B catch
  • C throw
  • D throws

解析

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

注意细节:使用try…catch块捕天时可以没有 catch块,但当没
用 catch块的时候必须得有 finallyt块

使用try…catch捕获异常的时候,若没有catch块时,一定要写上
finally

考点4:transient关键字

以下哪个不能用来处理线程安全

  • A synchronized关键字
  • B volatile关键字
  • C Lock
  • D transient关键字

解析

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

transient,变量修饰符,如果用 transient声明一个实例变
量,当对象存储时,它的值不需要维持。当一个变量不希望
被持久化的时候,比如说一些账号密码,就可以用transient
关键字来表示亥变量不参与序列化过程

volatile修饰一个变量时,可以保证当前线程对亥变量操作的
可见性。当前线程有改变变量时,其他线程保存的副本将失
效,其他线程会从主内存中重新读取。 volatile只保证对它修
饰的变量的读写操作具有原子性

单纯使用 volatile关键字是不能保证线程安全的
volatile只提供了一种弱的同步机制,用来确保将变量的更新操作通知到其他线程。
volatile语义是禁用CPU缓存,直接从主内存读、写变量。表现为:更新 volatile变量时,JVM会把线程对应的本地内存中的共享变星值刷新到主内存中;读volatile变量时,JVM会把线程对应的本地内存设置为无效,直
接从主内存中读取共享变量.
当把变量声明为 volatile类型后,JM增加内存屏章,禁
止CPU进行指令重。

实现,继承都具有遗传性,实现了serializable的类的子类也实现 serializable
基本类型,包装类, String默认实现serializable。

一个类实现serializable接口时,要保证其成员变量都要实现serializable。

transient修饰成员变量使其不被序列化。

volatile关键字:
1.保证了不同线程对该变量操作的内存可见性(当一个线程修改了变量其他使用次变量的线程可以立即知道
这一修改)。
2.禁止了指令重排序

Lock接口提供了与 synchronized关键字类似的同步功能,但
需要在使用时手动获取锁和释放锁。

transient-关键字简单地说,就是让某些被修饰的成员属性变
量不被序列化

synchrozied关键字称作同步,主要用来给方法、代码块加
锁,被加锁的代码段,同一时间内多线程同时访问同一对象
的加锁方法代码块时,只能有一个线程执行能执行方法代码
块中的代码,其余线程必须等待当前线程执行完以后才执行
该方法代码块。

考点5:ASCII码 向上转型

执行语句”int a= '2'“后,a的值是( )

  • A 2
  • B 50
  • C 49
  • D 0

解析

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

一个简便的记忆法:0:48,A:65,a:97

48 65 97

考点6:

在JAVA中,假设A有构造方法A(int a),则在类A的其他构造方法中调用该构造方法和语句格式应该为()

  • A this.A(x)
  • B this(x)
  • C super(x)
  • D A(x)

解析

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

this的作用其中一个就是在一个构造方法中调用另一个构造方
法,格式为this(参数)

考点7:

下面程序运行完之后,t2与t3的关系为()

1
2
3
4
5
6
7
8
9
10
11
12
13
Object obj=new Object();
List aList=new ArrayList();
List bList=new LinkedList();
long t1=System.currentTimeMillis();
for(int i=0;i<50000;i++){
aList.add(0,obj);
}
long t2=System.currentTimeMillis()-t1;
t1=System.currentTimeMillis();
for(int i=0;i<50000;i++){
bList.add(0,obj);
}
long t3=System.currentTimeMillis()-t1;
  • A t2
  • B t2=t3
  • C 不确定
  • D t2>t3

解析

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

Arraylist内部是动态数组实现,在增加空间时会复制全部数据到扩容后的新数组中。
Linkedlist内部为双向链表,可以按需分配空间,扩展时不需要批量赋值,因此Linkedlist用时少。

Arraylist:增删慢,查询快。

  • 由于是数据组实现,需要连续的内存空间,如果删除数组中间的值,为了保证下标的有效性,需要将后面的数据往前移,所以删除馒。
  • 当插入A对象到B对象的前面时,需要将B对象和B对象之后的所有对象后移一位,再插入A对象。所以插入慢。
  • 数组的大小是固定的,如果数组满了,需要重新分配空间,new一个新数组,然后copy旧数据到新数组中,最后再增加新数据,所以增加慢。
  • 因为是连续内存空间,可以通过下标查询数据,所以查询快。

Linkedlist:增删快,查询慢。

  • 由于是链表实现,当前节点的nex指向下一个节点,prev指向上一个节点,不需要连续的内存空间。增加或删除时只需要修改指针即可,不需要移动。所以增删快
  • 因为不是连续内存空间,所以不能使用下标查询,只能通过next遍历来查找,所以查询馒。

ArrayList容量不够需要扩容,依次扩容1.5倍,并且插入数据需要用到数组的copy,
Linklist不需要扩容,插入仅需要链表擅长的插入操作即可,故Linklisth的操作时间低.

但是如果讲究尾部插入的话,数据量小的情況下可难分伯仲,但是在插入数据量大的倩况下, ArrayList怕的效率是要
高于Linkliste的。
因为,数据量大之后,扩容不是很烦繁,仅需要尾部插入即可,但是Linklist需要每次进行链表节点指针的指向调整操作。
所以大量数据的尾部面入, ArrayList的效率是要高于Linkliste的,下图是数据量较大时的比较。

这里有一张图片

考点8:volatile关键字

volatile关键字的说法错误的是

  • A 能保证线程安全
  • B volatile关键字用在多线程同步中,可保证读取的可见性
  • C JVM保证从主内存加载到线程工作内存的值是最新的
  • D volatile能禁止进行指令重排序

解析

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

出于运行速率的考虑,java编译器会把经常经常访问的变量放到缓存(严格讲应该是工作内存)中,
读取变量则从缓存中读。
但是在多线程编程中,内存中的值和缓存中的值可能会出现不一致。

volatile用于限定变量只能从内存中读取,保证对所有线程而言,值都是一致的。但是 volatile不能保证原子性,也就不能保证线程安全

1.java的内存模型

java内存模型规定了所有的变量都存储在主内存中,
但是每个线程会有自己的工作内存,
线程的工作内存保存了该线程中使用了的变量(从主内存中拷贝的),
线程对变量的操作都必须在工作内存中进行,
不同线程之间无法直接访问对方工作内存中的变量,
线程间变量值从传递都要经过主内存完成

img

2.什么是原子性

一个操作是不可中断的,要么全部执行成功要么全部执行失败,比如银行转账

3.什么是可见性

当多个线程访问同一变量时,一个线程修改了这个变量的值,其他线程就能够立即看到修改的值。

4.什么是有序性

程序执行的顺序按照代码的先后顺序执行

1
2
int a=0;//1
int b=2;//2

像这2句代码,1会比2先执行,但是JVM在真正执行时不一定是1在2之前,这里渉及一个概念叫做指令重排,

指令重排

处理器为了提高程序运行效率,可能会对输入代码进行优化,它不保证程序中各个语句的执行先后顺序同代码中的顺序一致,但是它会保证程序最终执行结果和代码序执行的结果是一致的。

比如上面的代码语句1和语句2谁先执行对最终的程序结果并没有影响。那么就有可能在执行过程中,语句2先执行而语句1后执行

在指令重排时会考虑指令之间的数据依赖性,比如2依赖了1的数值,那么处理器会保证1在2之前执行。

但是在多线程的情况下,指令重排就会有影响了。

5.volatile到底做了什么

  • 禁止了指令重排
  • 保证了不同线程对这个变量进行操作时的可见性,即一个线程修改了某个变量值,这个新值对其他线程是立即可见的
  • 不保证原子性(线程不安全)

考点9:

以下哪种JAVA的变量表达式使得变量a和变量b具有相同的内存引用地址( )

  • A String a = "hello"; String b = "hello";
  • B Integer a; Integer b = a;
  • C int a = 1; Integer b = new Integer(1);
  • D int a = 1; Integer b = 1;

解析

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

1 Integer与int比较时, Integer会有拆箱的过程,我们可以看看拆箱的代码

1
2
3
public int inValue(){
return value;
}

直接返回的就是value,因此int a;与Integer b;以及new Integer(a);进行==比较时结果都是true。

解析混乱,我就不记下来了。