1. String,StringBuffer和StringBuilder的区别?
String:final修饰,String对象创建后不可修改;StringBuffer和StringBuilder对象是变量,可以进行修改。
如果String对象不断的创建赋值拼接,与后两者的append方法拼接相比,从运行速度上来说:String < StringBuffer < StringBuilder。
如果是直接复制,则String就免掉了中间过程的创建和销毁,则String的运行速度则大于后两者。
StringBuffer和StringBuilder的区别就是是否是线程安全的,StringBuffer是线程安全,而StringBuilder非线程安全。
适用场景:
- String:少量的字符串操作;
- StringBuffer:多线程下字符串缓冲区进行大量的字符串操作;
- StringBuilder:单线程下字符缓存区进行大量的字符串操作;
2.public, default, protected,private修饰的访问控制权区别?
3.封装,继承,多态的特征
- 封装性: 保护内部的定义结构的安全性。 private属性封装
- 继承性: 在已有的程序结构上继续扩充新的功能。
- 多态性: 指的是在某一概念范围内的满足。(继承,重新,父类指向子类,向上转型,父类无法调用子类特有数据)
4.抽象类和接口的区别
No |
区别 |
抽象类 | 接口 |
1 | 关键字 | abstract | interface |
2 | 组成 | 构造方法,普通方法,抽象方法,static 方法, 常量,变量 | 抽象方法,全局常量,默认方法,static方法 |
3 | 子类使用 | class子类extends抽象方法 | class子类implements接口 |
4 | 关系 | 抽象类可以实现接口 | 接口不可以继承抽象类,但是可以实现多个接口 |
5 | 权限 | 各种权限 | 只能用public权限 |
6 | 限制 | 单继承局限 | 没有局限 |
7 | 子类 | 抽象类和接口都必须有子类,子类必须覆写他们的抽象方法 | |
8 | 实例化对象 | 依靠子类的向上转型实现对象的额实例化 |
5.JVM原理,编译流程,类装载的过程
.java文件 -> 通过编译成.class字节码文件 -> .dex在通过各个平台的java虚拟机进行解释 -> 变成可执行的机器码进行执行
A.java -> javac A.java ->A.class -> java A ->执行;由于java虚拟机的存在,使得java的可移植性强
- 第一步:编译后的字节码文件格式主要分为两部分:常量池和方法字节码。常量池记录的是代码出现过的(常量、类名、成员变量等)以及符号引用(类引用、方法引用,成员变量引用等);方法字节码中放的是各个方法的字节码。
- 第二步(运行):java类运行的过程大概分为两个步骤:(1)类的加载 (2)类的执行。需要说明的一点的是:JVM主要在程序第一次运行时主动使用类的时候,才会立即去加载。换言之,JVM并不是在运行时就会把所有使用到的类都加载到内存中,而是用到,不得不加载的时候,才加载进来,而且只加载一次。
类的装载流程:
6.GC垃圾回收机制
相关概念:
- 引用计数:一个对象被引用计数器加一,取消引用计数器减一,引用计数器为0才能被回收。优点:简单。缺点:不能解决循环引用的问题,比如A引用B,B引用A,但是这两个对象没有被其他任何对象引用,属于垃圾对象,却不能回收;每次引用都会附件一个加减法,影响性能。
- 搜素算法GC Root Tracing:通过一系列的名为"GC Roots"的对象作为起始点,从这些节点开始向下搜索,搜索所走过的路径称为引用链(Reference Chain),当一个对象到GC Roots没有任何引用链相连,即从GC Roots到这个对象不可达,则证明此对象是不可用的。
- 标记清除法:分为两个阶段:标记阶段和清除阶段。标记阶段通过根节点标记所有可达对象,清除阶段清除所有不可达对象。缺点:因为清除不可达对象之后剩余的内存不连续,会产生大量内存碎片,不利于大对象的分配。
- 复制算法:将内存空间分成相同的两块,每次只是用其中的一块,垃圾回收时,将正在使用的内存中的存活对象复制到另外一块空间,然后清除正在使用的内存空间中的所有对象,这种回收算法适用于新生代垃圾回收。优点:垃圾回收对象比较多时需要复制的对象恨少,性能较好;不会存在内存碎片。缺点:将系统内存折半。
- 标记压缩算法:是一种老年代回收算法,在标记清除的基础上做了一些优化,首先从根节点开始标记所有不可达的对象,然后将所有可达的对象移动到内存的一端,最后清除所有不可达的对象。优点:不用将内存分为两块;不会产生内存碎片。
- 分代算法:新生代使用复制算法,老生带使用标记清除算法或者标记压缩算法。几乎所有的垃圾回收期都区分新生代和老生带。
- 分区算法:将整个堆空间分成很多个连续的不同的小空间,每个小空间独立使用,独立回收。为了更好的控制gc停顿时间,可以根据目标停顿时间合理地回收若干个小区间,而不是整个堆空间,从而减少gc停顿时间。
7.虚拟机栈,寄存器CPU,方法域,本地方法栈(java中的jni调用)(线程独有); 方法区(method),堆内存(heap),常量池(共享区)
Java内存管理:
共享区:方法区(方法区 常量池等) java堆
独占区:虚拟机栈 本地方法栈 CPU寄存器
独占内存主要是指线程独有的内存区,共享是全局共享,每个线程都可以访问的内存区。
8.异常处理机制try catch,finally的使用
- 当程序在运行过程中出现异常后,JVM自动根据异常的类型实例化一个与之匹配的异常类对象,(此处用户不用去关心new,由系统自动负责处理)
- 产生的异常对象之后会判断当前的语句上是否存在异常处理,如果没有进行异常处理,那么就由JVM进行默认的处理。处理的方式 :输出异常信息,然后程序自动结束。
- 产生异常对象后会判断当前语句是否存在异常处理,有try异常捕获操作,那么会由try语句来捕获产生的异常类实例化对象。而后与try语句后的catch进行比较,如果匹配,则用当前的catch 进行异常处理 ,如果不匹配,则向下继续进行匹配。
- 不管异常处理是否能够匹配,那么都要向后执行,如果此程序中存在有finally语句,那么先执行 finally中的代码,但是执行完毕后,需要根据之前的catch匹配来决定如何执行。如果之前成功的捕获异常,那么就继续执行finally之后的代码,如果没有捕获异常成功,那么就将次异常交给JVM处理,结束程序。
整个过程就好比方法重载一样。根据catch后面的参数进行匹配,类型不统一则不能处理,一样就可以处理(相当于接收方法参数)。Java所有对象都支持向上转型,而Exception是所有异常的父类,所以可以自动向上转型,那么处理异常就不用划分到底是什么样的异常了,直接用Exception进行处理就可以了。
9.匿名内部类的优点,适用于抽象和接口
interface Message{ public void print(); } public class TestDemo { public static void main(String[] args){ fun(new Message(){ //匿名内部类 @Override public void print() {//在里面覆写接口的抽象方法 System.out.println("hello word!"); } }); } public static void fun(Message msg){ msg.print(); } }
匿名内部类是在抽象类和接口的基础上发展的,匿名内部类的最大好处在于帮助减少类的定义。
10.包装类,类的装箱和拆箱,向下转型
基本类型的包装类:
byte(Byte), short(Short), int(Integer), long(Long), float(Float), double(Double), char(Character), boolean(Boolean)
但是以上给出的包装类又分为两种子类型:
- 对象型包装类(Object直接子类): Character, Boolean
- 数值型包装类(Number直接子类):Byte, Short, Integer, Double, Float, Long
Number是一个抽象类,里面一共定义了六个抽象方法(intValue, byteValue, shortValue, doubleValue,longValue, floatValue)
装箱与拆箱操作:
- 装箱操作:将基本数据类型变为包装类型的形式
- 每个包装类的构造方法都可以接收各自数据类型的基本形式。
- 拆箱操作:从包装类之中取出被包装的数据:
- 利用Number类中提供的一系列的:xxxValue()方法。
Object 流程eg:基本数据类型->自动装箱(成为对象)->向上转型为Object。
public class TestDemo { public static void main(String[] args){ Object obj = 10; //向上转型,自动装箱 int temp = (Integer) obj; //向下转型,自动拆箱 System.out.println(temp); } }