初级JAVA开发面试题分享(一)

68 阅读7分钟

面试题由23年8月开始记录,主要参考B站黑马程序员的视频(新版Java面试专题视频教程,java八股文面试全套真题+深度详解(含大厂高频面试真题)_哔哩哔哩_bilibili)和JavaGuide(项目介绍 | JavaGuide),并在多次面试中二次改进并增加题目。内容仅供参考,建议理解使用。

JAVA基础(没问过)

成员变量和局部变量

watermark,type_ZHJvaWRzYW5zZmFsbGJhY2s,shadow_50,text_Q1NETiBAWVhYWFlY,size_15,color_FFFFFF,t_70,g_se,x_16.png member-var-vs-local-var.png

语法形式:从语法形式上看,成员变量是属于类的,而局部变量是在代码块或方法中定义的变量或是方法的参数;成员变量可以被 public,private,static 等修饰符所修饰,而局部变量不能被访问控制修饰符及 static 所修饰;但是,成员变量和局部变量都能被 final 所修饰。

存储方式:从变量在内存中的存储方式来看,如果成员变量是使用 static 修饰的,那么这个成员变量是属于类的,如果没有使用 static 修饰,这个成员变量是属于实例的。而对象存在于堆内存,局部变量则存在于栈内存。

生存时间:从变量在内存中的生存时间上看,成员变量是对象的一部分,它随着对象的创建而存在,而局部变量随着方法的调用而自动生成,随着方法的调用结束而消亡。

默认值:从变量是否有默认值来看,成员变量如果没有被赋初始值,则会自动以类型的默认值而赋值(一种情况例外:被 final 修饰的成员变量也必须显式地赋值),而局部变量则不会自动赋值。

基本类型和包装类型的区别

  • 用途:除了定义一些常量和局部变量之外,我们在其他地方比如方法参数、对象属性中很少会使用基本类型来定义变量。并且,包装类型可用于泛型,而基本类型不可以。
  • 存储方式基本数据类型的局部变量存放在 Java 虚拟机栈中的局部变量表中,基本数据类型的成员变量(未被 static 修饰 )存放在 Java 虚拟机的堆中。包装类型属于对象类型,我们知道几乎所有对象实例都存在于堆中。
  • 占用空间:相比于包装类型(对象类型), 基本数据类型占用的空间往往非常小。
  • 默认值:成员变量包装类型不赋值就是 null ,而基本类型有默认值且不是 null
  • 比较方式:对于基本数据类型来说,== 比较的是值。对于包装数据类型来说,== 比较的是对象的内存地址。所有整型包装类对象之间值的比较,全部使用 equals() 方法

静态方法和实例方法有何不同?

1、调用方式

在外部调用静态方法时,可以使用 类名.方法名 的方式,也可以使用 对象.方法名 的方式,而实例方法只有后面这种方式。也就是说,调用静态方法可以无需创建对象

不过,需要注意的是一般不建议使用 对象.方法名 的方式来调用静态方法。这种方式非常容易造成混淆,静态方法不属于类的某个对象而是属于这个类。

因此,一般建议使用 类名.方法名 的方式来调用静态方法。

public class Person {
    public void method() {
      //......
    }
    public static void staicMethod(){
      //......
    }
    public static void main(String[] args) {
        Person person = new Person();
        // 调用实例方法
        person.method();
        // 调用静态方法
        Person.staicMethod()
    }
}

2、访问类成员是否存在限制

静态方法在访问本类的成员时,只允许访问静态成员(即静态成员变量和静态方法),不允许访问实例成员(即实例成员变量和实例方法),而实例方法不存在这个限制

Java多态

  • 父类引用变量可以指向子类对象

Java泛型

  • 限定传入的泛型参数
  • 泛型类、泛型接口、泛型方法
  • 泛型擦除、通配符

Java为什么不支持多继承?

  • 避免多个父类中的同一方法出现错误引用

Java实现多继承会有什么问题呢?

  • 引用复杂

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

  • implement extends
  • 接口可以多实现,抽象类不可以多继承
  • 接口 is like a ,抽象类 is a
  • 接口成员变量默认为public static final,必须赋初值,不能被修改;其所有的成员方法都是public、abstract的。抽象类中成员变量默认default,可在子类中被重新定义,也可被重新赋值;抽象方法被abstract修饰,不能被private、static、synchronized和native等修饰,必须以分号结尾,不带花括号。

