【面试题笔记-Java】Java基础

参考JavaGuide和一些面经做的笔记,方便自己记忆

Java基础

1. 面向对象和面向过程的区别

面向对象的设计思想是将需要解决的问题分解成一个个对象,这一个个对象可以用来描述在完成这件事中扮演的具体角色和行为。

面向过程的设计思想是将需要解决的问题拆分成一个个具体的步骤,然后设置这些步骤的实现方法,然后按照顺序一步步实现即可

优缺点:
面向对象相较于面向过程而言,有着易维护、易复用和易扩展的特点,由于面向对象有封装、继承和多态的特点,所以能够设计出低耦合的系统,易于去维护;而相对面向过程,面向对象性能较低

2.Java语言有哪些特点

1.简单易学

2.面向对象(具有封装、继承和多态的特性)

3.安全性高

4.可靠性强

5.具有跨平台性(JVM),一处编译、处处运行

6.支持多线程

7.能够进行网络编程且很容易实现

8.java是一门半解释半编译的语言

3.JVM及字节码

JVM能够在不同的系统上,将源码编译成的字节码翻译成系统能够读懂的二进制机器码,进而可以达到一处编译,处处运行的特点

【面试题笔记-Java】Java基础_第1张图片

Java是半解释半编译语言,首先使用解释器进行预热编译,出现次数超过阈值的热点代码将会直接通过JIT编译器进行编译,热点代码编译后的机器指令将存储在方法区,下次可以直接使用

字节码是源代码编译后的产物,也就是.class文件,可以被JVM处理,只面向虚拟机。使用它的好处是Java 语言通过字节码的方式,在一定程度上解决了传统解释型语言执行效率低的问题,同时又保留了解释型语言可移植的特点。所以 Java 程序运行时比较高效,而且,由于字节码并不针对一种特定的机器,因此,Java 程序无须重新编译便可在多种不同操作系统的计算机上运行。

4.JDK和JRE

JDK是功能齐全的Java SDK。它拥有JRE拥有的一切,还拥有编译器(Javac)和一些工具(如javadoc)。他能够创建和编译程序。

JRE是Java运行时环境,是运行已编译的Java程序的所需所有内容的集合,包括有JVM,Java类库,java命令和其他的一些基础构件。但是他不能用于创建新程序。

5.Oracle JDK和OpenJDK的对比

简单来说,OpenJDK是sun公司开源的oracle jdk中除去商业功能部分的所有内容。

也就是说,oracle jdk是open jdk的一个实现,并不是完全开源的,open jdk是完全开源的。

oracle jdk比open jdk更加稳定,因为进过了彻底的测试和稳定,如果要进行商业用途,最好是用oracle jdk。

在响应性和jvm性能方面,oracle jdk性能同样比open jdk 更加优秀。

Oracle JDK 不会为即将发布的版本提供长期支持,用户每次都必须通过更新到最新版本获得支持来获取最新版本。

Oracle JDK 根据二进制代码许可协议获得许可,而 OpenJDK 根据 GPL v2 许可获得许可

6.java和cpp的区别

1.都是面向对象的语言(有封装、继承、动态的特性)

2.java不提供指针直接访问内存,相对来说更加安全

3.java只支持单继承,cpp是多继承;java支持多实现接口

4.java内部有自动内存管理机制,不需要手动释放内存

5.C++字符串尾部会有一个’\0’作为结尾符,但是java语言中并没有

7.什么是java程序的主类,应用程序和小程序的主类有什么区别?

主类是java程序执行的入口点。一个程序可以有多个类,但是主类只能有一个。在应用程序中,主类可以不要求public修饰,是拥有main()方法的类;而在小程序中,主类必须要求是public修饰,这个主类是一个继承自系统类 JApplet 或 Applet 的子类

8.java应用程序与小程序之间有哪些差别?

简单来说,java应用程序是从主线程中启动,也就是main()方法启动,app小程序主要是嵌在浏览器页面上运行(调用init()或者是run()方法来启动),嵌入浏览器这点和小游戏类似

9.字符型常量和字符串常量的区别

1.形式上:字符型常量是用单引号’'引起来的单个字符;字符串常量是""若干个字符引起来的

2.含义上:字符型常量相当于一个整型值(ASCII值),可以参与表达式运算;字符串常量代表一个地址(描述字符串常量在内存中存放的位置)

