Java大厂笔试题及详细解答

基础知识

1. 名词解释

  • Eclipse:一个开源的集成开发环境(IDE),主要用于Java开发,但也可以通过插件支持其他语言。它提供了代码编辑、调试、代码补全等功能。
  • J2EE:Java 2 Platform, Enterprise Edition,是Java平台的一个企业级版本,用于开发和运行大型分布式多层应用程序。它包括EJB、JSP、Servlet等技术。
  • EJB:Enterprise JavaBeans,是一种用于开发和部署可重用、可移植的Java组件的服务器端组件架构。它用于构建企业级应用程序,支持事务管理、安全性和分布式计算。
  • Ajax:Asynchronous JavaScript and XML,是一种用于创建交互式网页应用的技术。它允许网页在不重新加载整个页面的情况下与服务器进行数据交换和更新。
  • Web service:一种基于网络的、分布式的、按标准协议进行通信的应用程序。它允许不同平台和语言的应用程序通过网络进行交互,通常使用SOAP或REST协议。

2. 代码问题排查

  • 问题代码

    public class test {
        public void print(String str) {
            char[] s = str; // 错误
        }
    }
    

    问题char[] s = str; 是错误的,因为String类型不能直接赋值给char[]类型。
    修正代码

    public class test {
        public void print(String str) {
            char[] s = str.toCharArray(); // 正确
        }
    }
    
  • 问题代码

    public class a {
        public static void main(String[] args) {
            puts(); // 错误
        }
    }
    

    问题puts() 方法未定义,且Java中没有puts()方法。
    修正代码

    public class a {
        public static void main(String[] args) {
            System.out.println(); // 正确
        }
    }
    

3. 代码输出题

  • 代码

    public class Parent {
        public void method() {
            System.out.println("parent");
        }
        public static void smethod() {
            System.out.println("parent");
        }
    }
    public class Child extends Parent {
        public void method() {
            System.out.println("child");
        }
        public static void smethod() {
            System.out.println("child");
        }
    }
    public class test {
        public static void main(String[] args) {
            Child c = new Child();
            Parent p = (Parent) c;
            p.method(); // 输出 "child"
            p.smethod(); // 输出 "parent"
        }
    }
    

    输出结果

    child
    parent
    

    解释

    • p.method() 调用的是Child类的method()方法,因为多态机制会调用实际对象的方法。
    • p.smethod() 调用的是Parent类的smethod()方法,因为静态方法不会发生多态,而是根据引用类型来调用。

编程能力

1. 实现单例模式

  • 懒汉式

    public class Singleton {
        private static Singleton instance = null;
        private Singleton() {} // 私有构造函数
        public static synchronized Singleton getInstance() {
            if (instance == null) {
                instance = new Singleton();
            }
            return instance;
        }
    }
    

    解释:懒汉式单例模式在第一次调用getInstance()时才初始化实例,synchronized确保线程安全。

  • 饿汉式

    public class Singleton {
        private static Singleton instance = new Singleton();
        private Singleton() {} // 私有构造函数
        public static Singleton getInstance() {
            return instance;
        }
    }
    

    解释:饿汉式单例模式在类加载时就初始化实例,因此线程安全,但可能会浪费资源。

2. 实现排序算法

  • 冒泡排序

    public static void bubbleSort(int[] array) {
        for (int i = 0; i < array.length - 1; i++) {
            for (int j = 0; j < array.length - i - 1; j++) {
                if (array[j] > array[j + 1]) {
                    int temp = array[j];
                    array[j] = array[j + 1];
                    array[j + 1] = temp;
                }
            }
        }
    }
    

    解释:冒泡排序通过相邻元素的比较和交换,将较大的元素“冒泡”到数组的末尾。

数据结构与算法

