Java面试宝典(2019版)

Java面试宝典(2019版)
面向对象的三个特征
封装,继承,多态.这个应该是人人皆知.有时候也会加上抽象.

多态的好处
允许不同类对象对同一消息做出响应,即同一消息可以根据发送对象的不同而采用多种不同的行为方式(发送消息就是函数调用).主要有以下优点:
可替换性:多态对已存在代码具有可替换性.
可扩充性:增加新的子类不影响已经存在的类结构.
接口性:多态是超累通过方法签名,想子类提供一个公共接口,由子类来完善或者重写它来实现的.
灵活性:
简化性:
代码中如何实现多态
实现多态主要有以下三种方式: 1. 接口实现 2. 继承父类重写方法 3. 同一类中进行方法重载
虚拟机是如何实现多态的
动态绑定技术(dynamic binding),执行期间判断所引用对象的实际类型,根据实际类型调用对应的方法.

接口的意义
接口的意义用三个词就可以概括:规范,扩展,回调.

抽象类的意义
抽象类的意义可以用三句话来概括:
为其他子类提供一个公共的类型
封装子类中重复定义的内容
定义抽象方法,子类虽然有不同的实现,但是定义时一致的 ## 接口和抽象类的区别

比较 抽象类 接口
默认方法 抽象类可以有默认的方法实现 ,java 8之前,接口中不存在方法的实现.
实现方式 子类使用extends关键字来继承抽象类.如果子类不是抽象类,子类需要提供抽象类中所声明方法的实现. 子类使用implements来实现接口,需要提供接口中所有声明的实现.
构造器 抽象类中可以有构造器, 接口中不能
和正常类区别 抽象类不能被实例化 接口则是完全不同的类型
访问修饰符 抽象方法可以有public,protected和default等修饰 接口默认是public,不能使用其他修饰符
多继承 一个子类只能存在一个父类 一个子类可以存在多个接口
添加新方法 想抽象类中添加新方法,可以提供默认的实现,因此可以不修改子类现有的代码 如果往接口中添加新方法,则子类中需要实现该方法.
父类的静态方法能否被子类重写
不能.子类继承父类后,有相同的静态方法和非静态,这是非静态方法覆盖父类中的方法(即方法重写),父类的该静态方法被隐藏(如果对象是父类则调用该隐藏的方法),另外子类可集成父类的静态与非静态方法,至于方法重载我觉得它其中一要素就是在同一类中,不能说父类中的什么方法与子类里的什么方法是方法重载的体现.

什么是不可变对象
不可变对象指对象一旦被创建,状态就不能再改变。任何修改都会创建一个新的对象,如 String、Integer及其它包装类。

能否创建一个包含可变对象的不可变对象?
当然可以创建一个包含可变对象的不可变对象的,你只需要谨慎一点,不要共享可变对象的引用就可以了,如果需要变化时,就返回原对象的一个拷贝。最常见的例子就是对象中包含一个日期对象的引用.

java 创建对象的几种方式
采用new
通过反射
采用clone
通过序列化机制
前2者都需要显式地调用构造方法. 造成耦合性最高的恰好是第一种,因此你发现无论什么框架,只要涉及到解耦必先减少new的使用.

java当中的四种引用
强引用,软引用,弱引用,虚引用.不同的引用类型主要体现在GC上:
强引用:如果一个对象具有强引用,它就不会被垃圾回收器回收。即使当前内存空间不足,JVM也不会回收它,而是抛出 OutOfMemoryError 错误,使程序异常终止。如果想中断强引用和某个对象之间的关联,可以显式地将引用赋值为null,这样一来的话,JVM在合适的时间就会回收该对象
软引用:在使用软引用时,如果内存的空间足够,软引用就能继续被使用,而不会被垃圾回收器回收,只有在内存不足时,软引用才会被垃圾回收器回收。
弱引用:具有弱引用的对象拥有的生命周期更短暂。因为当 JVM 进行垃圾回收,一旦发现弱引用对象,无论当前内存空间是否充足,都会将弱引用回收。不过由于垃圾回收器是一个优先级较低的线程,所以并不一定能迅速发现弱引用对象
虚引用:顾名思义,就是形同虚设,如果一个对象仅持有虚引用,那么它相当于没有引用,在任何时候都可能被垃圾回收器回收。