3.占内存大小:字符型常量占2个字节;字符串常量占若干个字节

10.构造器是否可以被重写

构造器不能被重写,但是可以被重载,重载方式:方法名一致,参数类型或参数个数不一样。

11.重载与重写的区别

重载:同样的方法,根据输入数据的不同,做出不同处理

重写:子类继承父类的相同方法,输入数据需要一致,要做出有别于父类的处理和响应,覆盖父类方法

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

  • 重写发生在运行期,能对子类对父类允许访问的方法内部逻辑进行改变实现

    • 其中方法名,返回值,参数列表必须相同,抛出的异常范围必须小于等于父类(也就是抛出的异常能够让父类接受),访问修饰符要大于等于父类
    • 如果父类方法访问修饰符为 private/final/static 则子类就不能重写该方法,但是被 static 修饰的方法能够被再次声明(private子类无访问权限,final保证不能被修改,子类可以声明同名的static方法,但是不是继承,仅是再次声明)
    • 构造方法无法被重写

12.java面向对象编程的三大特性:封装、继承和多态

封装

封装是将一个对象的属性进行私有化,给外界访问提供一些方法来访问这些私有属性,如果不想外界访问也可以不提供这些方法,但这个类存在也没什么意义了。

继承

继承是使用已存在的类来建立新的类的技术,新的类可以定义新的属性和新的方法,能够使用父类的技术,但是必须完全继承自存父类,不能选择性的继承。通过使用继承我们可以很方便的复用以前的代码

  1. 子类拥有父类对象所有的属性和方法(包括私有属性和私有方法),但是父类中的私有属性和方法子类是无法访问,只是拥有
  2. 子类可以拥有自己属性和方法,即子类可以对父类进行扩展。
  3. 子类可以用自己的方式实现父类的方法。

多态

指在程序定义中引用变量所指向的具体类型和通过该引用变量发出的方法具体调用对象在编译的时候并不确定,即引用变量指向哪个类的实例对象,引用对象调用的方法到底是哪个类发出的是并不确定,只有在程序运行时才能确定。

Java实现多态可以是继承和实现

13.String StringBuffer 和 StringBuilder 的区别是什么? String 为什么是不可变的?

String的不可变性:
String类是已经被声明为final的, 不可被继承

String代表不可变的字符序列(简称不可变性)

  • 当对字符串重新赋值时,需要重新指定内存区域赋值,不能使用原有的value进行赋值。
  • 当对现有的字符串进行连接操作时,也需要重新指定内存区域赋值,不能使用原有的value进行赋值。
  • 当调用String的replace()方法修改指定字符或字符串时,也需要重新指定内存区域赋值,不能使用原有的value进行赋值。

StringBuilder 与 StringBuffer 的区别

StringBuilder 与 StringBuffer 都继承自 AbstractStringBuilder 类,都有相同的一些方法比如append,indexof等

从线程安全性上来说,String对象是不可变的,可以理解成常量,是线程安全的。StringBuffer对内部方法调用了同步锁,是线程安全的;而StringBuilder没有加锁,是线程不安全的。

从性能上来说,当然是加锁了StringBuffer性能比较慢,而没有加锁的StringBuilder比较快

对于三者使用的总结:

  1. 操作少量的数据: 适用 String
  2. 单线程操作字符串缓冲区下操作大量数据: 适用 StringBuilder
  3. 多线程操作字符串缓冲区下操作大量数据: 适用 StringBuffer

14.自动拆箱与自动装箱

装箱:将基本类型用它们对应的引用类型包装起来;比如Integer i = 20;//将20包装成Integer

拆箱:将包装类型转换为基本数据类型;比如int a = i;//将上面的包装类型进行拆箱

使用integer时,数值在[-128,127]之间,便返回指向IntegerCache.cache中已经存在的对象的引用;否则创建一个新的Integer对象。

public class Main {
  public static void main(String[] args) {
    
    Integer i1 = 100;
    Integer i2 = 100;
    Integer i3 = 200;
    Integer i4 = 200;
    
    System.out.println(i1==i2);//true,指向同一个对象
    System.out.println(i3==i4);//false指向不同对象
  }
}
public class Test1 {
    public static void main(String[] args) {

        Double i1 = 100.0;
        Double i2 = 100.0;
        Double i3 = 200.0;
        Double i4 = 200.0;

        System.out.println(i1==i2);//false,直接创建两个不同对象
        System.out.println(i3==i4);//false,直接创建两个不同对象
    }
}