1. 数组问题

  • 代码

    Object[] object = new Person[2];
    Person[] person = new Person[3];
    person = (Person[]) object; // 可以转换
    

    解释Object[]可以向下转型为Person[],因为PersonObject的子类。

  • 代码

    int[] i = new int[2];
    long[] l = new int[3];
    i = (long[]) l; // 不可以转换
    

    解释int[]long[]是两种不同的数组类型,不能进行强制类型转换。

2. 二叉树操作

  • 插入值到二叉树

    class TreeNode {
        int val;
        TreeNode left;
        TreeNode right;
        TreeNode(int x) { val = x; }
    }
    
    public class BinarySearchTree {
        public TreeNode insertIntoBST(TreeNode root, int val) {
            if (root == null) {
                return new TreeNode(val);
            }
            if (val < root.val) {
                root.left = insertIntoBST(root.left, val);
            } else {
                root.right = insertIntoBST(root.right, val);
            }
            return root;
        }
    }
    

    解释:递归地将值插入到二叉搜索树中,确保左子树的值小于根节点,右子树的值大于根节点。

多线程与并发

1. 线程状态

  • 线程的基本状态
    • 新建状态(New):线程被创建但尚未启动。
    • 就绪状态(Runnable):线程已经启动,等待CPU调度。
    • 运行状态(Running):线程正在执行。
    • 阻塞状态(Blocked):线程被阻塞,等待某些条件(如锁)。
    • 等待状态(Waiting):线程调用了wait()方法,等待其他线程的通知。
    • 超时等待状态(Timed Waiting):线程调用了wait(long)sleep(long)方法,等待一定时间。
    • 终止状态(Terminated):线程执行完毕或因异常终止。

2. 线程同步

  • 使用synchronized关键字

    public class Counter {
        private int count = 0;
    
        public synchronized void increment() {
            count++;
        }
    
        public synchronized int getCount() {
            return count;
        }
    }
    

    解释synchronized确保同一时间只有一个线程可以访问同步方法或代码块。

3. 线程池实现

  • 简单线程池

    import java.util.concurrent.ExecutorService;
    import java.util.concurrent.Executors;
    
    public class ThreadPoolExample {
        public static void main(String[] args) {
            ExecutorService executor = Executors.newFixedThreadPool(5); // 创建固定大小的线程池
            for (int i = 0; i < 10; i++) {
                executor.submit(() -> {
                    System.out.println("Task executed by " + Thread.currentThread().getName());
                });
            }
            executor.shutdown(); // 关闭线程池
        }
    }
    

    解释:使用ExecutorService创建线程池,提交任务并关闭线程池。

网络编程

1. Socket通信

  • 客户端

    import java.io.*;
    import java.net.Socket;
    
    public class Client {
        public static void main(String[] args) throws IOException {
            Socket socket = new Socket("localhost", 12345); // 连接到服务器
            OutputStream out = socket.getOutputStream();
            out.write("Hello, Server".getBytes()); // 发送数据
            socket.close(); // 关闭连接
        }
    }
    
  • 服务器端

    import java.io.*;
    import java.net.ServerSocket;
    import java.net.Socket;
    
    public class Server {
        public static void main(String[] args) throws IOException {
            ServerSocket serverSocket = new ServerSocket(12345); // 监听端口
            Socket socket = serverSocket.accept(); // 接受客户端连接
            InputStream in = socket.getInputStream();
            byte[] buffer = new byte[1024];
            int bytesRead = in.read(buffer);
            System.out.println("Received: " + new String(buffer, 0, bytesRead)); // 输出接收的数据
            socket.close(); // 关闭连接
            serverSocket.close(); // 关闭服务器
        }
    }
    

    解释:客户端通过Socket连接到服务器,发送数据;服务器通过ServerSocket监听端口,接收客户端数据。

