分享几道常见的java面试题

简介: (1)类初始化执行顺序 1.类初始化过程 一个类要创建实例需要先加载并初始化该类 main方法所在的类需要先加载和初始化 一个子类要初始化需要先初始化父类 一个类初始化就是执行()方法 < clini

(1)类初始化执行顺序

/*
 * 父类的初始化<clinit>:
 * (1)j = method(); 父类的静态类变量    (5)
 * (2)父类的静态代码块                  (1)
 *
 *  父类的实例化方法:
 * (1)super()(最前)
 * (2)i = test();父类的非静态实例变量   (9)为什么这里是9,因为子类重写了该test()方法
 * (3)父类的非静态代码块                (3)
 * (4)父类的无参构造(最后)            (2)
 *
 * 非静态方法前面其实有一个默认的对象this
 * this在构造器(或<init>)它表示的是正在创建的对象,因为这里是在创建Son对象,所以
 * test()执行的是子类重写的代码(面向对象多态)
 *
 * 这里i=test()执行的是子类重写的test()方法
 */
public class Father {
    private int i = test();
    private static int j = method();
    static {
        System.out.print("(1)");
    }
    Father() {
        System.out.print("(2)");
    }
    {
        System.out.print("(3)");
    }
    public int test() {
        System.out.print("(4)");
        return 1;
    }
    public static int method() {
        System.out.print("(5)");
        return 1;
    }
}

/*
 * 先初始化父类:(5) (1)
 * 初始化子类:  (10)(6)
 *
 * 子类的初始化<clinit>:
 * (1)j = method(); 子类的静态类变量      (10)
 * (2)子类的静态代码块                    (6)
 *
 * 子类的实例化方法<init>:
 * (1)super()(最前,父类的)              (9)(3)(2)
 * (2)i = test(); 子类的非静态实例变量    (9)
 * (3)子类的非静态代码块                  (8)
 * (4)子类的无参构造(最后)              (7)
 *
 * 因为创建了两个Son对象,因此实例化方法<init>执行两次
 * <clinit>只会执行一次
 * (9)(3)(2)(9)(8)(7)
 */
public class Son extends Father {
    private int i = test();
    private static int j = method();
    static {
        System.out.print("(6)");
    }
    Son() {
        super();//写或不写都在,在子类构造器中一定会调用父类的构造器
        System.out.print("(7)");
    }
    {
        System.out.print("(8)");
    }
    public int test() {
        System.out.print("(9)");
        return 1;
    }
    public static int method() {
        System.out.print("(10)");
        return 1;
    }
    // 执行子类,下面代码输出的结果
    public static void main(String[] args) {
        Son s1 = new Son();
        System.out.println();
        Son s2 = new Son();
        // 结果:
        // (5)(1)(10)(6)(9)(3)(2)(9)(8)(7)
        // (9)(3)(2)(9)(8)(7)
    }
}
AI 代码解读

1.类初始化过程

  1. 一个类要创建实例需要先加载并初始化该类

    • main方法所在的类需要先加载和初始化
  2. 一个子类要初始化需要先初始化父类
  3. 一个类初始化就是执行()方法

    • < clinit >()方法由静态类变量显示赋值代码和静态代码块组成
    • 静态类变量显示赋值代码和静态代码块代码从上到下顺序执行(哪个在上面,谁先执行)
    • < clinit >()方法只执行一次

2.实例初始化过程

  1. 实例初始化就是执行()方法

    • < init >()方法可能重载有多个,有几个构造器就有几个方法
    • < init >()方法由非静态实例变量显示赋值代码和非静态代码块、对应构造器代码组成
    • 非静态实例变量显示赋值代码和非静态代码块代码从上到下顺序执行,而对应构造器的代码最后执行(哪个在上面,谁先执行)
    • 每次创建实例对象,调用对应构造器,执行的就是对应的方法
    • < init >方法的首行是super()或super(实参列表),即对应父类的方法