注意,Integer、Short、Byte、Character、Long这几个类的valueOf方法的实现是类似的。Double、Float的valueOf方法的实现是类似的。

15.在一个静态方法内调用一个非静态成员为什么是非法的?

由于静态方法可以不通过对象进行调用,因此在静态方法里,不能调用其他非静态变量,也不可以访问非静态变量成员。

一个非静态成员在未实例化前是不存在的,静态方法是不用实例化就可以调用的,所以调用不到非静态变量、成员和方法。

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

如果有该类有子类,就会在调用子类实例过程,在构造方法中默认调用super()。如果父类没有无参数构造方法,只有有参数构造方法,父类就不会默认创建一个无参构造方法,导致super()调用失败。

17.import java 和 javax 有什么区别?

java和javax都是Java的API包,java为baijava语言的核du心包,javax为java语言的扩展包。
java包是java基础zhi核心类库,也就是Java Development kit ,提供java语言编程核dao心包,如io、awt、集合库(如Collection、List、Map)等;
javax是java基础上的扩展包,如swing、servlet、jsp、xml等类库。

18.接口和抽象类的区别是什么?

  1. 接口的方法默认是 public,所有方法在接口中不能有实现(Java 8 开始接口方法可以有默认实现),而抽象类可以有非抽象的方法。
  2. 接口中除了 static、final 变量,不能有其他变量,而抽象类中则不一定。
  3. 一个类可以实现多个接口,但只能实现一个抽象类。接口自己本身可以通过 extends 关键字扩展多个接口。
  4. 接口方法默认修饰符是 public,抽象方法可以有 public、protected 和 default 这些修饰符(抽象方法就是为了被重写所以不能使用 private 关键字修饰!)。
  5. 从设计层面来说,抽象是对类的抽象,是一种模板设计,而接口是对行为的抽象,是一种行为的规范

总结一下 jdk7~jdk9 Java 中接口概念的变化:

  1. 在 jdk 7 或更早版本中,接口里面只能有常量变量和抽象方法。这些接口方法必须由选择实现接口的类实现。
  2. jdk8 的时候接口可以有默认方法和静态方法功能。
  3. Jdk 9 在接口中引入了私有方法和私有静态方法。

19.成员变量与局部变量的区别有哪些?

1.成员变量属于类,局部变量属于方法。成员变量可以使用访问权限符和static来修饰,而成员变量不行。他们都可以用final来修饰

2.存储方式也有区别。如果成员变量用static修饰,这个成员变量是属于类的,是类成员变量;如果没有用static,这个成员变量是属于实例的,只有实例对象可以使用。局部变量为基本数据类型,则存储在栈内存内,如果是引用数据类型,则存储堆中引用对象的地址或者是指向常量池的地址

3.从生命周期来看,成员变量和实例对象是一样的;局部变量随着方法的生命周期一致。

4.成员变量会被默认赋值,而局部变量不会默认赋值,必须手动赋值

20.创建一个对象用什么运算符?对象实体与对象引用有何不同?

new运算法。new的引用放在栈中,new的实体放在堆内存中。一个对象引用可以指向0个或者1个对象实例,一个对象实例可以被0-n个对象引用指向

21.什么是方法的返回值?返回值在类的方法里的作用是什么?

方法的返回值是指我们获取到的某个方法体中的代码执行后产生的结果。返回值就是一个值,可以用于操作运算和赋值

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

对一个类进行初始化。能。默认会创建一个无参构造方法

23.构造方法有哪些特性?

1.构造方法名字和类相同

2.没有返回值,但是不能用void

3.产生实例的时候自动调用

24.静态方法和实例方法有何不同

1.调用方式来说,实例方法的调用必须通过实例后的对象.方法进行调用,而静态方法无序实例化,直接类名.方法就可以调用,也可以通过对象.方法进行调用

2.静态方法只允许调用本类的静态方法和静态变量,因为执行前就已经初始化;而实例方法无限制

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

对象的相等是内存中的内容是否相等,而引用相等是地址是否相等

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

帮助子类做初始化工作

27.== 与 equals

==:

如果==比较的是基本数据类型,那就是比较他们的值是否相等。

