总结个人的面试经历以及一些网上的的面试题,以供以后面试与巩固java基础。
1.String、StringBuilder和StringBuffer的区别
String用于存储不可变字符串的类,StringBuilder和StringBuffer是用于存储可变字符串变量的类;
执行速度:String<StringBuffer<StringBuilder;
StringBuilder是线程不安全的,StringBuffer是线程安全的。
2.什么是反射
反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意一个方法和属性;这种动态获取的信息以及动态调用对象的方法的功能称为java语言的反射机制。
Java中的反射首先是能够获取到Java中要反射类的字节码,获取字节码有三种方法,1.Class.forName(className) 2.类名.class 3.this.getClass()。然后将字节码中的方法,变量,构造函数等映射成相应的Method、Filed、Constructor等类,这些类提供了丰富的方法可以被我们所使用。
3.final、finally、finalize分别是什么
finnal:用于声明属性、方法和类的,表示属性不可变,方法不可重写,类不可继承。
finally:异常处理语句结构中的一部分,表示必须执行。
finalize:是Object的一个方法,在垃圾回收的时候调用被回收对象的该方法。
4.接口和抽象类的区别
- 接口中不能有静态方法,抽象类中可以。
- 接口中的方法必须全部都是抽象的,抽象类中可以有非抽象方法。
- 抽象类可以有构造方法,接口不可。
- 抽象类可以有普通成员变量,接口不可以。
5.java类的访问权限
| 同一个类 | 同一个包 | 不同包的子类 | 不同包的非子类 |
Private | √ | |||
Default | √ | √ | ||
Protected | √ | √ | √ | |
Public | √ | √ | √ | √ |
6.类的加载过程
类从加载到虚拟机到卸载,它的整个生命周期包括:加载(Loading),验证(Validation),准备(Preparation),解析(Resolution),初始化(Initialization),使用(Using)和卸载(Unloading) 1、加载
加载阶段主要完成三件事,即通过一个类的全限定名来获取定义此类的二进制字节流,将这个字节流所代表的静态存储结构转化为方法区的运行时数据结构,在Java堆中生成一个代表此类的Class对象,作为访问方法区这些数据的入口。这个加载过程主要就是靠类加载器实现的,这个过程可以由用户自定义类的加载过程。
2、验证 这个阶段目的在于确保Class文件的字节流中包含信息符合当前虚拟机要求,不会危害虚拟机自身安全。主要包括四种验证:文件格式验证:基于字节流验证,验证字节流是否符合Class文件格式的规范,并且能被当前虚拟机处理元数据验证:基于方法区的存储结构验证,对字节码描述信息进行语义验证。 字节码验证:基于方法区的存储结构验证,进行数据流和控制流的验证。 符号引用验证:基于方法区的存储结构验证,发生在解析中,是否可以将符号引用成功解析为直接引用。
3、准备 仅仅为类变量(即static修饰的字段变量)分配内存并且设置该类变量的初始值即零值,这里不包含用final修饰的static,因为final在编译的时候就会分配了,同时这里也不会为实例变量分配初始化。类变量会分配在方法区中,而实例变量是会随着对象一起分配到Java堆中。
4、解析
解析主要就是将常量池中的符号引用替换为直接引用的过程。符号引用就是一组符号来描述目标,可以是任何字面量,而直接引用就是直接指向目标的指针、相对偏移量或一个间接定位到目标的句柄。有类或接口的解析,字段解析,类方法解析,接口方法解析。这里要注意如果有一个同名字段同时出现在一个类的接口和父类中,那么编译器一般都会拒绝编译。
5、初始化
初始化阶段依旧是初始化类变量和其他资源,这里将执行用户的static字段和静态语句块的赋值操作。这个过程就是执行类构造器方法的过程。
7.各种创建单例模式的优缺点
1.饿汉式:单例实例在类装载时就构建,急切初始化。(预先加载法)
/** * 饿汉式(推荐) * */ public class Singleton1 { private Singleton1() { } public static Singleton1 instance = new Singleton1(); public Singleton1 getInstance() { return instance; } }
优点 | 1.线程安全 2.在类加载的同时已经创建好一个静态对象,调用时反应速度快 |
缺点 | 资源效率不高,可能getInstance()永远不会执行到,但执行该类的其他静态方法或者加载了该类(class.forName),那么这个实例仍然初始化 |
2.懒汉式:单例实例在第一次被使用时构建,延迟初始化。
class Singleton2 { private Singleton2() { } public static Singleton2 instance = null; public static Singleton2 getInstance() { if (instance == null) {
//多个线程判断instance都为null时,在执行new操作时多线程会出现重复情况
instance = new Singleton2();
}
return instance;
}
}
懒汉式在单个线程中没有问题,但在多线程就可能会出现两个或多个Singleton2实例情况,
虽然后面实例化的Singleton2会覆盖前面实例化的Singleton2,但最好避免这样的情况。
改进方式就是加锁synchornized
class Singleton3 { private Singleton3() { } public static Singleton3 instance = null; public static synchronized Singleton3 getInstance() { if (instance == null) { instance = new Singleton3(); } return instance; } }
优点 | 资源利用率高,不执行getInstance()就不会被实例,可以执行该类的其他静态方法 |
缺点 | 第一次加载时不够快,多线程使用不必要的同步开销大 |
3.双重检测
class Singleton4 { private Singleton4() { } public static Singleton4 instance = null; public static Singleton4 getInstance() { if (instance == null) { synchronized (Singleton4.class) { if (instance == null) { instance = new Singleton4(); } } } return instance; } }
优点 | 资源利用率高,不执行getInstance()就不被实例,可以执行该类其他静态方法 |
缺点 | 第一次加载时反应不快,由于java内存模型一些原因偶尔失败 |
4.静态内部类
class Singleton5 { private Singleton5() { } private static class SingletonHelp { static Singleton5 instance = new Singleton5(); } public static Singleton5 getInstance() { return SingletonHelp.instance; } }
优点 | 资源利用率高,不执行getInstance()不被实例,可以执行该类其他静态方法 |
缺点 | 第一次加载时反应不够快 |
8.什么是JVM
JVM是一个虚构出来的计算机,是通过在实际的计算机上仿真模拟各种计算机功能来实现的。Java虚拟机在执行字节码时,把字节码解释成具体平台上的机器指令执行。使得Java语言可以是跨平台运行。
9.垃圾回收机制
GC (Garbage Collection)的基本原理:将内存中不再被使用的对象进行回收,GC中用于回收的方法称为收集器,由于GC需要消耗一些资源和时间,Java在对对象的生命周期特征进行分析后,按照新生代、旧生代的方式来对对象进行收集,以尽可能的缩短GC对应用造成的暂停
(1)对新生代的对象的收集称为minor GC;
(2)对旧生代的对象的收集称为Full GC;
(3)程序中主动调用System.gc()强制执行的GC为Full GC。
不同的对象引用类型, GC会采用不同的方法进行回收,JVM对象的引用分为了四种类型:
(1)强引用:默认情况下,对象采用的均为强引用(这个对象的实例没有其他对象引用,GC时才会被回收)
(2)软引用:软引用是Java中提供的一种比较适合于缓存场景的应用(只有在内存不够用的情况下才会被GC)
(3)弱引用:在GC时一定会被GC回收
(4)虚引用:由于虚引用只是用来得知对象是否被GC
10.JVM内存模型
Java虚拟机(Java Virtual Machine=JVM)的内存空间分为五个部分,分别是:
1. 程序计数器
2. Java虚拟机栈
3. 本地方法栈
4. 堆
5. 方法区。
11.Java 中应该使用什么数据类型来代表价格?
如果不是特别关心内存和性能的话,使用BigDecimal,否则使用预定义精度的 double 类型。
12.Java 中 ++ 操作符是线程安全的吗?
不是线程安全的操作。它涉及到多个指令,如读取变量值,增加,然后存储回内存,这个过程可能会出现多个线程交差。
13.Java 中堆和栈有什么区别?
JVM 中堆和栈属于不同的内存区域,使用目的也不同。栈常用于保存方法帧和局部变量,而对象总是在堆上分配。栈通常都比堆小,也不会在多个线程之间共享,而堆被整个 JVM 的所有线程共享。
14.java与C的区别
C语言是面向过程的语言,执行效率高;Java是面向对象的语言,执行效率比C语言低。
C语言最关键的是比Java多了指针,这也说明了Java的健壮性,还有Java的多线程机制使程序可以并行运行,Java程序多用于网络。
C语言的安全性不如Java,C语言没有Java的垃圾回收机制,申请的空间要手动释放。
Java的通用性好,可以跨平台直接移植,只要有安装Java虚拟机(JVM)就可以了。
后续补充