Java程序设计期末练习题
一、填空题(每空1分,共20分)
- 引用类型转型时可以使用
instanceof
操作符来判断转型的合法性。 - 将方法声明为
final
意味着它不能被继承。 - 自定义异常必须要继承的类是
Exception
。 - 在子类构造器中通过语句
super()
可以调用父类中的无参构造器。 - Java使用
Thread
类及子类对象表示线程。 - 类中构造器
this()
语句的含义是调用类中的无参构造器。 - 接口中的所有属性都是公开静态常量。
- 可以对象序列化的对象的所属类需要实现
Serializable
接口。 - 不定长参数定义的语法格式为:数据类型… 参数名。
- 源文件中的每一个类编译后都会生成一个字节码文件,字节码文件的扩展名是
.class
。 - 避免越界发生的有效方法是利用
length
属性作为数组下标的上界。 - 开闭原则是指程序对于扩展是开放的,对于修改是关闭的。
- 接口中的成员方法默认的修饰符是
public abstract
。 - 将对象放入
HashSet
中时,需要保证该对象所属类中的hashCode()
方法与equals()
方法要兼容。 Map
内部定义了一个Entry
类,封装了一个键值对,使用Map
的entrySet()
方法可以获取键值对集合。- 通过
Collection
接口中的iterator()
方法可以获得迭代器。 - 子类方法抛出的异常类型必须是父类方法抛出的异常类型或者父类方法抛出的异常类型的子类。
- Java的标准输入
System.in
是InputStream
类的对象。 - 泛型方法是带有参数类型的方法。
BufferedReader
类构造方法的参数是InputStreamReader
类的对象。
二、判断正误(每题1分,共10分)
- “
float x1=1.414f;
”语句中等号右边的‘f’
是多余的(错)。 - 可以在抽象类中定义非抽象方法(对)。
- 接口中的所有方法都是公开的抽象方法(对)。
- 静态内部类可以访问外部类的数据成员(错)。
- 泛型初始化过程中,一旦给定了参数类型之后,参数类型必须是定了参数类型的父类或子类(错)。
- 声明
String str[]
后,数组名str
可以直接使用,给指定数组元素赋值(错)。 - Java不允许数值类型和布尔类型之间进行转换(对)。
IOException
异常是非运行时异常,必须在程序中抛弃或捕获(对)。- 子类不可以调用父类中没有的方法(错)。
- 用布尔逻辑运算符不会产生短路现象(对)。
三、单选题(每题2分,共30分)
- 以下的变量定义语句中,合法的是(D)
- (A)
float _*5 = 123.456F;
- (B)
byte $_b1 = 12345;
- (C)
int _long_ = 123456L;
- (D)
double d = Double.MAX_VALUE;
- (A)
- 下列说法错误的是(C):
- A. 一个Java源文件不允许有多个公共类;
- B. 数组可以赋值给
Object
类型的对象; - C. 一个Java源文件生成一个
class
文件; - D. 数组可以调用
Object
类的所有方法;
- 类
A
有一个方法void method()
,要求能够通过类名A
直接调用method()
,则方法定义应该为(A)- A.
static void method()
- B.
public void method()
- C.
final void method()
- D.
abstract void method()
- A.
- 下面关于方法的说法,不正确的是(C)。
- (A)Java中的构造方法名必须和类名相同;
- (B)方法体是对方法的实现,包括变量声明和合法语句
- (C)如果一个类定义了构造方法,也可以用该类的默认构造方法
- (D)类的私有方法不能被其他类直接访问
- 区分类中重载方法的依据是(A)。
- A.形参列表的类型和顺序
- B.不同的形参名称
- C.返回值的类型不同
- D.访问权限不同
- 如果局部变量和成员变量同名,如何在局部变量作用域内引用成员变量?(B)
- A.不能引用,必须改名,使它们的名称不相同
- B.在成员变量前加
this
,使用this
访问该成员变量 - C.在成员变量前加
super
,使用super
访问该成员变量 - D.不影响,系统可以自己区分
- 已知有定义:
String s="I love"
,下面哪个表达式正确?(A)- A.
s += "you";
- B.
char c = s[1];
- C.
int len = s.length;
- D.
String s = s.toLowerCase();
- A.
- 对应
try
和catch
子句的排列方式,下列哪一项是正确的?(A)- A.子类异常在前,父类异常在后
- B.父类异常在前,子类异常在后
- C.只能有子类异常
- D.父类和子类不能同时出现在
try
语句块中
- 下列代码中给出正确的在方法体内抛出异常的是(B)。
- A.
new throw Exception(" ");
- B.
throw new Exception(" ");
- C.
throws IOException();
- D.
throws IOException;
- A.
- 若要删除一个文件,应该使用下列哪个类的实例(B)?
- A.
RandomAccessFile
- B.
File
- C.
FileOutputStream
- D.
FileReader
- A.
- 下列说法中,错误的一项是(A)。
- A.
Thread
类中没有定义run()
方法 - B.可以通过继承
Thread
类来创建线程 - C.
Runnable
接口中定义了run()
方法 - D.可以通过实现
Runnable
接口创建线程
- A.
- 下列说法中,错误的一项是(A)
- A. 在迭代器中可以使用
ArrayList
中的remove()
方法 ; - B. 处理流用于在节点流的基础上进行加工处理;
- C. JVM使用
serialVersionUID
来验证对象版本 - D.
static
修饰的是类变量,不会被序列化。
- A. 在迭代器中可以使用
- 下列赋值语句中,正确的是:(D)
- A.
byte b1 = 10, b2 = 20; byte b=b1+b2;
- B.
float c=1.3;
- C.
byte b1 = 10, byte b=b1+10;
- D.
byte b1 = 10; byte b=++b1;
- A.
- 单例模式的实现必须满足的条件包括(C)
- A. 类中的构造方法的访问权限必须设置为
public
- B. 类中的构造方法必须用
protected
修饰 - C. 必须在类中创建该类的静态私有对象
- D. 提供一个公有的静态方法用于创建获取静态私有对象.
- A. 类中的构造方法的访问权限必须设置为
A
类继承自B
类,那么A
类中不可以使用(C)- A、
B
类的保护方法 - B、
B
类的公有属性 - C、
B
类的私有属性 - D、
A
类的私有属性
- A、
四、简答题(每小题5分,共20分)
- 写出该程序的输出结果
class Insect {
int i = 9;
int j;
int m = prt("Insect.m initialized");
static int x1 = prt("static Insect.x1 initialized");
Insect() {
prt("i = " + i + ", j = " + j);
j = 39;
}
static int prt(String s) {
System.out.println(s);
return 47;
}
}
public class Beetle extends Insect {
int k = prt("Beetle.k initialized");
int l = prt("Beetle.l initialized");
static int x2 = prt("static Beetle.x2 initialized");
Beetle() {
prt("k = " + k);
prt("j = " + j);
}
public static void main(String[] args) {
prt("Beetle constructor");
Beetle b = new Beetle();
}
}
输出结果:
static Insect.x1 initialized
static Beetle.x2 initialized
Beetle constructor
Insect.m initialized
i = 9, j = 0
Beetle.k initialized
Beetle.l initialized
k = 47
j = 39
解析:程序运行时,先加载父类Insect
的静态成员,输出static Insect.x1 initialized
;接着加载子类Beetle
的静态成员,输出static Beetle.x2 initialized
。然后执行main
方法,调用prt("Beetle constructor")
输出Beetle constructor
。创建Beetle
对象时,先调用父类构造器,初始化父类成员变量,输出Insect.m initialized
,再输出i = 9, j = 0
,并将j
赋值为39。最后初始化子类成员变量,输出Beetle.k initialized
和Beetle.l initialized
,在子类构造器中输出k = 47
和j = 39
。
- 在
test1()
中调用Collection.sort()
方法,通过定制排序比较两个Employee
(先按年龄,年龄相同按姓名比)。请用匿名内部类在横线处补齐代码
public class Employee{
private String name;
private int age;
public int getAge(){
return age;
}
public String getName(){
return name;
}
public Employee(String name, int age){
this.name = name;
this.age = age;
}
}
public class TestLambda {
List<Employee> emps = Arrays.asList(new Employee("张三", 18),
new Employee("李四", 59),
new Employee("田七", 38)
);
public void test1() {
Collections.sort(emps,new Comparator<Employee>() {
public int compare(Employee o1, Employee o2) {
if (o1.getAge()!=o2.getAge()){
return o1.getAge()-o2.getAge();
}else{
return o1.getName().compareTo(o2.getName());
}
}
});
System.out.println("emps = " + emps);
}
}
解析:在Collections.sort()
方法中,通过传入一个实现了Comparator
接口的匿名内部类来定义排序规则。compare
方法中,先比较年龄,如果年龄不同,返回年龄差值;如果年龄相同,则比较姓名,调用String
类的compareTo
方法进行比较。
- 创建一个工厂类(
Factory
),并在该类中定义3个成员变量工厂ID(id
)、工厂名(name
)以及地址(address
),使用单例模式实现仅能创建Factory
类的1个实例
public class Factory {
private static Factory factory;
private int id;
private String name;
private String address;
private Factory() {
}
public int getId() {
return id;
}
public String getName() {
return name;
}
public String getAddress() {
return address;
}
public void setId(int id) {
this.id = id;
}
public void setName(String name) {
this.name = name;
}
public void setAddress(String address) {
this.address = address;
}
public Factory getInstance(){
if (factory == null){
factory = new Factory();
}
return factory;
}
}
解析:单例模式通过将构造器设为私有,防止外部直接创建对象。使用静态私有成员变量factory
保存唯一实例,通过静态公有方法getInstance
来获取该实例。在getInstance
方法中,先判断factory
是否为null
,如果是则创建实例,否则直接返回已有实例。
- 请填充并参考
SecondThread
代码,用Lambda表达式替换Test
中的代码(1)和(2)
public class SecondThread implements Runnable {
private int i=0;
public void run() {
for(; i < 5; i++) {
System.out.println(Thread.currentThread().getName());
}
}
}
public class Test {
public static void main(String[] args) {
// Runnable target = new SecondThread(); (1)
// Thread t1 = new Thread(target); (2)
Thread t1 = new Thread(()->{
for (int i = 0; i < 5; i++) {
System.out.println(Thread.currentThread().getName());
}
});
for(int i = 0; i < 5; i++) {
System.out.println(Thread.currentThread().getName() + " : " + i);
if(i == 1) t1.start();
}
}
}
解析:Lambda表达式简化了实现Runnable
接口的方式。原代码中创建SecondThread
对象并作为参数传递给Thread
构造器,使用Lambda表达式后,直接在Thread
构造器中传入一个代码块,该代码块实现了Runnable
接口的run
方法功能。
五、编程题(共20分)
- 编写员工
Employee
类,包含工号id
、姓名name
、工资salary
等属性,令Employee
类实现comparable
接口,并实现接口中的compareTo()
方法,制定比较规则。在测试类中创建几个Employee
对象,放入ArrayList
集合中,对其进行排序。关于比较的规则先按Name
进行升序排序,如果Name
相同,按照id
进行升序排序
//Employee类
public class Employee implements Comparable<Employee> {
private int id;
private String name;
private double salary;
public int getId() {
return id;
}
public String getName() {
return name;
}
public double getSalary() {
return salary;
}
public Employee(int id, String name, double salary) {
this.id = id;
this.name = name;
this.salary = salary;
}
@Override
public int compareTo(Employee o) {
if (this.getName().compareTo(o.getName()) == 0){
return this.getId() - o.getId();
}else{
return this.getName().compareTo(o.getName());
}
}
@Override
public String toString() {
return "{"+id+","+name+","+salary+"}";
}
}
//Test类
public class TestEmployee {
public static void main(String[] args) {
List<Employee> emps = Arrays.asList(new Employee(1,"Zhang3", 100.0),
new Employee(2,"Li4", 200.0),
new Employee(3, "Wang5", 300.0),
new Employee(4, "Zhao6", 400.0),
new Employee(5, "Tian7", 500.0));
Collections.sort(emps);
System.out.println(emps);
}
}
解析:Employee
类实现Comparable
接口,重写compareTo
方法定义排序规则。在compareTo
方法中,先比较姓名,如果姓名相同再比较工号。在测试类TestEmployee
中,创建Employee
对象并放入ArrayList
集合,调用Collections.sort
方法对集合进行排序,最后输出排序后的结果。
2. 使用数据过滤流将1000 - 2000间的素数写到文件中持久化保存;将这些素数从文件读出并打印到控制台
//MyOutputStream类继承FilterOutputStream装饰器类,增加writePrime(int)和writePrimesInRange(int,int)方法
public class MyOutputStream extends FilterOutputStream {
public MyOutputStream(OutputStream out) {
super(out);
}
public void writePrime(int n) throws IOException{
if (n < 2){
return;
}
for (int i = 2; i * i <= n; i++) {
if (n % i == 0){
return;
}
}
String sp = Integer.toString(n);
for (int i = 0; i < sp.length(); i++) {
super.write(sp.charAt(i));
}
super.write('\n');
}
public void writePrimesInRange(int low, int high) throws IOException {
for (int i = low; i <= high; i++) {
writePrime(i);
}
}
public static void main(String[] args) throws IOException {
MyOutputStream outputStream = new MyOutputStream(new FileOutputStream("primes.txt"));
outputStream.writePrimesInRange(1000, 2000);
outputStream.close();
BufferedInputStream inputStream = new BufferedInputStream(new FileInputStream("primes.txt"));
int c = 0;
while ((c = inputStream.read()) != -1){
System.out.print((char)c);
}
inputStream.close();
}
}
解析:
MyOutputStream
类继承自FilterOutputStream
,用于对输出流进行功能扩展。writePrime(int n)
方法用于判断一个数是否为素数,如果是则将其写入文件。判断素数的逻辑是:从2开始到该数的平方根,如果能被整除则不是素数。将素数转换为字符串后,逐个字符写入流,并在每个素数后写入换行符。writePrimesInRange(int low, int high)
方法遍历指定范围内的数,调用writePrime(int n)
方法将其中的素数写入文件。- 在
main
方法中,创建MyOutputStream
对象并传入FileOutputStream
,调用writePrimesInRange(1000, 2000)
方法将1000到2000之间的素数写入primes.txt
文件。然后使用BufferedInputStream
读取文件内容,将读取到的字符逐个打印到控制台,直到文件末尾(read()
方法返回 -1)。
3. 定义Student类,该类包括ID、姓名和年龄属性,创建一个Student对象持久化到文件,并从文件读出、打印
public class Student implements Serializable {
int id;
String name;
int age;
public Student(int id, String name, int age) {
this.id = id;
this.name = name;
this.age = age;
}
@Override
public String toString() {
return "{"+id+","+name+","+age+"}";
}
}
public class TestSerialize {
public static void main(String[] args) throws Exception {
File file = new File("student.txt");
ObjectOutputStream outputStream = new ObjectOutputStream(new FileOutputStream(file));
outputStream.writeObject(new Student(10001, "Zhang3", 18));
outputStream.close();
ObjectInputStream inputStream = new ObjectInputStream(new FileInputStream(file));
Student stu = (Student) inputStream.readObject();
inputStream.close();
System.out.println(stu);
}
}
解析:
Student
类实现了Serializable
接口,这是对象能够被序列化的必要条件。实现该接口表示Student
类的对象可以被转换为字节流进行存储或传输。TestSerialize
类的main
方法中:- 首先创建一个
File
对象,指定存储学生对象的文件名为student.txt
。 - 使用
ObjectOutputStream
将Student
对象写入文件。ObjectOutputStream
构造函数接受一个FileOutputStream
,用于指定输出的目标文件。通过调用writeObject
方法将新创建的Student
对象写入文件。 - 接着使用
ObjectInputStream
从文件中读取对象。同样,ObjectInputStream
构造函数接受一个FileInputStream
来指定读取的源文件。通过调用readObject
方法读取文件中的对象,并将其强制转换为Student
类型。 - 最后关闭输入输出流,并打印读取到的
Student
对象,验证对象的持久化和读取操作是否成功。
- 首先创建一个