Java基础面经

1. Java语言有哪些特性?

  • 面向对象(封装、继承、多态)

  • 平台无关性,一次编写,到处运行,具有很好的移植性,本质是因为Java的虚拟化机制,引入虚拟机之后,在不用的平台上不需要重新编译

  • 可靠性、安全性

  • 支持多线程。C++语言没有内置的多线程机制,必须调用操作系统的多线程来尽心设计

  • 支持网络编程,并且因为Java诞生的本身就是为了简化网络编程,所以非常方便

  • 编译与解释并存

2. Java和C++有什么关系,它们有什么区别?

  • 都是面向对象的语言,都支持封装、继承、多态;

  • C++支持指针,而Java没有指针的概念

  • C++支持多继承,而Java不支持多重继承,但允许一个类实现多个接口

  • Java自动进行无用内存回收操作,不需要程序员手动删除,而C++必须认为的释放内存

  • Java不支持操作符重载,而C++支持

3. JVM、JRE、JDK的关系是什么?

!!JDK是功能齐全的Java SDK,还包括编译器javac、javadoc等

JRE是运行已编译Java的所有内容的集合,包含Java虚拟机,java类库,但是不能用于创建新程序

4. 什么是字节码?采用字节码的好处是什么?

!!Java之所以可以一次编译,多次运行。一是因为jvm对各种操作系统都进行了定制;二是因为会生成固定的字节码供jvm使用

字节码文件是有十六进制值组成的,而jvm以两个十六进制值作为一组,以字节为单位进行读取。在java中使用javac编译源代码文件作为字节码文件,

.java–>javac编译–>.class–> (ClassLoader–>BytecodeVerifier–>JavaRuntimeSystem–>OS)

5. Oracle JDK和OpenJDK的区别是什么?

  • Oracle JDK 版本将每三年发布一次,而 OpenJDK 版本每三个月发布一次;

  • OpenJDK 是一个参考模型并且是完全开源的,而 Oracle JDK 是OpenJDK 的一个实现, 并不是完全开源的;

  • Oracle JDK 比 OpenJDK 更稳定

6. Java有哪些数据类型?

!!基本数据类型:byte、short、int、long、float、double、char、boolean

引用数据类型:包括数组、类、接口

7. switch 是否能作用在 byte 上,是否能作用在 long 上,是否能作用在 String 上?

!!Java5以前只能是:byte,char,short,int

Java5开始,加入了枚举类型,

Java7开始,可以是字符串。但是long是始终不支持的

8. 访问修饰符public、private、protected、以及不写(默认)时的区别?、

!!Java中可以使用访问控制符来保护对类、变量、方法和构造方法的访问

  • default:默认是在同一包下可见,适用对象:对象,类,接口,变量,方法

  • private:在同一类中可见。适用对象:变量,方法。不能修饰外部类

  • public:对所有的类都可见。适用对象:类,接口,变量,方法

  • protected:对同一包下的类和所有子类可见,适用对象:变量,方法。不能修饰外部类

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

!!break:跳出循环,不再执行循环

continue:跳出本次循环

return:程序返回,不再执行下面的代码

10. final、finally、finalize的区别?

!!final:用于修饰变量,方法和类

  • final变量:被修饰的变量不可变,指的是引用不可变,变量必须初始化

  • final方法:不允许子类重写,子类可以使用

  • final类:被修饰的类不能继承,方法不能被重写

finally:异常处理的一部分,在try/catch中执行,system.exit(0)可以打断finally执行

finalize是java.lang.Object里面的方法,该方法在gc启动,被回收的时候调用

一个对象的finalize只能被调用一次,被调用后不一定会立即回收。假如被调用后不需要回收了,再次回收的时候不会执行finalize方法了,所以不推荐使用

11. 为什么要用static关键字?

!!通常来说,用new创建类的对象时,数据存储空间才会被分配。如果不考虑创建多少对象,或者在不创建对象的情况下使用,可以使用static

12. ”static”关键字是什么意思?Java中是否可以覆盖(override)一个private或者是static的方法?

!!static关键字表明一个成员变量或者成员方法可以在没有所属类的实例变量的情况下被访问

static不能被覆盖,因为方法覆盖是基于运行动态绑定的,static是在编译时静态绑定的

