Java基础八股文

2024年 Java 面试八股文(20w字) 基本数据类型,如int,float,double,boolean,char,byte,不具备对象的特征,不能调用方法。装箱:将基本类型转换成包装类对象拆箱:将包装类对象转换成基本类型的值java为什么要引入自动装箱和拆箱的功能?主要是用于java集合中,List list=new ArrayList();list集合如果要放整数的话,只能放对象,不能放基本类型,因此需要将整数自动装箱成对象。 阅读详情
序号内容链接地址
1Java基础八股文https://zhuanlan.zhihu.com/p/379234291 https://blog.youkuaiyun.com/weixin_39290259/article/details/117746292
2Java容器八股文敬请期待
3Java异常八股文https://zhuanlan.zhihu.com/p/377557779 https://blog.youkuaiyun.com/weixin_39290259/article/details/117229021
4Java并发编程八股文敬请期待
5JVM八股文敬请期待
6Spring八股文敬请期待
7Spring MVC八股文敬请期待
8Spring Boot八股文敬请期待
9MySQL八股文敬请期待
10Redis八股文敬请期待
11MyBatis八股文敬请期待
12Netty八股文敬请期待
13网络原理八股文敬请期待
14Linux八股文敬请期待
15Tomcat八股文敬请期待
16Spring Cloud八股文敬请期待
17MQ与RabbitMQ八股文敬请期待
18Dubbo八股文敬请期待
19ZooKeeper八股文敬请期待
20设计模式八股文敬请期待

文章目录

一、Java概述

1.1 JVM、JDK、JRE都是什么

JVM:Java Virtual Machine是Java虚拟机,Java程序需要运行在虚拟机上,不同的平台有不同的Java虚拟机,因此Java可以实现跨平台。

JRE:Java Runtime Environment 包括Java虚拟机和Java程序所需要的核心类库。核心类库主要是java.lang包,主要包含了基本数据类型、基本数学函数、字符串处理、线程、异常处理类等,系统缺省加载这个包。如果只想要运行一个开发好的Java程序,只需要安装JRE即可。

JDK:Java Development Kit是提供给Java开发人员使用的,其中包含了JRE和开发工具,所以安装了JDK就不用再单独安装JRE了。其中的开发工具:编译工具(javac.exe),打包工具(jar.exe)等。

Java程序从源码到运行的一般步骤:
image

JVM、JRE、JDK的关系图:
image

1.2 Java跨平台性的原理是什么

跨平台性是指,Java开发的程序经过一次编译后可以才多个系统平台上运行。

实现原理:不同的平台上安装对应的Java虚拟机,Java程序跑在虚拟机上即可。

1.3 Java语言的特点

  • 简单易学(语法和c++相似)
  • 面向对象(封装、继承、多态)
  • 平台无关性(JVM虚拟机屏蔽了不同平台)
  • 支持网络编程并且很方便
  • 支持多线程
  • 健壮性(强类型机制、异常处理、垃圾自动收集)
  • 安全性

1.4 什么是字节码

字节码:Java源码经过编译器编译后形成的.class文件,不面向任何处理器,只面向Java虚拟机。

1.5 Java和C++的区别

  • 都是面向对象的语言
  • Java不提供指针来直接访问内存
  • Java类不支持多继承
  • Java有自动内存管理机制,而C++需要程序员手动释放内存

二、基础语法

2.1 数据类型

2.1.1 Java有哪些数据类型

image

2.1.2 switch能作用在哪些类型上

byte、short、int、long、char、String、enum可以,float、double、boolean不可以。

2.1.3 byte a = (byte) 128 a是几

a=-128,因为byte最大能表示127,byte是8个二进制位,最高位表示符号位,所以byte能表示的最大的数就是2的7次方-1=127,二进制表示就是01111111,01111111加1就是10000000,10000000就是0,而0已经被00000000代表了,所以规定10000000就代表-128。

2.1.4 float f=3.4 是否正确

不正确。3.4是双精度数,双精度(double)赋值给单精度数(float)会损失精度,所以需要强转float f = (float) 3.4或float f = 3.4f。

2.2 访问修饰符

2.2.1 Java中有哪些访问修饰符,有何区别

  • private:在同一类内可见。使用对象:变量,方法。
  • default(缺省,什么都不写):在同一包内可见。
  • protected:对同一包内的类和所有子类可见。
  • public:对所有类可见。
修饰符当前类同包子类其他包
private√×××
default√√××
protected√√√×
public√√√√

2.3 运算符

2.3.1 &和&&的区别

  • &可以用来按位与和逻辑与
  • &&短路与,&&左边的如果为false,后边的不进行运算

2.4 关键字

2.4.1 final的作用

用于修饰类、属性和方法。

  • 被final修饰的类不可被继承
  • 被final修饰的方法不可被重写
  • 被final修饰的变量不可被改变,是引用不可变,引用指向的内容是可以被改变的

2.4.2 final finally finalize区别

  • final用于修饰类、属性和方法。修饰的类不能被继承,修饰的方法不能被重写,修饰的属性的引用不能指向其他的值。
  • finally用于try-catch-finally中,表示不管是否出现异常都会执行finally块,一般存放关闭资源的代码。
  • finalize是Object的一个方法,当垃圾回收器将要回收对象所占内存之前被JVM调用。

2.4.3 this关键字的用法

this是指向对象本身的一个指针。用法大致分为三种:

  • 普通的直接引用,this相当于是指向当前对象本身。
  • 形参与成员名字重名,用this来区分。
  • 构造函数内引用本类的构造函数。

2.4.4 super关键字的用法

  • 普通的直接引用,super相当于是指向当前对象父类的引用,这样就可以使用super.xxx来引用父类成员。
  • 调用父类的构造函数。

2.4.5 this与super的区别

  • super引用当前对象的直接父类成员,this代表当前对象的引用。
  • super()在子类中调用父类的构造方法,this()在本类中调用其他构造方法。
  • this()和super()均需放在构造方法的第一行。
  • this()和super()只能在构造方法中调用,且只能调用一次。
  • this()和super()不能同时出现在同一个构造方法里。
  • this和super都不能在static环境中使用。

