Java基础面试题

导读:本篇文章讲解 Java基础面试题,希望对大家有帮助,欢迎收藏,转发!站点地址:www.bmabk.com

Java常见面试题_2022最新版

序号 内容 链接
1 Java基础面试题 https://blog.csdn.net/weixin_46030002/article/details/126399353
2 Java集合容器面试题 https://blog.csdn.net/weixin_46030002/article/details/126425298
3 Java线程面试题 https://blog.csdn.net/weixin_46030002/article/details/126518395
4 Java异常面试题 https://blog.csdn.net/weixin_46030002/article/details/126482778
5 Spring常见面试题 https://blog.csdn.net/weixin_46030002/article/details/127281194
6 SpringMVC常见面试题 https://blog.csdn.net/weixin_46030002/article/details/127057785
7 Mybatis常见面试题 https://blog.csdn.net/weixin_46030002/article/details/126026561
8 MySQL常见面试题 https://blog.csdn.net/weixin_46030002/article/details/126557564
9 Redis常见面试题 https://blog.csdn.net/weixin_46030002/article/details/126435834
  • Java常见面试题_2022最新版持续更新中…

文章目录


一、基础语法面试题

(一)Java基础

八大基本类型及所占的字节数

请添加图片描述

float f=3.4;是否正确

  • 不正确
  • 3.4 是浮点型,Java中小数字面量默认是double类型,float f = 3.4 可以理解为我想将一个double类型的值赋值给float类型,是基本类型转换中的大转小,需要强转;float f = (float)3.4 或者我们在什么 3.4 的时候就规范这个3.4的类型 float f = 3.4F

short s1 = 1; s1 = s1 + 1;有错吗?short s1 = 1; s1 += 1;有错吗

  • short s1 = 1; s1 = s1 + 1;
    • 报错。整型运算时,默认会先转换为 int 类型,表示 s1+1 为一个int类型。需要强制类型转换 s1 = (short)(s1 + 1)
  • short s1 = 1; s1 += 1;
    • 不报错。因为 += 有默认的强制类型转换

String 是最基本的数据类型吗

不是,String是引用类型,底层维护的是char类型的数组

switch…catch 结构中,switch()括号里都可以传递什么类型的参数

  • byte
  • short
  • char
  • int
  • String(JDK1.7以后可以)
  • enum

&与&&的区别

& 是 位运算符;可以操作boolean类型,也可以操作数值类型;
&& 是逻辑运算符,表示逻辑与,只能操作boolean类型;
当运算符两边的表达式都为 true 时,结果才为 true,反之则为 false;而其中&&比较特别,我们又称短路与,当&&左边的表达式为 false 时,则不再执行&&右侧的表达式,结果也为 false,我们称之为短路,用一句话概括&&的规则:见 false 则 false;
|与||也同理,||也会出现短路功能,我们可以将短路或的规则一句话概括为:见 true 则 true

break ,continue ,return 的区别及作用?

  • break 跳出/结束当前循环,不再执行当前层次的循环(单层)
  • continue 跳过本次循环,进入下一次的条件判定
  • return 用于方法中
    • 无返回值:结束方法的执行
    • 有返回值:结束当前方法,返回结果给调用方

数组和冒泡排序

冒泡排序详解:

public class Sort {
    public static void main(String[] args) {
        int[] arr = {3,44,38,5,47,15,36,26,27,2,46,4,19,50,48};
        bubbleSort(arr);
        //[2, 3, 4, 5, 15, 19, 26, 27, 36, 38, 44, 46, 47, 48, 50]
        System.out.println(Arrays.toString(arr));
    }
    /**
     * 冒泡排序
     * @param arr   想要排序的数组
     */
    public static void bubbleSort(int[] arr){
        //控制比较轮数
        for (int i = 0; i < arr.length -1; i++) {
            //每轮比较多少次
            for (int j = 0; j < arr.length -i -1; j++) {
                if (arr[j] > arr[j + 1]) {
                    // temp 为一个临时变量,为了存储交换时的临时值
                    int temp = arr[j];
                    arr[j] = arr[j + 1];
                    arr[j + 1] = temp;
                }
            }
        }
    }
}

