JAVA面试总结

一、Java基础

解释下什么是面向对象?面向对象和面向过程的区别?

面向过程:
面向过程侧重整个问题的解决步骤,着眼局部或者具体。

面向对象:
面向对象侧重具体的功能,让某个对象具有这样的功能。更加侧重于整体。

面向对象的三大特性?分别解释下?

一:封装
对于封装而言,一个对象它所封装的是自己的属性和方法,所以他是不需要依赖其他对象就可以完成自己的操作。
封装的三大好处:
1、良好的封装能够减少耦合。
2、类内部的结构可以自由修改。
3、可以对成员进行更精确的控制。
4、隐藏信息,实心细节。

二:继承
继承是使用已存在的类定义作为基础建立新类的技术,新类的定义课增加新的数据或新的功能,也可以用父类的功能,但不能选择性的继承父类。

1、子类拥有父类非private的属性和方法。
2、子类可以拥有自己的属性和方法,即子类可以对父类进行扩展。
3、子类可以用自己的方式实现父类的方法。

三:多态

多态是同一个行为具有多个不同表现形式或形态的能力。

多态的三种表现形式:
继承,重写,父类引用指向子类对象。
实现方式:
1.普通类
AnimalFu a = new AnimalZi new();
2.抽象类 animal 是父类抽象类
Animal a = new Cat();
3.接口

JDK、JRE、JVM 三者之间的关系?

jdk是JAVA程序开发时用的开发工具包,其内部也有JRE运行环境JRE。

JRE是JAVA程序运行时需要的运行环境,就是说如果你光是运行JAVA程序而不是去搞开发的话,只安装JRE就能运行已经存在的JAVA程序了。

JDk、JRE内部都包含JAVA虚拟机JVM,JAVA虚拟机内部包含许多应用程序的类的解释器和类加载器等等。

重载和重写的区别?

重载 :

​ 重载发生在本类,方法名相同,参数列表不同,与返回值无关,只和方法名,参数列表,参数的类型有关.

​ 首先是位于一个类之中或者其子类中,具有相同的方法名,但是方法的参数不同,返回值类型可以相同也可以 不同。

(1):方法名必须相同

(2):方法的参数列表一定不一样。

(3):访问修饰符和返回值类型可以相同也可以不同。

重写:

一般都是表示子类和父类之间的关系,其主要的特征是:方法名相同,参数相同,但是具体的实现不同。

(1):方法名必须相同,返回值类型必须相同

(2):参数列表必须相同

(3):访问权限不能比父类中被重写的方法的访问权限更低。例如:如果父类的一个方法被声明为public,那么在子类中重写该方法就不能声明为protected。

(4):子类和父类在同一个包中,那么子类可以重写父类所有方法,除了声明为private和final的方法。

(5):构造方法不能被重写,
————————————————

Java 中是否可以重写一个 private 或者 static 方法?

Java中static方法不能被覆盖,因为方法覆盖是基于运行时动态绑定的,而static方法是编译时静态绑定的。static方法类的任何实例都不相关,所以概念上不适用。

静态方法形式上可以被重写,即子类中可以重写父类中静态的方法。但是实际上从内存的角度上静态方法不可以被重写。子类重写父类的static方法时,编译的时候是子类特性,但运行时,确实用的父类方法,因为虚拟机把子类的static方法隐藏了。

静态方法虽然是同一个方法,但是不同线程在调用,程序计数器的值是不一样的,操作这两个线程不会相互影响(假设不存在访问共享变量的情况)

Java中也不可以覆盖private的方法,因为private修饰的变量和方法只能在当前类中使用,如果是其他的类继承当前类是不能访问到private变量或方法的,当然也不能覆盖。
————————————————

构造器是否可以被重写?

因为Java类的构造器不能够被继承,所以Java类的构造器不能被override重写,但是可以overload重载。

构造方法有哪些特性?

1.具有与类相同的名称;

2.不含返回类型;

3.在类实例化的时候,系统自动调用

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

​ Java在执行子类的构造方法时,假如没有用super()来调用父类特定的构造方法,则会默认调用父类中没有参数的构造方法。因此,假如父类中只定义了带参数的构造方法,而在子类的构造方法中没有调用又没有用super()来调用父类中特定的构造方法,则编译器将发生错误。

Java 中创建对象的几种方式?

第一种,也是最常用、一直接触到的方法:通过new 创建对象。这种方法需要用到构造器

**第二种,比较常用的的方法:**通过反射 newInstance()创建对象。这种方法用到构造器

