首页 > 编程语言 >java面试(基础)

java面试(基础)

时间:2022-12-07 18:36:49浏览次数:61  
标签:java Servlet 对象 方法 基础 面试 IO Java 异常


0. 面向对象

1.1 封装:利用抽象数据类型将数据和基于数据的操作封装在一起,使其构成一个不可分割的独立实体。减少耦合,提高可重用性。

1.2 继承:is-a 

Cat 可以当做 Animal 来使用,也就是说可以使用 Animal 引用 Cat 对象。父类引用指向子类对象称为 向上转型 。

Animal animal = new Cat();

1.3 多态

多态分为编译时多态和运行时多态:

  • 编译时多态主要指方法的重载
  • 运行时多态指程序中定义的对象引用所指向的具体类型在运行期间才确定

运行时多态有三个条件:

  • 继承
  • 覆盖(重写)
  • 向上转型(父类引用指向子类对象)

1. 用域 public,private,protected,以及不写时的区别

java面试(基础)_职场和发展

2. 对equals()和hashCode()的理解?

  • key -> hashCode -> 当hash冲突时,使用链地址或红黑树寻找value
  • 为什么在重写 equals 方法的时候需要重写 hashCode 方法?

因为有强制的规范指定需要同时重写 hashcode 与 equals 是方法,许多容器类,如 HashMap、HashSet 都依赖于 hashcode 与 equals 的规定。

  • 有没有可能两个不相等的对象有相同的 hashcode?

有可能,两个不相等的对象可能会有相同的 hashcode 值,这就是为什么在 hashmap 中会有冲突。相等 hashcode 值的规定只是说如果两个对象相等,必须有相同的hashcode 值,但是没有关于不相等对象的任何规定。

  • 两个相同的对象会有不同的 hash code 吗?

不能,根据 hash code 的规定,这是不可能的。

3. String、StringBuffer与StringBuilder的区别

String: 对象不可变。final修饰,因此是线程安全的。每次对 String 类型进行改变的时候,都会生成一个新的 String 对象,然后将指针指向新的 String 对象。操作少量数据。

StringBuilder: 对象可变线程不安全。StringBuilder每次都会对 StringBuilder对象本身进行操作,而不是生成新的对象并改变对象引用。但效率更高。单线程操作大量数据。

StringBuffer: 对象可变。线程安全。StringBuffer 每次都会对 StringBuffer 对象本身进行操作,而不是生成新的对象并改变对象引用。多线程操作大量数据。

面试题:String 为什么是不可变的?String 类中使用 final 关键字字符数组保存字符串。

private final char value[]

面试题:String 与 byte[]两者相互之间如何转换?

String -> byte[] 通过 String 类的 getBytes 方法

byte[] -> String 通过 new String(byte[]) 构造器
 

4. 接口与抽象类的区别?

4.1 语法区别

java面试(基础)_面试_02

4.2 语义区别

抽象类:描述概念 n.

接口:描述特征 v.

5. this() & super()在构造方法中的区别?

  • 调用super()必须写在子类构造方法的第一行, 否则编译不通过
  • super从子类调用父类构造, this在同一类中调用其他构造均需要放在第一行
  • 尽管可以用this调用一个构造器, 却不能调用2个
  • this和super不能出现在同一个构造器中, 否则编译不通过
  • this()、super()都指的对象,不可以在static环境中使用
  • 本质this指向本对象的指针。super是一个关键字,指向了当前对象自己的父类型特征(也就是继承过来的那些东西)。

6. java异常

java面试(基础)_Java_03

6.1 Error:程序中无法处理的错误。代码运行时 JVM 出现问题。

6.2 Exception:程序本身可以捕获并且可以处理的异常。

    6.2.1 运行异常(RuntimeException与其子类)RuntimeException类及其子类异常

    6.2.2 编译异常(非运行异常):RuntimeException以外的异常,类型上都属于Exception类      及其子类。

6.3 受检异常(checked exceptions)和非受检异常(unchecked exceptions)

    6.3.1 受检异常:编译异常。编译器要求必须处理的异常。除RuntimeException 及其子类外,其他的 Exception 异常都属于受检异常。

    6.3.2 非受检异常: 运行异常(RuntimeException与其子类)和错误(Error)。编译器不会进行检查并且不要求必须处理的异常。

6.4 异常的底层

异常表中包含了一个或多个异常处理者(Exception Handler)的信息,这些信息包含如下

  • from 可能发生异常的起始点
  • to 可能发生异常的结束点
  • target 上述from和to之前发生异常后的异常处理者的位置
  • type 异常处理者处理的异常的类信息

6.5 异常处理

Java 的异常处理是通过 5 个关键词来实现的:try、catch、throw、throws 和 finally。
 

java面试(基础)_职场和发展_04

java面试(基础)_面试_05

 6.6 面试

(1)Error 和 Exception 区别是什么?

Error 类型的错误通常为虚拟机相关错误,如系统崩溃,内存不足,堆栈溢出等,编译器不会对这类错误进行检测,JAVA 应用程序也不应对这类错误进行捕获,一旦这类错误发生,通常应用程序会被终止,仅靠应用程序本身无法恢复;Exception 类的错误是可以在应用程序中进行捕获并处理的,通常遇到这种错误,应对其进行处理,使应用程序可以继续正常运行。

(2)运行时异常和一般异常(受检异常)区别是什么?