13. 是否可以在static环境中访问非static变量?

!!static变量是属于类的,在所有的实例中的值都是一致的,当类被Java虚拟机载入的时候会对static进行初始化,如果不用实例对象来访问非static变量,编译器会报错,因为还没有被创建

14. static静态方法能不能引用非静态资源?

!!不能,new的时候才会产生的东西,对于初始化后就存在的静态资源,不认识

15. static静态方法里面能不能引用静态资源?

!!可以,因为都是在类初始化的时候加载的

16. 非静态方法里面能不能引用静态资源?

!!可以,非静态方法就是实例方法,那是new之后才产生的,那么属于类的内容它都认识。

17. java静态变量、代码块、和静态方法的执行顺序是什么?

!!静态代码块 –> 构造初始化块(只被大括号包围) –> 构造函数 –> 普通代码块

在继承当中:父类的静态块 –> 子类的静态块 –> 父类的初始化块 –> 父类的构造器 –> 子类的初始化块 –> 子类的构造器

18. 面向对象和面向过程的区别?

!!面向过程:

  • 优点:性能比面向对象高,因为类调用需要实例化,开销大,占资源,一般Linux采用面向过程

  • 缺点:没有面向对象容易维护、容易复用、容易扩展

面向对象:

  • 优点:容易维护、容易复用、容易扩展,低耦合,系统更加灵活

  • 缺点:性能比面向过程低

19. 讲讲面向对象三大特性

  • 封装:是对象和类的概念,将客观事物封装抽象的类。类可以把自己的数据和方法有针对性的隐藏

  • 继承:使用现有类的所有功能,在无需编写的情况下对类进行扩展

  • 多态:指在父类中定义的属性和方法被子类继承后,可以具有不同的数据类型或便显出不同的行为,使得同一个属性或方法在父类和子类中有不同的含义。

    • 一个对象的编译类型和运行类型可以不一致;

    • 编译类型在定义对象时,就确定了,而运行类型是可以改变的;

    • 编译类型看=的左边,运行类型看右边

20. Java语言是如何实现多态的?

!!本质上多态分为两种:1. 编译时多态 2. 运行时多态

重载就是编译时多态的例子,编译时多态在编译时已经确定,运行的时候调用的就是确定的方法

我们通常所说的多态都是指动态多态

实现多态的必要条件:继承、重写、向上转型

  • 向上转型:在多态中需要将子类的引用赋值给父类对象,只有这样才可以调用父类的方法,又能调用子类重写的方法

21. 重载(Overload)和重写(Override)的区别是什么?

!!重写:发生在子类和父类之间,方法名和参数都不能改变,与返回值和修饰符无关,访问修饰符的限制一定要大于等于被重写方法的访问修饰符

重载:在一个类中,方法名相同,参数不同

22. 重载的方法能否根据返回值类型进行区分?

!!不能根据返回值类型来区分重载的方法。因为调用时不指定类型信息,编译器不知道你要调

用哪个函数

23. 构造器(constructor)是否可被重写(override)?

!!构造器不能被继承,构造器必须与类名一致,无法继承,不会被重写,但可以重载。子类不会覆盖父类的构造函数,必须先开始调用父类的构造函数

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

!!语法层面上:

  • 抽象类可以提供成员方法的实现细节,而接口中只能存在public abstract方法

  • 抽象类中的成员变量可以是各种类型,而接口中的成员变量只能是public static final类型

  • 接口中不能含有静态代码块以及静态方法,而抽象类可以有静态代码块和静态方法

设计层面上:

  • 抽象类是对一种事物的抽象,是对类的抽象;而接口是对行为的抽象,抽象类是对整体进行抽象,接口只针对行为

  • 抽象类更多的是作为父类,一种模板。而接口更像是一种行为约束,是一种规范

25. 抽象类能使用 final 修饰吗?

!!不能,因为被final修饰的类是无法被继承的

26. java 创建对象有哪几种方式?

  • new创建新对象

  • 通过反射机制

  • 采用clone机制

  • 通过序列化机制

!!前两者需要显示的调用构造方法,clone需要注意浅拷贝和深拷贝,序列化是通过实现Externalizable或者Serializable实现的

27. 什么是不可变对象?好处是什么?

