Java语言练习答案03

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之前执行

volatile操作干了什么

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

虽然增量操作(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接口

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

muskfans

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值