WeakReference与SoftReference的区别?
这点在四种引用类型中已经做了解释,这里简单说明一下即可: 虽然 WeakReference 与 SoftReference 都有利于提高 GC 和 内存的效率,但是 WeakReference ,一旦失去最后一个强引用,就会被 GC 回收,而软引用虽然不能阻止被回收,但是可以延迟到 JVM 内存不足的时候。

为什么要有不同的引用类型
不像C语言,我们可以控制内存的申请和释放,在Java中有时候我们需要适当的控制对象被回收的时机,因此就诞生了不同的引用类型,可以说不同的引用类型实则是对GC回收时机不可控的妥协.有以下几个使用场景可以充分的说明:
利用软引用和弱引用解决OOM问题:用一个HashMap来保存图片的路径和相应图片对象关联的软引用之间的映射关系,在内存不足时,JVM会自动回收这些缓存图片对象所占用的空间,从而有效地避免了OOM的问题.
通过软引用实现Java对象的高速缓存:比如我们创建了一Person的类,如果每次需要查询一个人的信息,哪怕是几秒中之前刚刚查询过的,都要重新构建一个实例,这将引起大量Person对象的消耗,并且由于这些对象的生命周期相对较短,会引起多次GC影响性能。此时,通过软引用和 HashMap 的结合可以构建高速缓存,提供性能.http://www.wityx.com/post/861_1_1.html