运行时异常包括 RuntimeException 类及其子类,表示 JVM 在运行期间可能出现的异常。 Java 编译器不会检查运行时异常。受检异常是Exception 中除 RuntimeException 及其子类之外的异常。 Java 编译器会检查受检异常。
RuntimeException异常和受检异常之间的区别:
是否强制要求调用者必须处理此异常,如果强制要求调用者必须进行处理,那么就使用受检异常,否则就选择非受检异常(RuntimeException)。一般来讲,如果没有特殊的要求,我们建议使用RuntimeException异常。

(3)JVM 是如何处理异常的?

在一个方法中如果发生异常,这个方法会创建一个异常对象,并转交给 JVM,该异常对象包含异常名称,异常描述以及异常发生时应用程序的状态。创建异常对象并转交给 JVM 的过程称为抛出异常。可能有一系列的方法调用,最终才进入抛出异常的方法,这一系列方法调用的有序列表叫做调用栈。JVM 会顺着调用栈去查找看是否有可以处理异常的代码,如果有,则调用异常处理代码。当 JVM 发现可以处理异常的代码时,会把发生的异常传递给它。如果 JVM 没有找到可以处理该异常的代码块,JVM 就会将该异常转交给默认的异常处理器(默认处理器为 JVM 的一部分),默认异常处理器打印出异常信息并终止应用程序。

(4)throw 和 throws 的区别是什么?

throw 关键字用在方法内部,只能用于抛出一种异常,用来抛出方法或代码块中的异常,受查异常和非受查异常都可以被抛出。
throws 关键字用在方法声明上,可以抛出多个异常,用来标识该方法可能抛出的异常列表。一个方法用 throws 标识了可能抛出的异常列表,调用该方法的方法中必须包含可处理异常的代码,否则也要在方法签名中用 throws 关键字声明相应的异常。

(5)final、finally、finalize 有什么区别?

final 1) 修饰类: 不能被继承。final 类中的所有成员方法都会被隐式地指定为 final 方法。2) 修饰方法: 不能被重写。  3) 修饰变量: 不能被改变。
finally 一般作用在try-catch代码块中,在处理异常的时候,通常我们将一定要执行的代码方法finally代码块中,表示不管是否出现异常,该代码块都会执行,一般用来存放一些关闭资源的代码。
finalize 是一个方法,属于Object类的一个方法,而Object类是所有类的父类,Java 中允许使用 finalize()方法在垃圾收集器将对象从内存中清除出去之前做必要的清理工作。

(6)NoClassDefFoundError 和 ClassNotFoundException 区别?

NoClassDefFoundError 是一个 Error 类型的异常,是由 JVM 引起的,不应该尝试捕获这个异常。
引起该异常的原因是 JVM 或 ClassLoader 尝试加载某类时在内存中找不到该类的定义,该动作发生在运行期间,即编译时该类存在,但是在运行时却找不到了,可能是变异后被删除了等原因导致;ClassNotFoundException 是一个受查异常,需要显式地使用 try-catch 对其进行捕获和处理,或在方法签名中用 throws 关键字进行声明。当使用Class.forName, ClassLoader.loadClass 或 ClassLoader.findSystemClass 动态加载类到内存的时候,通过传入的类路径参数没有找到该类,就会抛出该异常;另一种抛出该异常的可能原因是某个类已经由一个类加载器加载至内存中,另一个加载器又尝试去加载它。

(7)try-catch-finally 中哪个部分可以省略?

答:catch 可以省略
原因:
更为严格的说法其实是:try只适合处理运行时异常,try+catch适合处理运行时异常+普通异常。也就是说,如果你只用try去处理普通异常却不加以catch处理,编译是通不过的,因为编译器硬性规定,普通异常如果选择捕获,则必须用catch显示声明以便进一步处理。而运行时异常在编译时没有如此规定,所以catch可以省略,你加上catch编译器也觉得无可厚非。理论上,编译器看任何代码都不顺眼,都觉得可能有潜在的问题,所以你即使对所有代码加上try,代码在运行期时也只不过是在正常运行的基础上加一层皮。但是你一旦对一段代码加上try,就等于显示地承诺编译器,对这段代码可能抛出的异常进行捕获而非向上抛出处理。如果是普通异常,编译器要求必须用catch捕获以便进一步处理;如果运行时异常,捕获然后丢弃并且+finally扫尾处理,或者加上catch捕获以便进一步处理。至于加上finally,则是在不管有没捕获异常,都要进行的“扫尾”处理。

(8)try-catch-finally 中,如果 catch 中 return 了,finally 还会执行吗?

答:会执行,在 return 前执行。
注意:在 finally 中改变返回值的做法是不好的,因为如果存在 finally 代码块,try中的 return 语句不会立马返回调用者,而是记录下返回值待 finally 代码块执行完毕之后再向调用者返回其值,然后如果在 finally 中修改了返回值,就会返回修改后的值。

(9)Java常见异常有哪些
java.lang.OutOfMemoryError:内存不足错误。当可用内存不足以让Java虚拟机分配给一个对象时抛出该错误。
java.lang.StackOverflowError:堆栈溢出错误。当一个应用递归调用的层次太深而导致堆栈溢出或者陷入死循环时抛出该错误。

java.lang.NullPointerException:空指针异常。当应用试图在要求使用对象的地方使用了null时,抛出该异常。譬如:调用null对象的实例方法、访问null对象的属性、计算null对象的长度、使用throw语句抛出null等等。

 (10) 说说你平时是怎么处理 Java 异常的

java面试(基础)_java_06

7. java反射

Java反射详解:入门+使用+原理+应用场景