String为什么要把他设计成不可变?

创建对象的方式?

  • 构造器new
  • 克隆
  • 反射
  • 序列化

String s=new String("xyz") 涉及到几个对象(String s1 = new String("abc");这句话创建了几个字符串对象?

  • String s=new String("xyz") 在运行时涉及到几个对象

    • 2
  • String s=new String("xyz") 在类加载时涉及到几个对象

    • 1
  • String s=new String("java") 在运行时涉及到几个对象

    • 1
    • 在sun.misc.Version#launcher_name中加载了java

异常类

  • Exception

    • Checked Exception
    • Unchecked Exception
  • Error

自定义异常类

public class ServiceException extends RuntimeException {
    private static final long serialVersionUID = 2359767895161832954L;
    private final IResultCode resultCode;
​
    public ServiceException(String message) {
        super(message);
        this.resultCode = ResultCode.FAILURE;
    }
​
    public ServiceException(IResultCode resultCode) {
        super(resultCode.getMessage());
        this.resultCode = resultCode;
    }
​
    public ServiceException(IResultCode resultCode, Throwable cause) {
        super(cause);
        this.resultCode = resultCode;
    }
​
    public Throwable fillInStackTrace() {
        return this;
    }
​
    public Throwable doFillInStackTrace() {
        return super.fillInStackTrace();
    }
​
    public IResultCode getResultCode() {
        return this.resultCode;
    }
}

Java集合(问的频率较高,多为list和map)

image-20230831163951635.png

数据结构 - 数组

image-20230831214506881.png

image-20230831215641844.png

为什么数组索引从0开始呢?假如从1开始不行吗?

image-20230831215857701.png

ArrayList底层的实现原理是什么

image-20230831231342913.png

ArrayList list = new ArrayList(10)的list扩容几次

image-20230831231602726.png

如何实现数组和List之间的转换

此处参考Kimi.AI

数组转换为List
  1. 使用Arrays类的asList方法:

    String[] array = {"a", "b", "c"};
    List<String> list = Arrays.asList(array);
    

    注意,使用Arrays.asList创建的List是固定大小的,不能添加或删除元素。

  2. 使用Collections类中的addAll方法:

    List<String> list = new ArrayList<>();
    String[] array = {"a", "b", "c"};
    Collections.addAll(list, array);
    
  3. 使用Java 8的Stream API:

    String[] array = {"a", "b", "c"};
    List<String> list = Arrays.stream(array).collect(Collectors.toList());
    
List转换为数组
  1. 使用List的toArray方法:

    List<String> list = new ArrayList<>(Arrays.asList("a", "b", "c"));
    String[] array = list.toArray(new String[0]);
    

    注意,需要提供一个数组实例来接收转换后的元素。

  2. 使用Arrays类的copyOf方法:

    List<String> list = new ArrayList<>(Arrays.asList("a", "b", "c"));
    String[] array = Arrays.copyOf(list.toArray(), list.size(), String[].class);
    
  3. 使用Java 8的Stream API:

    List<String> list = new ArrayList<>(Arrays.asList("a", "b", "c"));
    String[] array = list.stream().toArray(String[]::new);
    

这些方法可以根据你的具体需求来选择使用。如果你需要一个可修改的List,建议使用Collections.addAll或Stream API。如果你需要一个固定大小的List,可以使用Arrays.asList。在将List转换为数组时,确保提供正确的数组类型和大小。

ArrayList和LinkedList的区别是什么?

本质上是链表和数组的区别,建议理解后回答,可参考ArrayList 与 LinkedList 区别?

List和Set互相转换的问题

  • Set转List会乱序
  • List转Set会丢失数据

HashMap

此处红黑树只作了解即可,初级面试暂未问到

image-20230901134525101.png image-20230901134616364.png image-20230901134643617.png

说一下HaspMap的实现原理(建议理解后背诵,基本都问)

image-20230901135021811.png

image-20230901135048007.png

image-20230901135158200.png

亦可参考HashMap 的底层实现

HashMap的put方法的具体流程

image-20230901143646668.png

image-20230901193450832.png

image-20230902003636134.png

讲讲HashMap的扩容机制

image-20230902143026059.png

image-20230902143215497.png

hashMap的寻址算法(没问过)

image-20230903124310609.png

image-20230903125940303.png

haspMap在1.7情况下的多线程死循环问题

image-20230903131409862.png

image-20230903131955383.png

未完待续,有空继续