java中==和eqauls()的区别,equals()和`hashcode的区别
==是运算符,用于比较两个变量是否相等,而equals是Object类的方法,用于比较两个对象是否相等.默认Object类的equals方法是比较两个对象的地址,此时和==的结果一样.换句话说:基本类型比较用==,比较的是他们的值.默认下,对象用==比较时,比较的是内存地址,如果需要比较对象内容,需要重写equal方法

a.hashCode()有什么用?与a.equals(b)有什么关系
hashCode() 方法是相应对象整型的 hash 值。它常用于基于 hash 的集合类,如 Hashtable、HashMap、LinkedHashMap等等。它与 equals() 方法关系特别紧密。根据 Java 规范,两个使用 equal() 方法来判断相等的对象,必须具有相同的 hashcode。
将对象放入到集合中时,首先判断要放入对象的hashcode是否已经在集合中存在,不存在则直接放入集合.如果hashcode相等,然后通过equal()方法判断要放入对象与集合中的任意对象是否相等:如果equal()判断不相等,直接将该元素放入集合中,否则不放入.

有没有可能两个不相等的对象有相同的hashcode
有可能,两个不相等的对象可能会有相同的 hashcode 值,这就是为什么在 hashmap 中会有冲突。相等 hashcode 值的规定只是说如果两个对象相等,必须有相同的hashcode 值,但是没有关于不相等对象的任何规定。

“a==b”与a.equals(b)有什么区别
如果a 和b 都是对象,则 a==b 是比较两个对象的引用,只有当 a 和 b 指向的是堆中的同一个对象才会返回 true,而 a.equals(b) 是进行逻辑比较,所以通常需要重写该方法来提供逻辑一致性的比较。例如,String 类重写 equals() 方法,所以可以用于两个不同对象,但是包含的字母相同的比较。

a=a+b与a+=b有什么区别吗?
隐式的将加操作的结果类型强制转换为持有结果的类型。如果两这个整型相加,如 byte、short 或者 int,首先会将它们提升到 int 类型,然后在执行加法操作。如果加法操作的结果比 a 的最大值要大,则 a+b 会出现编译错误,但是 a += b 没问题,如下: byte a = 127; byte b = 127; b = a + b; // error : cannot convert from int to byte b += a; // ok (译者注:这个地方应该表述的有误,其实无论 a+b 的值为多少,编译器都会报错,因为 a+b 操作会将 a、b 提升为 int 类型,所以将 int 类型赋值给 byte 就会编译出错)

内部类的作用
内部类可以用多个实例,每个实例都有自己的状态信息,并且与其他外围对象的信息相互独立.在单个外围类当中,可以让多个内部类以不同的方式实现同一接口,或者继承同一个类.创建内部类对象的时刻病不依赖于外部类对象的创建.内部类并没有令人疑惑的”is-a”关系,它就像是一个独立的实体.
内部类提供了更好的封装,除了该外围类,其他类都不能访问

final,finalize和finally的不同之处
final 是一个修饰符,可以修饰变量、方法和类。如果 final 修饰变量,意味着该变量的值在初始化后不能被改变。finalize 方法是在对象被回收之前调用的方法,给对象自己最后一个复活的机会,但是什么时候调用 finalize 没有保证。finally 是一个关键字,与 try 和 catch 一起用于异常的处理。finally 块一定会被执行,无论在 try 块中是否有发生异常。

深拷贝和浅拷贝的区别是什么?
浅拷贝:被复制对象的所有变量都含有与原来的对象相同的值,而所有的对其他对象的引用仍然指向原来的对象。换言之,浅拷贝仅仅复制所考虑的对象,而不复制它所引用的对象。
深拷贝:被复制对象的所有变量都含有与原来的对象相同的值,而那些引用其他对象的变量将指向被复制过的新对象,而不再是原有的那些被引用的对象。换言之,深拷贝把要复制的对象所引用的对象都复制了一遍。

final有哪些用法
final也是很多面试喜欢问的地方,能回答下以下三点就不错了: 1.被final修饰的类不可以被继承 2.被final修饰的方法不可以被重写 3.被final修饰的变量不可以被改变.如果修饰的引用,那么表示引用不可变,引用指向的内容可变. 4.被final修饰的方法,JVM会尝试将其内联,以提高运行效率 5.被final修饰的常量,在编译阶段会存入常量池中.
当前回答出编译器对final域要遵守的两个重排序规则更好: 1.在构造函数内对一个final域的写入,与随后把这个被构造对象的引用赋值给一个引用变量,这两个操作之间不能重排序. 2.初次读一个包含final域的对象的引用,与随后初次读这个final域,这两个操作之间不能重排序.

数据类型相关
int 和Integer谁占用的内存更多?
Integer 对象会占用更多的内存。Integer是一个对象,需要存储对象的元数据。但是 int 是一个原始类型的数据,所以占用的空间更少。

什么是编译器常量?使用它有什么风险?
公共静态不可变(public static final )变量也就是我们所说的编译期常量,这里的 public 可选的。实际上这些变量在编译时会被替换掉,因为编译器知道这些变量的值,并且知道这些变量在运行时不能改变。这种方式存在的一个问题是你使用了一个内部的或第三方库中的公有编译时常量,但是这个值后面被其他人改变了,但是你的客户端仍然在使用老的值,甚至你已经部署了一个新的jar。为了避免这种情况,当你在更新依赖 JAR 文件时,确保重新编译你的程序。

java当中使用什么类型表示价格比较好?
如果不是特别关心内存和性能的话,使用BigDecimal,否则使用预定义精度的 double 类型。

如何将byte转为String
可以使用 String 接收 byte[] 参数的构造器来进行转换,需要注意的点是要使用的正确的编码,否则会使用平台默认编码,这个编码可能跟原来的编码相同,也可能不同。

可以将int强转为byte类型么?会产生什么问题?
我们可以做强制转换,但是Java中int是32位的而byte是8 位的,所以,如果强制转化int类型的高24位将会被丢弃,byte 类型的范围是从-128.到128

关于垃圾回收
你知道哪些垃圾回收算法?
垃圾回收从理论上非常容易理解,具体的方法有以下几种:
标记-清除
标记-复制
标记-整理


分代回收 更详细的内容参见深入理解垃圾回收算法
如何判断一个对象是否应该被回收
这就是所谓的对象存活性判断,常用的方法有两种:1.引用计数法;2:对象可达性分析.由于引用计数法存在互相引用导致无法进行GC的问题,所以目前JVM虚拟机多使用对象可达性分析算法.

你可能感兴趣的:(java后端开发)