1、面向对象可以解释下吗?都有哪些特征?
面向对象是一种编程思想,可以将复杂问题简单化,让编程人员从执行者变为了指挥者。面向对象的三大特征为:封装、继承与多态。
-
封装:将事物封装成一个类,减少耦合,隐藏细节。保留特定的接口与外界联系,当接口内部发生改变时,不会影响外部调用方。
-
继承:从一个已知的类中派生出一个新的类,新类可以拥有已知类的行为和属性,并且可以通过覆盖/重写来增强已知类的能力。
-
多态:多态的本质就是一个程序中存在多个同名的不同方法,主要通过三种方式来实现:
- 通过子类对父类的覆盖来实现
- 通过在一个类中对方法的重载来实现
- 通过将子类对象作为父类对象使用来实现
-
【注】
常见的封装:get()/set()方法。
Java 不支持多继承。
重写(覆盖):@Override,继承,返回值类型、方法名、参数相同。
重载:同名不同方法,参数个数、顺序以及类型不同。
如果只是方法/返回值不同,不可以构成重载。因为调用某个方法并不关心其返回值,这时候编译器根据方法名和参数无法确定我们调用的是哪个方法。
2、JDK、JRE、JVM 的区别与联系
三者的基本概念:
- JDK(Java Development Kit)是一个开发工具包,是Java开发环境的核心组件,并且提供编译、调试和运行一个Java程序所需要的所有工具,可执行文件和二进制文件,是一个平台特定的软件。
- JRE(Java Runtime Environment)是指Java运行时环境,是JVM的实现,提供了运行Java程序的平台。JRE包含了JVM,但是不包含Java编译器/调试器之类的开发工具。
- JVM(Java Virtual Machine)是指Java虚拟机,当我们运行一个程序时,JVM负责将字节码转换为特定机器代码,JVM提供了内存管理/垃圾回收和安全机制等。
区别与联系:
- JDK是开发工具包,用来开发Java程序,而JRE是Java的运行时环境。
- JDK和JRE中都包含了JVM。
- JVM是Java编程的核心,独立于硬件和操作系统,具有平台无关性,而这也是Java程序可以一次编写,多处执行的原因。
Java 语言的平台无关性是如何实现的:
- JVM屏蔽了操作系统和底层硬件的差异。
- Java面向JVM编程,先编译生成字节码文件,然后交给JVM解释成机器码执行。
- 通过规定基本数据类型的取值范围和行为。
Java语言是编译型还是解释型语言?
- Java的执行经历了编译和解释的过程,是一种先编译,后解释执行的语言,不可以单纯归到编译性或者解释性语言的类别中。
3、抽象类和接口有什么区别
抽象类和接口的主要区别:
- 抽象类中可以没有抽象方法,也可以抽象方法和非抽象方法共存。
- 抽象类和类一样是单继承的;接口可以实现多个父接口。
- 抽象类中可以存在普通的成员变量;接口中的变量必须是static final类型的,必须被初始化,接口中只有常量,没有变量。
- 接口中的方法在JDK8之前只能是抽象的,JDK8版本开始提供了接口中方法的default实现。
抽象类和接口应该如何选择?分别在什么情况下使用呢?
- 根据抽象类和接口的不同之处,当我们仅仅需要定义一些抽象方法而不需要其余额外的具体方法或者变量的时候,我们可以使用接口。反之,则需要使用抽象类,因为抽象类中可以有非抽象方法和变量。
4、Java 中8中基本数据类型及其取值范围
| 数据类型 | 关键字类型 | 内存占用 | 取值范围 | 默认值 | 包装类 |
|---|---|---|---|---|---|
| 字节型 | byte | 1字节 | -128-127 | 0 | java.lang.Byte |
| 短整型 | short | 2字节 | -32768-32767 | 0 | java.lang.Short |
| 整形 | int | 4字节 | -2147483648-2147483647 | 0 | java.lang.Integer |
| 长整型 | long | 8字节 | -9223372036854775808-9223372036854775807 | 0 | java.lang.Long |
| 单精度浮点数 | float | 4字节 | 1.4E-45-3.4028235E38 | 0.0f | java.lang.Float |
| 双精度浮点数 | double | 8字节 | 4.9E-324-1.7976931348623157E308 | 0.0d | java.lang.Double |
| 字符型 | char | 2字节 | 0-65535 | 'u0000' | java.lang.Character |
| 布尔型 | boolean | 1字节 | true,flase | flase | java.lang.Boolean |
5、Java 中的元注解有哪些
- @Target:
说明注解所修饰的对象范围,关键源码如下:
public @interface Target {
ElementType[] value();
}
public enum ElementType {
TYPE,FIELD,METHOD,PARAMETED,CONSTRUCTOR,LOCAL_VARIABLE,ANNOCATION_TYPE,PACKAGE,TYPE_PARAMETER,TYPE_USE
}
例如,如下的注解使用@Target标注,表明MyAnn注解就只能作用在类/接口和方法上。
@Target({ElementType.TYPE, ElementType.METHOD})
public @interface MyAnn {
}
- @Rentention:(保留策略)
保留策略定义了该注解被保留的时间长短。关键源码如下:
public @interface Retention {
RetentionPolicy value();
}
public enum RetentionPolicy {
SOURCE, CLASS, RUNTIME
}
其中,SOURCE:表示在源文件中有效(即源文件保留);CLASS:表示在class文件中有效(即class保留);RUNTIME:表示在运行时有效(即运行时保留)。例如,@Retention(RetentionPolicy.RUNTIME)标注表示该注解在运行时有效。
- @Documented:
该注解用于描述其它类型的annotation应该被作为被标注的程序成员的公共API,因此可以被javadoc此类的工具文档化。Documented是一个标记注解,没有成员。关键源码如下:
public @interface Documented {
}
- @Inherited:
该注解是一个标记注解,@Inherited阐述了某个被标注的类型是被继承的。如果一个使用了@Inherited修饰的annotation类型被用于一个class,则这个annotation将被用于该class的子类。关键源码如下:
public @interface Inherited {
}
注解的作用:
代替繁杂的配置文件,简化开发。
6、Java 的反射机制
反射机制是指在运行中,对于任意一个类,都能够知道这个类的所有属性和方法。对于任意一个对象,都能够调用它的任意一个方法和属性。即动态获取信息和动态调用对象方法的功能称为反射机制。
反射机制的作用:
- 在运行时判断任意一个对象所属的类
- 在运行时构造一个类的对象
- 在运行时判断任意一个类所具有的成员变量和方法
- 在运行时调用任意一个对象的方法,生成动态代理
与反射相关的类:
- Class:表示类,用于获取类的相关信息
- Field:表示成员变量,用于获取实例变量和静态变量等
- Method:表示方法,用于获取类中的方法参数和方法类型等
- Constructor:表示构造器,用于获取构造器的相关参数和类型等
7、Java中的Exception和Error有什么区别?
Exception和Error的主要区别可以概括如下:
- Exception是程序正常运行中预料到可能会出现的错误,并且应该被捕获并进行相应的处理,是一种异常现象。
- Error是正常情况下不可能发生的错误,Error会导致JVM处于一种不可恢复的状态,不需要捕获处理,比如说OutOfMemoryError。
Exception又分为了运行时异常和编译时异常。
- 编译时异常(受检异常)表示当前调用的方法体内部抛出了一个异常,所以编译器检测到这段代码在运行时可能会出异常,所以要求我们必须对异常进行相应的处理,可以捕获异常或者抛给上层调用方。
- 运行时异常(非受检异常)表示在运行时出现的异常,常见的运行时异常包括:空指针异常,数组越界异常,数字转换异常以及算术异常等。
捕获异常应该遵循哪些原则?
- 尽可能捕获比较详细的异常,而不是使用Exception一起捕获。
- 当本模块不知道捕获之后该怎么处理异常时,可以将其抛给上层模块。上层模块拥有更多的业务逻辑,可以进行更好的处理。
- 捕获异常后至少应该有日志记录,方便之后的排查。
- 不要使用一个很大的try – catch包住整段代码,不利于问题的排查。
NoClassDefFoundError 和 ClassNotFoundException 有什么区别?
-
NoClassDefFoundError一般是由于打包的时候漏掉了部分类或者Jar包被篡改已经损坏。