7.1 def

7.1.1 官方定义

JAVA反射机制(Reflection)是在运行状态中(注意不是编译的时候)

对于任意一个,都能够知道这个类的所有属性和方法;

对于任意一个对象,都能够调用它的任意一个方法和属性;这种动态获取的信息以及动态调用对象方法的功能称为java语言的反射机制。 

java面试(基础)_面试_07

7.1.2 分解

反射就是把java类中的各种成分映射成一个个的Java对象

java面试(基础)_职场和发展_08

(1)Class:类的实体,在运行的java程序中表示类和接口。必须先获得Class才能获取Method、Constructor、Field 

java面试(基础)_面试_09

java面试(基础)_职场和发展_10

(2)Field:类的成员变量/属性。

(3)Method:类的方法。

(4)Constructor:类的构造方法。

(5)Annotation:类的注解。java.lang.annotation

7.2 获取类对应的字节码的对象(三种)/  获取Class的三方式

三种方式常用第三种,第一种对象都有了还要反射干什么。第二种需要导入类的包,依赖太强,不导包就抛编译错误。

java面试(基础)_java_11

7.2.1 调用某个类的对象的getClass()方法,即:对象.getClass()

Person p = new Person();
Class clazz = p.getClass();

注意:此处使用的是Object类中的getClass()方法,因为所有类都继承Object类,所以调用Object类中的getClass()方法来获取。

7.2.2 调用类的class属性类获取该类对应的Class对象,即:类名.class

Class clazz = Person.class;

7.2.3 使用Class类中的forName()静态方法(最安全,性能最好)即:Class.forName(“类的全路径”)

Class clazz = Class.forName("类的全路径");

 注意:在运行期间,一个类,只有一个Class对象产生。

7.3 常用类和方法

7.3.1 Class:

java面试(基础)_职场和发展_12

7.3.2 Field:

java面试(基础)_面试_13

7.3.3 Method:

java面试(基础)_职场和发展_14

7.3.4 Constructor:

java面试(基础)_java_15

7.3.5 Annotation:

8. java集合类/容器类 (Collection 和 Map)

Java集合详解

黄色块为集合的接口,蓝色块为集合的实现类。表 1 介绍了接口,表2介绍了实现类。

8.1 Collection接口

java面试(基础)_职场和发展_16

8.2 Map接口

java面试(基础)_java_17

8.3 详细介绍

java面试(基础)_Java_18

java面试(基础)_Java_19

8.4 面试题(1)List,Set,Map三者的区别?

java面试(基础)_面试_20

 (2)集合框架底层数据结构

java面试(基础)_面试_21

(3)哪些集合类是线程安全的?

java面试(基础)_java_22

 (4)怎么确保一个集合不能被修改?

可以使用 Collections. unmodifiableCollection(Collection c) 方法来创建一个只读集合,这样改变
集合的任何操作都会抛出 Java. lang. UnsupportedOperationException 异常。

List<String> list = new ArrayList<>();
list.add("x");
Collection<String> clist = Collections. unmodifiableCollection(list);
clist.add("y"); // 运行时此行报错

(5)迭代器 Iterator

迭代器 Iterator 是什么?
Iterator 接口提供遍历任何 Collection 的接口。我们可以从一个 Collection 中使用迭代器方法来
获取迭代器实例。迭代器取代了 Java 集合框架中的 Enumeration,迭代器允许调用者在迭代过程
中移除元素。因为所有Collection接继承了Iterator迭代器。Iterator 的特点是只能单向遍历,但是更加安全。

java面试(基础)_java_23

Enumeration 和 Iterator 接口的区别?
Enumeration 的速度是 Iterator 的两倍,也使用更少的内存。 Enumeration 是非常基础的,也
满足了基础的需要。但是,与 Enumeration 相比, Iterator 更加安全,因为当一个集合正在
被遍历的时候,它会阻止其它线程去修改集合。
 

Iterater 和 ListIterator 之间有什么区别?

java面试(基础)_java_24

如何边遍历边移除 Collection 中的元素?

T:边遍历边修改 Collection 的唯一正确方式是使用 Iterator.remove() 方法

Iterator<Integer> it = list.iterator();
while(it.hasNext()){
it.remove();
}

F:运行以上错误代码会报 ConcurrentModificationException 异常

for(Integer i : list){
list.remove(i)
}

fail-fast 与 fail-safe 有什么区别?

java面试(基础)_职场和发展_25

在迭代一个集合的时候,如何避免ConcurrentModificationException?

在遍历一个集合的时候我们可以使用并发集合类来避免 ConcurrentModificationException,比
如使用 CopyOnWriteArrayList,而不是 ArrayList。
 

(6)遍历一个 List 有哪些不同的方式?每种方法的实现原理是什么?Java 中 List
遍历的最佳实践是什么?

遍历方式有以下几种:
1. for 循环遍历:基于计数器。在集合外部维护一个计数器,然后依次读取每一个位置的元素,
当读取到最后一个元素后停止。
2. 迭代器遍历:Iterator。Iterator 是面向对象的一个设计模式,目的是屏蔽不同数据集合的特
点,统一遍历集合的接口。Java 在 Collections 中支持了 Iterator 模式。
3. foreach 循环遍历:foreach 内部也是采用了 Iterator 的方式实现,使用时不需要显式声明
Iterator 或计数器。优点是代码简洁,不易出错;缺点是只能做简单的遍历,不能在遍历过程中操作数据集合,例如删除、替换。

