Java面试题库
Java基础

Java基础

1. Java语言特性

1.1 面向对象的特性

  • 封装:将数据和操作数据的方法绑定在一起,对外部隐藏对象的具体实现细节
  • 继承:允许创建一个类作为另一个类的基础,继承父类的属性和方法
  • 多态:同一个操作作用于不同的对象,可以有不同的解释和执行结果

示例代码:

// 封装示例
public class Student {
    private String name;    // 私有属性
    private int age;
    
    // 公共方法访问私有属性
    public String getName() {
        return name;
    }
    
    public void setName(String name) {
        this.name = name;
    }
}
 
// 继承示例
public class Person {
    protected String name;
    
    public void eat() {
        System.out.println("Person eating");
    }
}
 
public class Student extends Person {
    private int studentId;
    
    @Override
    public void eat() {
        System.out.println("Student eating");
    }
}

1.2 Java平台特性

  • 跨平台性:Write Once, Run Anywhere
  • 安全性:沙箱安全机制、字节码验证
  • 简单性:相比C++去除了指针、运算符重载等复杂特性

2. 基本数据类型

2.1 八种基本数据类型

  • 整型:byte(8位)、short(16位)、int(32位)、long(64位)
  • 浮点型:float(32位)、double(64位)
  • 字符型:char(16位)
  • 布尔型:boolean
// 基本数据类型示例
public class DataTypeDemo {
    public static void main(String[] args) {
        byte b = 127;
        short s = 32767;
        int i = 2147483647;
        long l = 9223372036854775807L;
        
        float f = 3.14f;
        double d = 3.14159265359;
        
        char c = 'A';
        boolean bool = true;
    }
}

2.2 包装类型

  • 每个基本类型都有对应的包装类型
  • 自动装箱和拆箱机制
Integer num = 100;    // 自动装箱
int n = num;          // 自动拆箱

3. 面试常考题

3.1 基本数据类型和包装类型的区别?

  1. 存储位置

    • 基本数据类型:存储在栈中
    • 包装类型:存储在堆中
  2. 默认值

    • 基本数据类型:有默认值(如int为0)
    • 包装类型:默认值为null
  3. 比较方式

    • 基本数据类型:使用==比较值
    • 包装类型:使用equals()比较值,==比较引用

3.2 String类的不可变性是什么?

String类的不可变性体现在:

  1. String类被final修饰,不能被继承
  2. 内部的char数组被private final修饰
  3. 不提供修改内部数组的方法
// String不可变性示例
String str = "Hello";
str = str + " World";    // 实际上创建了新的String对象

3.3 ==和equals的区别?

  1. ==

    • 比较基本数据类型:比较值
    • 比较引用类型:比较引用(内存地址)
  2. equals()

    • Object类的equals()方法默认与==相同
    • String等类重写了equals()方法,比较内容
String str1 = new String("Hello");
String str2 = new String("Hello");
 
System.out.println(str1 == str2);         // false
System.out.println(str1.equals(str2));    // true

4. 最佳实践

  1. 合理使用基本类型和包装类型

    • 频繁使用的小数据,优先使用基本类型
    • 需要存储null或使用泛型时,使用包装类型
  2. String操作优化

    • 大量字符串拼接时使用StringBuilder
    • 多线程环境下使用StringBuffer
  3. 避免可变性带来的问题

    • 重要的可变对象考虑深拷贝
    • 注意对象作为HashMap键时的不可变性
// 字符串拼接最佳实践
StringBuilder sb = new StringBuilder();
for (int i = 0; i < 1000; i++) {
    sb.append("item").append(i);
}
String result = sb.toString();

5. 反射机制

5.1 什么是反射?

反射机制允许程序在运行时获取任何类的内部信息,并能直接操作任意对象的内部属性及方法。

// 反射示例
public class ReflectionDemo {
    public static void main(String[] args) throws Exception {
        // 获取类的Class对象
        Class<?> clazz = Class.forName("com.example.Student");
        
        // 创建实例
        Object obj = clazz.newInstance();
        
        // 获取方法并调用
        Method method = clazz.getMethod("setName", String.class);
        method.invoke(obj, "张三");
    }
}

5.2 反射的应用场景

  1. 框架开发

    • Spring的依赖注入
    • MyBatis的对象映射
    • JUnit的测试用例加载
  2. 动态代理

    • AOP面向切面编程
    • RPC远程调用

6. 注解

6.1 什么是注解?

注解是一种代码级别的说明,可以对程序做出解释或者指示。

// 自定义注解示例
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface Test {
    String value() default "";
}
 
// 使用注解
public class TestDemo {
    @Test("测试方法")
    public void testMethod() {
        // 测试代码
    }
}

6.2 元注解有哪些?

  1. @Target:注解的作用目标
  2. @Retention:注解的生命周期
  3. @Documented:注解是否包含在JavaDoc中
  4. @Inherited:注解是否可以被继承

7. 泛型

7.1 什么是泛型?为什么要使用泛型?

泛型提供了编译时类型安全检测机制,可以在编译时检测到非法的类型。

// 泛型类示例
public class Box&lt;T&gt; {
    private T t;
    
    public void set(T t) {
        this.t = t;
    }
    
    public T get() {
        return t;
    }
}
 
// 使用泛型类
Box&lt;String&gt; stringBox = new Box&lt;&gt;();
stringBox.set("Hello World");

7.2 泛型通配符

  1. 上界通配符 <? extends Type>

    • 用于限制泛型类型的上界
    • 只能读取,不能写入
  2. 下界通配符 <? super Type>

    • 用于限制泛型类型的下界
    • 可以写入,读取时只能用Object接收

8. 异常处理

8.1 异常体系结构

  1. Throwable
    • Error:严重错误,程序无法处理
    • Exception:可以被程序处理的异常
// 异常处理示例
public class ExceptionDemo {
    public static void main(String[] args) {
        try {
            // 可能抛出异常的代码
            int result = divide(10, 0);
        } catch (ArithmeticException e) {
            // 处理异常
            System.out.println("除数不能为0");
        } finally {
            // 清理资源
            System.out.println("finally块总是执行");
        }
    }
    
    public static int divide(int a, int b) {
        return a / b;
    }
}

8.2 受检异常和非受检异常的区别?

  1. 受检异常(Checked Exception)

    • 必须显式处理或声明抛出
    • 代表可以恢复的异常情况
    • 如:IOException、SQLException
  2. 非受检异常(Unchecked Exception)

    • 不需要显式处理或声明
    • 代表编程错误
    • 如:NullPointerException、ArrayIndexOutOfBoundsException