Java面向对象技术与方法模拟卷三 
一、填空题(每空1分,共10分) 
- Java中,类的默认访问权限是_______。
- 使用_______关键字声明的变量在运行时确定具体值。
- 子类构造方法中,如果要调用父类的构造方法,必须使用_______关键字。
- Java中的常量通常使用_______和_______两个关键字修饰。
- Java中_______修饰的代码块会在类被加载时执行。
- Java中的异常分为_______和_______两大类。
- 将基本数据类型转换为对应的包装类称为_______。
- _______模式是一种创建型设计模式,它能产生各种不同但相关的对象。
- Java中支持I/O操作的包是_______。
- 使用_______类可以实现Java对象的克隆。
二、判断题(每题1分,共10分) 
- Java中的char类型占用1个字节。()
- Java中可以创建抽象类的对象。()
- 子类可以继承父类的构造方法。()
- Java中的内部类可以访问外部类的所有成员。()
- 在Java中,所有类都直接或间接继承自Object类。()
- 接口中可以定义构造方法。()
- 继承是实现代码重用的唯一方式。()
- Java中的枚举类型可以实现接口。()
- 静态方法中可以使用this关键字。()
- Java中的变量必须先声明后使用。()
三、单选题(每题2分,共10分) 
- 下列哪个不是Java中的集合类型?() A. ArrayListB.VectorC.StringBufferD.HashMap
- 以下哪个方法用于实现Java对象的浅克隆?() A. clone()B.copy()C.duplicate()D.replicate()
- 以下哪个关键字不用于流程控制?() A. breakB.continueC.finalD.return
- 在Java中,哪个不是线程的状态?() A. NEWB.RUNNINGC.BLOCKEDD.TERMINATED
- 以下哪个不属于Java的包装类?() A. IntegerB.CharacterC.StringD.Boolean
四、写出程序运行结果(每题5分,共20分) 
- 请写出下面程序的输出结果:
java
class StaticTest {
    static int i = 0;
    
    static {
        i = 1;
        System.out.println("Static block: " + i);
    }
    
    {
        i = 2;
        System.out.println("Instance block: " + i);
    }
    
    StaticTest() {
        i = 3;
        System.out.println("Constructor: " + i);
    }
}
public class Test {
    public static void main(String[] args) {
        System.out.println("Main begins: " + StaticTest.i);
        new StaticTest();
        System.out.println("After creation: " + StaticTest.i);
    }
}- 请写出下面程序的输出结果:
java
public class WrapperTest {
    public static void main(String[] args) {
        Integer a = 100;
        Integer b = 100;
        Integer c = 200;
        Integer d = 200;
        
        System.out.println(a == b);
        System.out.println(c == d);
        System.out.println(a.equals(b));
        System.out.println(c.equals(d));
    }
}- 请写出下面程序的输出结果:
java
class Animal {
    static void eat() {
        System.out.println("Animal eating");
    }
}
class Dog extends Animal {
    static void eat() {
        System.out.println("Dog eating");
    }
}
public class StaticMethodTest {
    public static void main(String[] args) {
        Animal a = new Animal();
        a.eat();
        
        Animal b = new Dog();
        b.eat();
        
        Dog c = new Dog();
        c.eat();
    }
}- 请写出下面程序的输出结果:
java
enum Color {
    RED(1), GREEN(2), BLUE(3);
    
    private int value;
    
    Color(int value) {
        this.value = value;
    }
    
