Java面试八股

一、反射

1.反射是指在运行时检查和操作类、接口、字段、方法等程序结构的能力。通过反射,可以在运行时获取类的信息,创建类的实例,调用类的方法,访问和修改类的字段等

2.反射执行效率低的核心原因
(1) 编译期校验缺失:反射调用绕过编译期类型检查,运行时需动态解析类名、方法名,额外消耗CPU资源。
(2)元数据获取开销:需通过  Class  对象获取方法/字段的元数据(如参数类型、访问权限),涉及JVM内部数据结构查询。
(3)方法调用间接性:通过  Method.invoke()  调用,需处理参数装箱、权限检查,无法直接执行字节码指令。
(4)JIT优化受限:反射操作动态性强,JVM难以对其进行即时编译(JIT)优化,无法生成高效机器码。

//定义一个需要被反射的对象User
public class User {
    public String name="张三";
    private int age=13;
    public void publicMethod(){
        System.out.println("do public method");
    }
    private void privateMethod(){
        System.out.println("do private method");
    }
    public static void staticMethod(){
        System.out.println("do static method");
    }

    public static void main(String[] args) {
        try {
            //1.反射得到对象
            Class<?> clazz=Class.forName("User");
            //2.1得到公共方法 getMethod仅能获取公共方法,包括从父类继承的公共方法
            Method method=clazz.getMethod("publicMethod");
            //2.2 得到私有方法 getDeclaredMethod 能获取类中所有声明的方法,
            // 包括public protected 默认 private 但不包含父类继承的方法
            Method privateMethod=clazz.getDeclaredMethod("privateMethod");
            //设置私有方法可访问
            privateMethod.setAccessible(true);
            //2.3得到静态方法
            Method staticMethod=clazz.getDeclaredMethod("staticMethod");
            //3.1反射执行普通方法
            method.invoke(clazz.getDeclaredConstructor().newInstance());
            //3.2执行私有方法 clazz.getDeclaredConstructor()获取clazz对应类的无参构造方法
            //newInstance() 通过构造器,创建该类的实例对象
            //privateMethod.invoke 调用privateMethod表示的私有方法,并传入创建好的实例对象
            //整体:绕开访问权限
            privateMethod.invoke(clazz.getDeclaredConstructor().newInstance());
            //3.3执行静态方法
            //静态方法:类级别的方法,不需要实例化对象就能调用;而非静态:实例级别,必须依附实例才可执行
            staticMethod.invoke(clazz);
        } catch (ClassNotFoundException | NoSuchMethodException | InvocationTargetException | IllegalAccessException |
                 InstantiationException e) {
            throw new RuntimeException(e);
        }


        try {
            //1.反射得到对象
            Class<?> clazz=User.class; //静态加载;Class.forName("User")--动态加载:运行时根据类名字符串加载,若类为加载会触发加载流程
            //2.1反射得到公共属性值
            Field field=clazz.getDeclaredField("name");
            //2.2反射得到私有属性
            Field privateField=clazz.getDeclaredField("age");
            //设置私有属性可访问
            privateField.setAccessible(true);
            //3.1得到公共属性值
            String name=(String) field.get(clazz.getDeclaredConstructor().newInstance());
            //3.2得到私有属性值
            int age=(Integer) privateField.get(clazz.getDeclaredConstructor().newInstance());
            //4.打印属性值
            System.out.println("name->"+name);
            System.out.println("age->"+age);
        } catch (NoSuchFieldException | InvocationTargetException | IllegalAccessException | InstantiationException |
                 NoSuchMethodException e) {
            throw new RuntimeException(e);
        }
    }
}

二、克隆

1.克隆是指创建一个与原始对象相同的新对象。这个新对象通常具有与原始对象相同的属性和方法,但是它们是两个不同的对象,它们在内存中的位置不同
2.浅克隆[.clone()]与深克隆(不共享)(让所有引用类型的属性实现克隆,或使用 JSON 工具实现深克隆。)--实现:继承Clomeable接口并重写clone()方法
区别在于克隆出来的新对象是否与原始对象共享引用类型的属性

三、链式设置/调用
1.通过设置方法的返回值,让返回值变为对象自身,从而实现连续的方法调用,
2.每个方法返回的是对象自身或包含对象自身的容器,使得可以连续地进行多个操作,从而实现更复杂的功能

3.链式调用常用的三种实现方式:

(1)原生setter

public class Student {
    private String name;
    private int age;

    public Student name(String name) {
        this.name = name;
        return this;
    }

    public Student age(int age) {
        this.age = age;
        return this;
    }
}

Student stu = new Student()
        .name("磊哥")
        .age(18);

(2)@Setter @Getter

@Getter
@Setter
@Accessors(chain = true) //开启链式调用
public class Student {
    private String name;
    private int age;
}

//调用
Student stu = new Student()
	.setName("John")
	.setAge(30);

(3)@Builder

import lombok.Builder;

@Builder
public class Student {
    private String name;
    private int age;
}

Student stu = Student.builder()
    .name("磊哥")
    .age(18)
    .build();

四、Java内存模型 JMM

1.JMM:

(1)为了解决既要CPU性能高,又要不同变量间相互可见

(2)JMM是一种规范,定义Java虚拟机(JVM)和计算机内存协作的工作方式

(3)JMM的价值:保证高效且正确的运行

(4)JMM中重要部分:

        工作内存(存储主内存中的数据的副本)、可见性(可通过Volatile实现)、有序性(可通过Sychronized或volatile实现)