**第三种,通过object类的clone方法。**需要实现Cloneable接口,重写object类的clone方法。无论何时我们调用一个对象的clone方法,jvm就会创建一个新的对象,将前面对象的内容全部拷贝进去。用clone方法创建对象并不会调用任何构造函数。

**第四种,反序列化。**java 中常常进行 JSON 数据跟 Java 对象之间的转换,即序列化和反序列化。
当我们序列化和反序列化一个对象,JVM会给我们创建一个单独的对象,在反序列化时,JVM创建对象并不会调用任何构造函数。为了反序列化一个对象,我们需要让我们的类实现Serializable接口,虽然该接口没有任何方法。不会调用任何构造函数

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

A:成员区别
1、成员变量
抽象类:可变量,可常量。

接口: 只能是静态常量。

2、构造方法
抽象类:有。

接口:无。

3、成员方法
抽象类:可以抽象、可以非抽象

接口:default(默认方法)、static(静态方法)、抽象方法、private

B:关系区别
1、类与类:单继承,多层继承

2、类与接口:单/多 实现。

3、接口与接口:单/多继承。

C:理念
A:抽象类:“is a” 继承体系的共性功能

B:接口:“like a” 继承体系的拓展功能
————————————————

静态变量和实例变量的区别?

**在语法定义上的区别:**静态变量前要加static关键字,而实例变量前则不加。

**在程序运行时的区别:**实例变量属于某个对象的属性,必须创建了实例对象,其中的实例变量才会被分配空间,才能使用这个实例变量。静态变量不属于某个实例对象,而是属于类,所以也称为类变量,只要程序加载了类的字节码,不用创建任何实例对象,静态变量就会被分配空间,静态变量就可以被使用了。总之,实例变量必须创建对象后才可以通过这个对象来使用,静态变量则可以直接使用类名来引用。

类的静态变量在内存中只有一个,java虚拟机在加载类的过程中为静态变量分配内存,静态变量位于方法区,被类的所有实例共享。静态变量可以直接通过类名进行访问,其生命周期取决于类的生命周期。

**而实例变量取决于类的实例。**每创建一个实例,java虚拟机就会为实例变量分配一次内存,实例变量位于堆区中,其生命周期取决于实例的生命周期。

成员变量和局部变量的区别?

定义的位置不同

成员变量:在方法的外部,直接写在类当中。局部变量:方法的内部。

作用的范围不同

成员变量:整个类可以通用。局部变量:只有在方法中才可以使用,出了方法就不可以使用。

默认值不一样

成员变量:如果没有进行赋值,会有默认值,规则和数组一样。局部变量:没默认值,需要赋值才可以使用。内存位置不一样成员变量:位于堆当中。局部变量:位于当中。

生命周期不同

成员变量:随着对象创建而诞生,随着对象被垃圾回收而消失。局部变量:随着方法进栈而诞生,随着方法出栈而消失。相对于成员变量,一般来说局部变量存在的时间更短一点。

short s1 = 1;s1 = s1 + 1;有什么错?那么 short s1 = 1; s1 += 1;呢?有没有错误?

1. short s1 = 1; s1 = s1 + 1;

错误!

根据java的基本数据类型转换规则,s1为short类型的变量,在表达式s1 = s1 + 1;中,s1会自动转为int类型与1进行运算,运算结果为int类型,而int类型的值 赋值给short类型的变量时需要强制类型转换。

2. short s1 = 1; s1 += 1;

正确!

在复合赋值运算符底层自动进行强制类型转换,所以此处实际上是s1 = (int) s1 + 1;因为此处有强制类型转换,所以编译可以通过。

Integer 和 int 的区别?

1、Integer是int的包装类,int则是java的一种基本数据类型   
  2、Integer实际是对象的引用,当new一个Integer时,实际上是生成一个指针指向此对象;而int则是直接存储数据值
  3、Integer的默认值是null,int的默认值是0

装箱和拆箱

1、自动装箱
自动装箱其实就是将基本数据类型转换为引用数据类型(对象)

2、自动拆箱
自动拆箱其实就是将引用数据类型转化为基本数据类型

switch 语句能否作用在 byte 上,能否作用在 long 上,能否作用在 String 上?

可以是int 基本类型或Integer 包装类型,由于,byte,short,char 都可以隐含转换为int,所以这些类型以及这些类型的包装类型也是可以的。

显然long 和String 类型都不符合switch 的语法规定,并且不能被隐式转换成int 类型,所以它们不能作用于swtich 语句中。

​ switch中可以是字符串类型,String(JDK1.7之后才可以作用在string上),switch中可以是枚举类型(JDK1.5之后)。

字节和字符的区别?