    public int getValue() {
        return value;
    }
}
public class EnumTest {
    public static void main(String[] args) {
        for (Color c : Color.values()) {
            System.out.println(c + ": " + c.getValue());
        }
    }
}五、简答题(每题6分,共30分) 
- 简述Java中的构造方法和普通方法的区别。
- 简述Java中的垃圾回收机制。
- 简述Java中的泛型及其作用。
- 简述Java中的线程同步机制。
- 简述Java中的IO流体系。
六、编程题(每题10分,共20分) 
- 设计一个图书管理系统,包含图书类(属性:编号、书名、作者、价格)和管理类,实现添加图书、删除图书、查询图书、借阅图书、归还图书等功能。
- 编写一个程序,实现对目录下所有文件的遍历,并根据文件类型进行分类统计(如统计.txt、.java、.pdf等类型文件的数量)。
参考答案与解析 
一、填空题答案 
- default(解析:Java中,类的默认访问权限是default(包级别),即只能被同一包中的其他类访问)
- final(解析:final关键字声明的变量是常量,只能赋值一次,赋值后不能再修改)
- super(解析:在子类构造方法中,如果要调用父类的构造方法,必须使用super关键字,且必须是构造方法的第一条语句)
- static和- final(解析:常量通常使用static和final修饰,static使其成为类常量,final使其值不可改变)
- static(解析:static修饰的代码块称为静态代码块,类加载时执行,只执行一次)
- 受检异常和- 非受检异常(解析:Java中异常分为受检异常(编译器检查)和非受检异常(运行时异常和错误))
- 自动装箱(解析:自动装箱是Java自动将基本数据类型转换为对应的包装类对象)
- 工厂(解析:工厂模式是一种创建型设计模式,通过工厂方法创建不同但相关的对象)
- java.io(解析:java.io包提供了丰富的I/O操作类,包括文件操作、流操作等)
- Cloneable(解析:实现Cloneable接口的类可以使用Object类的clone()方法进行对象克隆)
二、判断题答案 
- ✗(解析:Java中的char类型占用2个字节(16位),可以表示Unicode字符)
- ✗(解析:抽象类不能被实例化,只能被继承)
- ✗(解析:构造方法不能被继承,每个类都有自己的构造方法)
- ✓(解析:内部类可以访问外部类的所有成员,包括私有成员)
- ✓(解析:在Java中,所有类都直接或间接继承自Object类,Object是类层次结构的根类)
- ✗(解析:接口中不能定义构造方法,因为接口不能被实例化)
- ✗(解析:继承不是实现代码重用的唯一方式,还可以通过组合、委托等方式实现代码重用)
- ✓(解析:Java中的枚举类型可以实现接口,这使得枚举类型更加灵活)
- ✗(解析:静态方法中不能使用this关键字,因为静态方法属于类而不是对象实例)
- ✓(解析:Java中的变量必须先声明后使用,这是Java的语法规则)
三、单选题答案 
- C(解析:StringBuffer是字符串缓冲区类,不是集合类型;ArrayList、Vector、HashMap都是集合类型)
- A(解析:clone()方法用于实现对象的浅克隆,它是Object类的方法,需要对象的类实现Cloneable接口)
- C(解析:final不用于流程控制,而是用于修饰类、方法和变量;break、continue和return都用于流程控制)
- B(解析:Java线程的状态包括NEW、RUNNABLE、BLOCKED、WAITING、TIMED_WAITING和TERMINATED,没有RUNNING状态)
- C(解析:String不是包装类,它是一个独立的类;Integer、Character和Boolean都是基本数据类型的包装类)
四、程序运行结果 
- 输出结果:
Static block: 1
Main begins: 1
Instance block: 2
Constructor: 3
After creation: 3解析:首先执行静态代码块,将i赋值为1并输出;然后执行main方法,输出i的值1;创建StaticTest对象时,先执行实例代码块,将i赋值为2并输出;再执行构造方法,将i赋值为3并输出;最后输出创建对象后i的值3。
- 输出结果:
true
false
true
true解析:Integer类对-128到127之间的数值进行缓存,a和b都是100,在缓存范围内,指向同一个对象,所以a==b为true;c和d都是200,超出缓存范围,是不同对象,所以c==d为false;equals方法比较的是值,所以a.equals(b)和c.equals(d)都为true。
- 输出结果:
Animal eating
Animal eating
Dog eating解析:静态方法不能被重写,只能被隐藏,调用哪个静态方法取决于引用变量的类型,而不是对象的实际类型。a是Animal类型的引用,调用Animal.eat();b虽然指向Dog对象,但引用类型是Animal,调用Animal.eat();c是Dog类型的引用,调用Dog.eat()。
- 输出结果:
RED: 1
GREEN: 2
BLUE: 3解析:程序遍历Color枚举的所有值,输出枚举常量名和对应的值。Color.values()返回所有枚举常量的数组,按照声明顺序排列。
五、简答题参考答案 
- 构造方法和普通方法的区别: - 命名:构造方法名必须与类名相同,普通方法可以自定义名称
- 返回值:构造方法没有返回值类型(不能用void修饰),普通方法必须有返回值类型(可以是void)
- 调用时机:构造方法在创建对象时自动调用,普通方法需要通过对象显式调用
- 目的:构造方法用于初始化对象,普通方法用于定义对象的行为
- 继承:构造方法不能被继承,普通方法可以被继承
- 重载:构造方法和普通方法都可以重载,但构造方法不能重写
- 默认:如果没有定义构造方法,编译器会提供一个无参构造方法;普通方法必须显式定义
 