-
ClassNotFoundException一般都是类名字传入有误导致的。

8、解释下Java中的值传递和引用传递
值传递和引用传递的解释可以概括如下。
- 值传递,意味着传递了对象的一个副本,即使副本被改变,也不会影响源对象。
public class Test { public static void main(String[] args) { int x=0; change(x); System.out.println(x); } static void change(int i){ i=7; } }上边的代码会输出0。因为如果参数是基本数据类型,那么是属于值传递的范畴,传递的其实是源对象的一个copy副本,不会影响源对象的值。
- 引用传递,意味着传递的并不是实际的对象,而是对象的引用。因此,外部对引用对象的改变会反映到所有的对象上。
public class Test { public static void main(String[] args) { StringBuffer x = new StringBuffer("Hello"); change(x); System.out.println(x); } static void change(StringBuffer i) { i.append(" world!"); } }通过运行程序,输出为Hello world!
9、StringBuffer与StringBuilder的区别?
-
StringBuilder
- 线程不安全
- 效率高
-
StringBuffer
- 线程安全
- 效率低
-
如果要操作少量的数据用 String;
-
多线程操作字符串缓冲区下操作大量数据 StringBuffer;
-
单线程操作字符串缓冲区下操作大量数据 StringBuilder。
10、Java 中泛型的理解
泛型可理解为类的形参(类似方法的参数)。当定义了泛型以后,就可通过不同类型参数的构造方法声明该类的对象。该形参可以传入任何Object。
11、Java序列化与反序列化的过程
将对象转换为字节序列存储到硬盘上的过程叫做对象的序列化;反序列化则是把硬盘上的字节序列读取恢复成一个对象的过程。
12、equals和hashCode方法的关系?
hashcode方法存在主要是提高判断对象是否相等的效率,当对象equals相等时,它们的hashcode一定相等,但是当对象的hashcode相等时,两个对象不一定是相等的。再比较对象是否相等时,先比较通过hashcode进行比较,然后进行equals比较。
13、Java中equals方法和==的区别?
equals用来比较的是两个对象的内容是否相等,由于所有的类都是继承自java.lang.Object类的,所以适用于所有对象,如果没有对该方法进行覆盖的话,调用的仍然是Object类中的方法,而Object中的equals方法返回的却是==的判断。
== 比较的是变量(栈)内存中存放的对象的(堆)内存地址,用来判断两个对象的地址是否相同,即是否是指相同一个对象。比较的是真正意义上的指针操作。