(一)“字节”的定义
字节(Byte)是一种计量单位,表示数据量多少,它是计算机信息技术用于计量存储容量的一种计量单位。

(二)“字符”的定义
字符是指计算机中使用的文字和符号,比如1、2、3、A、B、C、~!·#¥%……—*()——+、等等。

(三)“字节”与“字符”
它们完全不是一个位面的概念,所以两者之间没有“区别”这个说法。不同编码里,字符和字节的对应关系不同:
①ASCII码中,一个英文字母(不分大小写)占一个字节的空间,一个中文汉字占两个字节的空间。一个二进制数字序列,在计算机中作为一个数字单元,一般为8位二进制数,换算为十进制。最小值0,最大值255。
②UTF-8编码中,一个英文字符等于一个字节,一个中文(含繁体)等于三个字节。
③Unicode编码中,一个英文等于两个字节,一个中文(含繁体)等于两个字节。
符号:英文标点占一个字节,中文标点占两个字节。举例:英文句号“.”占1个字节的大小,中文句号“。”占2个字节的大小。
④UTF-16编码中,一个英文字母字符或一个汉字字符存储都需要2个字节(Unicode扩展区的一些汉字存储需要4个字节)。
⑤UTF-32编码中,世界上任何字符的存储都需要4个字节。
————————————————

String 为什么要设计为不可变类?

1. 字符串常量池的需要

​ 字符串常量池(String pool, String intern pool, String保留池) 是Java堆内存中一个特殊的存储区域, 当创建一个String对象时,假如此字符串值已经存在于常量池中,则不会创建一个新的对象,而是引用已经存在的对象。

2. 允许String对象缓存HashCode
Java中String对象的哈希码被频繁地使用, 比如在hashMap 等容器中。

字符串不变性保证了hash码的唯一性,因此可以放心地进行缓存.这也是一种性能优化手段,意味着不必每次都去计算新的哈希码.

3. 安全性
String被许多的Java类(库)用来当做参数,例如 网络连接地址URL,文件路径path,还有反射机制所需要的String参数等, 假若String不是固定不变的,将会引起各种安全隐患。

值不变,引用可以变

String、StringBuilder、StringBuffer 的区别?

A,String 内容是不可变的,而StringBuffer,StringBuilder都是内容可变的

B、StringBuffer是同步的,数据安全效率低,StringBuilder是不同步的,数据不安全效率高。
————————————————

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

不一样

前者在常量池中创建了对象,只创建了一个对象。

后者在堆中和常量池中都创建了对象,创建了两个对象(两个或者一个)常量池中有则不会创建。

String 类的常用方法都有那些?

构造

public String(char[] value) 把字符数组转成字符串

public String(byte[] bytes) 把字节数组转成字符串

public String() 空构造

判断功能

boolean equals(Object obj) 比较字符串的内容是否相同,区分大小写

boolean isEmpty( ) 判断字符串是否为空

获取功能

int length() 获取字符串的长度,即字符串中字符的个数。

char charAt(int index) 获取指定索引位置上的字符。

int indexOf(String str) 获取指定字符串在此字符串中第一次出现的索引。

转换功能

static String valueOf() 转成字符串

替换功能

String replace(String old,String new)

final 修饰 StringBuffer 后还可以 append 吗?

可以

final的定义了:对于基本类型,final使数值恒定不变;而对于对象引用,final使引用恒定不变。一旦引用被初始化指向一个对象,就无法再把它改为指向另一个对象。然而,对象其自身却是可以被修改的。

Object 的常用方法有哪些?

public int hashCode()

public final Class getClass()

public String toString()

public boolean equals(Object obj)

protected void finalize()
当垃圾回收器确定确定不存在该对象更多引用时,由对象的垃圾回收器调用该方法。用于垃圾回收,什么时候回收不确定

protected Object clone()
创建并返回此对象的一个副本
————————————————

为什么 wait/notify 方法放在 Object 类中而不是 Thread 类中?

因为这些方法调用依赖于锁对象,而同步代码块的锁是任意锁

final、finally、finalize 的区别?

final修饰类,不能被继承

修饰方法,不能被重写

修饰变量,只能赋值一次

finally:

在异常处理时提供finally块来执行清除操作,如果抛出一个异常,那么相匹配的catch语句就会执行,然后控制就会进入finally块。finally块中无论异常是否发生,都会执行finally块的内容,所以在代码逻辑中有需要无论发生什么都必须执行的代码,就可以放在finally块中。

finalize :

是方法名,java技术允许使用finalize()方法在垃圾收集器将对象从内存中清除之前做必要的清理工作。这个方法是在垃圾收集器确定这个对象没有被引用的情况下调用的。