!!不可变对象指一旦被创建,状态就不能被改变,任何修改都会创建一个新的对象,例如:String,以及包装类

不可变对象是线程安全的

28. 能否创建一个包含可变对象的不可变对象?

!!可以,例如:final Person[] persons =newPersion[] ,persons是不可变对象的引用,但是 不要共享可变对象的引用。数据变化时可以返回对象的一个拷贝

29. 值传递和引用传递的区别的什么?为什么说Java中只有值传递?

!!值传递:指的是在调用方法时,传递的参数是按值的拷贝传递,传递后就不相关了

引用传递:在方法调用时,传递的参数是按照引用进行传递,传递的是引用的地址

30. == 和 equals 区别是什么?

!!== 常用于基本数据类型之间的比较,也可以用于相同类型的对象之间的比较

  • ==比较的是基本数据类型,就是判断值是否相等

  • ==比较的是两个对象,那么比较的就是两个对象的引用,判断是否指向了同一块内存空间

equals用于两个对象之间,检测一个对象是否等于另一个对象

  • 如果类没有覆盖equals,比较对象时相当于==

  • 若覆盖了equals,则比较的就是内容

31. 介绍下hashCode()?

!!hashCode()的作用就是获取哈希码,即散列码,返回的是一个int整数,用于确定该对象在哈希表中的索引

散列表的存储采用键值对。特点:可以快速找到所需要的对象

32. 为什么要有 hashCode?

!!以HashSet检查重复来说明:

当把对象加入HashSet时,HashSet辉县计算对象的hashCode值来判断对象加入的位置,如果没有相符的,假设没有重复存在;

但是如果发现有重复的hashcode值,这时会调用equals()方法来检查hashcode相等的对象是否真的相等,若相等就不加入,不同的话,散列到其他位置

33. hashCode(),equals()两种方法是什么关系?

  • 同一对象上多次调用 hashCode() 方法,总是返回相同的整型值

  • 如果 a.equals(b),则一定有 a.hashCode() 一定等于 b.hashCode()

  • 如果 !a.equals(b),则 a.hashCode() 不一定等于 b.hashCode()

  • a.hashCode()==b.hashCode() 则 a.equals(b) 可真可假

  • a.hashCode()!= b.hashCode() 则 a.equals(b) 为假

34. 为什么重写 equals 方法必须重写 hashcode 方法 ?

!!判断是先判断的hascode,后判断的equals。若只重写了equals方法,会造成hashcode值不同,但equals是真

在Java中的一些容器中,不允许有两个完全相同的对象,插入的时候,如果判断相同则会进行覆盖。这时候如果只重写了equals()的方法,而不重写hashcode的方法,Object中hashcode是根据对象的存储地址转换而形成的一个哈希值。这时候就有可能因为没有重写hashcode方法,造成相同的对象散列到不同的位置而造成对象的不能覆盖的问题

35. String,StringBuffer, StringBuilder 的区别是什么?

  1. 可变与不可变:String类中使用final修饰,使用字符串数组,修改时都是创建新对象然后将新的志存进字符串数组。String是不可变的,剩余两个是可变的。

  2. 是否线程安全:String是不可变的,所以线程安全;StringBuilder是不安全的。StringBuffer是安全的,因为添加了同步锁synchronized

  3. 如果只是在单线程中使用字符串缓冲区,StringBuilder效率更高,是在JDK1.5增加的

36. String为什么要设计成不可变的?

  1. !!便于实现字符串池:

  2. !!在Java中,会大量使用String常量,每次声明都创建会极大浪费资源,所在在堆中开辟了一块存储空间,Spring pool,当初始化String变量时,如果已经存在,则就不会创建新的变量了,会返回已经存在的引用

  3. !!使多线程安全,不可变对象保证了多线程的安全

  4. !!避免安全问题,在网络连接、数据库连接中经常使用String作为参数,如果是可变的,会引起安全问题

  5. !!加快字符串处理速度,

    1. 由于String是不可变的,保证了hashcode的唯一性,于是在创建对象时其hashcode就可以放 心的缓存了,不需要重新计算。这也就是Map喜欢将String作为Key的原因,处理速度要快过 其它的键对象。所以HashMap中的键往往都使用String。