3.方法的重写Override

  1. 哪些方法不可以被重写

    • final方法
    • 静态方法
    • private等子类中不可见方法
  2. 对象的多态性

    • 子类如果重写了父类的方法,通过子类对象调用的一定是子类重写过的代码
    • 非静态方法默认的调用对象是this
    • this对象在构造器或者说方法中就是正在创建的对象
  • 总结执行顺序:
  • 父类的静态类变量、静态代码块(谁写在代码前面,谁先执行)
  • 子类的静态类变量、静态代码块
  • 父类的非静态变量(有可能是通过非静态方法赋值,即有可能被子类重写)、非静态代码块、无参构造方法
  • 子类的非静态变量、非静态代码块、无参构造方法

(2).方法参数传递传递机制

/**
 * 方法的参数传递机制
 * 形参是基本数据类型
 *      传递数据值
 * 实参是引用数据类型
 *      传递地址值
 * 特殊的类型:String、包装类等对象不可变性
 */
public class Exam4 {
    // 执行main方法,下面代码输出的结果
    public static void main(String[] args) {
        int i = 1;
        String str = "hello";
        Integer num = 200;
        int[] arr = {1, 2, 3, 4, 5};

        MyData my = new MyData();
        change(i, str, num, arr, my);

        System.out.println("i = " + i);                       //1
        System.out.println("str = " + str);                   //hello
        System.out.println("num = " + num);                   //200
        System.out.println("arr = " + Arrays.toString(arr));  //[2,2,3,4,5]
        System.out.println("my.a = " + my.a);                 //11
    }

    public static void change(int j, String s, Integer n, int[] a, MyData m) {
        j += 1;
        s += "world";
        n += 1;
        a[0] += 1;
        m.a += 1;
    }
}
class MyData {
    int a = 10;
}
AI 代码解读

方法的参数传递机制

  • 形参是基本数据类型

    • 传递数据值
  • 实参是引用数据类型

    • 传递地址值
  • 特殊的类型:String、包装类等对象不可变性
  • 代码执行过程分析

代码执行过程分析

(3).成员变量和局部变量

public class Exam5 {
    static int s;//成员变量,类变量(方法区)
    int i;//成员变量,实例变量(堆)
    int j;//成员变量,实例变量(堆)
    {
        int i = 1;//非静态代码块中的局部变量 i
        i++;
        j++;
        s++; //类变量是共享的,所以每个实例对象初始化的时候,都会被加1
    }
    public void test(int j){//形参,局部变量,j(栈)
        j++;
        i++;
        s++;
    }
    // 执行main方法,下面代码输出的结果
    public static void main(String[] args) {//形参,局部变量,args
        Exam5 obj1 = new Exam5();//局部变量,obj1
        Exam5 obj2 = new Exam5();//局部变量,obj1
        obj1.test(10);
        obj1.test(20);
        obj2.test(30);
        System.out.println(obj1.i + "," + obj1.j + "," + obj1.s);  // 2,1,5
        System.out.println(obj2.i + "," + obj2.j + "," + obj2.s);  // 1,1,5
    }
}
AI 代码解读
  • 就近原则
  • 变量的分类

    • 成员变量:类变量、实例变量
    • 局部变量
  • 非静态代码块的执行:每次创建实例对象都会执行
  • 方法的调用规则:调用一次执行一次

局部变量与成员变量的区别:

1. 声明的位置
  • 局部变量:方法体{}中,形参,代码块{}中
  • 成员变量:类中方法外

    • 类变量:有static修饰
    • 实例变量:没有static修饰
2. 修饰符
  • 局部变量:final
  • 成员变量:public、protected、private、final、static、volatile、transient
3. 值存储的位置
  • 局部变量:栈
  • 实例变量:堆
  • 类变量:方法区

局部变量与成员变量的区别:

4.作用域
  • 局部变量:从声明处开始,到所属的}结束
  • 实例变量:在当前类中“this.”(有时this.可以缺省),在其他类中“对象名.”访问
  • 类变量:在当前类中“类名.”(有时类名.可以省略),在其他类中“类名.”或“对象名.”访问
5.生命周期
  • 局部变量:每一个线程,每一次调用执行都是新的生命周期
  • 实例变量:随着对象的创建而初始化,随着对象的被回收而消亡,每一个对象的实例变量是独立的
  • 类变量:随着类的初始化而初始化,随着类的卸载而消亡,该类的所有对象的类变量是共享的 (注意)