finally 块中的代码什么时候被执行?finally 是不是一定会被执行到?

在Java语言的异常处理中,finally块的作用就是为了保证无论出现什么情况,finally块里的代码一定会被执行。

如果catch里有return ,在return前执行。

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

catch-finally可以省略其中一个

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

static 关键字的作用?

(1)static成员变量

虽然java语言中没有全局的概念,但可以通过static关键字来达到全局的效果。

(2) static成员方法
与变量类似,java类同时也提供了static方法与非static方法。static方法是类的方法,不需要创建对象就可以被使用

(3) static 代码块

static代码块在类中是独立与成员变量和成员函数的代码块,他不在任何一个方法体内,JVM在加载类的时候会执行static代码块,如果有多个static代码块,JVM将会按顺序来执行,static代码块经常会被用来初始化静态变量,需要注意的是static代码块只会被执行一次。

(4)static内部类

static内部类是指被申明为static的内部类,他可以不依赖于外部类实例对象而被实例化,而通常的内部类需要外部类实例化后才能实例化。

transient关键字的作用?

被transient修饰的变量不参与序列化和反序列化。

== 和 equals 的区别?

1)对于==,比较的是值是否相等

        如果作用于基本数据类型的变量,则直接比较其存储的 “值”是否相等;

如果作用于引用类型的变量,则比较的是所指向的对象的地址

2)对于equals方法,注意:equals方法不能作用于基本数据类型的变量,equals继承Object类,比较的是是否是同一个对象

如果没有对equals方法进行重写,则比较的是引用类型的变量所指向的对象的地址;

诸如String、Date等类对equals方法进行了重写的话,比较的是所指向的对象的内容。
————————————————

两个对象的 hashCode() 相同,则 equals() 也一定为 true 吗?

不对,两个对象的 hashCode()相同,equals()不一定 true。

hashCode()是通过hash算法算出来的一个值。

hashCode()相等即两个键值对的哈希值相等,然而哈希值相等,并不一定能得出键值对相等。

两个对象相等,hashcode一定相等

两个对象不等,hashcode不一定不等

hashcode相等,两个对象不一定相等

hashcode不等,两个对象一定不等

为什么重写 equals() 就一定要重写 hashCode() 方法?

**hashCode的通用规定:**如果两个对象根据equals(Object)方法比较是相等的,那么调用这两个对象中的hashCode方法都必须产生同样的整数结果。

如果一个类重写了equals方法但是没有重写hashCode方法,那么该类无法结合所有基于散列的集合(HashMap,HashSet)一起正常运作。

& 和 && 的区别?

&和&&都是逻辑运算符号,&&又叫短路运算符
& 不管前面的条件是否正确,后面都执行
&& 前面条件正确时,才执行后面,不正确时,就不执行,就效率而言,这个更好

Java 中的参数传递时传值呢?还是传引用?

值传递

Java 中的 Math.round(-1.5) 等于多少?

-1

两个数的异或结果是什么?

二进制数a与b异或,即a和b两个数按位进行,如果对应位相同,即为0(这个时候相当于对应位算术相减),如果不相同,即为1(这个时候相当于对应位算术相减的绝对值)。由于二进制每个位只有两种状态,要么是0,要么是1,则按位异或操作可以表达为按位相减取绝对值,再按位累加。

举个例子:6(110)与3(011)异或为(101),按位相减为(1 0 -1)取绝对值是(101),在按位累加得5(101)。
————————————————

error 和 exception 的区别?

Error类和Exception类都是继承Throwable类

**Error(错误)**是系统中的错误,程序员是不能改变的和处理的,是在程序编译时出现的错误,只能通过修改程序才能修正。一般是指与虚拟机相关的问题,如系统崩溃,虚拟机错误,内存空间不足,方法调用栈溢等。对于这类错误的导致的应用程序中断,仅靠程序本身无法恢复和和预防,遇到这样的错误,建议让程序终止。

**Exception(异常)**表示程序可以处理的异常,可以捕获且可能恢复。遇到这类异常,应该尽可能处理异常,使程序恢复运行,而不应该随意终止异常。

Exception又分为两类

CheckedException:(编译时异常) 需要用try——catch显示的捕获,对于可恢复的异常使用CheckedException。

UnCheckedException(RuntimeException):(运行时异常)不需要捕获,对于程序错误(不可恢复)的异常使用RuntimeException

throw 和 throws 的区别?

throw

1、throw是语句抛出一个异常,一般是在代码块的内部,当程序

现某种逻辑错误时由程序员主动抛出某种特定类型的异常