如果==比较是的引用数据类型,就是比较他们的地址是否相等。

equals():

比较两个对象是否相等。如果没有重写equals,作用和==类似。如果重写了equals,一般重写都是比较内容了

拿String来说:

  • String 中的 equals 方法是被重写过的,因为 object 的 equals 方法是比较的对象的内存地址,而 String 的 equals 方法比较的是对象的值。
  • 当创建 String 类型的对象时,虚拟机会在常量池中查找有没有已经存在的值和要创建的值相同的对象,如果有就把它赋给当前引用。如果没有就在常量池中重新创建一个 String 对象。

28.hashCode 与 equals (重要)

面试官可能会问你:“你重写过 hashcode 和 equals 么,为什么重写 equals 时必须重写 hashCode 方法?”

hashCode()介绍

hashCode() 的作用是获取哈希码,也称为散列码;它实际上是返回一个 int 整数。这个哈希码的作用是确定该对象在哈希表中的索引位置。hashCode() 定义在 JDK 的 Object.java 中,这就意味着 Java 中的任何类都包含有 hashCode() 函数。

散列表存储的是键值对(key-value),它的特点是:能根据“键”快速的检索出对应的“值”。这其中就利用到了散列码!(可以快速找到所需要的对象)

为什么要有 hashCode

我们先以“HashSet 如何检查重复”为例子来说明为什么要有 hashCode: 当你把对象加入 HashSet 时,HashSet 会先计算对象的 hashcode 值来判断对象加入的位置,同时也会与该位置其他已经加入的对象的 hashcode 值作比较,如果没有相符的 hashcode,HashSet 会假设对象没有重复出现。但是如果发现有相同 hashcode 值的对象,这时会调用 equals()方法来检查 hashcode 相等的对象是否真的相同。如果两者相同,HashSet 就不会让其加入操作成功。如果不同的话,就会重新散列到其他位置。(摘自我的 Java 启蒙书《Head first java》第二版)。这样我们就大大减少了 equals 的次数,相应就大大提高了执行速度。

通过我们可以看出:hashCode() 的作用就是获取哈希码,也称为散列码;它实际上是返回一个 int 整数。这个哈希码的作用是确定该对象在哈希表中的索引位置。hashCode()在散列表中才有用,在其它情况下没用。在散列表中 hashCode() 的作用是获取对象的散列码,进而确定该对象在散列表中的位置。

hashCode()与 equals()的相关规定

  1. 如果两个对象相等,则 hashcode 一定也是相同的
  2. 两个对象相等,对两个对象分别调用 equals 方法都返回 true
  3. 两个对象有相同的 hashcode 值,它们也不一定是相等的
  4. 因此,equals 方法被覆盖过,则 hashCode 方法也必须被覆盖
  5. hashCode() 的默认行为是对堆上的对象产生独特值。如果没有重写 hashCode(),则该 class 的两个对象无论如何都不会相等(即使这两个对象指向相同的数据)
public class Student {
    int age;
    String name ;

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        Student student = (Student) o;
        return age == student.age &&
                Objects.equals(name, student.name);
    }

    @Override
    public int hashCode() {
        return Objects.hash(age, name);
    }
}

29.为什么 Java 中只有值传递?

方法参数是基本数据类型的话,就是将数据进行拷贝后执行方法体;如果是引用数据类型,就可以改变指向的具体内存中的数据。

  • 一个方法不能修改一个基本数据类型的参数(即数值型或布尔型)。
  • 一个方法可以改变一个对象参数的状态。
  • 一个方法不能让对象参数引用一个新的对象。

请你解释什么是值传递和引用传递?

值传递是对基本型变量而言的,传递的是该变量的一个副本,改变副本不影响原变量.
引用传递一般是对于对象型变量而言的,传递的是该对象地址的一个副本, 并不是原对象本身 。 所以对引用对象进行操作会同时改变原对象.一般认为java内的传递都是值传递.

30.简述线程、程序、进程的基本概念。以及他们之间关系是什么?

线程与进程相似,但线程是一个比进程更小的执行单位。一个进程在其执行的过程中可以产生多个线程。与进程不同的是同类的多个线程共享同一块内存空间和一组系统资源,所以系统在产生一个线程,或是在各个线程之间作切换工作时,负担要比进程小得多,也正因为如此,线程也被称为轻量级进程。