2. TCP与UDP的区别

  • TCP(Transmission Control Protocol)

    • 面向连接,提供可靠的字节流服务。
    • 数据传输前需要建立连接,传输完成后关闭连接。
    • 保证数据的顺序和完整性,适合传输大文件。
    • Java中使用SocketServerSocket实现。
  • UDP(User Datagram Protocol)

    • 无连接,提供不可靠的数据报服务。
    • 数据传输不需要建立连接,适合实时性要求高的应用(如视频通话)。
    • 不保证数据的顺序和完整性,但传输速度快。
    • Java中使用DatagramSocketDatagramPacket实现。

设计模式

1. 单例模式

  • 懒汉式饿汉式已在前面实现。

2. 工厂模式

  • 简单工厂模式

    interface Product {
        void use();
    }
    
    class ConcreteProductA implements Product {
        public void use() {
            System.out.println("Using Product A");
        }
    }
    
    class ConcreteProductB implements Product {
        public void use() {
            System.out.println("Using Product B");
        }
    }
    
    class SimpleFactory {
        public static Product createProduct(String type) {
            if ("A".equals(type)) {
                return new ConcreteProductA();
            } else if ("B".equals(type)) {
                return new ConcreteProductB();
            }
            return null;
        }
    }
    
    public class FactoryExample {
        public static void main(String[] args) {
            Product product = SimpleFactory.createProduct("A");
            product.use(); // 输出 "Using Product A"
        }
    }
    

    解释:简单工厂模式通过工厂类的方法创建对象,根据参数决定创建哪种产品。

数据库

1. SQL语句

  • 查询订单信息

    SELECT * FROM orders WHERE order_date BETWEEN '2024-01-01' AND '2024-12-31';
    

    解释:查询2024年内的订单信息。

2. 数据库连接

  • 使用JDBC连接数据库

    import java.sql.*;
    
    public class JdbcExample {
        public static void main(String[] args) {
            String url = "jdbc:mysql://localhost:3306/mydatabase";
            String user = "root";
            String password = "password";
    
            try (Connection conn = DriverManager.getConnection(url, user, password)) {
                Statement stmt = conn.createStatement();
                ResultSet rs = stmt.executeQuery("SELECT * FROM users");
                while (rs.next()) {
                    System.out.println(rs.getString("username"));
                }
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
    }
    

    解释:通过JDBC连接到MySQL数据库,查询users表中的用户名。

其他

1. final、finally、finalize的区别

  • final
    • 修饰符,用于修饰类、方法和变量。
    • final类不能被继承,final方法不能被覆盖,final变量一旦赋值就不能改变。
  • finally
    • 用于异常处理,try-catch-finally结构中的finally块。
    • 无论是否捕获异常,finally块都会执行,常用于资源清理(如关闭文件流、数据库连接)。
  • finalize
    • Object类中的方法,用于垃圾回收前的资源清理。
    • 重写finalize()方法可以在对象被回收前执行一些清理操作,但不推荐使用,因为其行为不可预测。

2. ArrayList和Vector的区别

  • 同步性
    • ArrayList是线程不安全的,性能较高。
    • Vector是线程安全的,性能较低。
  • 数据增长
    • ArrayList默认扩容为原来的1.5倍。
    • Vector默认扩容为原来的2倍。

3. 多线程的实现方法

  • 继承Thread

    class MyThread extends Thread {
        public void run() {
            System.out.println("Thread is running");
        }
    }
    
    public class ThreadExample {
        public static void main(String[] args) {
            MyThread thread = new MyThread();
            thread.start(); // 启动线程
        }
    }
    
  • 实现Runnable接口

    class MyRunnable implements Runnable {
        public void run() {
            System.out.println("Thread is running");
        }
    }
    
    public class RunnableExample {
        public static void main(String[] args) {
            Thread thread = new Thread(new MyRunnable());
            thread.start(); // 启动线程
        }
    }
    

    解释

    • 继承Thread类简单直接,但Java不支持多继承,因此如果类已经继承了其他类,则不能继承Thread
    • 实现Runnable接口更灵活,推荐使用。
posted @ 2025-03-26 12:46  软件职业规划  阅读(37)  评论(0)    收藏  举报