2、定义在方法体内

3、创建的是一个异常对象

4、确定了发生哪种异常才可以使用

throws

1、在方法参数列表后,throws后可以跟着多个异常名,表示抛出的异常用逗号隔开

2、表示向调用该类的位置抛出异常,不在该类解决

3、可能发生哪种异常

总结:throws可以单独使用,throw不可以,必须搭配try catch,或者throws,若程序执行到throw exception 语句,则后面的语句不会再执行。

常见的异常类有哪些?

Java异常的顶层父类为Throwable,并实现了Serializable接口

由Throwable派生出来的异常有两种,分别为Error类与Exception

Error,即错误,代表JVM本身的错误,处理程序运行环境方面的异常,不能通过代码处理。比如OutOfMemoryError,AWTError等。

Exception:即异常,程序运行时发生,可以被java异常处理机制使用。比如IOException,SQLEXception,RuntimeException等等。

运行时异常与受检异常有何异同?

  • 运行时异常,表示程序代码在运行时发生的异常,程序代码设计的合理,这类异常不会发生
  • 受检异常跟程序运行的上下文环境有关,即使程序设计无误,仍然可能因使用的问题而引发
  • Java编译器要求方法必须声明抛出可能发生未被捕获的受检异常,不要求必须声明抛出运行时异常

主线程可以捕获到子线程的异常吗?

正常情况下,如果不做特殊的处理,在主线程中是不能够捕获到子线程中的异常的。

如果想要在主线程中捕获子线程的异常,我们需要使用ExecutorService,同时做一些修改。

上面的方式是设置每一个线程执行时候的异常处理。如果每一个线程的异常处理相同,我们可以用如下的方式进行处理,使用Thread的静态方法。
Thread.setDefaultUncaughtExceptionHandler(new MyUncaughtExceptionHandle());

Java 的泛型是如何工作的 ? 什么是类型擦除 ?

泛型还有一种较为准确的说法就是为了参数化类型,或者说可以将类型当作参数传递给一个类或者是方法。

Java中的泛型基本上都是在编译器这个层次来实现的。在生成的Java字节码中是不包含泛型中的类型信息的。使用泛型的时候加上的类型参数,泛型信息只存在于代码编译阶段,在进入 JVM 之前,与泛型相关的信息会被擦除掉,专业术语叫做类型擦除。

如在代码中定义的List和List等类型,在编译后都会编程List。JVM看到的只是List,而由泛型附加的类型信息对JVM来说是不可见的。

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

限定通配符;对类型进行了限制。

表示类型的上界,格式为:<? extends T>,即类型必须为T类型或者T子类

表示类型的下界,格式为:<? super T>,即类型必须为T类型或者T的父类

非限定通配符:类型为,可以用任意类型来替代。

如何实现对象的克隆?

1). 实现Cloneable接口并重写Object类中的clone()方法;
2). 实现Serializable接口,通过对象的序列化和反序列化实现克隆,可以实现真正的深度克隆,

深克隆和浅克隆的区别?

浅克隆:创建一个新对象,新对象的属性和原来对象完全相同,对于非基本类型属性,仍指向原有属性所指向的对象的内存地址。

深克隆:创建一个新对象,属性中引用的其他对象也会被克隆,不再指向原有对象地址。

总之深浅克隆都会在堆中新分配一块区域,区别在于对象属性引用的对象是否需要进行克隆(递归性的)。

什么是 Java 的序列化,如何实现 Java 的序列化?

什么是序列化: 序列化理解成“打碎”是可以的,不过在书本上的名词就是将对象转换成二进制。

首先我们要把准备要序列化类,实现 Serializabel接口 然后使用一个输出流(如:FileOutputStream)来构造一个ObjectOutputStream(对象流)对象,接着,使用ObjectOutputStream对象的writeObject(Object obj)方法就可以将参数为obj的对象写出(即保存其状态),要恢复的话则用输入流。

Java 中的反射是什么意思?有哪些应用场景?

java反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能调用它的任意一个方法和属性;这种动态获取的信息以及动态调用对象的方法的功能称为java语言的反射机制。

①我们在使用JDBC连接数据库时使用Class.forName()通过反射加载数据库的驱动程序;

②Spring框架也用到很多反射机制,最经典的就是xml的配置模式。Spring 通过 XML 配置模式装载 Bean 的过程:1) 将程序内所有 XML 或 Properties 配置文件加载入内存中; 2)Java类里面解析xml或properties里面的内容,得到对应实体类的字节码字符串以及相关的属性信息; 3)使用反射机制,根据这个字符串获得某个类的Class实例; 4)动态配置实例的属性。