2.4.6 static存在的主要意义

  • static的主要意义就在于创建独立于具体对象的域变量和方法,从而没有对象就可以使用类的属性和方法。
  • 用static静态代码块来优化程序性能。static块可以置于程序的任何地方,可以有多个静态代码块。在类初次被加载的时候,会按照static块的顺序执行静态代码块,并且只会执行一次。

2.4.7 static注意事项

  • static的只能访问static的。
  • 非static可以访问static的。

2.4.8 在⼀个静态⽅法内调⽤⼀个⾮静态成员为什么是⾮法的?

非静态成员需要通过对象来进行访问,而静态方法不可以通过具体对象进行调用。

2.4.9 类中各个部分的加载顺序

class Print {
    public Print(String s){
        System.out.print(s + " ");
    }
}

public class Parent{

     public static Print obj1 = new Print("1");

     public Print obj2 = new Print("2");

     public static Print obj3 = new Print("3");

     static{
         new Print("4");
     }

     public static Print obj4 = new Print("5");

     public Print obj5 = new Print("6");

     public Parent(){
         new Print("7");
     }

 }
public class Child extends Parent{

     static{
         new Print("a");
     }

     public static Print obj1 = new Print("b");

     public Print obj2 = new Print("c");

     public Child (){
         new Print("d");
     }

     public static Print obj3 = new Print("e");

     public Print obj4 = new Print("f");

     public static void main(String [] args){
         Parent obj1 = new Child ();
     }
 }

Child类继承自Parent类,输出结果:

1 3 4 5 a b e 2 6 7 c f d 

所以加载顺序是:

  1. 加载父类中的静态的,包括静态变量的初始化和静态代码块的,静态变量和静态代码块的执行顺序是按照代码的编写顺序。
  2. 加载子类中的静态的。
  3. 执行父类中非静态变量的初始化。
  4. 执行父类的构造方法。
  5. 执行子类中非静态变量的初始化。
  6. 执行子类的构造方法。

三、面向对象

3.1 面向对象概述

3.1.1 面向对象和面向过程的区别

  • 面向过程:就是分析出解决问题所需要的步骤,然后用函数把这些步骤一步一步实现,使用的时候一个一个依次调用就可以了。性能比面向对象高,因为面向对象的类调用时需要实例化,开销大。单片机、嵌入式开发一般采用面向过程开发。缺点就是开发出来的代码不易维护、不易复用、不易扩展。
  • 面向对象:是把构成问题事务分解成各个对象,建立对象的目的不是为了完成一个步骤,而是为了描述某个事物在整个解决问题的步骤中的行为。易维护、易复用、易扩展。由于面向对象有封装、继承、多态的特性,可以设计出高内聚低耦合的系统。缺点就是性能比面向过程低。

3.2 面向对象三大特性

3.2.1 面向对象的特征有哪些方面

抽象:将一类对象的共同特征总结出来构造类的过程,包括数据抽象和行为抽象。

  • 封装:把类的属性私有化,同时对外界提供可被访问的方法。
  • 继承:继承是使用已存在的类作为基础建立新的类的技术,新的类拥有父类的属性和方法,也可以定义自己的属性和方法。通过继承可以很方便地服用以前的代码。
  • 多态:多态就是指程序中定义的引用变量所指的具体类型和通过该引用变量发出的方法调用在编译时不确定,而是在程序运行期间才能确定,即一个引用变量到底会指向哪个具体的实例对象,方法到底是哪个对象的方法必须在运行期间才能决定。

3.2.2 什么是多态机制?Java语言是如何实现多态的?

多态就是指程序中定义的引用变量所指的具体类型和通过该引用变量发出的方法调用在编译时不确定,而是在程序运行期间才能确定,即一个引用变量到底会指向哪个具体的实例对象,方法到底是哪个对象的方法必须在运行期间才能决定。即不修改程序代码就可以改变程序运行时所绑定的具体代码,让程序可以选择多个运行状态,这就是多态性。多态有编译时多态和运行时多态,编译时多态主要指方法重载,运行时多态是动态绑定,一般说多态就是指运行时多态。

多态的实现

Java中实现多态的三个必要条件:继承或实现接口、重写、向上转型。

继承:在多态中必须存在有继承关系的子类和父类中,或者是接口和接口的实现类中。

重写:子类对父类的方法进行重新定义,在调用时就会调用子类的方法。

向上转型:在多态中需要将子类的引用赋给父类的类型。这样才能调用父类和对用的子类中的方法。

多态遵循的一个原则:当超类对象引用变量引用子类对象时,被引用对象的类型决定了调用谁的方法,但是这个被调用的方法必须在超类中定义过,也就是说被子类覆盖了的方法。

具体案例分析:

public class A {
    public String show(D obj) {
        return ("A and D");
    }
    public String show(A obj) {
        return ("A and A");
    }
}
public class B extends A{
    public String show(B obj){
        return ("B and B");
    }
    public String show(A obj){
        return ("B and A");
    }
}
public class C extends B{

}
public class D extends B{

}
public class Test {
    public static void main(String[] args) {
        A a1 = new A();
        A a2 = new B();
        B b = new B();
        C c = new C();
        D d = new D();
        //this.show(o)-->super.show(o)-->this.show((super)o)-->super.show((super)o)
        System.out.println("1--" + a1.show(b));//A.show(B)-->Object.show(B)-->A.show(A) = A and A
        System.out.println("2--" + a1.show(c));//A.show(C)-->Object.show(C)-->A.show(B)-->A.show(A) = A and A
        System.out.println("3--" + a1.show(d));//A.show(D)-->Object.show(D)-->A.show(D) = A and D
        System.out.println("4--" + a2.show(b));//A.show(B)-->Object.show(B)-->A.show(A)此时发现a2引用的是B类的一个对象,并且B类覆盖了A的show(A obj)方法,所以调用B.show(A) = B and A
        System.out.println("5--" + a2.show(c));//A.show(C)-->Object.show(C)-->A.show(B)-->A.show(A)此时发现a2引用的是B类的一个对象,并且B类覆盖了A的show(A obj)方法,所以调用B.show(A) = B and A
        System.out.println("6--" + a2.show(d));//A.show(D) A中有show(D)的方法,由于a2引用的是B类的一个对象,所以再看B是否覆盖了show(D),如果覆盖了就执行B的方法,否则就执行A的方法,由于这里没覆盖所以执行A.show(D) = A and D
        System.out.println("7--" + b.show(b));//B.show(B) = B and B
        System.out.println("8--" + b.show(c));//B.show(C)-->A.show(C)-->B.show(B) = B and B
        System.out.println("9--" + b.show(d));//B.show(D)-->A.show(D) = A and D
    }
}

