Java基础高频面试题带答案

本文深入讲解Java OOP思想,解析重载与重写区别,探讨Java接口与抽象类的不同之处,介绍单例模式及其实现方式,对比String、StringBuilder与StringBuffer的优劣,阐明==与equals、hashCode和equals的关系,梳理Java异常体系,详解final关键字的用法,阐述泛型的概念与好处,剖析冒泡排序算法,并解释BIO、NIO、AIO的区别。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

深入理解OOP思想

面向对象的三大特征是封装、继承、多态。

封装是指一个类可以有一些私有的属性和方法,可以把功能封装起来,对外只提供一部分接口。

继承是指:一个类可以继承另一个类的非私有属性和方法,这样的话,被继承的类的属性和方法就可以被复用。

多态是指:同一个类实例化出来的子对象,通过调用同一个方法,可以得到不同的结果,这就是多态。

重载和重写的区别

重载:发生在同一个类中,方法名必须相同,参数类型、个数、顺序可以不同,方法返回值和访问修饰符可以不同

    // 重载,方法名必须相同,参数列表,顺序不同,方法返回值和访问修饰符可以不同
    public void a(){

    }
    private int a(int a){
        return 1;
    }

重写:发生在父类和子类中,方法名、参数列表,返回值类型必须相同,抛出的异常范围小于等于父类,访问权限不能比父类中被重写的方法的访问权限更低,父类中方法的访问修饰符为private,则子类就不能重写该方法

    public String a (){
        return null;
    }    
    // 重写,方法名,参数列表,顺序,返回值类型必须相同。子访问修饰符必须大于等于父类,抛出的异常范围小于等于父类
    @Override
    public String a(){
      return null;
    }

Java接口和抽象类有什么区别?

  1. 首先,接口中的所有方法默认都是抽象的,而抽象类中可以存在普通的成员函数

  2. 接口中声明的变量默认是public static final修饰的,方法的访问修饰符默认是public。而抽象类的成员变量可以是各种类型的。

  3. 一个类可以实现多个接口,但只能继承一个抽象类。接口和抽象类都不能实例化。


接口的设计目的是对类进行约束,而抽象类的设计目的是代码复用。当你关注一个事物的本质的时候,用抽象类;当关注一个操作的时候用接口。

什么是单例模式?有几种?

单例模式是:某个类的实例在多线程环境下只会被创建一次出来

  • 饿汉式单例模式:线程安全,比较常用,但容易产生垃圾,因为一开始就初始化
class Singleton{
    private static Singleton instance = new Singleton();
    private Singleton(){}
    
    public static Singleton getInstance(){
        return instance;
    }
}
  • 懒汉式单例模式:非线程安全,延迟初始化,严格意义上不是单例模式
class Singleton{
    private static Singleton instance;
    private Singleton(){}
    
    public static Singleton getInstance(){
        if(instance==null){
            instance = new Singleton();
        }
        return instance;
    }
}
  • 双锁机制的懒汉式单例模式:线程安全,延迟初始化。这种方式采用双锁机制,安全且在多线程的情况下还能保证高性能
    1. 进行了两次判断,第一次是为了避免不必要的实例
    2. 第二次是为了进行同步,避免多线程问题。使用volatile修饰signleton实例变量有效,解决该问题
class Singleton{
    private static volatile Singleton instance;
    private Singleton(){}
    
    public static Singleton getInstance(){
        if(instance==null){
            synchroniced(Singleton.class){
                 if(instance==null){
                     instance = new Singleton();
                 }
            }
        }
        return instance;
    }
}

String,StringBuilder和StringBuffer的区别?

提示:区别的问题?相同点 不同点 为什么不同

String,String Builder和StringBuffer三者都可以用来操作字符串,但是在效率上区别比较大。String因为底层是由final修饰的char数组,导致内容不可变,因此在字符串拼接的时候,会创建多个对象,并且数组长度确定后不可以更改,涉及到内容的赋值,因此带来大量的性能和内存开销,效率太低。

而StringBuilder与StringBuffer在拼接字符串,返回值是当前操作对象,不会创建多个对象,因此效率相对较高。但是StringBuffer由于底层使用synchornized同步锁,保证了线程安全,因此效率相对StringBuilder较低一些。因此在平常的工作中如果没有涉及到线程安全我们都是使用的String Builder。

==和equals的区别

双等号和equals都可以比较对象是否相等。

但是双等号在判断基本数据类型的时候比较的是值,判断引用数据类型的时候比较的是内存地址。

equals的话,它在类中没有被重写的话,其作用和双等号一样;如果在类中重写了equals()方法的话,则只比较两个对象的内容是否相等。

hashCode和equals

hashCode的作用是获取哈希值,能够根据键快速的检索出对应的值