最佳实践:Java Collections 框架中提供了一个 RandomAccess 接口,用来标记 List 实现是否支
持 Random Access。
如果一个数据集合实现了该接口,就意味着它支持 Random Access,按位置读取元素的平均
时间复杂度为 O(1),如ArrayList。如果没有实现该接口,表示不支持 Random Access,如LinkedList。推荐的做法就是,支持 Random Access 的列表可用 for 循环遍历,否则建议用 Iterator 或 foreach 遍历。

(7)如何实现数组和 List 之间的转换?
数组转 List:使用 Arrays. asList(array) 进行转换。
List 转数组:使用 List 自带的 toArray() 方法。
 

(8)集合和数组的区别

数组是固定长度的;集合可变长度的。
数组可以存储基本数据类型,也可以存储引用数据类型;集合只能存储引用数据类型。
数组存储的元素必须是同一个数据类型;集合存储的对象可以是不同数据类型。
 

(9)ArrayList和LinkedList的异同?

java面试(基础)_数组_26

(10)ArrayList和Vector的区别?

java面试(基础)_面试_27

(11)插入数据时,ArrayList、LinkedList、Vector谁速度较快?阐述ArrayList、Vector、LinkedList 的存储性能和特性?

java面试(基础)_java_28

(12)多线程场景下如何使用 ArrayList?

ArrayList 不是线程安全的,如果遇到多线程场景,可以通过 Collections 的 synchronizedList 方
法将其转换成线程安全的容器后再使用。

List<String> synchronizedList = Collections.synchronizedList(list);
synchronizedList.add("aaa");
System.out.println(synchronizedList.get(0));

(13)ArrayList自动扩容?

每当向数组中添加元素时,都要去检查添加后元素的个数是否会超出当前数组的长度,如果超出,数组将会进行扩容,以满足添加数据的需求。数组扩容通过ensureCapacity(int minCapacity)方法来实现。数组进行扩容时,会将老数组中的元素重新拷贝一份到新的数组中,每次数组容量的增长大约是其原容量的1.5倍。这种操作的代价是很高的,因此在实际使用时,我们应该尽量避免数组容量的扩张。

(14)List 和 Set 的区别

java面试(基础)_数组_29

(15)HashSet 实现原理

HashSet 是基于 HashMap 实现的,HashSet的值存放于HashMap的key上,HashMap的value统一为present. HashSet是对HashMap的简单包装,对HashSet的函数调用都会转换成合适的HashMap方法。

(16)HashSet与HashMap的区别

java面试(基础)_面试_30

(17)HashMap实现原理

HashMap 基于 Hash 算法实现的:
1. 当我们往HashMap中put元素时,利用key的hashCode重新hash计算出当前对象的元素在数
组中的下标

2. 存储时,如果出现hash值相同的key,此时有两种情况。
(1)如果key相同,则覆盖原始值;
(2)如果key不同(出现冲突),则将当前的key-value放入链表中

3. 获取时,直接找到hash值对应的下标,在进一步判断key是否相同,从而找到对应值。
4. 理解了以上过程就不难明白HashMap是如何解决hash冲突的问题,核心就是使用了数组的
存储方式,然后将冲突的key的对象放入链表中,一旦发现冲突就在链表中做进一步的对比
 

(18)HashMap在JDK1.7和JDK1.8中有哪些不同?

<jdk8

哈希表有两种实现方式,一种开放地址方式(Open addressing),另一种是冲突链表方式(Separate chaining with linked lists)。Java7 HashMap采用的是冲突链表方式

>=jdk8

根据 Java7 HashMap 的介绍,我们知道,查找的时候,根据 hash 值我们能够快速定位到数组的具体下标,但是之后的话,需要顺着链表一个个比较下去才能找到我们需要的,时间复杂度取决于链表的长度,为 O(n)。

在 Java8 中,当链表中的元素达到了 8 个时,会将链表转换为红黑树,在这些位置进行查找的时候可以降低时间复杂度为 O(logN)。引入了红黑树,目的是避免单条链表过长而影响查询效率。

java面试(基础)_面试_31

(19)HashMap扩容

1. 在jdk1.8中,resize方法是在hashmap中的键值对大于阀值时或者初始化时,就调用resize方法进行扩容;
2. 每次扩展的时候,都是扩展2倍;
3. 扩展后Node对象的位置要么在原位置,要么移动到原偏移量两倍的位置。

(20)HashMap是怎么解决哈希冲突的

链表法就是将相同hash值的对象组织成一个链表放在hash值对应的槽位;
开放地址法是通过一个探测算法,当某个槽位已经被占据的情况下继续查找下一个可以使用的槽位。
(21)Map 的 key

能否使用任何类作为 Map 的 key?

java面试(基础)_Java_32

为什么HashMap中String、Integer这样的包装类适合作为K?

java面试(基础)_数组_33

 如果使用Object作为HashMap的Key,应该怎么办呢?

java面试(基础)_Java_34

 (22)HashMap 与 HashTable 有什么区别?

java面试(基础)_面试_35

 (23)TreeMap

java面试(基础)_职场和发展_36

 (24)HashMap 和 TreeMap 区别

对于在Map中插入、删除和定位元素这类操作,HashMap是最好的选择。然而,假如你需要对一
个有序的key集合进行遍历,TreeMap是更好的选择。基于你的collection的大小,也许向HashMap中添加元素会更快,将map换为TreeMap进行有序key的遍历。

(25)HashMap 和 ConcurrentHashMap 的区别