递归

求累加和

//递归:方法自己调用自己
//求 1~n 的和
public class Demo {
    public static void main(String[] args) {
       int sum= b1(100);
        System.out.println(sum);
    }

    private static int b1(int i) {
        if(i==1){
            return 1;
        }
        return i+b1(i-1);
    }
}

斐波那契数列

// 斐波那契数列,1,1,2,3,5,8,13...这样一个数列就是斐波那契数列,求第n项的值。
public static int f1(int n) {
    if(n < 1) {
        return 0;
    }else if(n == 1 || n == 2) {
        return 1;
    }
 
    return f1(n-1) + f1(n-2);
}

(二)面向对象

什么是面向对象

面向对象是以对象为核心来思考,解决问题的一种方式,它是 Java 核心的一种思想;
世间的万事万物我们都可以理解成一个对象,所以才有我们万物皆对象的说法。

面向对象的有哪些特征?以及你对这些特征的理解?

面向对象三大特征:封装,继承,多态

  1. 封装
    • 类:封装的是对象属性和行为
    • 方法:封装的是具体的业务逻辑功能
    • 访问控制修饰符:封装的是访问权限
  2. 继承
    继承是一种利用已有的类快速创建新的类的一种机制
    • 作用:代码的复用
    • 父类:所有子类共有的行为和属性
      子类:子类所特有的属性和行为
    • 子类继承父类后,子类具有:父类+子类
    • 单一继承,多实现,继承是具有传递性的
  3. 多态
    • 行为的多态,对象的多态
    • 多态的表现形式:行为的多态(重载,重写),对象的多态(向上造型,强制类型转换(instanceof)/向下转型)

面向对象的优点:易复用、易维护、易扩展,降低了系统代码的耦合度。

重写和重载的区别

  1. 重载(overload)
    • 发生在 同一个类 中,方法名相同,参数列表不同,方法体不同
    • 与返回值类型无关
    • 编译期绑定
  2. 重写(override)
    • 发生在 父子类 中,方法名称相同,参数列表相同(方法名称+参数列表=方法的签名)方法体不同
    • 重写遵循两同两小一大
      • 1)两同:方法名相同,参数列表相同(方法的签名)
      • 2)两小:(返回值类型、异常、访问权限)
        • A. 子类方法的返回值小于等于父类方法的返回值
          • a. void/基本类型返回值必须相同
          • b. 引用类型的返回值小于等于父类的返回值(父类大,子类小)
        • B. 子类方法抛出的异常小于或等于超类的方法抛出的异常
      • 3)一大:子类方法的访问权限大于或等于父类方法的访问权限
    • 运行期绑定

注意:构造方法不能重写,声明为 final 的方法不能被重写,声明为 static 的方法不能被重写,但是可以被再次声明;

构造方法可以重载吗

//构造方法可以重载
public class Aoo {
    String name;
    Aoo(){}//无参构造方法
    Aoo(String name){//含参构造方法
        this.name = name;
        System.out.println("超类");
    }
}

构造方法可以重写吗

//构造方法不可以重写
public class Aoo {
    String name;
    Aoo(){}//无参构造方法
    Aoo(String name){//含参构造方法
        this.name = name;
        System.out.println("超类");
    }
}
public class Boo extends Aoo{
    int age;
    Boo(){}
    Boo(String name,int age){
        super(name);//子类的构造方法中会调用父类的构造方法,但是不能重写
        this.age = age;
        System.out.println("派生类");
    }
}

构造器(构造方法)是如何工作的?(-)

Java 在构造实例时的顺序是这样的:

  • 分配对象空间,并将对象中成员初始化为 0 或 null,java 不允许用户操纵一个不定值的对象。
  • 执行属性值的显式初始化
  • 执行构造器
  • 将变量关联到堆中的对象上