- Java中的垃圾回收机制: - 概念:垃圾回收(Garbage Collection)是Java自动管理内存的机制,负责识别和回收不再使用的对象
- 判断对象是否可回收的算法: - 引用计数法:记录对象被引用的次数,当计数为0时回收(Java不采用这种方法)
- 可达性分析:从GC Roots开始,如果对象不可达则认为是垃圾
 
- 垃圾回收算法: - 标记-清除算法:标记所有可达对象,清除不可达对象
- 复制算法:将内存分为两块,使用一块时将存活对象复制到另一块,然后清空当前块
- 标记-整理算法:标记后将所有存活对象移到内存的一端,清理边界外的内存
- 分代收集算法:根据对象的生命周期将内存划分为年轻代和老年代,采用不同的策略
 
- 垃圾回收器:Serial、ParNew、Parallel Scavenge、CMS、G1等
- 触发条件:内存不足、显式调用System.gc()(只是建议)等
- 优点:自动管理内存,减少内存泄漏和悬挂指针
- 缺点:垃圾回收时可能导致应用暂停(Stop-The-World),不可完全控制回收时机
 
- Java中的泛型及其作用: - 概念:泛型是Java 5引入的特性,允许类、接口和方法在定义时使用类型参数
- 语法:使用<>括起类型参数,如List<String>、Map<String, Integer>
- 作用: - 类型安全:在编译时进行类型检查,避免运行时类型转换错误
- 消除类型转换:避免显式类型转换,提高代码可读性和安全性
- 代码复用:同一代码可以操作不同类型的数据
- 实现通用算法:如排序、查找等
 
- 特性: - 类型擦除:编译后泛型信息会被擦除,替换为原始类型(通常是Object)
- 不能用于基本类型:必须使用包装类,如Integer而不是int
- 泛型通配符:? 表示未知类型,可以用extends和super进行限定
- 泛型方法:可以在普通类中定义泛型方法
- 泛型类:整个类可以参数化
 
- 局限性: - 不能创建泛型数组
- 不能使用instanceof操作符检查泛型类型
- 静态变量不能使用泛型类的类型参数
 
 
- Java中的线程同步机制: - 概念:线程同步是为了解决多线程并发访问共享资源时的竞争条件和数据不一致问题
- 主要同步机制: - synchronized关键字: - 可以修饰方法(实例方法、静态方法)或代码块
- 基于对象监视器(monitor)实现
- 自动获取和释放锁
 
- Lock接口及其实现类: - ReentrantLock:可重入锁,功能类似synchronized但更灵活
- ReadWriteLock:读写锁,允许多个线程同时读,只允许一个线程写
- 需要显式获取和释放锁
 
- volatile关键字: - 保证变量的可见性,但不保证原子性
- 禁止指令重排序优化
 
- 原子类: - AtomicInteger、AtomicLong等,保证基本类型操作的原子性
 
- ThreadLocal: - 为每个线程提供独立的变量副本,避免共享变量
 
- 并发容器: - ConcurrentHashMap、CopyOnWriteArrayList等线程安全的集合类
 
 
- synchronized关键字: 
- 同步原理: - 互斥:一次只允许一个线程访问共享资源
- 可见性:一个线程修改变量后,其他线程能立即看到最新值
- 有序性:禁止指令重排序
 
 
- Java中的IO流体系: - 基本分类: - 字节流(8位):处理二进制数据 - 输入流基类:InputStream
- 输出流基类:OutputStream
 
