Java
TreeMap 和 TreeSet 在排序时如何比较元素?Collections 工具类中的 sort()方法如何比较元素?
TreeSet 要求存放的对象所属的类必须实现 Comparable 接口,该接口提供了比较元素的 compareTo()方法,当插入元素时会回调该方法比较元素的大小。
TreeMap 要求存放的键值对映射的键必须实现 Comparable 接口从而根据键对元素进行排序。
Collections 工具类的 sort 方法有两种重载的形式:
第一种要求传入的待排序容器中存放的对象实现 Comparable 接口以实现元素的比较;
第二种不强制性的要求容器中的元素必须可比较,但是要求传入第二个参数,参数是Comparator 接口的子类型(需要重写 compare 方法实现元素的比较),相当于一个临时定义的排序规则,其实就是通过接口注入比较元素大小的算法,也是对回调模式的应用。
List、Map、Set 三个接口存取元素时,各有什么特点?
List 以特定索引来存取元素,可以有重复元素。
Set 不能存放重复元素(用对象的equals()方法来区分元素是否重复)。
Map 保存键值对,映射关系可以是一对一或多对一。
Collection 和 Collections 的区别?
Collection 是一个接口,它是 Set、List 等容器的父接口;
Collections 是个一个工具类,这些方法包括对容器的搜索、排序、线程安全化等等。
解释内存中的栈、堆和方法区的用法。
栈中存放的是局部变量、方法参数、方法帧。线程有私有的栈不对外共享。执行方法时,作为方法帧入栈,当执行完后出栈。
堆中主要用来存放的是对象。为所有的线程所共享。
方法区中存放的都是一些静态的数据,比如static变量、class等。为共享区域。方法区中都是存放的永远唯一的元素。
ArrayList、Vector、LinkedList 的存储性能和特性
ArrayList 和 Vector 都是数组方式存储数据
数组元素数大于实际存储的数据以便增加元素
按序号索引元素,插入元素涉及数组元素移动
Vector 中的方法由于添加了 synchronized 修饰。
LinkedList 使用双向链表实现存储
按序号索引数据需要进行前向或后向遍历,但是插入数据时只需要记录本项的前后项
ArrayList 和LinkedList 可以通过Collections 中的 synchronizedList 方法将其转换成线程安全的容器后再使用。
列出一些你常见的运行时异常?
ArithmeticException(算术异常)
ClassCastException (类转换异常)
IllegalArgumentException (非法参数异常)
IndexOutOfBoundsException (下标越界异常)
NullPointerException (空指针异常)
SecurityException (安全异常)
final、finally、finalize 的区别。
final
(1) 修饰类:表示该类不能被继承;
(2) 修饰方法:表示方法不能被重写;
(3) 修饰变量:表示变量只能一次赋值以后值不能被修改(常量)。
finally
通常放在 try…catch…的后面
这就意味着程序无论正常执行还是发生异常,这里的代码只要 JVM 不关闭都能执行,
可以将释放外部资源的代码写在 finally 块中。
finalize
Object 类中定义的方法
垃圾收集器在销毁对象时调用的,通过重写 finalize()方法可以整理系统资源或者执行其他清理工作。
Java 中会存在内存泄漏吗,请简单描述
理论上 Java 因为有垃圾回收机制不会存在内存泄露问题;
而在实际开发中,可能会存在无用但可达的对象,这些对象不能被 GC 回收,因此也会导致内存泄露的发生。
例如Hibernate 的 Session(一级缓存)中的对象属于持久态,垃圾回收器是不会回收这些对象的,然而这些对象中可能存在无用的垃圾对象,如果不及时关闭(close)或清空(flush)一级缓存就可能导致内存泄露。
如何实现对象克隆?
1). 实现 Cloneable 接口并重写 Object 类中的 clone()方法;
2). 实现 Serializable 接口,通过对象的序列化和反序列化实现克隆,可以实现深度克隆,
GC 是什么?为什么要有 GC?
对内存堆中已经死亡的或者长时间没有使用的对象进行回收
防止内存泄露,有效的利用可使用的内存。
不能实时的调用垃圾回收器对某个对象进行垃圾回收。
垃圾回收机制有很多种:
分代复制垃圾回收
标记垃圾回收
增量垃圾回收等。
GC采用“分代式垃圾收集”。
将堆内存划分为不同的区域:
伊甸园(Eden):对象诞生的区域。
幸存者乐园(Survivor):在Eden幸存下来的对象。
终身颐养园(Tenured):保存老的幸存对象。年轻代收集(Minor-GC)过程是不会触及这个地方的。当年轻代收集不能把对象放进Tenured时,就会触发一次完全收集(Major-GC)
与垃圾回收相关的 JVM 参数:
-Xms / -Xmx — 堆的初始大小 / 堆的最大大小
-Xmn — 堆中年轻代的大小
-XX:-DisableExplicitGC — 让 System.gc()不产生任何作用
-XX:+PrintGCDetails — 打印 GC 的细节
-XX:+PrintGCDateStamps — 打印 GC 操作的时间戳
-XX:NewSize / XX:MaxNewSize — 设置新生代大小/新生代最大大小
-XX:NewRatio — 可以设置老生代和新生代的比例
-XX:PrintTenuringDistribution — 设置每次新生代 GC 后输出幸存者乐园中对象年龄的分布
-XX:InitialTenuringThreshold / -XX:MaxTenuringThreshold:设置老年代阀值的初始值和最大值
-XX:TargetSurvivorRatio:设置幸存区的目标使用率
静态变量和实例变量的区别
静态变量:
static 修饰
属于类,也称为类变量
不属于类的任何一个对象,一个类不管创建多少个对象,静态变量在内存中有且仅有一个拷贝;
静态变量可以实现让多个对象共享内存。
实例变量:
必须依存于某一实例,需要先创建对象然后通过对象才能访问到它。
事物的四个特点——ACID是靠什么保证的
原子性
由undolog日志进行保证,记录需要回滚的信息,事物回滚时撤销已经执行成功的sql
一致性
由其他三大特征保证
隔离性
是由MVCC多版本并发控制保证
持久性
由redolog保证,mysql修改数据时,会在redolog中记录一份日志数据,就算数据没有保存成功,只要日志保存成功,数据就不会消失
try{}里有一个 return 语句,那么紧跟在这个 try 后的finally{}里的代码会不会被执行,什么时候被执行,在 return前还是后?
会执行,在方法返回调用者前执行。
如果存在 finally 代码块,try中的 return 语句不会立马返回调用者,而是记录下返回值待 finally 代码块执行完毕之后再向调用者返回其值,然后如果在 finally 中修改了返回值,就会返回修改后的值。
JVM、JRE和JDK的关系
JVM
Java Virtual Machine是Java虚拟机,Java程序需要运行在虚拟机上,不同的平台有自己的虚拟机,因此Java语言可以实现跨平台。
JRE
Java Runtime Environment包括Java虚拟机和Java程序所需的核心类库等。核心类库主要是java.lang包:如基本数据类型、基本数学函数、字符串处理、线程、异常处理类等
JDK
其中包含了Java的开发工具,也包括了JRE。所以安装了JDK,就无需再单独安装JRE了。
面向对象三大特性?
其中Java 面向对象编程三大特性:封装 继承 多态
封装
封装把一个对象的属性私有化
提供一些可以被外界访问的属性的方法
继承
在父类的基础上建立子类
子类可以增加属性方法,也可以用父类的属性方法,但不能选择性地继承。
关于继承如下 3 点请记住:
1. 子类拥有父类非 private 的属性和方法。
2. 子类可以拥有自己属性和方法。
3. 子类可以重写父类的方法。
多态
父类的引用指向子类的具体实现,调用的实现方法,必须在由程序运行期间才能决定。
实现多态的两种形式:
继承(多个子类对同一方法的重写)和接口(实现接口并覆盖接口中同一方法)。
多态实现三个必要条件
继承、重写、向上转型。
继承:在多态中必须存在有继承关系的子类和父类。
重写:子类对父类中某些方法进行重新定义。
向上转型:将子类的引用赋给父类对象。
接口和抽象类的区别
抽象类和接口都不能够实例化,但可以定义抽象类和接口类型的引用。
一个类如果继承了某个抽象类或者实现了某个接口都需要对其中的抽象方法全部进行实现,否则该类仍然需要被声明为抽象类。
接口比抽象类更加抽象,抽象类中可以定义构造器,可以有抽象方法和具体方法,而接口中不能定义构造器而且其中的方法全部都是抽象方法。
抽象类中的成员可以是 private、默认、protected、public 的,而接口中的成员全都是 public 的。
抽象类中可以定义成员变量,而接口中定义的成员变量实际上都是常量。
有抽象方法的类必须被声明为抽象类,而抽象类未必要有抽象方法。
Overload和Override的区别。
如果在子类中定义某方法与其父类有相同的名称和参数,我们说该方法被重写 (Overriding)。
如果在一个类中定义了多个同名的方法,它们或有不同的参数个数或有不同的参数类型,则称为方法的重载(Overloading)。Overloaded的方法是可以改变返回值的类型
“==”与“equals()”的区别。
"=="判断的是两个对象的内存地址是否一样
equals 是 Object 类的方法,Object 对它的实现是比较内存地址,我们可以重写这个方法来自定义 “相等”这个概念。
线程池的原理,为什么要创建线程池?
在线程池中维护一组线程,这些线程可以重复利用,以减少线程的创建和销毁的开销。
线程池中的线程被维护在一个队列中,新来的任务会被插入到队列的尾部。当线程池中有空闲线程时,它会从队列的头部取出任务。
最大线程数限制了线程池中最多能有多少个线程同时工作
辅助线程要监控线程池的状态,及时调整线程池的大小。
Java 有没有 goto?
goto 是 Java 中的保留字,在目前版本的 Java 中没有使用。
&和&&的区别?
&运算符有两种用法:(1)按位与;(2)逻辑与。
&&运算符是短路与运算。
逻辑与跟短路与的差别是非常巨大的,虽然二者都要求运算符左右两端的布尔值都是true 整个表达式的值才是 true。
&&之所以称为短路运算是因为,如果&&左边的表达式的值是 false,右边的表达式会被直接短路掉,不会进行运算。
例如在验证用户登录时判定用户名不是 null 而且不是空字符串,应当写为:username != null &&!username.equals(“”),二者的顺序不能交换,更不能用&运算符,因为第一个条件如果不成立,根本不能进行字符串的 equals 比较,否则会产生空值异常。
switch 是否能作用在 byte 上,是否能作用在 long 上,是否能作用在 String 上?
在 Java 5 以前,switch(expr)中,expr 只能是 byte、short、char、int。从 Java5 开始,Java 中引入了枚举类型,expr 也可以是 enum 类型,从 Java 7 开始,expr 还可以是字符串(String),但是长整型(long)在目前所有的版本中都是不可以的
数组有没有 length()方法?String 有没有 length()方法?
数组没有 length()方法,有 length 的属性。String 有 length()方法。JavaScript中,获得字符串的长度是通过 length 属性得到的,这一点容易和 Java 混淆。
构造器(constructor)是否可被重写(override)
构造器不能被继承,因此不能被重写,但可以被重载。
两个对象值相同(x.equals(y) == true),但却可有不同的hash code,这句话对不对
两个值相同,哈希码一定相同,哈希码相同,两个值不一定相同
是否可以继承 String 类?
String 类是 final 类,不可以被继承。
String 和 StringBuilder、StringBuffer 的区别
其中 String 是只读字符串,内容不能被改变。
而 StringBuffer/StringBuilder 类表示的字符串对象可以直接进行修改。
StringBuilder没有被synchronized 修饰
接口是否可继承接口?抽象类是否可实现接口?抽象类是否可继承具体类?
接口可继承接口,支持多重继承。
抽象类可以实现接口,抽象类可继承具体类也可以继承抽象类。
是否可以继承其它类?是否可以实现接口?
可以继承其他类或实现其他接口
内部类可以引用它的包含类(外部类)的成员吗?有没有什么限制?
一个内部类对象可以访问创建它的外部类对象的成员,包括私有成员。