java面试(基础)_面试_37

 (26)ConcurrentHashMap 和 Hashtable 的区别

答:ConcurrentHashMap 结合了 HashMap 和 HashTable 二者的优势。HashMap 没有考虑同步,HashTable 考虑了同步的问题使用了synchronized 关键字,所以 HashTable 在每次同步执行
时都要锁住整个结构。 ConcurrentHashMap 锁的方式是稍微细粒度的。

java面试(基础)_职场和发展_38

1、HashTable:

java面试(基础)_数组_39

2. JDK1.7的ConcurrentHashMap:

java面试(基础)_java_40

 3. JDK1.8的ConcurrentHashMap(TreeBin: 红黑二叉树节点 Node: 链表节点):

java面试(基础)_java_41

 (27)ConcurrentHashMap 底层具体实现知道吗?实现原理是什么?

java面试(基础)_数组_42

java面试(基础)_数组_43

java面试(基础)_面试_44

  (28)Array 和 ArrayList 有何区别?

java面试(基础)_职场和发展_45

 (29)Collections 工具类中的 sort()方法如何比较元素?

comparable接口实际上是出自java.lang包,它有一个 compareTo(Object obj)方法用来排序
comparator接口实际上是出自 java.util 包,它有一个compare(Object obj1, Object obj2)方法用
来排序
一般我们需要对一个集合使用自定义排序时,我们就要重写compareTo方法或compare方法,当
我们需要对某一个集合实现两种排序方式,比如一个song对象中的歌名和歌手名分别采用一种排
序方法的话,我们可以重写compareTo方法和使用自制的Comparator方法或者以两个
Comparator来实现歌名排序和歌星名排序,第二种代表我们只能使用两个参数版的
Collections.sort().

(30)Collection 和 Collections 有什么区别?

java面试(基础)_面试_46

(31)comparable 和 comparator的区别?TreeMap 和 TreeSet 在排序时如何比较元素?

java面试(基础)_面试_47

(32)哪些集合类提供对元素的随机访问?

ArrayList、 HashMap、 TreeMap 和 HashTable 类

(33)哪些集合类是线程安全的?

1)Vector、 HashTable、 Properties 和 Stack 是同步类,所以它们是线程安全的
2)JUC下线程安全集合类

(34)并发集合类是什么?

并发包(java.util.concurrent)包含线程安全集合类,允许在迭代时修改集合。迭代器 被 设 计 为 fail-fast 的 , 会 抛 出 ConcurrentModificationException 。 一 部 分 类 为 fail-safe:
CopyOnWriteArrayList、 ConcurrentHashMap、 CopyOnWriteArraySet。

(35)如何对一组对象进行排序?

如果我们需要对一个对象数组进行排序,我们可以使用 Arrays.sort()方法。如果我们需要排
序一个对象列表,我们可以使用 Collection.sort()方法。
两个类都有用于自然排序(使用 Comparable)或基于标准的排序(使用 Comparator)的重
载方法 sort()
。 Collections 内部使用数组排序方法,所有它们两者都有相同的性能,只是
Collections 需要花时间将列表转换为数组。

(36)当一个集合被作为参数传递给一个函数时,如何才可以确保函数不能修改它?

在作为参数传递之前,我们可以使用 Collections.unmodifiableCollection(Collection c)方法创建
一个只读集合,
这将确保改变集合的任何操作都会抛出 UnsupportedOperationException。

(37)为什么集合类没有实现 Cloneable 和 Serializable 接口?
克隆(cloning)或者是序列化(serialization)的语义和含义是跟具体的实现相关的。 因此, 应该
由集合类的具体实现来决定如何被克隆或者是序列化。

(38)快速失败(fail-- fast)和安全失败(fail-- safe)的区别是什么?

Iterator 的安全失败是基于对底层集合做拷贝, 因此, 它不受源集合上修改的影响。 java.util 包
下面的所有的集合类都是快速失败的, 而 java.util.concurrent 包下面的所有的类都是安全失败的。快速失败的迭代器会抛出 ConcurrentModificationException 异常,而安全失败的 迭代器永远不会抛出这样的异常。

(39)HashSet 和 TreeSet 有什么区别?
HashSet 是由一个 hash 表来实现的, 因此, 它的元素是无序的。 add(), remove(), contains()
方法的时间复杂度是 O(1)。
另一方面, TreeSet 是由一个树形的结构来实现的, 它里面的元素是有序的。 因此, add(),
remove(), contains()方法的时间复杂度是 O(logn)。
 

9. IO

9.1 5种IO模型

9.1.1 阻塞?同步?

  • 阻塞IO 和 非阻塞IO

这两个概念是程序级别的。主要描述的是程序请求操作系统IO操作后,如果IO资源没有准备好,那么程序该如何处理的问题: 前者等待;后者继续执行(并且使用线程一直轮询,直到有IO资源准备好了)

  • 同步IO 和 非同步IO

这两个概念是操作系统级别的。主要描述的是操作系统在收到程序请求IO操作后,如果IO资源没有准备好,该如何响应程序的问题: 前者不响应,直到IO资源准备好以后;后者返回一个标记(好让程序和自己知道以后的数据往哪里通知),当IO资源准备好以后,再用事件机制返回给程序。

9.1.2 Linux IO模型

网络IO的本质是socket的读取,socket在linux系统被抽象为流,IO可以理解为对流的操作。对于一次IO访问(以read举例),数据会先被拷贝到操作系统内核的缓冲区中,然后才会从操作系统内核的缓冲区拷贝到应用程序的地址空间

