1.以下哪个不能用来处理线程安全
- synchronized关键字
- volatile关键字
- Lock类
- transient关键字
正确答案D 答案解析
先看一下transient关键字的作用
该变量无法被序列化
被transient修饰的变量无法在序列化后
再次进行反序列化后无法被读取
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;
class UserInfo implements Serializable {
private static final long serialVersionUID = 996890129747019948L;
private static String name;
private transient String psw; // 密码无法被序列化
public UserInfo(String name, String psw) {
this.name = name;
this.psw = psw;
}
public String toString() {
return "name=" + name + ", psw=" + psw;
}
}
public class Test {
public static void main(String[] args) {
UserInfo userInfo = new UserInfo("张三", "123456");
System.out.println(userInfo);
try {
//被设置为transient的属性没有被序列化
ObjectOutputStream o = new ObjectOutputStream(new FileOutputStream("用户缓存.txt"));
//写内容
o.writeObject(userInfo);
o.close();
} catch (Exception e) {
e.printStackTrace();
}
try {
//在反序列化之前改变name的值
//userInfo.setName("hello");
//重新读取内容
ObjectInputStream in = new ObjectInputStream(new FileInputStream("用户缓存.txt"));
UserInfo readUserInfo = (UserInfo) in.readObject();
//反序列化读取psw的内容为null
System.out.println(readUserInfo.toString());
} catch (Exception e) {
e.printStackTrace();
}
}
}
2.volatile关键字的说法错误的是
- 能保证线程安全
- volatile关键字用在多线程同步中,可保证读取的可见性
- JVM保证从主内存加载到线程工作内存的值是最新的
- volatile能禁止进行指令重排序
正确答案A 答案解析
先了解下面几个概念
原子性:一个操作是不可中断的,要么全部执行成功要么全部执行失败,比如银行转账
有序性:程序执行的顺序按照代码的先后顺序执行
可见性:当多个线程访问同一变量时,一个线程修改了这个变量的值,其他线程就能够立即看到修改的值
指令重排:这是一种编译器优化,不保证程序中各个语句的执行先后顺序同代码中的顺序一致,但是它会保证程序最终执行结果和代码顺序执行的结果是一致的,指令重排的时候考虑了数据依赖性,语句2依赖语句1的数值,语句1就会在语句2之前执行
禁止了指令重排优化
保证了不同线程对这个变量进行操作时的可见性,即一个线程修改了某个变量值,这个新值对其他线程是立即可见的
不保证原子性(导致线程不安全)
虽然增量操作(x++)看上去类似一个单独操作,实际上它是一个由读取-修改-写入操作序列组成的组合操作,必须以原子方式执行,volatile 不能提供必须的原子特性,不能保证在进行操作的时候不被其它线程干扰
实现正确的操作需要使 x 的值在操作期间保持不变,而 volatile 变量无法实现这点
volatile用于限定变量只能从缓存(工作内存)中读取,保证对所有线程而言,值都是一致的,但是不能说volatile能保证线程安全
synchronized才保证了原子性和可见性
3.以下哪项不属于java类加载过程
- 生成java.lang.Class对象
- int类型对象成员变量赋予默认值
- 执行static块代码
- 类方法解析
正确答案B 答案解析
说错了,不是对象成员变量,是类成员变量
对象成员变量是构造函数初始化的
这也涉及到了JVM内容了,这里就步过多阐述了
4.关于匿名内部类叙述正确的是? ( )
- 匿名内部类可以继承一个基类,不可以实现一个接口
- 匿名内部类不可以定义构造器
- 匿名内部类不能用于实参
- 以上说法都不正确
正确答案B 答案解析
由于构造器的名字必须与类名相同,而匿名类没有类名,所以匿名类不能有构造器
然后再看看什么是匿名内部类
1、使用匿名内部类时,我们必须是继承一个类或者实现一个接口,但是两者不可兼得,同时也只能继承一个类或者实现一个接口。
2、匿名内部类中是不能定义构造函数的。
3、匿名内部类中不能存在任何的静态成员变量和静态方法。
4、匿名内部类为局部内部类,所以局部内部类的所有限制同样对匿名内部类生效。
5、匿名内部类不能是抽象的,它必须要实现继承的类或者实现的接口的所有抽象方法。
匿名内部类的创建格式为: new 父类构造器(参数列表)| 实现接口(){ //匿名内部类的类体实现 }
public class HelloWorldAnonymousClasses {
/**
* 包含两个方法的HelloWorld接口
*/
interface HelloWorld {
public void greet();
public void greetSomeone(String someone);
}
public void sayHello() {
// 1、局部类EnglishGreeting实现了HelloWorld接口
class EnglishGreeting implements HelloWorld {
String name = "world";
public void greet() {
greetSomeone("world");
}
public void greetSomeone(String someone) {
name = someone;
System.out.println("Hello " + name);
}
}
HelloWorld englishGreeting = new EnglishGreeting();
// 2、匿名类实现HelloWorld接口
HelloWorld frenchGreeting = new HelloWorld() {
String name = "tout le monde";
public void greet() {
greetSomeone("tout le monde");
}
public void greetSomeone(String someone) {
name = someone;
System.out.println("Salut " + name);
}
};
// 3、匿名类实现HelloWorld接口
HelloWorld spanishGreeting = new HelloWorld() {
String name = "mundo";
public void greet() {
greetSomeone("mundo");
}
public void greetSomeone(String someone) {
name = someone;
System.out.println("Hola, " + name);
}
};
englishGreeting.greet();
frenchGreeting.greetSomeone("Fred");
spanishGreeting.greet();
}
public static void main(String... args) {
HelloWorldAnonymousClasses myApp = new HelloWorldAnonymousClasses();
myApp.sayHello();
}
}
5.关于以下代码的说明,正确的是
class StaticStuff{
static int x=10;
static {
x+=5;
}
public static void main(String args[ ]){
System.out.println(“x=” + x);
}
static { x/=3;}
}
- 3行与9行不能通过编译,因为缺少方法名和返回类型
- 9行不能通过编译,因为只能有一个静态初始化器
- 编译通过,执行结果为:x=5
- 编译通过,执行结果为:x=3
正确答案C 答案解析
首先这道题是一个罕见的只有1个正确选项的多选题
先复习一下Java初始化的加载顺序
父类静态成员变量 父类静态代码块 子类静态成员 子类静态代码块
父类非静态成员 父类非静态代码块 父类构造方法
子类非静态成员 子类非静态代码块 子类构造方法
6.Java语言中,下面哪个语句是创建数组的正确语句?( )
float f[][] = new float[6][6];
float []f[] = new float[6][6];
float f[][] = new float[][6];
float [][]f = new float[6][6];
float [][]f = new float[6][];
正确答案ABDE 易错选ABCD 答案解析
就容易和C语言记混
C语言是第2维必须给
Java是第1维必须给
7.以下Java程序运行的结果是
public class Tester{
public static void main(String[] args){
Integer var1=new Integer(1);
Integer var2=var1;
doSomething(var2);
System.out.print(var1.intValue());
System.out.print(var1==var2);
}
public static void doSomething(Integer integer){
integer=new Integer(2);
}
}
- 1true
- 2true
- 1false
- 2false
正确答案A 答案解析
看下面的代码
class SimInt{
int value;
public SimInt(int value){
this.value=value;
}
}
public class Main{
public static void change1(SimInt si){
si=new SimInt(3);//重新指向了新的对象,原对象不受影响
}
public static void change2(SimInt si){
si.value=3;//通过引用操作对象内部成员,原对象被改变
}
public static void main(String args[]) {
SimInt si1=new SimInt(1);
System.out.println(si1.value);//输出1
change1(si1);
System.out.println(si1.value);//输出1
change2(si1);
System.out.println(si1.value);//输出3
}
}
8.下列说法正确的是
- 调用Thread的sleep()方法会释放锁,调用wait()方法不释放锁
- 一个线程调用yield方法,可以使具有相同优先级线程获得处理器
- 在Java中,高优先级的可运行的线程会抢占低优先级线程的资源
- java中,线程可以调用yield方法使比自己低优先级的线程运行
正确答案BC 答案解析
yield()让当前正在运行的线程回到可运行状态,以允许具有相同优先级的其他线程获得运行的机会。因此,使用yield()的目的是让具有相同优先级的线程之间能够适当的轮换执行。
但是,实际中无法保证yield()达到让步的目的,因为,让步的线程可能被线程调度程序再次选中
还记得马老师说过,yiled方法属于高风亮节的行为,这个坑位我不上了,后面跟我同级别的先上厕所
高优先级的就是你们的县长,县长要上厕所,对不起,你得出来,县长先上,县长上完了,CPU分配到你了,你才能继续上厕所
9.下面有关 JAVA 异常类的描述,说法正确的有()
- 异常的继承结构:基类为 Throwable,Error 和 Exception 。实现 Throwable, RuntimeException 和 IOException 等继承 Exception
- 非 RuntimeException 一般是外部错误(不考虑Error的情况下),其可以在当前类被 try{}catch 语句块所捕获
- Error 类体系描述了 Java 运行系统中的内部错误以及资源耗尽的情形,Error 不需要捕捉
- RuntimeException 体系包括错误的类型转换、数组越界访问和试图访问空指针等等,必须 被 try{}catch 语句块所捕获
正确答案ABC 答案解析
逐个选项给大家说明一下
A. 基类没什么好说的,虽然Error和Exception都实现了Throwable,但这三个确实都是基类,后半句我重写一下有觉得它文字描述有问题的应该就懂了,实现 Throwable,RuntimeException 和 IOException 等继承Exception
B. 注意括号里的不考虑Error,这里是说Exception下的所有异常类均可捕捉,除了RuntimeException基本是外部错误,比较典型的是IOException
C. 正确,很简单解释略
D. 可以不抛出,外部错误才需要抛出,java里面异常允许被抛出,要记得 throws 关键词的使用
10.类之间存在以下几种常见的关系
- “USES-A”关系
- “HAS-A”关系
- “IS-A”关系
- “INHERIT-A”关系
正确答案ABC 答案解析
USES-A:依赖关系,A类会用到B类,这种关系具有偶然性,临时性。但B类的变化会影响A类
这种在代码中的体现为:A类方法中的参数包含了B类
关联关系:A类会用到B类,这是一种强依赖关系,是长期的并非偶然。在代码中的表现为:A类的成员变量中含有B类
HAS-A:聚合关系,拥有关系,是关联关系的一种特例,是整体和部分的关系。比如鸟群和鸟的关系是聚合关系,鸟群中每个部分都是鸟,比如成员变量集合的泛型
IS-A:表示继承。父类与子类
LIKE-A:A link-a B,A实现了B接口