输出:

1--A and A
2--A and A
3--A and D
4--B and A
5--B and A
6--A and D
7--B and B
8--B and B
9--A and D

方法调用的优先级:this.show(o)–>super.show(o)–>this.show((super)o)–>super.show((super)o)

以5为例进行分析,a2.show©,a2是A类型的引用,所以this代表A,也就是this.show(o)=A.show©,在A中没找到show©的方法,所以根据调用链往下找,来到了super.show(o),A没有父类,所以继续往下找,来到了this.show((super)o)=A.show(B),没找到,继续找B的父类,也就是找A.show(A),发现A中有show(A)的方法,由于a2指向的是B类的对象,这时会继续寻找B类中是否覆盖了A类中的show(A)方法,如果有则执行B.show(A),否则执行A.show(A),在这里B覆盖了show(A)方法,所以执行B.show(A),所以结果是B and A。

3.2.3 面向对象五大基本原则是什么

  • 单一职责原则:类的功能要单一
  • 开放封闭原则:对扩展开放,对修改封闭。想要增加功能可以,想要修改功,不好意思,不让。
  • 里氏替换原则:子类可以替换父类出现在父类能够出现的地方。
  • 依赖倒置原则:高层次的模块不应该依赖于低层次的模块,他们都应该依赖于抽象。抽象不应该依赖于具体实现,具体实现应该依赖抽象。
  • 接口分离原则:设计时采用多个与特定客户类有关的接口比采用一个通用的接口要好。

3.3 类与接口

3.3.1 抽象类和接口的区别

抽象类是将类的通用性进行抽象,是一种模板设计;接口时将行为进行抽象,是一种行为的规范。

相同点:

  • 接口和抽象类都不能实例化。
  • 都包含抽象方法。

不同点:

image

在接口和抽象类的选择上要遵循以下原则:

  • 行为模型应该总是通过接口而不是抽象类定义,所以优先选择接口。
  • 如果需要定义子类行为,又要为子类提供通用的功能,优先选择抽象类。

3.3.2 普通类和抽象类有哪些区别?

  • 普通类不能包含抽象方法,抽象类既可以包含普通方法又可以包含抽象方法。
  • 抽象类不能被实例化。

3.3.3 抽象类能使用 final 修饰吗?

不能。抽象类就是用来被继承的,如果用final修饰就不能被继承了,违反了抽象类设计的初衷。

3.3.4 创建一个对象用什么关键字?对象实例与对象引用有何不同?

new关键字。对象实例在堆内存中,对象引用在栈内存中。一个对象引用可以指向0或1个对象,一个对象可以被多个引用指向。

3.4 变量与方法

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

变量: 在程序执行的过程中,在某个范围内其值可以发生改变的量。本质上是内存中的一块区域。

成员变量: 在类内部,方法外部定义的变量。

局部变量: 在方法内部定义的变量。

区别:

image

3.4.2 在Java中定义一个不做事且没有参数的构造方法的作用

如果父类中有构造方法,但是没有无参构造方法,在子类中的构造方法中如果没有使用super来调用父类的带参构造方法,这种情况下会发生编译错误。解决办法就是要么是在子类的构造方法中调用父类的带参构造方法,要么在父类中定义无参构造方法。

3.4.3 在调用子类构造方法之前会先调用父类没有参数的构造方法,其目的是?

帮助子类做初始化工作。

3.4.4 一个类的构造方法的作用是什么?若一个类没有声明构造方法,该程序能正确执行吗?为什么?

构造函数用于创建类的对象,完成对象的初始化工作。可以执行。因为一个类如果没有声明构造方法,也会有一个隐藏的默认的不带参数的构造方法。

3.4.5 构造方法有哪些特性?

  1. 方法名与类名相同。
  2. 没有返回值,不能用void修饰。
  3. 生成类的对象时自动执行。
  4. 构造方法可以被重载。

3.4.6 静态变量和实例变量区别

静态变量: 静态变量是属于类的变量,不属于任何一个类的实例,在内存中只有一份,JVM在类初次加载时分配内存空间。

实例变量: 实例变量是属于对象的,每次创建对象,都会为对象分配变量内存空间。

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

  1. 静态方法使用“类名.方法名”的方式调用,实例方法使用“对象名.方法名”的方式调用。
  2. 静态方法只能使用本类中静态成员,实例方法无此限制。

3.4.8 在一个静态方法内调用一个本对象非静态成员为什么是非法的?

静态方法在任意对象实例化之前就已经存在,而非静态成员只有在对象实例化之后才会分配内存,然后通过实例对象引用来进行访问。也就是说静态方法在调用非静态成员时,这个对象实例都不存在,非静态成员当然更不存在。

3.5 内部类

内部类的详解请见我的系列文章:Java八股文系列五:内部类

3.6 重写与重载

3.6.1 构造器(constructor)是否可被重写(override)

构造方法不能被重写,但可以被重载。

3.6.2 重载(Overload)和重写(Override)的区别。重载的方法能否根据返回类型进行区分?