37. 字符型常量和字符串常量的区别?

  1. 形式上:字符常量是单引号引起的一个字符,字符串常量是双引号引起的若干字符

  2. 含义上:字符常量相当于一个整数值ASCII值,可以参加表达式运算;字符串常量代表一个地址值,相当于对象

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

38. 什么是字符串常量池?

!!jvm为了提升性能和减少内存开销,避免字符的重复创建,在堆中维护了一块内存空间,当使用字符串时,会先去查找字符串是否存在,若存在,则直接使用;若不存在,则初始化,并将该字符串放入字符串常量中

字符串常量池的位置在jdk6中,存放在永久代当中,也就是方法区当中,此时存储的是对象;在jdk7当中,存放在堆中,此时存放的是引用;在jdk8中永久代就被元空间取代了

39. String str=”aaa”与 String str=new String(“aaa”)一样吗?new String(“aaa”); 创建了几个字符串对象?

  • 使用String a=”aaa”;程序会在常量池中查找字符串,若没有,会将字符串放入当中,将地址给a;若有直接将地址赋给a

  • 使用String b=new String(”aaa”);程序会在堆内存中开辟一块新空间存放对象,同时将字符串放入常量池。相当于创建了两个对象,无论常量有没有aaa都会开辟一块空间存放新对象

40. String 是最基本的数据类型吗?

!!不是,Java基本的数据类型只有8个

41. String有哪些特性?

  • 不变性:对它进行任何操作都是创建一个新的对象

  • 常量池优化:String对象创建后,会在字符串常量池进行缓存,下次创建相同的对象时,会直接返回缓存的引用

  • final:使用final来定义String类,表示不能被继承,提高了系统的安全性

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

!!HashMap内部是通过key的hashcode来确定存储位置,因为字符串是不可变的,所以创建字符串时,hashcode会被缓存,不需要再次计算,更快

43. 包装类型是什么?基本类型和包装类型有什么区别?

!!Java为每一个基本类型引入了对应的包装类型,从java5之后引入了自动装箱、自动拆箱。

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

  • 包装类可以是null,而基本类型不可以。使得包装类可以应用于POJO,如果使用基本类型,自动拆箱时,会抛出NullPointerException异常

  • 包装类型可以用于泛型,基本类型不可以。使用基本类型会报错

  • 基本类型比包装类型更高效。基本类型在栈中直接存储具体数值,而包装类型存储的是堆中的引用,包装类型占用的内存空间更大

44. 解释一下自动装箱和自动拆箱?

  • 自动装箱:将基本类型重新转化为对象

  • 自动拆箱:将对象重新转化为基本数据类型