- 字符流(16位):处理文本数据 - 输入流基类:Reader
- 输出流基类:Writer
 
 
- 字节流(8位):处理二进制数据 
- 常用字节流: - FileInputStream/FileOutputStream:文件读写
- ByteArrayInputStream/ByteArrayOutputStream:字节数组读写
- DataInputStream/DataOutputStream:基本数据类型读写
- ObjectInputStream/ObjectOutputStream:对象序列化与反序列化
- BufferedInputStream/BufferedOutputStream:带缓冲的字节流
 
- 常用字符流: - FileReader/FileWriter:文件读写
- CharArrayReader/CharArrayWriter:字符数组读写
- StringReader/StringWriter:字符串读写
- BufferedReader/BufferedWriter:带缓冲的字符流
- PrintWriter:格式化输出
 
- 转换流: - InputStreamReader:字节流转字符流
- OutputStreamWriter:字符流转字节流
 
- 特点: - 装饰者模式:通过组合实现功能叠加
- 缓冲提高效率:缓冲流可提高IO性能
- 资源释放:使用try-with-resources或finally确保关闭流
 
- NIO(New IO): - 基于Channel和Buffer
- 支持非阻塞IO
- 提供更高效的IO操作
 
 
- 基本分类: 
六、编程题参考答案 
- 图书管理系统:
java
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
// 图书类
class Book {
    private String id;
    private String name;
    private String author;
    private double price;
    private boolean borrowed;
    
    public Book(String id, String name, String author, double price) {
        this.id = id;
        this.name = name;
        this.author = author;
        this.price = price;
        this.borrowed = false;
    }
    
    // getter和setter方法
    public String getId() { return id; }
    public void setId(String id) { this.id = id; }
    public String getName() { return name; }
    public void setName(String name) { this.name = name; }
    public String getAuthor() { return author; }
    public void setAuthor(String author) { this.author = author; }
    public double getPrice() { return price; }
    public void setPrice(double price) { this.price = price; }
    public boolean isBorrowed() { return borrowed; }
    public void setBorrowed(boolean borrowed) { this.borrowed = borrowed; }
    
    @Override
    public String toString() {
        return "编号:" + id + ",书名:" + name + ",作者:" + author + 
               ",价格:" + price + ",状态:" + (borrowed ? "已借出" : "可借阅");
    }
}
// 管理类
class LibraryManager {
    private List<Book> books;
    private Map<String, String> borrowRecords; // 借阅记录:图书ID -> 借阅者
    
    public LibraryManager() {
        books = new ArrayList<>();
        borrowRecords = new HashMap<>();
    }
    
    // 添加图书
    public void addBook(Book book) {
        books.add(book);
        System.out.println("添加图书成功:" + book.getName());
    }
    
    // 删除图书
    public boolean deleteBook(String id) {
        Book book = findBook(id);
        if (book != null) {
            if (book.isBorrowed()) {
                System.out.println("该图书已被借出,无法删除!");
                return false;
            }
            books.remove(book);
            System.out.println("删除图书成功:" + book.getName());
            return true;
        }
        System.out.println("未找到该图书!");
        return false;
    }
    
    // 查询图书
    public Book findBook(String id) {
        for (Book book : books) {
            if (book.getId().equals(id)) {
                return book;
            }
        }
        return null;
    }
    
    // 借阅图书
    public boolean borrowBook(String id, String borrower) {
        Book book = findBook(id);
        if (book != null) {
            if (book.isBorrowed()) {
                System.out.println("该图书已被借出!");
                return false;
            }
            book.setBorrowed(true);
            borrowRecords.put(id, borrower);
            System.out.println(borrower + "成功借阅图书:" + book.getName());
            return true;
        }
        System.out.println("未找到该图书!");
        return false;
    }
    