this 与 super 的区别

  • this
    • this 指代的时当前对象
    • this.属性 调用的是当前对象的属性
    • this() 是对本类构造函数的调用
      • 必须放在构造方法的第一行,否则会出现编译错误
    • this.方法 调用的是当前对象的方法
  • super
    • super 指代的时当前对象父级(直接)对象
    • super.属性 指代的是超类对象的属性
    • super() 是对超类构造函数的调用
      • 必须放在构造方法的第一行,否则会出现编译错误
    • super.方法 调用的是父类对象的方法

在这里插入图片描述

访问控制修饰符有哪些?有什么区别?

访问范围 private default(默认的) protected public
本类中 可访问 可访问 可访问 可访问
同包中的其它类 不可访问 可访问 可访问 可访问
不同包中的子类 不可访问 不可访问 可访问 可访问
不同包中的非子类 不可访问 不可访问 不可访问 可访问

final 关键字

final 是最终的意思,可以修饰变量,方法,类

  • final 修饰的变量叫常量,常量必须初始化,初始化之后值就不能被修改。
  • final 修饰的方法不能被重写
  • final 修饰的类不能被继承

static 关键字

static 是静态的意思,常用于修饰变量和方法,当然也可以修饰代码块和内部类。
静态的特点:

  • 随着类的加载而加载
  • 优先于对象存在
  • 被所有对象所共享
  • 可以被类名点直接调用

注意事项:

  • 为什么静态方法只能访问静态成员?
    • 因为静态的内容是随着类的加载而加载,他是先进入内存中的
  • 静态方法中不能使用 this,super 关键字(静态方法中没有隐式的 this)

抽象类能使用 final 修饰吗?

不能,定义抽象类就是为了让其他类继承的,如果定义为 final 该类就不能被继承了,这样彼此就会产生矛盾,所以 final 不能修饰抽象类

静态代码块,构造代码块,构造方法,局部代码块的执行顺序

静态代码块>构造代码块>构造方法>局部代码块

// 静态代码块>构造代码块>构造方法>局部代码块
public class Test{
    public Test(){
        System.out.println("三");
    }
    public void aa(){
        System.out.println("一");
    }
    {
        System.out.println("九");
    }
    public class TestChild{
        public TestChild(){
            System.out.println("五");
        }
        {
            System.out.println("七");
        }
        public void bb(){
            System.out.println("二");
        }
    }

	public static void main(String[]args){
    	new Test().new TestChild().bb();//八,九,三,七,五,二
	}
	static{
    	System.out.println("八");
	}
}

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

变量:在程序执行的过程中,在某个范围内其值可以发生改变的量。从本质上讲,变量其实是内存中的一小块区域。
成员变量:类里方法外的变量,我们称为成员变量
局部变量:方法中的变量,我们称为局部变量
区别:

  • 作用域
    • 成员变量:针对整个类有效
    • 局部变量:只在某个范围内有效(一般指的时方法内或者代码块内)
  • 存储位置
    • 成员变量:随着对象的创建而存在,随着对象的消失而消失,存储在堆内存中。
    • 局部变量:在方法被调用,或者语句被执行的时候存在,存储在栈内存中。当方法调用完,或者语句结束后,就自动释放。
  • 生命周期
    • 成员变量:随着对象的创建而存在,随着对象的消失而消失。
    • 局部变量:当方法调用完,或者语句结束后,就自动释放。
  • 初始值
    • 成员变量:有默认初始值。
    • 局部变量:没有默认初始值,使用前必须赋值。
  • 使用原则
    • 在使用变量时需要遵循的原则为:就近原则。即:首先在局部范围找,有就使用;接着在成员位置找。

什么是值传递,什么是引用传递

值传递(pass by value)是指在调用函数时将实际参数的值复制一份传递到函数中,这样在函数中如果对参数的副本进行修改,将不会影响到原来的实际参数值。
引用传递(pass by reference)是指在调用函数时将实际参数的引用地址(引用的对象在堆中的内存地址)直接传递到函数中,那么在函数中对参数所进行的修改,将影响到实际参数。