反射的优缺点?

优点:

​ 反射提高了程序的灵活性和扩展性,降低耦合性,提高自适应能力。它允许程序创建和控制任何类的对象,无需提前硬编码目标类;

缺点:

​ 1、性能问题:使用反射基本上是一种解释操作,用于字段和方法接入时要远慢于直接代码。因此反射机制主要应用在对灵活性和扩展性要求很高的系统框架上,普通程序不建议使用。
​ 2、使用反射会模糊程序内内部逻辑:程序员希望在源代码中看到程序的逻辑,反射等绕过了源代码的技术,因而会带来维护问题。反射代码比相应的直接代码更复杂。

Java 中的动态代理是什么?有哪些应用?

动态代理:当想要给实现了某个接口的类中的方法,加一些额外的处理。比如说加日志,加事务等。可以给这个类创建一个代理,故名思议就是创建一个新的类,这个类不仅包含原来类方法的功能,而且还在原来的基础上添加了额外处理的新类。这个代理类并不是定义好的,是动态生成的。具有解耦意义,灵活,扩展性强。

动态代理的应用:Spring的AOP,加事务,加权限,加日志。

怎么实现动态代理?

动态代理实现:首先必须定义一个接口,还要有一个InvocationHandler(将实现接口的类的对象传递给它)处理类。再有一个工具类Proxy(习惯性将其称为代理类,因为调用他的newInstance()可以产生代理对象,其实他只是一个产生代理对象的工具类)。利用到InvocationHandler,拼接代理类源码,将其编译生成代理类的二进制码,利用加载器加载,并将其实例化产生代理对象,最后返回。
————————————————

Java 中的 IO 流的分类?说出几个你熟悉的实现类?

按流的方向分:
输出流:OutputStream和Writer为基类
输入流:InputStream和Reader为基类
按类型分:
字节流:字节输入流:InputStream基类
字节输出流:OutputStream基类
字符流: 字符流:字符输入流:Reader基类
字节输出流:Writer基类

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

BIO、NIO、AIO 有什么区别?

BIO:线程发起IO请求,不管内核是否准备好IO操作,从发起请求起,线程一直阻塞,直到操作完成。
NIO:线程发起IO请求,立即返回;内核在做好IO操作的准备之后,通过调用注册的回调函数通知线程做IO操作,线程开始阻塞,直到操作完成。
AIO:线程发起IO请求,立即返回;内存做好IO操作的准备之后,做IO操作,直到操作完成或者失败,通过调用注册的回调函数通知线程做IO操作完成或者失败。

BIO是一个连接一个线程。
NIO是一个请求一个线程。
AIO是一个有效请求一个线程。

BIO:同步并阻塞,服务器实现模式为一个连接一个线程,即客户端有连接请求时服务器端就需要启动一个线程进行处理,如果这个连接不做任何事情会造成不必要的线程开销,当然可以通过线程池机制改善。
NIO:同步非阻塞,服务器实现模式为一个请求一个线程,即客户端发送的连接请求都会注册到多路复用器上,多路复用器轮询到连接有I/O请求时才启动一个线程进行处理。
AIO:异步非阻塞,服务器实现模式为一个有效请求一个线程,客户端的I/O请求都是由OS先完成了再通知服务器应用去启动线程进行处理。

AQS

AQS的核心思想是,如果被请求的共享资源空闲,则将当前请求资源的线程设置为有效的工作线程,并将共享资源设置为锁定状态,如果被请求的共享资源被占用,那么就需要一套线程阻塞等待以及被唤醒时锁分配的机制,这个机制AQS是用CLH队列锁实现的,即将暂时获取不到锁的线程加入到队列中。
CLH(Craig,Landin,and Hagersten)队列是一个虚拟的双向队列,虚拟的双向队列即不存在队列实例,仅存在节点之间的关联关系。
AQS是将每一条请求共享资源的线程封装成一个CLH锁队列的一个结点(Node),来实现锁的分配。

用大白话来说,AQS就是基于CLH队列,用volatile修饰共享变量state,线程通过CAS去改变状态符,成功则获取锁成功,失败则进入等待队列,等待被唤醒。

**注意:AQS是自旋锁:**在等待唤醒的时候,经常会使用自旋(while(!cas()))的方式,不停地尝试获取锁,直到被其他线程获取成功

Synchronized

https://blog.youkuaiyun.com/Virgil_K2017/article/details/99736755