publicvoidtest(){//声明一个对象,用到了自动装箱,Integernum=9;//执行操作用到了自动拆箱System.out.print(num--);}

45. int 和 Integer 有什么区别?

  • Integer是int的包装类,int是基本类型

  • Integer变量必须实例化后才能使用,int变量不需要

  • Integer是技术对象的引用,int存储的是值

  • Integer默认是null,int是0

46. 两个new生成的Integer变量的对比

!!Integer变量是对对象的引用,tongguonew生成的两个Integer 是永远不相等的

47. Integer变量和int变量的对比

!!两者比较时,会将Integer自动拆箱为int,只要两个变量的值相等,结果就是True

48. 非new生成的Integer变量和new Integer()生成变量的对比

!!两者比较时,非new生成的Integer变量指向的是java常量池中的对象,而new生成的指向堆中新建的对象。地址不同

49. 两个非new生成的Integer对象的对比

!!若两个都是非new出来的,进行比较时,如果两个变量的值在-128-127之间,则是True,否则就是false

当值在-128-127之间时,java会自动进行装箱,然后对值进行缓存。下次有相同的值时,直接使用即可,缓存是通过Integer的内部类IntegerCache完成的;

当值不再这范围中会在堆中new出一个对象

50. 什么是反射?

!!反射是在运行状态中,对于任意一个类,都能知道这个类的所有属性和方法;对于任意一个对象,都能调用欧冠它的任意一个方法和属性;动态获取信息以及动态调用对象的方法就叫做反射机制

51. 反射机制的优缺点有哪些?

!!优点:能够运行时动态获取类的实例,提高灵活性;可与动态编译结合

Class.forName(‘com.mysql.jdbc.Driver.class’);夹在MYSQL驱动类

缺点:使用反射性能较低,需要解析字节码,将内存中的对象进行解析。

解决方案:通过setAccessible(true)关闭JDK的安全检查来提升反射速度;多次创建一个类的实例时,

有缓存会快很多,ReflflectASM工具类,通过字节码生成的方式加快反射速度

52. 如何获取反射中的Class对象?

  1. Class.forName(“类的路径”);

  2. 类名.class。这种方法只适合在编译前就知道操作的Class

  3. 对象名.getClass()

  4. 如果是基本类型的包装类,可以调用包装类的Type属性来获得该包装类的Class对象

53. Java反射API有几类?

!!反射API用来生成JVM中的类、接口、或者对象的信息

  • Class类:反射的核心类,可以获取类的属性,方法等信息

  • Field类:Java.Lang.reflec包中的类,表示类的成员变量,可以用来获取和设置类之中的属性值

  • Method类:Java.lang.reflec包中的类,表示类的方法,它可以用来获取类中的方法信息或者执行方法

  • Construtor类:Java.lang.reflec包中的类,表示类的构造方法

54. 反射使用的步骤?

  1. 获取想要操作的类Class对象

  2. 调用Class类的方法

  3. 调用反射API来操作这些信息

55. 为什么引入反射概念?反射机制的应用有哪些?

56. 反射机制的原理是什么?

57. Java中的泛型是什么 ?

!!就是将类型参数化,在编译时才确定具体的参数

58. 使用泛型的好处是什么?

  1. 类型安全

    1. 泛型的主要目标是提高Java程序的类型安全

    2. 编译时期就可以检测出因Java类型不正确导致的ClassCastException异常

    3. 符合越早出错代价越小原则

  2. 消除强制类型转化

    1. 使用时直接得到目标类型,消除许多强制类型转换

  3. 潜在的性能收益

60. 什么是泛型中的限定通配符和非限定通配符 ?

!!限定通配符对类型进行了限制,有两种限定通配符,一种是它通过确保类型必须是T的子类来设定类型的上界,另一种是它通过确保类型必须是T的父类来设定类型的下界

非限定通配符?他可以用任意类型来代替

61. List和List 之间有什么区别 ?

!!两个都是限定通配符的例子,

List:可以接受任意继承自T类型的List

List :可以接受任何T的父类构成的List

63. 判断 ArrayList与 ArrayList是否相等?

!!创建两个相对应的对象比较getClass(),发现是true,

String和Integer具体体现在类编译:当JVM进行类编译时,会进行泛型检查,如果一个集合被声明为String,在存储时会进行判断

Array不可以用于泛型,不能提供编译期的类型安全保证

64. Java序列化与反序列化是什么?

!!Java序列化是指把Java对象转换成为字节序列的过程,而Java反序列化是指把字节序列恢复为Java对象的过程

  • 序列化:把对象转换成为有序字节流,以便在网络上传输或者保存在本地文件中。核心作用是为了对象状态的保存与重建

  • 反序列化:客户端从文件中或网络上获得序列化的对象字节流后通过反序列化重建对象

65. 为什么需要序列化与反序列化?

!!对内存中的对象进行持久化或者网络传输

  1. 对象序列化可以实现分布式对象

  2. java对象序列化不仅保留一个对象的数据,而且递归保存对象引用的每个对象的数据

  3. 可以将内存中的类写入文件或者是现对象

  4. 对象、文件、数据,格式不同难以保存,序列化实现了字节流

66. 序列化实现的方式有哪些?

!!实现Serializable接口,或者Externalizable接口

  • 实现Serializable接口

    • 系统自动存储必要的信息

    • Java内建支持,易于实现,只需要实现该接口即可,无需任何代码支持

    • 性能略差

  • 实现Externalizable接口

  • 程序员决定存储哪些信

  • 必须实现接口内的两个方法

  • 性能略好

67. 什么是serialVersionUID?

!!用来表示类的不同版本之间的兼容性

Java的序列化机制是通过在运行时判断类的serialVersionUID来验证版本的一致性。在进行反序列化时JVM会把传入的字节流的UID与本地的serialVersionUID进行比较,若相同,则进行反序列化

68. 为什么还要显示指定serialVersionUID的值?

!!如果不指定serialVersionUID,JVM会自动生成一个serialVersionUID,然后与属性一起序列化。

如果我们的类写完后不再修改, 那当然不会有问题,

如果类会不断迭代, 一旦类被修改了, 那旧对象反序列化就会报错.

所以在实际开发中, 我们都会显示指定一个serialVersionUID, 值是多少无所谓, 只要不变就行

69. serialVersionUID什么时候修改?

!!序列化类新增属性时,不要修改serialVersionUID字段,避免反序列化失败。如果完全不兼容升级,避免反序列化混乱,可以修改serialVersionUID值

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

!!对于不想序列化的变量,可以使用transient关键字修饰

该关键字适用于控制变量的序列化,在变量声明前加上该关键字,组织被序列化到文件,在被反序列化后,transient变量的值被设为初始值,如int是0,对象时null,transient只能修饰变量,不能修饰类和方法

71. 静态变量会被序列化吗?

!!不会。因为序列化是针对对象而言的,而静态变量优先于对象存在,随着类的加载而加载,不会被序列化

serialVersionUID也被static修饰,serialVersionUID属性并没有被序列化, JVM在序列化对象时会自动生成一个

serialVersionUID, 然后将我们显示指定的serialVersionUID属性值赋给自动生成的serialVersionUID。

72. Error 和 Exception 区别是什么?

!!两个都是java.lang包中的Throwable类的子类

  • Error:是程序无法处理的错误,例如:系统崩溃,内存不够,堆栈溢出等

  • Exception:程序可以处理的异常,分为运行时异常,编译时异常

73. 非受检查异常(运行时异常)和受检查异常(一般异常)区别是什么?

  • 运行时异常:Java编译器不会检查,例如空指针异常、字符串转为数字异常、数组越界、类型转换异常、数据存储异常等

  • 编译时异常:例如:IO类的异常、数据库异常、语法异常、类找不到异常等

74. throw 和 throws 的区别是什么?

!!两者的区别:

  • 相同点:

    • 两者都算是消极的处理异常吧,只是抛出或者可能抛出异常,但是不会由函数去处理异常,真正处理异常的还是函数的上层调用

  • 不同点:

    • throw是语句抛出一个异常,throws是方法可能抛出异常的声明

    • throws出现在方法函数头,而throw出现在函数体

    • throw只能用于抛出一种异常,而throws可以抛出多个异常

75. NoClassDefFoundError 和 ClassNotFoundException 区别?

!!NoClassDefFoundError :是一个Error类型的异常,是由JVM引起的,不应该尝试捕获这个异常。引起异常的原因是在JVM或者ClassLoader尝试加载时内存中找不到该类的定义,该动作发生在运行期间、即编译时存在,但运行时不存在,可能编译后被删除了

ClassNotFoundException:是编译时异常,需要显式地使用 try-catch 对其进行捕获和处理,或在方法签名中用 throws 关键字进行声明。当使用 Class.forName,ClassLoader.loadClass 或 ClassLoader.findSystemClass 动态加载类到内存的时候,通过传入的类路径参数没有找到该类,就会抛出该异常;另一种抛出该异常的可能原因是某个类已经由一个类加载器加载至内存中,另一个加载器又尝试去加载它

76. Java常见异常有哪些?

77. try-catch-finally 中哪个部分可以省略?

!!catch 可以省略。更为严格的说法其实是:try只适合处理运行时异常,try+catch适合处理运行时异常+普通异常。也就是说,如果你只用try去处理普通异常却不加以catch处理,编译是

通不过的,因为编译器硬性规定,普通异常如果选择捕获,则必须用catch显示声明以便进一

步处理。而运行时异常在编译时没有如此规定,所以catch可以省略,你加上catch编译器也觉

78. try-catch-finally 中,如果 catch 中 return 了,finally 还会执行吗?

!!会执行,在return前执行。

如果存在 finally 代码块,try中的 return 语句不会立马返回调用者,而是记录下返回值待 finally 代码块执行完毕

之后再向调用者返回其值,然后如果在 finally 中修改了返回值,就会返回修改后的值

在 finally 中返回或者修改返回值会对程序造成很大的困扰,Java 中也可以通过提升编译器

的语法检查级别来产生警告或错误。

79. JVM 是如何处理异常的?

!!在一个方法中如果发生异常,这个方法会创建一个异常对象,并转交给JVM,该异常对象包含异信息。

创建异常对象名转交给JVM的过程成为抛出异常。可能有一系列的方法调用才进入抛出异常的方法,这一系列方法调用的有序列表叫做调用栈。

JVM 会顺着调用栈去查找看是否有可以处理异常的代码,如果有,则调用异常处理代码。当JVM 发现可以处理异常的代码时,会把发生的异常传递给它。如果 JVM 没有找到可以处理该异常的代码块,JVM 就会将该异常转交给默认的异常处理器(默认处理器为 JVM 的一部分),默认异常处理器打印出异常信息并终止应用程序。

80. Java的IO 流分为几种?

  • 按照流的方向:输入流inputStream和输出流putputStream

  • 按照实现功能分:节点流(可以从或者向一个特定的地方读写数据,FileReader)和处理流(是对一个已存在的流的连接和封装,通过所封装的流的功能调用实现数据的读写,BufferReader)

  • 按照处理数据的单位:字节流和字符流。

81. 字节流如何转为字符流?

!!方式:通过InputStreamReader实现,该类的构造函数可以传入InputStream对象;相反字节输出流通过OutputStreamWriter实现

82. 字符流与字节流的区别?

  • 读写的时候字节流是按照字节读写,字符流按照字符读写

  • 字节流适合所有类型文件的数据传输,因为字节是信息的最小单位。字符流只能处理纯文本数据,替他累行不行,但是字符流处理文本要方便

  • 在读取文件对内容进行处理时,比如特定字符,一般选择字符流

  • 只是读取文件,和内容无关一般选择字节流

83. 什么是阻塞IO?什么是非阻塞IO?

!!IO操作包括:对硬盘的读写、对socket的读写、对外设的读写

当用户线程发起一个IO请求操作,内核回去查看要读取的数据是否就绪,对于阻塞IO来说,如果数据没有就绪,会一直等待,直到数据就绪;对于非阻塞IO来说,如果数据没有就绪,则会翻返回一个标志信息告知用户线程当前要读取的数据没有就绪。当数据就绪后,便将数据拷贝到用户线程

一个完整的IO读取请求包括:

  1. 查看数据是否就绪

  2. 进行数据拷贝(内核将数据拷贝到用户线程)

Java中传统的IO都是阻塞IO,比如通过socket读数据,数据没有就绪会一直等待

84. BIO、NIO、AIO的区别?

  • BIO:同步并阻塞,在服务器中实现的模式是一个连接一个线程,当客户端有连接请求的时候,服务器就需要启动一个线程进行处理,如果这个连接不做任何操作会造成不必要的开销。一般适用于链接数目小且固定的架构,对服务器的资源要求比较高,并发局限于应用中,程序直观简单,在JDK1.4之前的唯一选择

  • NIO:同步并非阻塞,在服务器中实现的模式为一个请求一个线程,客户端发送的请求会注册到多路复用器上,多路复用器轮询到有连接IO请求时才会启动一个线程进行处理。一般适用于连接数目较多且连接比较短的架构,在JDK1.4之后支持,并发局限于应用当中,编程比较复杂

  • AIO:异步并非阻塞,实现的模式一个有效请求一个线程,客户端的IO请求经过操作系统先完成之后,再通知服务器去启动线程进行处理。一般适用于连接数目多,且连接比较长的架构,从JDK1.7开始支持,充分调用操作系统参与并发操作,编程比较复杂

85. Java IO都有哪些设计模式?

!!使用了适配器模式和装饰器模式

适配器模式:Reader reader=new InputStreamReader(inputStream)

把一个类的接口变换成客户端所期待的另一种接口,eg:字节:InputStream经过适配器InputStreamReader变成了字符Reader

装饰器模式:new BufferedInputStream(new FileInputStream(inputStream))

一种动态的往一个类中添加新的行为的设计模式,相比生成子类更加灵活,可以给某个对象而不是整个类添加功能,可以被多个装饰者重复装饰