Java基础技术基础面试【笔记】

时间:2021-03-03 23:56:59

Java基础技术基础面试【笔记】

String、StringBuilder以及StringBuffer三者之间的区别?

三者的区别可以从可变性,线程安全性,性能这三个部分进行说明

可变性

从可变性来说,String不可变,StringBuilder与StringBuffer可变

因为在String类中,是使用只读字符数组保存字符串的,所以String是不可变的

而StringBuilder与StringBuffer,两者都继承自AbstractStringBuilder类,而在AbstractStringBuilder中,是使用字符数组保存字符串,所以,这两种都是可变的

线程安全性

从线程安全性来说,String和StringBuffer是线程安全的,StringBuilder是非线程安全的

String是因为其对象是不可变的,所以String是线程安全的,而StringBuffer的线程安全是因为其对方法加了同步锁或者对调用的方法加了同步锁,所以StringBuffer是线程安全的

而StringBuilder并没有对方法进行加同步锁,所以StringBuilder是非线程安全的

性能

从性能来说,String的性能较差,而StringBuffer以及StringBuilder的性能更高

因为每次对String类型进行改变的时候,都会生成一个新的String对象,然后将指针指向新的String对象才可以,这就会导致String的性能比较差

而StringBuffer和StringBuilder每次都是对对象本身进行操作,不需要生成新的对象并改变对象引用,需要注意的是,两者虽然都比String的性能高,但是在一般情况下,其实StringBuilder是比StringBuffer高出10%左右的性能

总的来说,如果要操作少量的数据,就可以用String,单线程操作字符串缓冲区下操作大量数据的话,就可以用StringBuilder,而像是多线程操作字符串缓冲区下操作大量数据,就可以用StringBuffer

int和Integer二者之间的区别?

int是Java内置的8种基本数据类型之一,而Integer是Java为int对应引入的对应的包装类型

Java为每个原始类型提供了包装类型:

Java基础技术基础面试【笔记】

eqauls方法和hashCode方法的关系?

Java对于eqauls方法和hashCode方法是这样规定的:

(1) 如果两个对象相同,那么它们的 hashCode 值一定要相同

(2) 如果两个对象的 hashCode 相同,它们并不一定相同

这个要求并不是强制性的,可以不按照这个来操作,但是违背了这些就会出现错误,在使用容器时,相同的对象可以出现在 Set/Map 集合中,同时增加新元素的效率会大大下降

在《Effective Java》中是这样介绍 equals方法的,equals需要满足:

自反性,x.equals (x) 必须返回 true

对称性,x.equals (y) 返回 true 时,y.equals (x) 也必须返回 true

传递性,x.equals (y) 和 y.equals (z) 都返回 true 时,x.equals (z) 也必须返回 true

一致性,当 x 和 y 引用的对象信息没有被修改时,多次调用 x.equals (y) 应该得到同样的返回值,而且对于任何非 null 值的引用 x,x.equals (null) 必须返回 false

Serializable类中包含一个不可序列化的成员的时候会发生什么?解决方法?

任何序列化该类的尝试都会因NotSerializableException而失败,但这可以通过在 Java 中给属性设置瞬态变量来轻松解决

Java中跳出多重循环的方式?

Java中跳出多重循环有三种方式:

break + 标签

在最外层循环前加一个标签如 label,然后在最里层的循环使用用 break label

public static void main(String[] args) {
label: //标记
for (int i = 0 ; i < 10; i++) {
for (int j = 0; j < 10; j++) {
System.out.println("i = " + i + ", j = " + j);
if(j == 5) { //满中一定条件跳到某个标记
break label;
}
}
}
}

通过捕获异常

public static void main(String[] args) {
try {
for (int i = 0; i < 10; i++) {
for (int j = 0; j < 10; j++) {
System.out.println("i = " + i + ", j = " + j);
if (j == 5) {// 满足一定条件抛异常
throw new RuntimeException("test exception for j = 5");
}
}
}
} catch (RuntimeException e) { //循环外层捕获异常
e.printStackTrace();
}
}

通过标置变量

   public static void main(String[] args) {
boolean flag = false; //初始化标置变量
for (int i = 0; i < 10; i++) {
for (int j = 0; j < 10; j++) {
System.out.println("i = " + i + ", j = " + j);
if (j == 5) { //满足一定条件进行设置标置变量
flag = true;
}
if (flag) { //内层循环判断标置变量
break;
} }
if (flag) {//外层循环判断标置变量
break;
}
}
}

抽象类和接口有什么异同?

相同点:

(1)抽象类和接口都不能直接实例化,抽象类想要实例化的话,抽象类变量必须实现所有抽象方法,而接口想要实例化的话,接口变量必须实现所有接口未实现的方法

(2)二者都可以不需要实现类或者继承者去实现所有方法

(3)抽象类和接口都可以有实现方法

不同点:

(1)抽象类和接口所反映出的设计理念不同,抽象类表示的是对象 / 类的抽象,而接口表示的是对行为的抽象

(2)抽象类不可以多重继承,接口可以多重继承,即一个类只能继承一个抽象类,却可以继承多个接口

(3)抽象类可以有构造器,接口没有构造器

(4)访问修饰符,抽象类中的抽象方法可以用public protected和default abstract修饰符,不能用private、static、synchronize、native修饰,变量可以在子类中重新定义,也可以重新赋值,接口的方法默认修饰符是public abstract,变量默认是public static final型,且必须给其初值,在实现类中也不能重新定义,也不能改变其值