重载和重写都能实现多态性。重载实现的是编译时多态,重写实现的是运行时多态,重写是真正的多态。

  • 重载: 发生在同一个类中,方法名相同参数列表不同(参数的个数不同、类型不同、顺序不同),与方法的返回值类型和访问修饰符无关。
  • 重写: 发生在父子类中,方法名、参数列表必须相同,返回值的类型要小于等于父类,抛出的异常类要小于等于父类的异常类,访问修饰符大于等于父类(里氏代换原则)。如果父类的方法是private的,则子类不能重写。

3.7 对象相等判断

3.7.1 == 和 equals 的区别是什么

  • ==: 它的作用是比较两个对象的内存地址是否相等。即判断两个对象是否是同一个对象(基本类型比较的是值,引用类型比较的是内存地址)。
  • equals(): 也是比较两个对象是否相等,分两种情况:没有覆盖equals()方法和覆盖了equals()方法。没有覆盖equals()方法等价于“==”比较这个两个对象,覆盖了equals()方法一般是比较对象的内容是否相同。

3.7.2 hashCode() 与 equals()

1. hashCode()的作用

hashCode()是所有对象的方法,它返回一个int型的整数,叫做哈希码,这个哈希码的作用是确定该对象在哈希表中的位置。也就是说hashCode()在散列表中才有用,在其他情况下没用。 进一步说就是将对象放入HashMap、HashSet等散列表结构的类中,要根据HashCod()来确定对象在数组中的位置。

2. 为什么要有HashCode(),为什么要根据HashCode()来确定对象在散列表中的位置?

HashCode()是一个native方法,hashCode() 的默认⾏为是对堆上的对象产⽣独特值。如果没有重写HashCode()方法,则该类的两个对象无论如何都不会相等(即使两个对象的内容完全相等)。

以HashSet为例:假设HashSet中已经有1万个元素,插入第10001个元素时如何确定这个元素不与前1万个元素重复呢?“用equals()方法逐个与前1万个元素比较”,这样可以但是效率很低。可不可以用HashCode()呢,如果HashCode()不被重写即使两个对象的内容完全相等那么这两个对象的HashCode()也不相等,这样两个内容相等的对象算出的位置却不同,就失去了HashSet的元素不重复的意义。所以要重写HashCode(),来保证两个内容相等的对象的HashCode()一定要相等。如果重写了HashCode(),保证了两个内容相等的对象的HashCode()一定相等,就可以判断是相等的对象了吗?不可以,因为内容不同的对象的HashCode()也可能相同,所以HashCode()相同的话还要用equals()再比较一下,如果内容真的相同,那么就是相等的对象。

3. hashCode() 与 equals()

如果不将对象放入像HashMap这样的散列表结构中,hashCode() 与 equals()没有任何关系。

将对象放入像HashMap这样的散列表结构中,hashCode() 与 equals()是有关系的。

  • 如果两个对象相等,那么它们的HashCode()值一定相同。这里的相等是指通过equals()比较两个对象时返回true。
  • 如果两个对象的HashCode()相等,那它们不一定相等。因为在散列表中会存在hash冲突,即两个不同的键值对哈希值相等。

因此,equals()方法被覆盖过,hashCode()方法也要被覆盖。

3.7.3 对象的相等与指向他们的引用相等,两者有什么不同?

  • 对象相等:比较内存中存放的内容是否相等。
  • 引用相等:比较他们是否指向同一块内存地址。

3.8 值传递

3.8.1 当一个对象被当作参数传递到一个方法后,此方法可改变这个对象的属性,并可返回变化后的结果,那么这里到底是值传递还是引用传递

是值传递。Java的方法调用只支持值传递。当一个对象实例作为参数被传递到方法中时,参数的值就是该对象的引用,就是一个地址,形参是这个地址的一份拷贝。对象的属性可以在被调用的过程中被改变,但是对这个对象引用的改变是不会影响到调用者的,也就是说如果在方法中改变了这个对象的引用,将这个引用指向了一个新的地址,那么传过来的那个引用还是指向原来的地址。

3.8.2 为什么 Java 中只有值传递

  • 按值调用(值传递):表示方法接收的是调用者提供的值,实际参数的副本将传递给形式参数,也就是说方法得到的是所有参数值的一个拷贝。
  • 按引用调用(引用传递):通过引用调用(也称为引用传递)是一种评估策略,其中函数接收对用作参数的变量的隐式引用,而不是其值的副本。

值传递和引用传递最本质的区别就是:值传递不会修该之前的值,引用传递会修改原来的值。这里的“原来的值”有两只情况,一种是参数是基本数据类型,另一种是引用类型。如果参数类型是引用类型,“引用传递会修改引用类型的值”的意思就是引用传递会修改原来引用的地址,“值传递不会修改引用类型的值”的意思就是值传递不会修改原来引用的地址,而通过引用修改对应内存地址中的内容是引用的最基本的功能,不能叫引用传递,所以是不是引用传递关键就在于看能不能修改原来引用的地址。

当参数是基本数据类型时:

public static void main(String[] args) {
    int num1 = 10;
    int num2 = 20;

    swap(num1, num2);

    System.out.println("num1 = " + num1);
    System.out.println("num2 = " + num2);
}

public static void swap(int a, int b) {
    int temp = a;
    a = b;
    b = temp;

    System.out.println("a = " + a);
    System.out.println("b = " + b);
}

输出:

a = 20
b = 10
num1 = 10
num2 = 20

可以看到num1和num2的值没有被改变,所以基本数据类型是值传递。

当参数是引用类型时:

public class Foo {

    private String name;

    public Foo(String name) {
        this.name = name;
    }

    public void setName(String name) {
        this.name = name;
    }


    public String getName() {
        return name;
    }

    public static void changeReference(Foo a) {
        Foo b = new Foo("b");
        a = b;
    }

    public static void modifyReference(Foo c) {
        c.setName("c");
    }

    public static void main(String[] args) {
        Foo f = new Foo("f");
        Foo old = f;
        System.out.println(f == old);//true
        changeReference(f); // 将f指向一个新的对象
        System.out.println(f.getName().equals("f"));//true
        System.out.println(f.getName().equals("b"));//false
        System.out.println(f == old);//true
        modifyReference(f); // 修改f的内容
    }
}