(5)volatile 
         含义:是 Java 中的一个关键字,用于修饰变量。它的核心作用是保证变量的可见性和禁止指令重排序。
        作用:
                可见性:当一个线程修改了  volatile  变量的值,其他线程能够立即看到这个修改后的值。例如,多个线程操作一个共享的  volatile  变量时,一个线程对它的修改会被快速同步到主内存,其他线程从主内存读取时能获取到最新值。
                禁止指令重排序:在一些情况下,Java 编译器和处理器为了优化性能会对指令执行顺序进行重排序, volatile  可以阻止这种重排序,保证代码的执行顺序与预期一致。它常用于多线程环境下对变量的同步操作,不过它不具备原子性(即不能保证复合操作的线程安全,比如  i++  操作)。

(6)synchronized 
        含义:是 Java 中的关键字,可用于修饰方法、代码块等,用于实现线程同步,解决多线程环境下的并发问题。
        作用:
                原子性:保证被  synchronized  修饰的代码块或方法在同一时间只能被一个线程执行,从而避免多线程同时操作共享资源导致的数据不一致问题。
                可见性:当线程释放锁时,会将对变量的修改同步到主内存;当线程获取锁时,会从主内存中读取最新的变量值,从而保证了变量的可见性。
                可重入性:同一个线程可以多次获取同一把锁,不会出现自己阻塞自己的情况。它是 Java 中实现线程安全的一种重要手段,常用于对共享资源的复杂操作场景,确保操作的原子性和线程安全。

2.计算机内存结构

(1)包括CPU 、一级缓存(L1)、二级缓存(L2)、主内存

(2)主内存与CPU处理器的运算能力指尖存在差距,会引入高速缓存(L2)作为主存与处理器之间的缓冲;CPU将常用的数据放在高速缓存中,运算结束后CPU再将运算结果同步到主内存中,就导致了多个线程在操作时,CPU缓存与主内存数据不一致的问题。

(3)简单说,就是多个指尖,变量是互不可见的。而 JMM就可以解决这种“不一致”的问题

3.happens-before规则(先行执行)

        是对JMM规范的具体实现

### 常见Java面试问题及答案 #### Java基础 1. **什么是Java中的多态?** 多态是指同一个接口可以被不同的类实现,或者同一方法可以在不同对象中有不同的表现形式。它通过继承和重写来实现[^1]。 2. **解释一下final关键字的作用?** `final` 关键字可以用在变量、方法和类上: - 如果用于变量,则表示该变量一旦赋值就不能再改变。 - 如果用于方法,则表示该方法不能被子类覆盖。 - 如果用于类,则表示该类不能被继承[^2]。 3. **String、StringBuilder 和 StringBuffer 的区别是什么?** - `String` 是不可变的字符串对象,每次修改都会创建新的实例。 - `StringBuilder` 是可变的字符序列,线程不安全。 - `StringBuffer` 同样是可变的字符序列,但它是线程安全的。 ```java // 示例代码 public class StringExample { public static void main(String[] args) { StringBuilder sb = new StringBuilder("Hello"); sb.append(" World"); // 不会创建新对象 System.out.println(sb.toString()); final int number = 10; // 使用final修饰的变量不能再更改 // number = 20; 这里会报错 } } ``` #### Java集合框架 1. **List、Set 和 Map 的主要区别是什么?** - `List` 接口允许重复元素并保持插入顺序。 - `Set` 接口不允许重复元素。 - `Map` 接口存储的是键值对,其中键唯一而值可以重复。 2. **HashMap 和 Hashtable 的区别有哪些?** - `HashMap` 是非同步的,而 `Hashtable` 是同步的。 - `HashMap` 可以有一个 null 键和多个 null 值,而 `Hashtable` 不支持任何 null 键或值。 ```java // HashMap 示例 import java.util.HashMap; public class HashMapExample { public static void main(String[] args) { HashMap<String, Integer> map = new HashMap<>(); map.put(null, 1); // 支持null键 map.put("One", null); // 支持null值 System.out.println(map); } } ``` #### JVM 1. **JVM内存结构分为哪几部分?** JVM 内存主要包括以下几个区域: - 方法区:存储已被虚拟机加载的类信息、常量、静态变量等。 - 堆:所有对象实例以及数组都在堆上分配。 - 虚拟机栈:每个线程都有自己的栈,保存局部变量表、操作数栈等。 - 本地方法栈:为 Native 方法服务。 - 程序计数器:记录当前线程所执行的字节码指令地址[^3]。 2. **GC的工作原理是什么?** GC(垃圾回收机制)负责自动管理内存资源,其工作方式主要有标记清除法、复制算法、分代收集法等。现代 JVM 中通常采用分代收集策略,将堆划分为年轻代和老年代分别处理。 #### Spring框架 1. **Spring的核心概念有哪些?** Spring 框架的主要核心概念包括依赖注入 (DI)、控制反转 (IoC)、面向切面编程 (AOP)[^4]。 2. **DispatcherServlet的作用是什么?** DispatcherServlet 是前端控制器,在整个请求流程中起到调度作用,接收所有的 HTTP 请求并将它们转发到相应的处理器。最后统一将返回的结果交给 ViewResolver 解析成实际视图。 ```xml <!-- Spring配置文件 --> <bean id="viewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver"> <property name="prefix" value="/WEB-INF/views/" /> <property name="suffix" value=".jsp" /> </bean> ```
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值