Java中创建对象的方式?

java创建对象的方式有五种:

(1)使用new关键字

(2)反射,使用java.lang.Class类的newInstance方法,这种方式会调用无参的构造函数来创建对象,有两种实现方式,一种是使用全路径包名,另一种是使用class类

(3)反射,使用java.lang.reflect.Constructor类的newInstance方法

(4)使用 clone 方法

(5)使用反序列化

各个创建对象方式的构造器的使用情况

Java基础技术基础面试【笔记】

浅拷贝和深拷贝?

浅拷贝:

被复制对象的所有变量都含有与原来的对象相同的值,对拷贝后对象的引用仍然指向原来的对象

深拷贝:

不仅要复制对象的所有非引用成员变量值,还要为引用类型的成员变量创建新的实例,并且初始化为形式参数实例值

&和&&的区别?

&运算符有两种用法:按位与和逻辑与

&&运算符是短路与运算,逻辑与跟短路与的差别是非常巨大的,虽然二者都要求只有在运算符左右两端的布尔值都是true时,整个表达式的值才是true

&&之所以称为短路运算是因为,如果&&左边的表达式的值是false,右边的表达式会被直接短路掉,不会进行运算

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

语法定义

静态变量前要加static关键字,而实例变量前则不加

程序运行

实例变量属于某个对象的属性,必须创建了实例对象,其中的实例变量才会被分配空间,才能使用这个实例变量

静态变量不属于某个实例对象,而是属于类,所以也称为类变量,只要程序加载了类的字节码,不用创建任何实例对象,静态变量就会被分配空间,静态变量就可以被使用了

如何实现多态?

实现多态主要有以下三种方式:

1.接口实现

2.继承父类重写方法

3.同一类中进行方法重载

面向对象有哪些特征?

抽象:

抽象就是忽略一个主题中与当前目标无关的那些方面,以便更充分地注意与当前目标有关的方面,简单来说就是,抽象是优先选择目前的,将无关的忽略掉

抽象包括两个方面,一是过程抽象,二是数据抽象

继承:

继承是一种联结类的层次模型,并且允许和鼓励类的重用,它提供了一种明确表述共性的方法

我们说,对象的一个新类从现有的类中派生,那么这个过程就被称为类继承,而新类继承了原始类的特性,新类就可以称为原始类的派生类(子类),而原始类就可以称为新类的基类(父类),而这个时候,派生类就可以从它的基类那里继承方法和实例变量,且类可以修改或增加新的方法使其更适合特殊的需要

封装:

面向对象计算始于这个基本概念,封装是把过程和数据包围起来,对数据的访问只能通过已定义的界面,即现实世界可以被描绘成一系列完全自治、封装的对象,这些对象通过一个受保护的接口访问其他对象

多态性:

多态性是指允许不同类的对象对同一消息作出响应,多态性包括参数化多态性和包含多态性,多态性语言具有灵活、抽象、行为共享、代码共享的优势,很好的解决了应用程序函数同名问题

Java中的final关键字的用法?

主要用三种用法

(1)修饰类:表示该类不能被继承

(2)修饰方法:表示方法不能被重写

(3)修饰变量:表示变量只能一次赋值以后值不能被修改(常量)

Java反射是指什么?它的使用场景及其优缺点分别什么?

反射

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

使用场景

主要用于根据运行时信息来发现该类、对象、方法、属性的场景

优点

通过在运行期访问装载到JVM中的类信息,来动态获取类的属性方法等信息,从而根据业务参数动态执行方法、访问属性,提高了java语言的灵活性和扩展性,还可以提高代码复用率

缺点

反射的性能较差,通常慢于直接执行java代码,而且程序的可维护性相对较差

动态代理是指什么?它有哪几种实现方法?

动态代理

动态代理是指在程序运行时生成代理类

实现方式

有两种实现方式:JDK动态代理和字节码实现

JDK动态代理,被代理对象必须实现接口,利用反射机制生成一个实现代理接口的匿名类,在调用具体方法前调用InvokeHandler来处理

字节码实现,需要用ASM开源包,将代理对象类的class文件加载进来,通过修改其字节码生成子类来处理

包括静态代理在内的三种代理方式的异同?

Java基础技术基础面试【笔记】

JVM、JRE、JDK及JIT之间有什么不同?

java虚拟机 (JVM)

是实现java语言平*立性的基础,可以理解伪代码字节码,提供对多个平台的良好支持,在用户和操作系统之间建立了一层枢纽

java运行时环境 (JRE)

是JVM的一个超集,JVM对于一个平台或者操作系统是明确的,而JRE确实一个一般的概念,其代表了完整的运行时环境,事实上,运行时JRE变成了JVM

所以对于一般情况时候使用JRE,对于明确的操作系统来说使用JVM,下载了JRE的时候,也就自动下载了JVM

java开发工具箱 (JDK)

java开发工具箱指的是编写一个java应用所需要的所有jar文件和可执行文件

即时编译器 (JIT)

即时编译器是种特殊的编译器,它通过有效的把字节码变成机器码来提高JVM的效率

JIT这种功效很特殊,因为其将检测到的相似的字节码编译成单一运行的机器码,从而节省了CPU的使用,这和其他的字节码编译器不同,因为他是运行时编译而不是在程序运行之前