错误理解一:值传递和引用传递,区分的条件是传递的内容,如果是个值,就是值传递。如果是个引用,就是引用传递。
错误理解二:Java是引用传递。
错误理解三:传递的参数如果是普通类型,那就是值传递,如果是对象,那就是引用传递。

Java是值传递还是引用传递

java中无论是基本类型还是引用类型,都是值传递:

  • 对于基本类型而言,传递的是具体的值的副本
  • 对于引用类型而言,传递的是具体的地址值的副本

静态变量与实例变量的区别

  • 调用方式
    • 静态变量也称为类变量,可以直接通过类名点调用,也可以通过对象名点(引用)调用[但是不建议]。这个变量是属于类的。
    • 实例变量只能通过对象名(引用)点调用,这个变量属于对象的。
  • 储存方式
    • 静态变量在类加载到内存的时候会对其进行分配空间,且只会分配一次内存空间,以后对该静态变量的操作都是在这一块内存上完成的,这块内存空间我们成为方法区/静态区。
    • 成员变量时在每创建一个对象时,都会对该对象的实例变量进行分配空间,这块内存空间我们成为堆内存。
  • 生命周期
    • 静态变量随着类的加载而存在,随着类的消失而消失,声明周期较长
    • 成员变量随着对象的创建而存在,随着对象的消失而消失
  • 与对象的相关性
    • 静态变量是所有对象共享的数据
    • 实例变量是每个对象所特有的数据