当局部变量与xx变量重名时,如何区分:
  • 局部变量与实例变量重名

    • 在实例变量前面加“this.”
  • 局部变量与类变量重名

    • 在类变量前面加“类名.”
  • 代码执行过程分析

代码执行过程分析

(4)自增自减的问题

public class VariableTest {
    /**
     * 赋值=,最后计算
     * =右边的从左到右加载值依次压入操作数栈
     * 实际先算哪个,看运算符优先级
     * 自增、自减操作都是直接修改变量的值,不经过操作数栈
     * 最后的赋值之前,临时结果也是存储在操作数栈中
     */
    public static void main(String[] args) {
        int i = 1;
        i = i++; // 执行结果:i=1
        int j = i ++; // 执行结果:j=1,i=2
        int k = i + ++i * i++;  // 执行结果:2+3*3=11
        System.out.println("i=" + i);  // 4
        System.out.println("j=" + j);  // 1
        System.out.println("k=" + k);  // 11
    }
}
AI 代码解读

(5)单例模式(饿汉式和懒汉式)

  • 饿汉式
/**
 * 饿汉式
 *  1.直接实例化饿汉式
 * (1)构造器私有化
 * (2)自行创建,并且用静态变量保存
 * (3)向外提供这个实列
 * (4)强调这是一个单例,用final修饰(不可被修改)
 */
public class Singleton1 {
    public static final Singleton1 INSTANCE = new Singleton1();
    private Singleton1() {}
}

/**
 * 饿汉式:
 * 2.枚举类型:表示该类型的对象是有限的几个
 * 我们就可以限定为一个单例
 */
public enum Singleton2 {
    INSTANCE
}

/**
 * 饿汉式:
 * 3.静态代码块饿汉式
 * (需要读取到配置文件)
 */
public class Singleton3 {
    public static final Singleton3 INSTANCE;
    private String info;
    
    static {
        try {
            // 从配置文件中获取info(resource下面即可)
            Properties properties = new Properties();
            properties.load(Singleton3.class.getClassLoader().getResourceAsStream("singleton.properties"));
            INSTANCE = new Singleton3(properties.getProperty("info"));
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }
    // 构造方法私有化
    private Singleton3(String info) {
        this.info = info;
    }
    public String getInfo() {
        return info;
    }
    public void setInfo(String info) {
        this.info = info;
    }
    @Override
    public String toString() {
        return "Singleton3{" +
                "info='" + info + '\'' +
                '}';
    }
}

public class TestMain1 {
    /**
     * 饿汉式:直接创建对象,不存在线程安全问题(在类初始化的时候创建对象)
     * 1.直接实例化饿汉式(简洁直观)
     * 2.枚举式(最简洁)(推荐使用)
     * 3.静态代码块饿汉式(适合复杂实例化)
     */
    public static void main(String[] args) {
        Singleton1 s1 = Singleton1.INSTANCE;
        System.out.println(s1);

        Singleton2 s2 = Singleton2.INSTANCE;
        System.out.println(s2);

        Singleton3 s3 = Singleton3.INSTANCE;
        System.out.println(s3);
    }
}
AI 代码解读
  • 懒汉式
/**
 * 懒汉式:(延迟创建这个实例对象,当需要使用到的时候再创建)
 * 1.适用于单线程,多线程不行
 * (1)构造器私有化
 * (2)用一个静态变量保存这个唯一的实列
 * (3)提供一个静态方法,获取这个实例对象
 */
public class Singleton4 {
    private static Singleton4 instance;
    private Singleton4() {}

