Appearance
1.面向对象的五大基本原则?
单一职责原则:一个类最好只做一件事
开放封闭原则:对扩展开放、对修改封闭
里氏替换原则:子类替换父类时要确保原程序的逻辑以及正确性,应用时尽量不直接使用父类,而是使用子类实现
依赖倒置原则:程序要依赖于抽象接口,而不是具体的实现
接口隔离原则:使用多个小的专门的接口,而不要使用一个大的总接口,接口中的方法尽量少
2.为什么Java不支持多继承?
因为多继承存在菱形继承的问题,而经过分析人们发现我们其实真正想要使用多继承的情况并不多。菱形继承如图所示:
因为D同时继承了B和C,并且B和C又同时继承了A,那么D中就会因为多重继承,继承到两份来自A中的属性和方法。这时候在使用D的时候,如果想要调用一个定义在A中的方法时,就会出现歧义。
java中如果需要实现多继承效果可以使用接口,java支持同一个类可以同时实现多个接口
3.java8的接口支持默认函数,一个类继承多个接口引发菱型问题如何处理?
代码如下所示,定义了两个接口都由名称相同的eat()
默认函数,Cat类继承两个接口,就有两个eat该使用谁的呢?
java
public interface Pet {
public default void eat(){
System.out.println("Pet Is Eating");
}
}
public interface Mammal {
public default void eat(){
System.out.println("Mammal Is Eating");
}
}
public class Cat implements Pet,Mammal {}
编译期会报错:error: class Cat inherits unrelated defaults for eat() from types Mammal and Pet
要求Cat类中,必须重写eat()方法。所以Java并没有帮我们解决多继承的歧义问题,而是把这个问题留给开发人员,通过重写方法的方式自己解决。
4.接口和抽象类的区别,如何选择?
接口主要用于制定规范,而抽象类主要目的是为了复用,通常在工具类或完成某个功能使用抽象类。
比如我想通过MQ发送广播消息,在发送前和发送后在定义时并没有规定完成什么功能,可以交给子类自己实现。
抽象类中的抽象方法可以有public、protected和default这些修饰符,而接口中默认修饰符是public。不可以使用其它修饰符。
5.方法中的重载与重写有什么区别?
- 重载:函数或方法有同样的名称,但是参数列表不相同
- 重写:Java的子类与父类中有两个名称、参数列表都相同的方法的情况,子类中的新方法将覆盖父类中原有的方法。
6.为什么需要包装类?
- 首先Java面向对象语言,很多地方都需要使用对象而不是基本数据类型,比如在集合类中无法将int 、double等类型放进去;
- 为了让基本类型也具有对象的特征就出现了包装类型,java为包装类添加了属性和方法,丰富了基本类型的操作。
- 基本类型和包装类型的默认值不同,基本类型的默认值为0, false或\u0000等,包装类默认均为null
7.在对象内使用静态变量初始化对象,和使用static代码块初始化对象有什么区别?
如下所示是使用static静态代码块初始化对象,静态代码块在类加载时执行,这意味着defaultProcess
对象只会被创建一次,而不是每次调用defaultProcess
时都创建一个新的实例。
java
public class ProcessFactory {
// 使用静态代码块初始化 defaultProcess 对象
private static final BaseProcess defaultProcess;
static {
defaultProcess = new BaseProcess() {
@Override
public void processBefore() {
// ...
}
@Override
public void processAfter() {
// ...
}
};
}
}
直接在声明时初始化defaultProcess
对象,这意味着每次调用defaultProcess
时都会创建一个新的实例,这种方法可能会导致性能下降,特别是在创建成本较高的对象时。
java
public class ProcessFactory {
// 直接在声明时初始化 defaultProcess 对象
private static final BaseProcess defaultProcess = new BaseProcess() {
@Override
public void processBefore() {
// ...
}
@Override
public void processAfter() {
// ...
}
};
}
8.new一个String创建了几个对象?
1个或两个,一次new的过程会在堆创建对象这是必然的;如果是第一次执行还会在堆的字符串常量池创建字符数组对象。
9.什么是类型擦除,开发中有什么提现?泛型中KTVN分别是什么含义?
类型擦除是指在编译后的字节码(.class)文件中是不包含泛型中的类型信息的,比如在类方法的重载不支持两个方法名称相同参数为List<String>
与List<Integer>
的方法,因为jdk只有List.class
,没有List<String>.clasee
- T – Type(Java 类)
- K – Key(键)
- V – Value(值)
- N – Number(数值类型)
- ?– 表示不确定的java类型(无限制通配符类型)
10.泛型中上下界限定符extends和super有什么区别?
<? extends T>
只能是T或其子类<? super T>
只能使用T或其父类直至Object
11.什么是反射机制?为什么反射慢?
反射可以用来在运行时获取到任意一个对象所属的类,类所具有的变量或方法,调用任意一个对象的方法,构造任意对象。
反射不能执行一些JVM优化,反射调用方法时会从方法数组中遍历查找,需要做很多额外的检查,比如说参数等。
12.Java中创建对象有哪些种方式?
- new关键字
- 反射
- 使用clone方法
- 使用反序列化
13.Java的动态代理如何实现?
- JDK动态代理
- Cglib
14.Serializable有什么用?
用于声明一个类可序列化;当试图对一个对象进行序列化的时候,如果遇到不支持 Serializable 接口的对象。在此情况下,将抛出 NotSerializableException。
15.serialVersionUID 有何用途? 如果没定义会有什么问题?
- 进行反序列化时,JVM会把传来的字节流中的serialVersionUID与本地相应实体类的serialVersionUID进行比较,如果相同就认为是一致的,可以进行反序列化。
- 如果UID没有显式的定义虚拟机会随机分配一个UID,如果Class文件没有发生变化就算再编译多次,serialVersionUID也不会变化的。但是,如果发生了变化,那么这个文件对应的serialVersionUID也就会发生变化,如果此时反序列化之前的数据则会报错。