程序是含有指令和数据的文件,被存储在磁盘或其他的数据存储设备中,也就是说程序是静态的代码。

进程是程序的一次执行过程,是系统运行程序的基本单位,因此进程是动态的。系统运行一个程序即是一个进程从创建,运行到消亡的过程。简单来说,一个进程就是一个执行中的程序,它在计算机中一个指令接着一个指令地执行着,同时,每个进程还占有某些系统资源如 CPU 时间,内存空间,文件,输入输出设备的使用权等等。换句话说,当程序在执行时,将会被操作系统载入内存中。 线程是进程划分成的更小的运行单位。线程和进程最大的不同在于基本上各进程是独立的,而各线程则不一定,因为同一进程中的线程极有可能会相互影响。从另一角度来说,进程属于操作系统的范畴,主要是同一段时间内,可以同时执行一个以上的程序,而线程则是在同一程序内几乎同时执行一个以上的程序段。

31.线程有哪些基本状态?

1.初始状态:线程被构建,未调用start()方法

2.运行状态:java将运行和就绪都成为运行状态

3.阻塞状态:表示线程被阻塞

4.等待状态:表示该线程进入等待,需要线程通知或中断

5.超时等待状态:不同于等待,可以在指定的时间自行返回

6.终止状态:表示当前线程已被执行完毕

当线程执行 wait()方法之后,线程进入 **WAITING(等待)**状态。进入等待状态的线程需要依靠其他线程的通知才能够返回到运行状态,而 TIME_WAITING(超时等待) 状态相当于在等待状态的基础上增加了超时限制,比如通过 sleep(long millis)方法或 wait(long millis)方法可以将 Java 线程置于 TIMED WAITING 状态。当超时时间到达后 Java 线程将会返回到 RUNNABLE 状态。当线程调用同步方法时,在没有获取到锁的情况下,线程将会进入到 BLOCKED(阻塞) 状态。线程在执行 Runnable 的run()方法之后将会进入到 TERMINATED(终止) 状态。

32.关于 final 关键字的一些总结

final主要用于变量、方法和类中

1.变量中:被final修饰的基本数据类型变量必须被显式地初始化,且初始化以后不能被改变;被final修饰的引用变量在初始化以后不能指向别的对象。

2.方法中:被final修饰的方法无法被其子类重写;同时能够在一定程度上提升方法执行效率。类中所有的private方法被隐式定义为了final方法

3.类中:被final修饰的类无法被继承,类中的所有成员方法都默认修饰final

33.Java中的异常处理

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-vz3l8SGc-1597310853805)(D:\学习笔记\面试题复习\imgs\java基础\Exception.png)]

在 Java 中,所有的异常都有一个共同的祖先 java.lang 包中的 Throwable 类。Throwable: 有两个重要的子类:Exception(异常)Error(错误) ,二者都是 Java 异常处理的重要子类,各自都包含大量子类。

Error(错误):是程序无法处理的错误,表示运行应用程序中较严重问题。大多数错误与代码编写者执行的操作无关,而表示代码运行时 JVM(Java 虚拟机)出现的问题。例如,Java 虚拟机运行错误(Virtual MachineError),当 JVM 不再有继续执行操作所需的内存资源时,将出现 OutOfMemoryError。这些异常发生时,Java 虚拟机(JVM)一般会选择线程终止。

这些错误表示故障发生于虚拟机自身、或者发生在虚拟机试图执行应用时,如 Java 虚拟机运行错误(Virtual MachineError)、类定义错误(NoClassDefFoundError)等。这些错误是不可查的,因为它们在应用程序的控制和处理能力之 外,而且绝大多数是程序运行时不允许出现的状况。对于设计合理的应用程序来说,即使确实发生了错误,本质上也不应该试图去处理它所引起的异常状况。在 Java 中,错误通过 Error 的子类描述。

Exception(异常):是程序本身可以处理的异常。Exception 类有一个重要的子类 RuntimeException。RuntimeException 异常由 Java 虚拟机抛出。NullPointerException(要访问的变量没有引用任何对象时,抛出该异常)、ArithmeticException(算术运算异常,一个整数除以 0 时,抛出该异常)和 ArrayIndexOutOfBoundsException (下标越界异常)。

注意:异常和错误的区别:异常能被程序本身处理,错误是无法处理。