9.1.3 网络IO模型

网络应用需要处理的无非就是两大类问题:网络IO,数据计算。相对于后者,网络IO的延迟,给应用带来的性能瓶颈大于后者。网络IO的模型大致有如下几种:

  1. 同步阻塞IO(bloking IO):应用进程被阻塞,直到数据复制到应用进程缓冲区中才返回。
  2. 同步非阻塞IO(non-blocking IO):应用进程执行系统调用之后,内核返回一个错误码。应用进程可以继续执行,但是需要不断的执行系统调用来获知 I/O 是否完成,这种方式称为轮询(polling)。
  3. 多路复用IO(multiplexing IO):系统调用可能是由多个任务组成的,所以可以拆成多个任务,这就是多路复用。
  4. 信号驱动式IO(signal-driven IO):应用进程使用 sigaction 系统调用,内核立即返回,应用进程可以继续执行,也就是说等待数据阶段应用进程是非阻塞的。内核在数据到达时向应用进程发送 SIGIO 信号,应用进程收到之后在信号处理程序中调用 recvfrom 将数据从内核复制到应用进程中。 相比于非阻塞式 I/O 的轮询方式,信号驱动 I/O 的 CPU 利用率更高。
  5. 异步IO(asynchronous IO):相对于同步IO,异步IO不是顺序执行。用户进程进行aio_read系统调用之后,无论内核数据是否准备好,都会直接返回给用户进程,然后用户态进程可以去做别的事情。等到socket数据准备好了,内核直接复制数据给进程,然后从内核向进程发送通知。IO两个阶段,进程都是非阻塞的。

java面试(基础)_面试_48

9.2 Java IO