    public static Singleton4 getInstance() {
        if (instance == null) {
            try {
                Thread.sleep(100);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            instance = new Singleton4();
        }
        return instance;
    }
}

/*
 * 懒汉式:(延迟创建这个实例对象,当需要使用到的时候再创建)
 * 2.线程安全(适用于多线程)
 * (1)构造器私有化
 * (2)用一个静态变量保存这个唯一的实例
 * (3)提供一个静态方法,获取这个实例对象
 */
public class Singleton5 {
    private static Singleton5 instance;
    private Singleton5(){}
    public static Singleton5 getInstance(){
        // 加了if,是提高性能的问题(instance已经有了,直接返回)
        if(instance == null){
            // 下面这块已经解决安全问题
            synchronized (Singleton5.class) {
                if(instance == null){
                    try {
                        Thread.sleep(1000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    instance = new Singleton5();
                }
            }
        }
        return instance;
    }
}

/*
 * 懒汉式:(延迟创建这个实例对象,当需要使用到的时候再创建)
 * 3.静态内部类形式(适用于多线程)(推荐使用)
 * 在内部类被加载和初始化时,才创建INSTANCE实例对象
 * 静态内部类不会自动随着外部类的加载和初始化而初始化,它是要单独去加载和初始化的。
 * 因为是在内部类加载和初始化时,创建的,因此是线程安全的
 */
public class Singleton6 {

    private Singleton6() {}

    private static class Inner {
        private static final Singleton6 INSTANCE = new Singleton6();
    }

    public static Singleton6 getInstance() {
        return Inner.INSTANCE;
    }
}


public class TestMain2 {
    /**
     * 懒汉式:延迟创建对象
     * 1.线程不安全(使用于单线程)
     * 2.线程安全(适用于多线程)
     * 3.静态内部类形式(适用于多线程)(推荐使用)
     */
    public static void main(String[] args) throws ExecutionException, InterruptedException {
        // 1.单线程
        // Singleton4 s1 = Singleton4.getInstance();
        // Singleton4 s2 = Singleton4.getInstance();
        // System.out.println(s1 == s2); // 结果为true

        // 2.多线程
        Callable<Singleton4> c = new Callable<Singleton4>() {
            public Singleton4 call() throws Exception {
                return Singleton4.getInstance();
            }
        };
        // 创建两个线程的线程池
        ExecutorService es = Executors.newFixedThreadPool(2);
        Future<Singleton4> f1 = es.submit(c);
        Future<Singleton4> f2 = es.submit(c);
        Singleton4 s3 = f1.get();
        Singleton4 s4 = f2.get();
        System.out.println(s3 == s4); // 结果不一定为true
        es.shutdown();
    }
}
AI 代码解读
目录
打赏
0
0
1
0
330
分享
相关文章
最新技术栈下 Java 面试高频技术点实操指南详解
本指南结合最新Java技术趋势,涵盖微服务(Spring Cloud Alibaba)、响应式编程(Spring WebFlux)、容器化部署(Docker+Kubernetes)、函数式编程、性能优化及测试等核心领域。通过具体实现步骤与示例代码,深入讲解服务注册发现、配置中心、熔断限流、响应式数据库访问、JVM调优等内容。适合备战Java面试,提升实操能力,助力技术进阶。资源链接:[https://pan.quark.cn/s/14fcf913bae6](https://pan.quark.cn/s/14fcf913bae6)
97 25
常见 JAVA 集合面试题整理 自用版持续更新
这是一份详尽的Java集合面试题总结,涵盖ArrayList与LinkedList、HashMap与HashTable、HashSet与TreeSet的区别,以及ConcurrentHashMap的实现原理。内容从底层数据结构、性能特点到应用场景逐一剖析,并提供代码示例便于理解。此外,还介绍了如何遍历HashMap和HashTable。无论是初学者还是进阶开发者,都能从中受益。代码资源可从[链接](https://pan.quark.cn/s/14fcf913bae6)获取。
72 3
2025 最新史上最全 Java 面试题独家整理带详细答案及解析
本文从Java基础、面向对象、多线程与并发等方面详细解析常见面试题及答案,并结合实际应用帮助理解。内容涵盖基本数据类型、自动装箱拆箱、String类区别,面向对象三大特性(封装、继承、多态),线程创建与安全问题解决方法,以及集合框架如ArrayList与LinkedList的对比和HashMap工作原理。适合准备面试或深入学习Java的开发者参考。附代码获取链接:[点此下载](https://pan.quark.cn/s/14fcf913bae6)。
167 48
2025 年一线互联网大厂最新高质量 Java 面试八股文整理及答案汇总
本文整理了一线互联网大厂最新的高质量Java面试八股文及其答案,涵盖Java基础、集合框架与多线程三大核心模块。内容包括面向对象与面向过程的区别、`equals`与`==`的差异、`final`和`static`的用法、集合类如`ArrayList`与`LinkedList`的对比、`HashMap`的工作原理及其与`Hashtable`的区别,以及多线程中的线程创建方式、生命周期、上下文切换和死锁等知识点。通过系统化的梳理与解析,帮助读者高效备考Java面试,掌握核心技术要点。资源可从文末链接下载。
227 40
|
20天前
|
Java Redis 面试题集锦 常见高频面试题目及解析
本文总结了Redis在Java中的核心面试题,包括数据类型操作、单线程高性能原理、键过期策略及分布式锁实现等关键内容。通过Jedis代码示例展示了String、List等数据类型的操作方法,讲解了惰性删除和定期删除相结合的过期策略,并提供了Spring Boot配置Redis过期时间的方案。文章还探讨了缓存穿透、雪崩等问题解决方案,以及基于Redis的分布式锁实现,帮助开发者全面掌握Redis在Java应用中的实践要点。
62 6
2025 年最新 Java 面试从基础到微服务实战指南全解析
《Java面试实战指南:高并发与微服务架构解析》 本文针对Java开发者提供2025版面试技术要点,涵盖高并发电商系统设计、微服务架构实现及性能优化方案。核心内容包括:1)基于Spring Cloud和云原生技术的系统架构设计;2)JWT认证、Seata分布式事务等核心模块代码实现;3)数据库查询优化与高并发处理方案,响应时间从500ms优化至80ms;4)微服务调用可靠性保障方案。文章通过实战案例展现Java最新技术栈(Java 17/Spring Boot 3.2)的应用.
85 9
Java 基础知识面试题全解析之技术方案与应用实例详解
本内容结合Java 8+新特性与实际场景,涵盖函数式编程、Stream API、模块化、并发工具等技术。通过Lambda表达式、Stream集合操作、Optional空值处理、CompletableFuture异步编程等完整示例代码,助你掌握现代Java应用开发。附面试题解析与技术方案,提升实战能力。代码示例涵盖计算器、员工信息统计、用户查询、模块化系统设计等,助你轻松应对技术挑战。
56 8
2025 年 Java 面试必备最常见 200 + 面试题及答案解析
这是一份针对Java面试的综合技术方案与应用实例文档,涵盖Java基础(JDK/JRE、字符串、IO流)、容器(ArrayList/LinkedList、HashMap)、多线程(线程创建、同步、线程池)、数据库(MySQL索引、Redis缓存穿透)及Spring框架(IOC容器、热部署)等核心模块。通过详细解析常见面试题,帮助读者深入理解并掌握Java核心技术,为应对面试提供全面指导。此外,还涉及反射、设计模式、JVM调优等进阶内容,助力开发者全面提升技能。代码示例可从提供的链接下载。
114 6
Java 集合篇面试题全面总结及答案解析
本文总结了Java集合框架的核心概念、常见集合类的特性与应用场景,以及开发中可能遇到的问题与解决方案。内容涵盖集合框架的基础接口(如Collection、Set、List、Map)、泛型的优点、线程安全集合类(如ConcurrentHashMap、CopyOnWriteArrayList)、常见集合类的区别(如ArrayList与LinkedList、HashMap与HashTable)等。此外,还详细介绍了如何实现LRU缓存、FIFO队列、优先级队列及栈等数据结构,并提供了相关代码示例。通过本文,读者可以全面掌握Java集合相关的面试知识点及其实际应用技巧。
44 1
2025 校招必看:Java 开发面试核心知识点深度解析及最新笔面试题汇总
本文针对2025校招Java开发面试,系统梳理了Java基础、集合框架、多线程并发、JVM等核心知识点,并附带最新笔面试题。内容涵盖封装、继承、多态、异常处理、集合类使用、线程同步机制、JVM内存模型及垃圾回收算法等。同时深入探讨Spring、数据库(MySQL索引优化、Redis持久化)、分布式系统(CAP理论、分布式事务)等相关知识。通过理论结合实例解析,帮助考生全面掌握面试要点,提升实战能力,为成功拿下Offer奠定坚实基础。
109 2
AI助理

你好,我是AI助理

可以解答问题、推荐解决方案等