Throwable 类常用方法

  • public string getMessage():获取异常信息
  • public string toString():获取异常详细信息
  • public string getLocalizedMessage():返回异常对象的本地化信息。使用 Throwable 的子类覆盖这个方法,可以生成本地化信息。如果子类没有覆盖该方法,则该方法返回的信息与 getMessage()返回的结果相同
  • public void printStackTrace():在控制台上打印 Throwable 对象封装的异常信息

异常处理总结

  • try 块: 用于捕获异常。其后可接零个或多个 catch 块,如果没有 catch 块,则必须跟一个 finally 块。
  • catch 块: 用于处理 try 捕获到的异常。
  • finally 块: 无论是否捕获或处理异常,finally 块里的语句都会被执行。当在 try 块或 catch 块中遇到 return 语句时,finally 语句块将在方法返回之前被执行。

在以下 4 种特殊情况下,finally 块不会被执行:

  1. 在 finally 语句块第一行发生了异常。 因为在其他行,finally 块还是会得到执行
  2. 在出现异常前中用了 System.exit(int)已退出程序。 exit 是带参函数 ;
  3. 程序所在的线程死亡。
  4. 关闭 CPU。

34.Java 序列化中如果有些字段不想进行序列化,怎么办?

序列化:将java对象转换成字节序列;反序列化:将字节序列恢复成java对象

对于不想进行序列化的变量,使用 transient 关键字修饰。

transient 关键字的作用是:阻止实例中那些用此关键字修饰的的变量序列化;当对象被反序列化时,被 transient 修饰的变量值不会被持久化和恢复。transient 只能修饰变量,不能修饰类和方法。

35.获取用键盘输入常用的两种方法

Scanner和BufferedReader都可以读入键盘输入

方法 1:通过 Scanner

Scanner input = new Scanner(System.in);
String s  = input.nextLine();
input.close();Copy to clipboardErrorCopied

方法 2:通过 BufferedReader

BufferedReader input = new BufferedReader(new InputStreamReader(System.in));
String s = input.readLine();

36.Java 中 IO 流详解

IO流分类

  • 按流的流向分,可分为输入流和输出流
  • 按操作单元可以分为字节流和字符流
  • 按照流的角色可以分为节点流和处理流

基类是InputStream、Reader、OutputStream、Writer

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

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

问题本质想问:不管是文件读写还是网络发送接收,信息的最小存储单元都是字节,那为什么 I/O 流操作要分为字节流操作和字符流操作呢?

回答:字符流是由 Java 虚拟机将字节转换得到,需要->字节流->另一端接收->转换成字符流读取。所以如果仅涉及文本内容的I/O流,直接使用字符流会更加方便,也不会产生乱码。

37.BIO,NIO,AIO 有什么区别?

同步与异步

  • 同步: 同步就是发起一个调用后,被调用者未处理完请求之前,调用不返回。
  • 异步: 异步就是发起一个调用后,立刻得到被调用者的回应表示已接收到请求,但是被调用者并没有返回结果,此时我们可以处理其他的请求,被调用者通常依靠事件,回调等机制来通知调用者其返回结果。

同步和异步的区别最大在于异步的话调用者不需要等待处理结果,被调用者会通过回调等机制来通知调用者其返回结果。

阻塞和非阻塞

  • 阻塞: 阻塞就是发起一个请求,调用者一直等待请求结果返回,也就是当前线程会被挂起,无法从事其他任务,只有当条件就绪才能继续。
  • 非阻塞: 非阻塞就是发起一个请求,调用者不用一直等着结果返回,可以先去干其他事情。