changeReference(Foo a)方法将接收到的Foo类型对象的引用指向了一个新的地址,执行完此方法后结果发现引用类型f的指针并没有指向其他的地址,也就是说当参数是引用类型时也没有修改指针的值,所以也是值传递。以下是大致流程:

  1. 声明一个Foo类型的引用f,并指向一个name属性为"f"的对象。
Foo f = new Foo("f");

image

  1. 在方法形参上声明一个Foo类型的引用a,并指向null。
public static void changeReference(Foo a)

image

  1. 当调用changeReference(f)方法时,将引用a指向f所指向的对象。
changeReference(f);

image

  1. 声明一个Foo类型的引用b,并指向一个name属性为"b"的对象。
Foo b = new Foo("b");

image

  1. 将a指向b所指向的对象。
a=b;

image

  1. 当调用modifyReference(f)方法时,将引用c指向f所指向的对象。

image

  1. 当调用c.setName(“c”)时,c所指向的对象的name将被改成"c"。

image

下面总结一下Java中参数传递的情况:

  • 一个方法不能修改基本数据类型的参数
  • 一个方法可以改变一个对象的参数的状态
  • 一个方法不能让参数对象引用一个新的对象

3.8.3 值传递和引用传递有什么区别

image

四、IO流

4.1 java 中 IO 流分为几种?

  • 按照流的流向分:输入流和输出流。
  • 按照操作单元分:字节流和字符流。
  • 按照流的角色分:节点流和处理流。

Java IO流的40多个类都是从下面4个抽象类中派生出来的:

  • InputStream/Reader:所有输入流的基类,前者是字节输入流,后者是字符输入流。
  • OutputStream/Writer:所有输出流的基类,前者是字节输出流,后者是字符输出流。

按操作对象分类结构图:

image

4.2 既然有了字节流,为什么还要有字符流?

字符流是由Java虚拟机将字节转换得到的,这个过程非常耗时,并且如果我们不知道编码类型就很容易出现乱码问题。所以,就直接提供了一个字符流来操作字符。
像音视频文件、图片文件用字节流操作,涉及到字符的话用字符流操作。

4.3 BIO,NIO,AIO 有什么区别?

  • BIO(Blocking I/O): 同步阻塞IO。数据的读写必须阻塞在一个线程内等待其完成,在活动连接数不是特别高的情况下,这种模型还是不错的,可以让每一个连接专注于自己的I/O并且编程模型简单。但是当连接数达到数十万的时候,这种模型是无能为力的。
  • AIO: 异步非阻塞的IO模型。异步IO是基于事件和回调机制实现的,也就是应用操作之后会直接返回,不会阻塞在那里,当后台处理完成,操作系统会通知相应的线程进行后续的操作。
  • NIO(New I/O或Non-blocking I/O): 同步非阻塞IO。它支持面向缓冲的,基于通道的I/O操作方法。NIO提供了与传统BIO模型中的 Socket 和 ServerSocket 相对应的 SocketChannel 和 ServerSocketChannel 两种不同的套接字通道实现,两种通道都支持阻塞和非阻塞两种模式。阻塞模式使用就像传统中的支持一样,比较简单,但是性能和可靠性都不好;非阻塞模式正好与之相反。对于低负载、低并发的应用程序,可以使用同步阻塞I/O来提升开发速率和更好的维护性;对于高负载、高并发的(网络)应用,应使用 NIO的非阻塞模式来开发.

五、反射

关于反射,具体请看我的系列文章 Java八股文系列三:反射

六、常用API

6.1 String相关

6.1.1 什么是字符串常量池?

字符串常量池存在于堆内存中,专门用来存储字符串常量,可以提高内存的使用率,避免开辟多块内存空间存储相同的字符串,在创建字符串时JVM会首先检查字符串常量池,如果该字符串已经存在于常量池中,则返回它的引用,如果不存在,则实例化一个字符串放到常量池中,并返回其引用。

6.1.2 String 是最基本的数据类型吗

不是,Java中的基本数据类型只有8个:byte、short、int、long、float、double、char、boolean,而String是一个char类型的数组。

6.1.3 String有哪些特性

  1. 不变性。String底层是private final char value[],一个用final修饰的char数组。对它进行任何操作,其实是创建一个新的对象,再把引用指向该对象。
  2. 常量池优化。String对象创建后,会在常量池里进行缓存,如果下次创建相同的对象,会直接返回缓存的引用。
  3. String类不能被继承。String是一个被final修饰的类。

6.1.4 String为什么是不可变的?

  1. String的底层是一个final修饰的char型数组,不可变的是这个数组中的字符,但是我们可以通过改变这个数组的引用,使其指向其他的数组。
String str = "Hello";
str = str + " World";
System.out.println("str=" + str);

str指向了一个新的String对象"Hello World",而原来在内存中的"Hello"还是"Hello"。

  1. 可以通过反射技术来打破String的不可变。
public class Test {
    public static void main(String[] args) throws NoSuchFieldException, IllegalAccessException {
        String s = "Hello World";

        System.out.println("before s = " + s);
        
        //获取String的value字段
        Field values = String.class.getDeclaredField("value");

        //改变访问权限
        values.setAccessible(true);

        //获取value属性的值
        char[] o = (char[]) values.get(s);

        //修改value所引用的数组中的第五个字符
        o[5] = '_';

        System.out.println("after s = " + s);
    }
}

输出:

before s = Hello World
after s = Hello_World
  1. String为什么被设计成不可变的?
  • 缓存的需要:被缓存的String字面量需要在多个线程之间共享,如果一个客户端将"test"修改为"prod",其他客户端也会得到这个结果,但显然并不想要这个接口,为了避免这个风险,String被设计成不可变的。
  • HashMap的需要:HashMap的key通常都是String类型,如果String可以修改,其hashcode也将会改变,这样导致在HashMap中找不到原来的value。

总之,考虑到安全性和字符串常量池等原因,String被设计成不可变的。

6.1.5 是否可以继承 String 类

不可以被继承。String是final类。