为什么要有hashCode,单独的equals不行吗?

  1. 当对象加入的时候,hashCode值会先来判断对象加入的位置
    1. 如果该位置没有值,hashSet会假设该对象没有出现过。
    2. 如果有值,这时候会调用equals()方法来检查两个对象是否真的相同
      1. 如果相同则加入失败,
      2. 不同的话就会重新散列到其他位置进行比较。
  2. 可以大大减少equals()的次数,相应的就大大提高了执行速度。

  • 如果两个对象相等,则hashCode也一定相同的,对象分别调用equals方法都返回true

  • 如果两个对象有相同的hashCode值,他们不一样相同。

  • 所以,equals被重写过,则hashcode方法也要重写

  • hashCode() 的默认行为是对堆上的对象产生独特值,如果没有重写则改class的2个对象无论如果都不会相等。

Java的异常体系?受检查和非受检查异常区别?

首先Java中的所有异常都来自顶级父类Throwable,有2个子类Error和Exception,其中error表示JVM无法处理的错误,如栈溢出,内存溢出;Exception又分为受检异常和非受检异常,其中受检异常指的是在编写代码的时候必须处理的异常,需要用try…catch语句捕获并进行处理。非受检异常指的是程序运行时的错误,例如下标越界异常,空指针异常。

final关键字

首先final关键字它可以修饰类,方法和变量。当修饰类的时候,说明这个类不能被继承。当修饰方法的时候,说明这个方法不能被重写。当修饰变量的时候,说明这个变量只能赋值一次,不能再次被更改。

final、finally、finalize三个关键字的区别?

final关键字

一个基本数据类型声明为final,就只能进行一次赋值(初始化),编译器会自动检查代码,如果需要修改final的初始化,就会编译报错。final声明的引用数据类型,当前引用是不能改变的,但是可以改变引用指向的内存空间的值final一般和static搭配使用作为常量。
final关键字的三种用法:

  • 1)修饰类:表示该类不能被继承(extends)
  • 2)修饰方法:表示方法不能被重写(override)
  • 3)修饰变量: 表示变量只能一次赋值以后值不能被修改(常量)(final修饰成员变量必须在声明时初始化或者再构造器中初始化,否则报编译错误,而且final修饰的变量通常都是常量,常量名全部大写)

如果一个类被声明为final,意味着它不能再派生出新的子类,即不能被继承,因此它和abstract是反义词。
将变量声明为final,可以保证它们在使用中不被改变,被声明为final 的变量必须在声明时给定初值,而在以后的引用中只能读取不可修改。
被声明为final 的方法也同样只能使用,不能在子类中被重写

final优势:

  • 1)final关键字可以提高性能,JVM和Java应用都会缓存final变量。
  • 2)final变量可以在安全的多线程环境下进行资源共享,而不需要额外的同步开销。
finally

通常放在try…catch…的后面构造总是执行代码块,这就意味着程序无论正常执行还是发生异常,这里的代码只要JVM 不关闭都能执行,可以将释放.

  try { }
  catch(Excetption e){ }
  finally{ }
finalize

Object 类中定义的方法,Java 中允许使用finalize()方法在垃圾收集器将对象从内存中清除出去之前做必要的清理工作。

这个方法是由垃圾收集器在销毁对象时调用的通过重写finalize()方法可以整理系统资源或者执行其他清理工作

Java中的泛型是什么 ? 使用泛型的好处是什么?(重点)

我所理解的泛型就是编写的代码可以被不同类型的对象重复利用。

泛型的运行机制类型擦除。在生成的Java字节码中是不包含泛型中的类型信息的,虽然在使用泛型的时候加上了类型参数,但是在编译阶段会去掉,这就叫类型擦除。

冒泡排序

核心思想就是循环遍历,比较相邻的数,当前面的数大于后面的数的时候,将前面的数先存到临时变量里面,然后将后面的数赋值到到前一位的数字上,再将临时值赋值到后面的数的位置上。

        int[] arr = {1,33,2,333,44,0};

        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]){
                    int temp = arr[j];
                    arr[j] = arr[j+1];
                    arr[j+1] = temp;
                }
            }
        }

BIO、NIO、AIO有什么区别?了解

BIO(Blocking I/O):是同步阻塞IO,数据的读取和写入必须阻塞在一个线程内等待其完成。

NIO(Non-blocking io,也叫New io),是一种同步非阻塞IO模型。它支持面向缓冲机制。

AIO(Asynchronous IO): 也就是NIO2,是异步非阻塞的IO模型。

Java反射机制及使用场景

Java反射的话可以动态的获取类的所有信息就叫做Java的反射机制。

使用场景:

  1. JDBC中,利用反射动态加载了数据库驱动程序
  2. spring框架通过反射来创建对象
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值