BIO、NIO、AIO区别

  • BIO (Blocking I/O): 同步阻塞 I/O 模式,数据的读取写入必须阻塞在一个线程内等待其完成。在活动连接数不是特别高(小于单机 1000)的情况下,这种模型是比较不错的,可以让每一个连接专注于自己的 I/O 并且编程模型简单,也不用过多考虑系统的过载、限流等问题。线程池本身就是一个天然的漏斗,可以缓冲一些系统处理不了的连接或请求。但是,当面对十万甚至百万级连接的时候,传统的 BIO 模型是无能为力的。因此,我们需要一种更高效的 I/O 处理模型来应对更高的并发量。
  • NIO (Non-blocking/New I/O): NIO 是一种同步非阻塞的 I/O 模型,在 Java 1.4 中引入了 NIO 框架,对应 java.nio 包,提供了 Channel , Selector,Buffer 等抽象。NIO 中的 N 可以理解为 Non-blocking,不单纯是 New。它支持面向缓冲的,基于通道的 I/O 操作方法。 NIO 提供了与传统 BIO 模型中的 SocketServerSocket 相对应的 SocketChannelServerSocketChannel 两种不同的套接字通道实现,两种通道都支持阻塞和非阻塞两种模式。阻塞模式使用就像传统中的支持一样,比较简单,但是性能和可靠性都不好;非阻塞模式正好与之相反。对于低负载、低并发的应用程序,可以使用同步阻塞 I/O 来提升开发速率和更好的维护性;对于高负载、高并发的(网络)应用,应使用 NIO 的非阻塞模式来开发
  • AIO (Asynchronous I/O): AIO 也就是 NIO 2。在 Java 7 中引入了 NIO 的改进版 NIO 2,它是异步非阻塞的 IO 模型。异步 IO 是基于事件和回调机制实现的,也就是应用操作之后会直接返回,不会堵塞在那里,当后台处理完成,操作系统会通知相应的线程进行后续的操作。AIO 是异步 IO 的缩写,虽然 NIO 在网络操作中,提供了非阻塞的方法,但是 NIO 的 IO 行为还是同步的。对于 NIO 来说,我们的业务线程是在 IO 操作准备好时,得到通知,接着就由这个线程自行进行 IO 操作,IO 操作本身是同步的。查阅网上相关资料,我发现就目前来说 AIO 的应用还不是很广泛,Netty 之前也尝试使用过 AIO,不过又放弃了。

38.深拷贝和浅拷贝

简单来说,如果是对于基本数据类型而言,深拷贝和浅拷贝都仅仅是对值进行复制;而对于引用类型,深拷贝是拷贝一个内容完全一样的对象,而浅拷贝仅仅是拷贝地址。比如一个Int类型数据,无论深浅拷贝,都是拷贝这个数具体值,而例如一个int数组{1,2,3},深拷贝拷贝一个{1,2,3}的数组,地址不一致,浅拷贝则是拷贝数组地址

39.什么是java序列化?如何实现java序列化?

java序列化就是将对象转换成字节序列。实现方法就是让对应对象实现serialization接口,是一个标记性接口,不需要重写方法,然后构造一个ObjectOutPutStream对象输出流,使用writeObject方法将Obj写成字节序列

40.你知道java8的新特性吗,请简单介绍一下

Lambda 表达式 :Lambda允许把函数作为一个方法的参数
方法引用: 方法引用提供了非常有用的语法,可以直接引用已有Java类或对象(实例)的方法或构造器。与lambda联合使用,方法引用可以使语言的构造更紧凑简洁,减少冗余代码。
默认方法:默认方法就是一个在接口里面有了一个实现的方法。
新工具:新的编译工具,如:Nashorn引擎 jjs、 类依赖分析器jdeps。

41.请你说说Lamda表达式的优缺点。

优点:

  1. 简洁
  2. 非常容易并行计算。
  3. 可能代表未来的编程趋势。

缺点:

  1. 若不用并行计算,很多时候计算速度没有比传统的 for 循环快。(并行计算有时需要预热才显示出效率优势)
  2. 不容易调试。
  3. 可读性比较差 若其他程序员没有学过 lambda 表达式,代码不容易让其他语言的程序员看懂。

42.java序列化

1.什么java序列化?

java序列化就是把对象改成二进制的过程,可以保存到磁盘或者网络发送

1.实现java.io.serializable

2.java.io.externalizable

3.ObjectInputStream

4.ObjectOutputStream

2.序列化有什么用

用于跨平台数据交互

3.如果不想序列化,怎么办

1.变量声明为静态变量 static

2.变量声明为瞬态变量 transient

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-r8hU6DYO-1597310853808)(D:\学习笔记\面试题复习\imgs\MySQL\瞬态变量.png)]

静态变量反序列化是直接从内存中拿值

4.serialVersionUID有什么用?

修改属性,会报异常InvalidClassException无效类,因为每次修改会使得serialVersionUID改变,这时的办法是自己定义

5.是否可以自定义序列化过程

你可能感兴趣的:(面试题笔记,面试笔记,面试,面试题,java基础)