同步代码块是通过monitorenter和monitorexit来实现,当线程执行到monitorenter的时候要先获得monitor锁,才能执行后面的方法。当线程执行到monitorexit的时候则要释放锁。
同步方法是通过中设置ACC_SYNCHRONIZED标志来实现,当线程执行有ACC_SYNCHRONI标志的方法,需要获得monitor锁。
每个对象维护一个加锁计数器,为0表示可以被其他线程获得锁,不为0时,只有当前锁的线程才能再次获得锁。
同步方法和同步代码块底层都是通过monitor来实现同步的。
每个对象都与一个monitor相关联,线程可以占有或者释放monitor。
————————————————Monitor

Mark Word 有一个字段指向 monitor 对象。monitor 中记录了锁的持有线程,等待的线程队列等信息。前面说的每个对象都有一个锁和一个等待队列,就是在这里实现的。 monitor 对象由 C++ 实现。其中有三个关键字段:

_owner 记录当前持有锁的线程

_EntryList 是一个队列,记录所有阻塞等待锁的线程

_WaitSet 也是一个队列,记录调用 wait() 方法并还未被通知的线程。

Monitor的操作机制如下:

多个线程竞争锁时,会先进入 EntryList 队列。竞争成功的线程被标记为 Owner。其他线程继续在此队列中阻塞等待。

如果 Owner 线程调用 wait() 方法,则其释放对象锁并进入 WaitSet 中等待被唤醒。Owner 被置空,EntryList 中的线程再次竞争锁。

如果 Owner 线程执行完了,便会释放锁,Owner 被置空,EntryList 中的线程再次竞争锁。

synchronized 是重量级锁,由于消耗太大,虚拟机对其做了一些优化。

自旋锁与自适应自旋

锁消除

虚拟机在运行时,如果发现一段被锁住的代码中不可能存在共享数据,就会将这个锁清除。

锁粗化

当虚拟机检测到有一串零碎的操作都对同一个对象加锁时,会把锁扩展到整个操作序列外部。如 StringBuffer 的 append 操作。

轻量级锁

对绝大部分的锁来说,在整个同步周期内都不存在竞争。如果没有竞争,轻量级锁可以使用 CAS 操作避免使用互斥量的开销。

偏向锁

偏向锁的核心思想是,如果一个线程获得了锁,那么锁就进入偏向模式,当这个线程再次请求锁时,无需再做任何同步操作,即可获取锁。

CAS

ConcurrentHashMap

jdk1.7中采用Segment + HashEntry的方式进行实现,分段锁的设计 继承ReentrantLock

把HashMap分割成若干个Segment,在put的时候需要锁住Segment,get时候不加锁,使用volatile来保证可见性。

1.8中放弃了Segment分段锁的设计臃肿的设计,取而代之的是采用Node + CAS + Synchronized来保证并发安全进行实现

局部变量

每个线程都有自己独立的调用栈,局部变量保存在各自的调用栈中,不会被共享,自然也就没有并发问题。

如果是一个对象就不安全(对象引用是局部变量, 在栈内存, 但是对象本身还是处于堆内存)

String 属于基础的数据类型吗?

String 不属于基础类型,基础类型有 8 种:byte8、short16、int32、long64、char16、float32、double64,boolean字节 1 2 4 8 2 4 8而 String 属于对象。

java 中操作字符串都有哪些类?它们之间有什么区别?

String 和 StringBuffer、StringBuilder 的区别在于 String 声明的是不可变的对象
进行操作,所以在经常改变字符串内容的情况下最好不要使用 String。
StringBuffer 和 StringBuilder 最大的区别在于,StringBuffer 是线程安全的,而 StringBuilder 是非线程安全

String 类的常用方法都有那些?

indexOf():返回指定字符的索引。
charAt():返回指定索引处的字
replace():字符串替换。
trim():去除字符串两端空白。
split():分割字符串,返回一个分割后的字符串数组。
StringBuffer 添加元素append

HashMap 和 Hashtable 有什么区别?

hashMap去掉了HashTable 的contains方法,但是加上了containsValue()和containsKey()方法。
hashTable同步的,而HashMap是非同步的,效率上逼hashTable要高。
hashMap允许空键值,而hashTable不允许。

Spring AOP中的动态代理主要有两种方式,JDK动态代理和CGLIB动态代理:

1、JDK动态代理只提供接口的代理,不支持类的代理。核心InvocationHandler接口和Proxy类,InvocationHandler 通过invoke()方法反射来调用目标类中的代码,;接着,Proxy利用 InvocationHandler动态创建一个符合某一接口的的实例, 生成目标类的代理对象。
2、如果代理类没有实现 InvocationHandler 接口,那么Spring AOP会选择使用CGLIB来动态代理目标类。CGLIB(Code Generation Library),是一个代码生成的类库,可以在运行时动态的生成指定类的一个子类对象,并覆盖其中特定方法并添加增强代码,从而实现AOP。CGLIB是通过继承的方式做的动态代理,因此如果某个类被标记为final,那么它是无法使用CGLIB做动态代理的。