9.2.1 BIO (同步阻塞

(1)Java的基本IO都是阻塞IO

(2)Java IO设计上使用了什么设计模式?装饰者模式: 所谓装饰,就是把这个装饰者套在被装饰者之上,从而动态扩展被装饰者的功能。

(3)如何从数据传输方式理解IO流?

从数据传输方式或者说是运输方式角度看,可以将 IO 类分为:

  1. 字节流, 字节流读取单个字节,字符流读取单个字符(一个字符根据编码的不同,对应的字节也不同,如 UTF-8 编码中文汉字是 3 个字节,GBK编码中文汉字是 2 个字节。)
  2. 字符流, 字节流用来处理二进制文件(图片、MP3、视频文件),字符流用来处理文本文件(可以看做是特殊的二进制文件,使用了某种编码,人可以阅读)。

java面试(基础)_数组_49

9.2.2 NIO (同步非阻塞

NIO主要有三大核心部分:Channel(通道),Buffer(缓冲区), Selector。传统IO基于字节流和字符流进行操作,而NIO基于Channel和Buffer(缓冲区)进行操作,数据总是从通道读取到缓冲区中,或者从缓冲区写入到通道中。Selector(选择区)用于监听多个通道的事件(比如:连接打开,数据到达)。因此,单个线程可以监听多个数据通道。

NIO和传统IO(一下简称IO)之间第一个最大的区别是,IO是面向流的,NIO是面向缓冲区的。

java面试(基础)_数组_50

9.2.3 AIO (异步非阻塞

服务器实现模式为一个有效请求一个线程,客户端的I/O请求都是由操作系统先完成了再通知服务器应用去启动线程进行处理,一般适用于连接数较多且连接时间较长的应用

10. 构造器 Constructor 是否可被 override

在讲继承的时候我们就知道父类的私有属性和构造方法并不能被继承,所以Constructor 也就不能被 override(重写) ,但是可以 overload(重载),所以你可以看到一个类中有多个构造函数的情况。

11. 重载和重写的区别

重载: 发生在同一个类中,方法名必须相同,参数类型不同、个数不同、顺序
不同,方法返回值和访问修饰符可以不同,发生在编译时。
重写: 发生在父子类中,方法名、参数列表必须相同,返回值范围小于等于父
类,抛出的异常范围小于等于父类,访问修饰符范围大于等于父类;如果父类
方法访问修饰符为 private 则子类就不能重写该方法。
 

12. 自动装箱与拆箱

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

13. 静态方法和实例方法区别
 

(1) 在外部调用静态方法时,可以使用"类名.方法名"的方式,也可以使用"对象名.方法名"的方式。而实例方法只有后面这种方式。也就是说,调用静态方法可以无需创建对象
(2) 静态方法在访问本类的成员时,只允许访问静态成员(即静态成员变量和静态方法),而不允许访问实例成员变量和实例方法;实例方法则无此限制
 

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

Java 程序在执行子类的构造方法之前,如果没有用 super() 来调用父类特定的构造方法,则会调用父类中“没有参数的构造方法”。因此,如果父类中只定义了有参数的构造方法,而在子类的构造方法中又没有用 super() 来调用父类中特定的构造方法,则编译时将发生错误,因为 Java 程序在父类中找不到没有参数的构造方法可供执行。解决办法是在父类里加上一个不做事且没有参数的构造方法。

15. 成员变量与局部变量的区别有那些

(1) 从语法形式上,看成员变量是属于类的,而局部变量是在方法中定义的变量或是方法的参数;成员变量可以被 public,private,static 等修饰符所修饰,而局部变量不能被访问控制修饰符及 static 所修饰;但是,成员变量和局部变量都能被 final 所修饰;
(2) 从变量在内存中的存储方式来看,成员变量是对象的一部分,而对象存在于堆内存,局部变量存在于栈内存
(3) 从变量在内存中的生存时间上看,成员变量是对象的一部分,它随着对象的创建而存在,而局部变量随着方法的调用而自动消失。
(4) 成员变量如果没有被赋初值,则会自动以类型的默认值而赋值(一种情况例外被 final 修饰的成员变量也必须显示地赋值);而局部变量则不会自动赋值。

16. == 与 equals

== : 它的作用是判断两个对象的地址是不是相等。即,判断两个对象是不是同一个对象。 (基本数据类型==比较的是值,引用数据类型==比较的是内存地址)
equals() : 它的作用也是判断两个对象是否相等。但它一般有两种使用情况:
情况 1:类没有覆盖 equals() 方法。则通过 equals() 比较该类的两个对象时,等价于通过“==”比较这两个对象。
情况 2:类覆盖了 equals() 方法。一般,我们都覆盖 equals() 方法来两个对象的内容相等;若它们的内容相等,则返回 true (即,认为这两个对象相等)。

17. 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 就不会让其加入操作成功。如果不同的话,就会重新散列到其他位置。

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

(1) 如果两个对象相等,则 hashcode 一定也是相同的(hashCode是jdk根据对象的地址或者字符串或者数字算出来的int类型的数值)
(2) 两个对象相等,对两个对象分别调用 equals 方法都返回 true
(3) 两个对象有相同的 hashcode 值,它们也不一定是相等的
(4) 因此, equals 方法被覆盖过,则 hashCode 方法也必须被覆盖
(5) hashCode() 的默认行为是对堆上的对象产生独特值。如果没有重写hashCode(),则该 class 的两个对象无论如何都不会相等(即使这两个对象指向相同的数据)

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

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

19. Main方法

(1)main 方法为什么是静态的?能不能改为非静态?
main()方法一定是静态的,如果 main()是非静态的那么在调用 main 方法时 JVM 就得实例化
它的类。

(2)main 方法能被重载吗?
可以,我们可以重载 main()方法。一个 Java 类可以有任意数量的 main()方法。

(3)main 方法能被覆盖吗?
在 Java 中静态方法在编译时会编译在一起, main 方法是静态方法,所以你在 Java 中不能覆
盖静态方法。

(4)main 方法的返回类型是什么?能不能改变?
void,不能改变。

20. java 事件机制

java 事件机制包括三个部分:事件、事件监听器、事件源

1、事件。一般继承自 java.util.EventObject 类,封装了事件源对象及跟事件相关的信息。
com.javaedu.event.CusEvent 类
2、事件监听器。实现 java.util.EventListener 接口,注册在事件源上,当事件源的属性或状态
改变时,取得相应的监听器调用其内部的回调方法。
com.javaedu.event.CusEventListener 类
3、事件源。事件发生的地方,由于事件源的某项属性或状态发生了改变(比如 BUTTON 被
单击、 TEXTBOX 的值发生改变等等)导致某项事件发生。换句话说就是生成了相应的事件
对象。因为事件监听器要注册在事件源上,所以事件源类中应该要有盛装监听器的容器
(List,Set 等等)。
 

21. Cookie 和 Session

​​ Cookie 和 Session 都为了用来保存状态信息,都是保存客户端状态的机制,它
们都是为了解决 HTTP 无状态的问题而所做的努力。
Session 可以用 Cookie 来实现,也可以用 URL 回写的机制来实现。用 Cookie
来实现的 Session 可以认为是对 Cookie 更高级的应用。
Cookie 和 Session 有以下明显的不同点:
1) Cookie 将状态保存在客户端, Session 将状态保存在服务器端;
2) Cookies 是服务器在本地机器上存储的小段文本并随每一个请求发送至同一
个服务器。 在客户终端,浏览器解析这些 cookies 并将它们保存为一个本地文件,
它会自动将同一服务器的任何请求缚上这些 cookies。 Session 并没有在 HTTP
的协议中定义;
3) Session 是针对每一个用户的,变量的值保存在服务器上,用一个 sessionID
来区分是哪个用户 session 变量,这个值是通过用户的浏览器在访问的时候返回
给服务器, 当客户禁用 cookie 时,这个值也可能设置为由 get 来返回给服务器;

22. Java创建对象有几种方式?

java中提供了以下四种创建对象的方式:
1) new创建新对象
2) 通过反射机制
3) 采用clone机制
4) 通过序列化机制

23. 深拷贝和浅拷贝

浅拷贝(shallowCopy)只是增加了一个指针指向已存在的内存地址。
深拷贝(deepCopy)是增加了一个指针并且申请了一个新的内存,使这个增加 的指针指向这个新的内存。
使用深拷贝的情况下,释放内存的时候不会因为出现浅拷贝时释放同一个内存的错误。
浅复制:仅仅是指向被复制的内存地址,如果原地址发生改变,那么浅复制出来 的对象也会相应的改变。
深复制:在计算机中开辟一块新的内存地址用于存放复制的对象。

24. 设计模式

单例模式

工厂模式

工厂模式的最大好处是增加了创建对象时的封装层次。如果你使用工厂来创建对象,之后你
可以使用更高级和更高性能的实现来替换原始的产品实现或类,这不需要在调用层做任何修

​三种工厂模式及其区别(简单工厂、工厂方法、抽象工厂) - 李清灿的开发笔记​

观察者模式