6.1.6 String str="i"与 String str=new String(“i”)一样吗?

不一样。str="i"是将str指向字符串常量池中的地址,str=new String(“i”)是将str指向堆中的地址。这两个地址不一样。

String对象创建的两种方式:

  • String a=“abc”:直接在字符串常量池中创建"a",并返回常量池中的引用,如果常量池中已经有了"a",则直接返回"a"的引用。
  • String a=new String(“abc”):在堆中创建一个"abc"对象,并返回一个在堆中的引用,并将"abc"写入常量池中,如果常量池中已经有了"abc"则不会再常量池中创建一个新的"abc"。

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

两个对象。一个是在字符串常量池中的"xyz"对象,一个是在堆中的"xyz"对象,s指向的是堆中的对象。

  1. String类型的变量相加时,其实是使用的StringBuilder.append来完成的,会在堆上创建新的对象。
String s1 = "abc"; 
String s2 = "a"; 
String s3 = "bc"; 
String s4 = s2 + s3; 
System.out.println(s1 == s4);//false
  1. String类型的常量相加时,编译器会进行优化,将引用直接替换成字符串的值。
String S1 = "abc"; 
final String S2 = "a"; 
final String S3 = "bc"; 
String S4 = S2 + S3; 
System.out.println(S1 == S4);//true
  1. String类型变量和String的字面量相加时,是使用的StringBuilder.append来完成的。
String str1 = "abcd"; // 常量池创建"abcd"
String str4 = "ab"; // 常量池已经有了"ab"
str4 += "cd"; // str4+"cd"连接的字符串编译器不能优化,所以此时str4指向堆
System.out.println(str1 == str4); // false
  1. String类型的字面量相加时
String fg = "fg";
System.out.println("f" + "g" == fg);//true 生成"ab",发现常量池中已经存在"ab",所以直接指向"ab"。

6.1.8 在使用 HashMap 的时候,用 String 做 key 有什么好处?

HashMap是通过key的hashcode来计算value的存储位置的,由于String是不可变的,所以String的hashcode也是不可变的,就可将它的hashcode缓存下来,不需要再次计算,所以效率高。

6.1.9 String和StringBuffer、StringBuilder的区别是什么?

  1. 可变与不可变。
  • String的底层是使用final修饰的char数组,所以String不可变。
  • StringBuilder和StringBuilder都继承自AbstractStringBuilder类,AbstractStringBuilder类使用的是没有final修饰的char数组,所以可变。
  1. 是否多线程安全。
  • String对象是不可变的,也就是常量,显然是线程安全的。
  • StringBuilder对象可变,并且方法也没有用到同步锁,所以是非线程安全的。
  • StringBuffer对象可变,但是方法加了同步锁,所以是线程安全的。
  1. 性能
  • 由于String类型进行改变时,每次都会生成一个新的对象,而那两个是对对象本身进行操作,不会生成新的对象,所以String的性能最差。

6.2 包装类相关

6.2.1 自动装箱与拆箱

  • 装箱: 将基本数据类型用它们的引用类型包装起来。
  • 拆箱: 将包装类型转换为基本类型。

6.2.2 int 和 Integer 有什么区别

int是基本数据类型,Integer是其包装类型。

6.2.3 Integer a= 127 与 Integer b = 127相等吗

  • 对于基本数据类型:==比较的是值。
  • 对于对象引用类型:==比较的是内存地址。
  • Java的6种基本类型的包装类实现了常量池技术,即Byte、Short、Integer、Long、Character、Boolean,这6种包装类型会有相应的缓存数据,但是超出范围仍然会创建新的对象。Byte、Short、Integer、Long缓存[-128,127]间的数据,Character缓存[0,127]之间的数据,Boolean缓存true和false两个对象。
  • 两个浮点型的包装类Float、Double没有常量池。
Integer t = 127;
Integer t1 = 127;
Integer t2 = 128;
Integer t3 = 128;
Integer i4 = new Integer(40);
Integer i5 = new Integer(40);
Integer i6 = new Integer(0);
System.out.println(t == t1);
System.out.println(t2 == t3);
System.out.println("i4=i5   " + (i4 == i5));
System.out.println("i4=i5+i6   " + (i4 == i5 + i6));

输出:

true
false
i4=i5   false
i4=i5+i6   true

Integer.valueOf源码:

    public static Integer valueOf(int i) {
        if (i >= IntegerCache.low && i <= IntegerCache.high)
            return IntegerCache.cache[i + (-IntegerCache.low)];
        return new Integer(i);
    }

解释:Integer t = 127;会在编译时直接将代码封装成Integer.valueOf(127),这叫自动装箱,Integer.valueOf(127)的源码在上方,于此可见,由于t和t1的127都在常量池中,所以t和t1都引用常量池中的同一块内存。t2和t3的128不在常量池中,所以t2和t3都分别创建了新的对象。解释i4=i5,new Integer(40)是手动装箱,不会调用Integer.valueOf(40)的方法,所以i4和i5分别直接new了两个新的对象。解释i4=i5+i6,Integer的加操作会将包装类型自动拆箱成int型,即i4==40,然后Integer对象无法与数值进行直接比较,所以将i4自动拆箱成int型的40,最后转化成数值比较。

关注Java技术吧公众号,会持续更新深入理解Java开发涉及到的各种技术的文章和面试题总结。

image

Java八股文 在实际应用中,如果不需要考虑线程安全问题,优先选择HashMap;Java八股文是Java开发者在面试中需要重点掌握的知识,熟练掌握这些内容有助于在面试中更好地展示自己的技术能力,但实际开发中也需要深入理解这些知识点背后的原理和应用场景,才能更好地运用Java语言进行高效的程序开发。这些常见的Java八股文面试题及答案涵盖了Java开发中的多个重要知识点,对于准备Java面试的人来说是需要重点掌握的内容。在实际面试中,可能会根据具体职位和公司的要求,对这些知识点进行不同程度的深入考查。 阅读详情

相关推荐

Java八股文面试题

Java基础八股文(背诵版)