    // 归还图书
    public boolean returnBook(String id) {
        Book book = findBook(id);
        if (book != null) {
            if (!book.isBorrowed()) {
                System.out.println("该图书未被借出!");
                return false;
            }
            book.setBorrowed(false);
            String borrower = borrowRecords.remove(id);
            System.out.println(borrower + "成功归还图书:" + book.getName());
            return true;
        }
        System.out.println("未找到该图书!");
        return false;
    }
    
    // 显示所有图书
    public void showAllBooks() {
        if (books.isEmpty()) {
            System.out.println("图书馆暂无图书!");
        } else {
            System.out.println("图书馆共有" + books.size() + "本图书:");
            for (Book book : books) {
                System.out.println(book);
            }
        }
    }
    
    // 显示借阅记录
    public void showBorrowRecords() {
        if (borrowRecords.isEmpty()) {
            System.out.println("暂无借阅记录!");
        } else {
            System.out.println("当前借阅记录:");
            for (Map.Entry<String, String> entry : borrowRecords.entrySet()) {
                Book book = findBook(entry.getKey());
                System.out.println("借阅者:" + entry.getValue() + ",图书:" + book.getName());
            }
        }
    }
}
// 测试类
public class LibrarySystem {
    public static void main(String[] args) {
        LibraryManager manager = new LibraryManager();
        
        // 添加图书
        manager.addBook(new Book("B001", "Java编程思想", "Bruce Eckel", 108.0));
        manager.addBook(new Book("B002", "深入理解Java虚拟机", "周志明", 89.0));
        manager.addBook(new Book("B003", "设计模式", "Erich Gamma", 78.5));
        
        // 显示所有图书
        manager.showAllBooks();
        
        // 借阅图书
        manager.borrowBook("B001", "张三");
        manager.borrowBook("B002", "李四");
        
        // 显示借阅记录
        manager.showBorrowRecords();
        
        // 尝试删除已借出的图书
        manager.deleteBook("B001");
        
        // 归还图书
        manager.returnBook("B001");
        
        // 删除图书
        manager.deleteBook("B001");
        
        // 再次显示所有图书
        manager.showAllBooks();
    }
}- 文件类型统计程序:
java
import java.io.File;
import java.util.HashMap;
import java.util.Map;
public class FileTypeCounter {
    public static void main(String[] args) {
        // 指定要遍历的目录
        String directoryPath = "D:/MyFiles"; // 替换为实际的目录路径
        File directory = new File(directoryPath);
        
        // 检查路径是否存在且是目录
        if (!directory.exists() || !directory.isDirectory()) {
            System.out.println("指定的路径不存在或不是目录!");
            return;
        }
        
        // 用于存储文件类型统计信息的Map
        Map<String, Integer> typeCountMap = new HashMap<>();
        
        // 遍历目录并统计文件类型
        countFileTypes(directory, typeCountMap);
        
        // 显示统计结果
        System.out.println("文件类型统计结果:");
        for (Map.Entry<String, Integer> entry : typeCountMap.entrySet()) {
            System.out.println(entry.getKey() + ": " + entry.getValue() + "个");
        }
    }
    
    /**
     * 递归遍历目录,统计文件类型
     * @param directory 要遍历的目录
     * @param typeCountMap 存储统计结果的Map
     */
    private static void countFileTypes(File directory, Map<String, Integer> typeCountMap) {
        File[] files = directory.listFiles();
        if (files != null) {
            for (File file : files) {
                if (file.isDirectory()) {
                    // 如果是目录,递归遍历
                    countFileTypes(file, typeCountMap);
                } else {
                    // 如果是文件,获取文件扩展名并统计
                    String extension = getFileExtension(file.getName());
                    if (extension.isEmpty()) {
                        extension = "无扩展名";
                    }
                    typeCountMap.put(extension, typeCountMap.getOrDefault(extension, 0) + 1);
                }
            }
        }
    }
    
    /**
     * 获取文件扩展名
     * @param fileName 文件名
     * @return 文件扩展名(小写)
     */
    private static String getFileExtension(String fileName) {
        int dotIndex = fileName.lastIndexOf('.');
        if (dotIndex > 0 && dotIndex < fileName.length() - 1) {
            return fileName.substring(dotIndex + 1).toLowerCase();
        }
        return "";
    }
}