接口(interface)和抽象类(abstract class)的区别

  • 抽象类是由 abstract class 修饰的,接口是由 interface 修饰的,interface 需要被实现 implements,而 abstract class 需要被继承 extends
  • 抽象类中可以有成员变量,也可以有常量,接口中都是常量
  • 抽象类中可以有普通方法也可以有抽象方法,接口中都是抽象方法(Java8 以后可以有普通方法,但是普通方法必须由 static 或 default 修饰的
  • 抽象类中可以定义构造方法,接口中不能定义构造方法,但是都没有意思,因为不能被实例化
  • 抽象类中任何访问控制修饰符都可以,接口中访问控制修饰符只能为 public

接口的作用

  • 重要性:abstract class/interface 与对应的实体类这两种耦合机制才使得 Java 强大的面向对象思维得以实现
  • 简单,规范:项目庞大时,我们定义的一些关键的接口能告诉我们要实现具体的业务逻辑,使得代码开发简单,规范
  • 维护,扩展性:便于后期的维护和功能的扩展
  • 安全,严密性:接口是实现低耦合的重要手段,它描述了系统对外的所有服务,而不涉及具体的实现细节,这样比较安全,严密。

JDK 中常用的包有哪些

  • java.lang
    • 这个是系统的基础类,使用时不需要导包
  • java.util
    • 这个是系统的工具类,起到了辅助作用
  • java.io
    • 这里是所有和输入输出有关的类,包括文件的相关操作
  • java.net
    • 这里是与网络有关的类
  • java.sql
    • 这个是与数据库操作的类

JDK8新特性

  • 函数式接口
  • Stream API
  • 接口中的默认方法和静态方法
  • 新时间日期API
  • Optional

Lambda 语法

Lambda表达式可参考:Lambda表达式详解

(参数列表)->{
  方法体
}

这里引入了一个新的符号:-> ,我们称之为箭头符号
由上述语法可以看出,Lambda表达式由箭头符号分为了两部分:

  • 左侧:Lambda表达式中的参数列表
  • 右侧:Lambda表达式中的方法体/代码块

注意事项:Lambda表达式只能用于接口中只有一个抽象方法的情境中

Lambda 表达式什么时候用

当我们想使得我们的代码更简洁更灵活,我们使用 Lambda 表达式;
只有满足只有一个抽象方法的抽象类或者接口我们才能使用 Lambda 表达式

所有的接口都支持 Lambda 表达式嘛

Lambda表达式只能用于接口中只有一个抽象方法的情境中,一般我们称这种接口为函数式接口


二、API面试题

(一)String

== 和 equals 的区别

  • ==
    • 基本类型中,比较的是值是否相等
    • 引用类型中,比较的是引用是否相等
  • equals
    • equals 是 Object 的方法,默认的情况下比较的也是引用是否相等,实际就是 ==,但是很多类中重写了equals 方法,所以比较的就是对象的内容是否相等。
// ==  equals  ->  比较
int a = 5;
int b = 7;
System.out.println(a == b);
// == 比较基本类型的时候,比较的是 值是否相等
// == 比较引用类型的时候,比较的是 地址值是否相等(内存中地址不一样)
//equals 不能比较基本类型,只能比较引用类型
//equals 是 Object 的方法 
//       => public boolean equals(Object obj) {return (this == obj);}
//       -> 相当于 ==  -> 比较的就是 地址值
//如果我们重写了 equlas 方法,我们比较的就是值的相等
Student s1 = new Student("张三",15);
Student s2 = new Student("张三",15);
System.out.println(s1);//地址值 com.cy.entity.Student@16e8e07
System.out.println(s2);//地址值 com.cy.entity.Student@16e8e08
System.out.println(s1 == s2);//地址值不相等,所以结果为 false
System.out.println(s1.equals(s2));//不重写 equals 结果为 false,重写 equlas 结果为 true

String 中有哪些常用的方法

  • charAt() 返回指定索引处的字符
  • indexOf/lastIndexOf() 返回指定字符的索引
  • startsWith/endsWith() 以什么开头/以什么结尾
  • subString() 截取字符串
  • matches() 此字符串是否匹配给定的正则表达式。
  • split() 分割字符串,返回一个分割后的字符串数组
  • toLowerCase/toUpeerCase() 将字符串转成小写字母/将字符串转成大写字符
  • trim() 去除字符串两端空白
  • replaceAll() 字符串替换
  • length() 返回字符串长度
  • valueOf() 将其他类型转换成字符串类型
  • isEmpty() 判断字符串是否为空
  • getBytes() 返回字符串的 byte 类型数组
  • contains() 字符串中是否包含指定字符
  • compareTo() 按字典顺序比较两个字符串

是否可以继承String 类

不能,因为 String 类是由 final 修饰的类,故不能被继承

String s = new String(“abc”);创建了几个字符串对象

创建了一个或者两个 String 类型对象

  • new 对象的时候,系统会先检测常量池中是否含有”abc”这个字符串对象,如果有,则不在常量池中创建,只在堆中开辟一个空间存放 String 对象。
  • 如果字符串常量池中没有这个字符串对象,则在常量池中和堆中各创建一个对象。

String s = new String(“ab”+“c”);创建了几个字符串对象

创建了一个或者两个 String 类型对象
“ab”+“c” 在编译时 自动 转变成”abc”

  • new 对象的时候,系统会先检测常量池中是否含有”abc”这个字符串对象,如果有,则不在常量池中创建,只在堆中开辟一个空间存放 String 对象。
  • 如果字符串常量池中没有这个字符串对象,则在常量池中和堆中各创建一个对象

String,StringBuilder,StringBuffer 的区别

  • String,StringBuffer,StringBuilder 这三者都是操纵字符串的类
  • String 底层是由 final 修饰的 char[],声明的对象不可以被改变。如果每次改变相当于重新生成一个 String 对象,并将指针指向新的对象;
  • StringBuffer,StringBuilder 没有被 final 修饰,并且提供了一个自动扩容的机制(初始的默认长度为 16),会自动扩容。扩容的长度为原长度的 2 倍加 2,所以在对于拼接字符串效率要比 String 要高;
  • StringBuffer,StringBuilder 虽然都是可变的字符串,但是 StringBuffer 是由 synchronized 锁修饰的,线程安全,但是效率较低。
  • 从执行效率来讲:StringBuilder > StringBuffer > String

如何将字符串进行反转

//使用 StringBuilder 或者 StringBuffer 的 reverse()方法
String s = "123456789";
StringBuilder sb = new StringBuilder(s);
sb.reverse();
s = sb.toString();
System.out.println(s);

数据类型的转换

  • 基本类型转字符串
    • 字符串拼接,拼接一个字符串的空串””
      • 例如:5 + ""
    • 调用 String 类中 valueOf()方法,返回相应的字符串
      • 例如:String.valueOf(5)
    • 调用 Integer 类中 toString()方法,返回相应的字符串
      • 例如:Integer.toString(5)
  • 字符串转基本类型
    • 调用Integer类中 parsexx(String s)方法
      • 例如:Integer.parseInt("10")
    • 调用Integer类中 valueOf(String s)方法
      • 例如:Integer.valueOf("8").inValue()

说说 equals 和 hashcode 方法

  • 如果两个对象 equals 相等,则 hashcode 一定也是相同
  • 两个对象的 hashcode 值相等,它们的 equals 不一定是相等

hashCode() 的作用是获取哈希码,也称为散列码;这个哈希码的作用是确定该对象在哈希表中的索引位置。这种散列表的存储结构是键值对的方式(key-value),可以根据这个键(key)快速检索出对应的值(value),以为着可以快速找到所需要的对象。
equals 的作用默认是比较内存中的地址是否相等,重写了 equals 方法后,比较的就是内容是否相等


(二)IO流

Java中 IO 流分为几种

  • 按照流的流向分
    • 输入流
      • 读操作,将文件读入到内存
      • InputStream 字节输入流基类
      • Reader 字符输入流基类
    • 输出流
      • 写操作,将内存中的内容写入到文件
      • OutputStream 字节输出流基类
      • Writer 字符输出流基类
  • 按照单元划分
    • 字节流
    • 字符流
  • 按照流的角色划分
    • 节点流
      • 直接与数据源相连
    • 处理流
      • 用于对节点流性能的处理1

Java IO流 共涉及40多个类,这些类看上去很杂乱,但是都是从上述的四个抽象类基类派生出来的
在这里插入图片描述

同步,异步,阻塞,非阻塞的区别

  • 同步
    • 一个任务完成之前不能做其他操作,必须等待(打电话/一个队伍排队买票)
  • 异步
    • 一个任务完成之前可以进行其他操作(微信聊天/不同队伍排队买票)
  • 阻塞
    • 对于CPU而言,挂起当前线程,不能做其他操作,只能等待
  • 非阻塞
    • 无须挂起当前线程,可以去执行其他操作

BIO,NIO,AIO 有什么区别

  • BIO Block IO 同步阻塞式IO
    • 传统IO,模式简单使用方便
    • JDK1.4以前的唯一选择
    • 面向流,单向读写
  • NIO Non IO 同步非阻塞IO
    • BIO 的升级版,客户端和服务端通过 Channel (通道)通讯,适合并发
    • JDK1.4之后支持
    • 面向缓冲,双向读写
    • 聊天服务器
  • AIO Asynchronous IO 异步非堵塞IO
    • NIO 的升级版,实际属于 nio ,但是解决了 nio 不能异步实现的问题
    • JDK1.7之后支持
    • 相册服务器

说说对序列化的理解,是怎么实现的,什么场景下需要它

  • 序列化是指将 Java 对象转换为字节序列(二进制形式)的过程(内存 -> 硬盘)
  • 反序列化则是将字节序列(二进制文件)转换为 Java 对象的过程(硬盘 -> 内存)

Java 对象序列化必须实现 Serializable 接口,使得对象能通过网络传输或者文件储存等方式传输。
如果不想将某个字段序列化,则在属性上添加 transient 关键字 修饰。
本质上讲,序列化就是把实体对象状态按照一定的格式写入到有序字节流,反序列化就是从有序字节流重建对象,恢复对象状态。

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/107633.html

(0)
小半的头像小半

相关推荐

极客之音——专业性很强的中文编程技术网站,欢迎收藏到浏览器,订阅我们!