y190115的博客 6934

全网最全JAVA面试八股文,终于整理完了

今天为大家整理了目前互联网出现率最高的大厂面试题,所谓八股文也就是指文章的八个部分,文体有固定格式:由破题、承题、起讲、入题、起股、中股、后股、束股八部分组成,题目一律出自四书五经中的原文。 而JAVA面试八股文也就是为了考验大家的JAVA基础功底,所以强烈建议背诵全文。

weixin_64403990的博客 3万+

后端面试八股文骚套路之Java基础

一年一度的秋招大戏又快拉开序幕了,近年来后端岗位越来越卷,毕业生的压力也越来越大。个人感觉目前各个大中厂校招面试不好的地方是,都在朝着背面试八股文的方向发展(曾经面试某二线厂,对着面试官纯背了 40 分钟概念),但不得不承认这也是企业在短时间内筛选面试者的一个重要手段。 为了帮助大家了解后端面试八股文应该怎么背,特此推出面试八股文画重点系列(包含的内容有 Java 基础、JVM、MySQL、Redis、操作系统、计算机网络、设计模式)。希望能帮助到 Java 基础不是很好的同学能快速的准备好面试八股文。.

CS指南 4497

2025年 Java 面试八股文(20w字)

目录第一章-Java基础篇1、你是怎样理解OOP面向对象 难度系数:⭐2、重载与重写区别 难度系数:⭐3、接口与抽象类的区别 难度系数:⭐4、深拷贝与浅拷贝的理解 难度系数:⭐5、sleep和wait区别 难度系数:⭐6、什么是自动拆装箱 int和Integer有什么区别 难度系数:⭐7、==和equals区别 难度系数:⭐8、String能被继承吗 为什么用final修饰 难度系数:⭐9、String buffer和String builder区别

leader_song的博客 44万+

Java八股文你会背了吗?