观察者模式是基于对象的状态变化和观察者的通讯,以便他们作出相应的操作。简单的例子
就是一个天气系统,当天气变化时必须在展示给公众的视图中进行反映。这个视图对象是一
个主体,而不同的视图是观察者。

Java 实现的装饰模式
装饰模式增加强了单个对象的能力。 Java IO 到处都使用了装饰模式,典型例子就是 Buffered
系列类如 BufferedReader 和 BufferedWriter,它们增强了 Reader 和 Writer 对象,以实现提升
性能的 Buffer 层次的读取和写入。

列举出在 JDK 中几个常用的设计模式?
单例模式(Singleton pattern)用于 Runtime, Calendar 和其他的一些类中。工厂模式(Factory
pattern)被用于各种不可变的类如 Boolean,像 Boolean.valueOf,观察者模式( Observer
pattern)被用于 Swing 和很多的事件监听中。装饰器设计模式(Decorator design pattern)
被用于多个 Java IO 类中。

25. java8新特性

26. Onject划分

27. 拦截器

28. abstract 的 method 是否可同时是 static,是否可同时是 native,是否可同时是 synchronized

都不能

29. Servlet

什么是 Servlet?
Servlet 是用来处理客户端请求并产生动态网页内容的 Java 类。 Servlet 主要是用来处理或
者是存储 HTML 表单提交的数据, 产生动态内容, 在无状态的 HTTP 协议下管理状态信息。
Servlet 的体系结构?

所有的 Servlet 都必须要实现的核心的接口是 javax.servlet.Servlet。每一个 Servlet 都必须
要直接或者是间接实现这个接口,或者是继承 javax.servlet.GenericServlet 或者
javax.servlet.http.HTTPServlet。最后, Servlet 使用多线程可以并行的为多个请求服务。
GenericServlet 和 HttpServlet 有什么区别?

GenericServlet 是一个通用的协议无关的 Servlet, 它实现了 Servlet 和 ServletConfig 接口。
继承自 GenericServlet 的 Servlet 应该要覆盖 service()方法。 最后, 为了开发一个能用在网
页上服务于使用 HTTP 协议请求的 Servlet,你的 Servlet 必须要继承自 HttpServlet。这里
有 Servlet 的例子。

什么是 Servlet 链(Servlet Chaining)?
Servlet 链是把一个 Servlet 的输出发送给另一个 Servlet 的方法。第二个 Servlet 的输出可
以发送给第三个 Servlet,依次类推。链条上最后一个 Servlet 负责把响应发送给客户端。
如何知道是哪一个客户端的机器正在请求你的 Servlet?
ServletRequest 类可以找出客户端机器的 IP 地址或者是主机名。 getRemoteAddr()方法获
取客户端主机的 IP 地址, getRemoteHost()可以获取主机名。
浏览器和 Servlet 通信使用的是什么协议?
浏览器和 Servlet 通信使用的是 HTTP 协议。
 

30. 内部类

标签:java,Servlet,对象,方法,基础,面试,IO,Java,异常
From: https://blog.51cto.com/u_15905340/5919901

相关文章

  • #yyds干货盘点# LeetCode程序员面试金典:返回倒数第 k 个节点
    题目:实现一种算法,找出单向链表中倒数第k个节点。返回该节点的值。注意:本题相对原题稍作改动示例:输入:1->2->3->4->5和k=2输出:4代码实现:/***Definitionforsingly-......
  • java对象/谈谈Java虚拟机
    ......
  • Java学习十三
    1.异常处理能够使一个方法给它的调用者抛出一个异常。2.Java异常是派生自java.lang.Throwable的类的实例。Java提供大量预定义的异常类,例如,Error、Exception、RuntimeExc......
  • 初学Java
    Java概念三大版本JavaSE(basis)JavaME(嵌入式,手机...)JavaEE(E企业级,web端、服务器开发,)JDKJREJWMJDK:JavaDevelopmentKitJRE:JavaRuntimeEnvironmen......
  • java高频面试题(反射、对象拷贝)
    java高频面试题(反射、对象拷贝)java高频面试题(反射、对象拷贝)1.什么是反射?反射主要是指程序可以访问、检测和修改它本身状态或行为的一种能力Java反射:在Java运行时环境......
  • Java Swing的练习感悟
    感悟心得这还是我第一次使用JavaSwing写代码呢,直接就是趣味性拉满!在相关的界面代码的基础上,在必要的位置嵌入Java代码,就可以很好的实现啦!简单的嘞!(有兴趣的各位可以选......
  • 【matlab基础】matlab通过方向角画射线
    前言好久不使用matlab,很多操作函数都忘记了,需要度娘才能熟悉起来,非常影响开发速度。code根据角度可以知道直线的斜率,根据斜率可以画射线;xx=-lateral:latera......
  • java安全 反序列化(一)
    介绍序列化就是把对象转换成字节流,便于保存在内存、文件、数据库中;反序列化即逆过程,由字节流还原成对象。序列化是一种对象持久化的手段,可以将对象的状态转换为字节数组,来......
  • MongoDB数据库的基础特性
    MongoDB是全球领先的NoSQL数据库,是一个可扩展、开源、表结构自由,用C++语言编写且面向文档的高性能分布式数据库。 MongoDB在持续演进中,不断优化自己的特色功能,保证了数据......
  • 【JAVA笔记】JAVA-入门基础-面向对象04
    一、OOP详解面向对象编程(Object-OrientedProgramming,OOP)面向对象编程的本质就是:以类的方式组织代码,以对象的组织(封装)数据。抽象三大特性:封装、继承、多态、1、cla......