Spring的IoC理解:

(1)IOC就是控制反转,是指创建对象的控制权的转移,以前创建对象的主动权和时机是由自己把控的,而现在这种权力转移到Spring容器中,并由容器根据配置文件去创建实例和管理各个实例之间的依赖关系,对象与对象之间松散耦合,也利于功能的复用。DI依赖注入,是它的实现方,可以通过IoC容器来动态注入对象需要的外部资源。
(2)IOC让对象的创建不用去new了,可以由spring自动生产,使用java的反射机制,根据配置文件在运行时动态的去创建对象以及管理对象,并调用对象的方法的。
(3)Spring的IOC有三种注入方式 :构造器注入、setter方法注入、根据注解注入。
静态变量:线程非安全。
静态变量即类变量,位于方法区,为所有对象共享,共享一份内存,一旦静态变量被修改,其他对象均对修改可见,故线程非安全。

静态方法:安全

static 方法线程安全吗
静态方法如果没有使用静态变量,则没有线程安全问题。

为什么呢?因为静态方法内声明的变量,每个线程调用时,都会新创建一份,而不会共用一个存储单元。
注意,静态变量,由于是在类加载时占用一个存储区,每个线程都是共用这个存储区的,所以如果在静态方法里使用了静态变量,这就会有线程安全问题!

String类能被继承吗,为什么

不可以,因为String类有final修饰符,而final修饰的类是不能被继承的,实现细节不允许改变

自己写的String类可以加载吗?

一般情况不可以,但是可以通过自定义类加载器加载!

String 类型和Int类型比较效率谁快?

Int 更快!String 类型底层是 char[]数组 比较的是ASCII码值。

局部变量:线程安全。

局部变量是定义在方法内,作用域也是在方法内部。当方法运行结束后,局部变量也就失效了。
每个线程执行时将会把局部变量放在各自栈帧的工作内存中,线程间不共享,故不存在线程安全问题。

Connection不是线程安全的,它在多线程环境中使用时,会导致数据操作的错乱,特别是有事务的情况.connection.commit()方法就是提交事务,你可以想象,在多线程环境中,线程A开启了事务,然后线程B却意外的commit,这该是个多么纠结的情况.

spring 创建对象的方式

默认无参:contex.getbean
有参情况:
1、下标赋值 index=0 下标为o的第一个参数 然后 value =xxx 赋值
2、通过类型:type=xxx value
3、直接通过参数名赋值:name=“name” value=“xxx”

Bean三种自动装配方式
1、在xml中显示的配置
2、在java中显示配置
3、隐式的 自动装配bean

springMVC的流程

在这里插入图片描述

jdbc 连接数据库几大步骤

1、加载JDBC驱动程序:
2、创建数据库的连接
3、创建一个preparedStatement 执行SQL语句
4、执行SQL语句
5、遍历结果集
6、处理异常,关闭JDBC对象资源

数据库

ACID 隔离级别 三大范式
事务:ACID 原子 一致 隔离 持久
更新丢失 脏读(已修改为提交) 不可重复读 幻读
级别: 未提交读 已提交读 可重复读、可序列化
三大范式:第一:每列原子性 第二每列和主键相关 第三直接相关

JUC常用工具类

JVM

创建对象的过程?
创建对象的过程?

设计模式应用场景

Mybatis

Mysql SQL语句复用
使用sql标签就可以重用sql标签里面的SQL语句,
只要调用标签就可以了,refid属性值填标签的id属性
Mybatis 设计模式
2、工厂模式,例如SqlSessionFactory、ObjectFactory、MapperProxyFactory;
3、单例模式,例如ErrorContext和LogFactory;
4、代理模式,Mybatis实现的核心,比如MapperProxy、ConnectionLogger,用的jdk的动态代理;还有executor.loader包使用了cglib或者javassist达到延迟加载的效果;
Mybatis 能执行一对一、一对多的关联查询吗
多对一查询,其实就是一对一查询,只需要把 selectOne()修改selectList()即可;多对多查询,其实就是一对多查询,只需要把 selectOne()修改为selectList()即可。
Mybatis 是如何将 sql 执行结果封装为目标对象并返回的?都有哪些映射形式?
答:
第一种是使用标签,逐一定义列名和对象属性名之间的映射关系。
第二种是使用sql列的别名功能,将列的别名书写为对象属性名。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值