这份Java面试八股文让329人成功进入大厂,堪称2021最强 2021秋招已经一段时间了,很多同学会问Java面试八股文有必要背吗? 我的回答是:很有必要。你可以讨厌这种模式,但你一定要去背,因为不背你就进不了大厂。 国内的互联网面试,恐怕是现存的、最接近科举考试的制度。 而且,我国的八股文确实是独树一帜。以美国为例,北美工程师面试比较重视算法(Coding),近几年也会加入Design轮(系统设计和面向对象设计OOD)和BQ轮(Behavioral que...

Joyces.iboc 1326

西门子S7-1200模拟量的使用

模块类型核心参数输入信号处理输出信号配置转换原理数值范围TIA Portal配置编程要点 转换公式: 输出模拟量: 五、校准与线性化 硬件校准非线性补偿抗干扰措施数字滤波温度控制压力监控流量调节信号异常精度不足实践操作参考文档项目案例借鉴博客

weixin_51020122的博客 4771

Java面试必备八股文

Java面试必备的八股文

weixin_46350527的博客 6万+

Difftest踩坑笔记(一)

Difftest是差分测试框架,有什么用呢?高性能CPU的设计需要做复杂的测试,传统的测试方法运行较慢,而且出了问题很难定位,Difftest就是为了解决这两个问题。

http://www.icfgblog.com/ 4196

2024年Java面试八股文(全网最全)

死锁就是一组互相竞争资源的线程,因为互相等待又互不相让资源,导致永久阻塞无法进行下去的情况死锁产生的条件有四个:互斥条件:资源x和y只能分别被一个线程占用占有且等待:线程t1占有资源x后,等待资源y被释放,同时自己不释放资源x不可抢占:其他线程不能强行抢占线程t1占有的资源循环等待:线程t1等待线程t2占有的资源,线程t2等待线程t1占有的资源避免死锁的方法(破坏对应的条件):一次性申请所有资源(破坏互斥条件)

2301_78976656的博客 2万+

OAI数据集申请下载全攻略:从个人NDA账号注册到数据包下载的保姆级避坑指南

本文提供OAI数据集申请下载的完整指南,涵盖从个人NDA账号注册到数据包下载的全流程。重点解析login.gov验证陷阱、浏览器兼容性问题、NDA权限申请技巧及nda-tools高效使用方法,帮助医学影像研究者避开常见技术障碍,快速获取全球骨关节炎研究数据库OAI的宝贵数据资源。

weixin_28698059的博客 752

ALTERA Triple-Speed Ethernet IP核在UDP通信中的实战配置指南

本文详细介绍了在Intel FPGA(原ALTERA)平台上配置Triple-Speed Ethernet IP核以实现UDP通信的实战指南。内容涵盖从IP核选型、QSYS系统搭建、关键参数配置,到UDP数据包组装、NIOS C程序调试及上板验证的全流程,重点解析了如何利用该IP核快速构建稳定的千兆网通信基础,为FPGA网络应用开发提供清晰路径。

m3n5b7v8c9x的博客 512

Java八股文——Java基础篇

本文详细收集了Java八股文面试中常见的24个经典问题,并给出了详细的解答方案。

郎逸的博客 2155

在claude code desktop中安装pdf处理skill的实战教程

本文介绍了在Claude Code Desktop中安装PDF处理Skill的详细教程。针对国内用户使用第三方API时无法直接调用官方插件的问题,提供了完整的解决方案。教程从下载Anthropic官方Skills源码开始,逐步演示了如何将PDF处理模块打包、上传至Claude Code Desktop,并最终成功加载使用。整个过程采用全流程拆解方式,确保新手也能快速上手。通过本文,读者可以掌握在非官方环境下扩展Claude Code功能的方法,从而提升工作效率

weixin_43178406的博客 9万+

java八股文笔记

Java八股文是Java面试常见知识点的集合,涵盖Java基础、框架、多线程、JVM、数据库、中间件等10大核心领域。 Java基础包括面向对象特性(封装、继承、多态)、基本数据类型、final/static关键字、String特性、重载与重写、抽象类与接口区别、==与equals比较等。 容器区别: List(有序、可重复):如ArrayList、LinkedList。 Set(无序、唯一):如HashSet、TreeSet。 Map(键值对):如HashMap、TreeMap。 其他重点:JVM内存模型

2401_89221445的博客 1103

Camera HAL 多线程管理详解

本文摘要:Camera HAL 采用双线程管理体系(CAMX与CHI-CDK)实现高效并发处理。CAMX ThreadManager负责HAL内部及框架交互,采用线程池+任务调度机制,将节点处理、回调等封装为Job异步执行;CHI ThreadManager专注于OEM定制逻辑,支持异步/同步两种作业模式。两套系统通过函数指针解耦但共享地址空间,共同实现硬件流水线的强实时性。文章详细解析了两者的类层次架构、核心数据结构及典型应用场景,并提供了问题排查的代码切入点,为Camera HAL开发与性能优化提供指导

DU_YULIN的博客 56

【01】总目录——软件设计师50讲通关地图|从零基础到工程师职称

本文是《软件设计师·50讲通关|从零基础到工程师职称》专栏的01篇总目录,系统梳理了50篇博文的完整架构与核心逻辑。专栏覆盖软考软件设计师(中级)全部考点,分为导学规划、基础知识、设计模式、下午题专项、算法实战、冲刺模拟、收官进阶七大模块,既兼顾上午题75道单选题的理论攻坚,也聚焦下午题案例分析的解题能力提升。每篇博文均包含考点精讲、真题解析、实战技巧与速记方法,配套可运行代码、解题模板及备考资源。无论你是零基础转行、在校学生还是在职程序员,都能通过这份学习地图明确进度、精准定位薄弱环节,高效搭建知识体系

专注于人工智能、软件开发、工控自动化、工厂数字化及智能化等领域,希望和大家共同进步! 1279

Java八股文基础知识

Java八股文的基本知识以及Java的基本运用。你我山巅自相逢!赠给正在努力的我们!

m0_73430476的博客 2217

YOLOv11涨点改进 | 全网独家创新,注意力改进篇 | TGRS 2025 | 引入APCM自适应像素级协同机制,动态增强目标区域、抑制背景噪声,助力YOLOv11做红外小目标检测有效涨点

本文提出了一种基于APCM模块改进的YOLOv11网络模型,通过像素级局部-全局协同建模增强目标特征并抑制背景噪声。APCM模块采用轻量化设计,无需复杂参数,能有效提升小目标检测性能。文章详细介绍了APCM的原理、优势及其在红外小目标检测中的应用,包括模块结构、核心代码实现和YAML配置文件修改方法。实验结果表明,该方法在NUAA-SIRST和IRSTD-1K数据集上优于现有技术,显著提高了复杂场景下的检测精度与鲁棒性。

Ai缝合怪、助力小伙伴高效发论文 116

行业黑话——Java八股文到底是啥?

在解释行业黑话之前,我们先来说一说正儿八经的八股文。 首先说清楚八股文的原意,是明清科举考试的一种文体,有固定格式:由破题、承题、起讲、入手、起股、中股、后股、束股八部分组成,题目一律出自四书五经中的原文。后四部分是文章议论的中心,各有两股对偶文字,共八股,故名。 那为什么我们会说JAVA八股文呢? 因为现在Java程序员在面试的时候,大多数公司模式都比较固定,问的问题也差不多,所以Java程序员八股文是指程序员在面试过程中经常被问到的问题,大多都有固定化、格式化的答案,俗称为面经。 问题示意:

weixin_42097508的博客 3万+

android 蓝牙通讯demo

android 下蓝牙通讯demo,实现了发现蓝牙,使能蓝牙,通过蓝牙发送消息。

ET2012新版免狗免安装绿色软件

ET2012新版免狗免安祖昂绿色软件。,新界面,新视觉,

java八股文是什么?

在现代编程面试中,"Java八股文"涵盖了Java基础、Java集合、多线程与并发、JVM(Java虚拟机)、设计模式、框架(如Spring、Hibernate)、数据库、网络编程等领域的知识点。3. **多线程与并发**:包括线程的创建和管理、同步机制、Java内存模型、并发工具类(如ExecutorService、CountDownLatch)等。1. **Java基础知识**:包括Java数据类型、面向对象编程(OOP)概念、异常处理、泛型、反射等。

2301_79507619的博客 2848

ssm框架搭建

这个是一个在idea上成功跑起来的ssm框架项目,保存在这里方便以后使用直接下载

Java面试为什么要背八股文?

Java面试中的"八股文"指那些标准化、高频的技术问题,涵盖Java基础、JVM、并发编程、框架原理等核心知识点。这类问题便于企业快速筛选候选人,评估技术深度,但也可能抑制创新。建议采取理解优先、知识关联、刻意练习等方法高效准备,同时注重项目实践和系统设计能力。当前的面试趋势正转向更多场景化问题,但扎实的基础和清晰的思维仍是关键。真正的技术成长需要将八股文框架与实践经验结合,形成自己的技术认知体系。

m0_66884848的博客 1588

迈瑞BS系列全自动生化分析仪LIS协议接口手册(内含HL7和ASTM)

迈瑞BS系列全自动生化分析仪LIS协议接口手册,内含HL7和ASTM)

三天吃透Java面试八股文

所以,我采访了超过20位资深大厂面试官后,一直在尽量精炼准确的整理一套切实可行的八股文,现在已经有129位粉丝通过这套题走入了理想的岗位,所以分享出来给大伙看看,有什么不足之处欢迎评论补充。简单来说,互联网IT行业的求职者太多了,如果考察的是清一溜的算法题和设计题,那么会要求面试官有极高的技术水平,还要花大量的时间成本和精力。篇幅所限本文就只贴一下题目了,各位可以自己先看看有哪些题是会的,答案的话我整理的一本。23. SpringMVC 的控制器是不是单例模式,如果是会有什么问题,怎么解决?

tangjieqing的博客 2043

java基础八股文

java基础八股文

weixin_43928138的博客 415
上一篇: Java八股文系列六:泛型
weixin_39290259
博客等级 码龄9年 3粉丝 13原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值