前言
译文链接:http://www.journaldev.com/2366/core-java-interview-questions-and-answers
Java 8有哪些重要的特性
Java 8发布于2014年3月,这块内容在Java面试中非常常见。如果你能清晰的回答这方面的问题,说明you are not out,喜欢学习最新的技术。Java 8是继Java 5的注解和泛型之后所做的最大的改动,主要的新特性如下:
强烈建议大家打开上面的链接,以便更加深入理解这些知识。
你是怎样理解Java的平*立性的
平*立性意味着你可以在任何操作系统上运行同样的Java程序,你可以在Windows操作系统上编写Java程序,然后在Mac系统上运行。
什么是JVM,它是否平*立
Java虚拟机(JVM)是Java编程语言的核心,JVM负责将字节码转换成机器可读的代码,JVM并不拥有平*立性,所以不同的操作系统会有不同的JVM。我们可以自定义一些JVM参数,如配置最大内存和最小内存给JVM。JVM之所以叫做虚拟机,是因为它提供了一个不依赖于底层操作系统的接口。
JDK与JVM的区别
Java Development Kit(JDK)主要是以开发为目的,而JVM是JDK的一部分,用于执行Java程序。
JDK提供了全套工具,包括编译、调试和执行Java程序,其中执行部分是由JVM负责的,JVM保证了Java的平*立性。
JVM与JRE的区域
Java Runtime Environment (JRE)是JVM的实现,JRE由JVM(Java虚拟机)和Java核心类库组成,可以保证任何Java程序成功运行。
但是,JRE并不包含任何开发工具,如Java的编译、调试等。
如果你仅仅想运行Java程序,那么安装JRE即可。
Java中哪个类是所有类的超类
java.lang.Object是所有类的根类,并且我们不需要显示的继承它。
为什么Java不支持多重继承
Java之所以不支持多重继承是因为“菱形继承问题”(砖石问题),如下图:假定类A和B都实现了SuperClass中的一个方法,那么将导致编译器在编译类C时产生歧义,不知道应该选择哪个方法。详情请阅读Multiple Inheritance in Java。
虽然Java类不支持多重继承,但是接口是可以多重继承的,一个接口可以继承多个类因为接口仅仅只是申明方法,具体实现由实现类来定义,所以对于接口来说是不会有“菱形继承问题”的。
为什么Java不是一门完全面向对象的语言
Java之所以被认为不是一门完全面向对象的语言是因为它支持基本数据类型,如int、short、long等。这些基本数据类型给Java程序开发带来了方便,显然Java是可以给这些基本类型封装成对象,但是如果仅仅用于表示,并没有带来过多的好处。(据说基本数据类型不需要垃圾回收,因此比对象类型多了另一个性能优势)
众所周知,对于所有的基本数据类型,Java都提供了对应的封装类,如Integer, Long等,它们额外提供了一些方法。
path和classpath变量的区别
PATH是操作系统使用的一个环境变量,用于定位可执行程序所在的位置,所以当我们安装Java或想要让任何可执行程序被操作系统找到的时候,都需要添加可执行程序所在位置的路径到系统PATH变量里。
Classpath是针对Java而言的,用于让Java程序在运行时查找依赖的类文件,classpath可以是一个目录、zip文件、jar文件等。
Java中的main方法
main()方法是java程序的入口,main()方法的语法如下:
public static void main(String args[])
.
main方法是公共静态方法,所以java能够在不实例化该类的情况下直接访问该方法,main方法的输入参数是一个字符串数组,通过该数组我们可以传入运行时参数给java程序。
什么是Java的重载和覆盖
当我们有多个重名的方法且这些方法的入参不同时,这种情况叫做方法重载;
覆盖与继承相关,当父类和子类有一个相同的方法(方法名和参数),叫方法重写,一般会在子类方法前面添加@Override注解,保证父类方法被修改时,子类也一起修改。
是否可以重载main方法
答案是可以的,一个类可以拥有多个名称为“main”的方法,但是,当我们运行该类时,java运行环境只会查找符合特性语法(public static void main(String args[])
)的main方法。
是否可以在一个Java源文件里定义多个public类
答案是不能,java源文件里只能有一个public类,但是我们可以定义多个非public类。
什么是Java包,哪个包是默认引入的
Java包主要用于组织Java类并对它们分组,可以按功能或模块分组。一个Java类的完整名称包含包名和类名,如java.lang.Object
类,位于java.lang
包下,类名为Object。
java.lang
是默认引入的,我们不需要显式的引入该包下的任何类。
什么是访问控制符
Java中的访问控制符有public、private、protected,如果未使用以上关键字修饰,则为默认访问权限。
访问控制符主要用于访问权限的控制。
一个Java类只能用public修饰或不修饰(默认访问权限)。想要了解更多详细信息,请访问Java Access Modifiers。
关于final关键字
修饰类:被final关键字修饰的类不能被其它类继承,如String类是一个final类,不能被任何类继承。
修饰方法:我们可以用final关键字修饰方法,以保证该方法不能被子类重写。
修饰变量:final关键字可用于修饰变量,保证其只能被赋值一次,不过这里需要注意,变量的状态是可以改变的,举给例子,如果该变量是一个对象,即使用final修饰,该对象的成员属性的值是可以改变的。
接口变量:Java中的接口变量默认是用final和static修饰的。
interface a{
String str="hello.";//final and static
}
关于static关键字
修饰类变量:static可用于修饰类里的成员属性,让其成为全局变量;
修饰方法:static可用于修饰类里的方法,即静态方法,静态方法只能访问静态变量、调用静态方法;
更多详细信息,请访问java static keyword.
关于finally和finalize关键字
finally关键字是与try-catch一起使用的,用于保证finally语句块始终执行,即使有异常在try-catch语句块内部抛出。
finally语句块经常用于释放在try语句块里创建的资源。
finalize()是Object类里一个特殊的方法,我们可以在自己的类里重写该方法。这个方法会在该对象被回收时,被垃圾回收器调用。
finalize()方法经常用于在该对象被回收时释放系统资源。
是否可以声明一个静态类
我们不能将一个顶层类声明为静态类,但是内部类是可以用static修饰的。被static修饰的内部类叫静态内部类。
静态内部类与其它顶层类类似,主要是方便打包。
更多内部类内容请阅读java inner class.
什么是静态导入
当我们想要使用任何静态变量或者方法时,通常都是先导入这个类,然后根据这个类名来引用其方法或变量,如下示例:
import java.lang.Math; //inside class
double test = Math.PI * 5;
其实,还有一种方法是使用静态导入,即直接import该静态变量:
import static java.lang.Math.PI; //no need to refer class now
double test = PI * 5;
不过,使用静态导入会造成一定的混淆,过度使用会使程序变得难于阅读和维护,所以最好是避免使用。
关于try-with-resources语句
Java 7的一个新特性是使用try-with-resources语句自动管理资源。在Java 7之前,对于资源的关闭,只能显式的调用关闭资源方法,通常都是在finally语句块里关闭,当我们忘了关闭资源的时候,经常会造成内存泄漏。
从Java 7开始,我们可以在try代码块里创建资源,当try代码块执行完毕的时候,资源会自动关闭。
关于这方面的更多内容,请阅读Java Automatic Resource Management.
关于multi-catch代码块
Java 7的一个改进是引入了multi-catch代码块,我们可以使用一个catch块来捕获多个异常,当每个catch块代码相似的时候,这会让我们的代码更加简短、清晰。
如果一个catch块处理多个异常,你可以使用|分隔它们,在这种情况下异常参数是final类型的,所以不能修改。
举个例子:
Java 7之前:
catch (IOException ex) {
logger.error(ex);
throw new MyException(ex.getMessage());
catch (SQLException ex) {
logger.error(ex);
throw new MyException(ex.getMessage());
}catch (Exception ex) {
logger.error(ex);
throw new MyException(ex.getMessage());
}
Java 7之后:
catch(IOException | SQLException | Exception ex){
logger.error(ex);
throw new MyException(ex.getMessage());
}
想了解更多信息,请阅读Java multi catch block。
关于静态(static)代码块
Java静态代码块是一组代码语句,这些代码会在加载器加载这些类到内存的时候执行。它可用于初始化静态变量,经常用于创建静态资源(当类被加载时);
什么是一个接口
接口是Java编程语言的核心内容,广泛应用于JDK中,同样也应用于设计模式、各种框架及工具中。接口在Java中实现了一种方法打到抽象的目的,可用于定义一些抽象的约定让子类去实现。
使用接口定义类型、作为顶层层次接口来设计非常有好处。另外,由于一个Java类可以实现多个接口,所以在大多数情况下,最好使用接口作为超级父类。
更多关于接口的内容,请阅读java interface.
什么是抽象类
抽象类用于为子类创建默认方法实现,一个抽象类可以包含没有body的抽象方法,也可以包含已实现的方法。
abstract关键字用于创建一个抽象类,抽象类不能被实例化,通常用于让子类继承、实现抽象类中定义的抽象方法、覆盖或者使用抽象类中已实现的方法。
更多关于抽象类的信息,请阅读java abstract class.
抽象类与接口的区别
抽象类用abstract关键字定义,接口用interface关键字定义;
抽象类可以有实现方法,接口不行;
一个类只能继承一个抽象类,但是可以继承多个接口;
我们可以运行一个包含main方法的抽象类,但是接口不行;
更多关于接口与抽象类的区别,请阅读Difference between Abstract Class and Interface.
接口是否可以实现或继承其它接口
接口不能实现接口,但是可以继承其它接口。
由于接口不能包含具体实现方法,所以它们没有“砖石问题”,这也是为什么接口可以多重继承的原因;
什么是标识接口
一个标识接口是一个空接口,不包含任何方法,仅仅用于标识实现类拥有某些功能。典型的例子是Serializable 和 Cloneable接口,标识可以序列化和克隆。
什么是包装类
Java的包装类是对8个基本数据类型进行封装后形成的类,所有包装类都用final修饰,是不可变的。
Java 5提供的自动拆装箱功能允许基本数据类型和包装类自动转换。
更多关于包装类的内容,请阅读Wrapper classes in Java.
关于Java中的枚举
枚举是Java 5引入的一个新类型,它的字段包含若干固定的常量,举个例子,我们可以创建一个Direction枚举,包含四个固定字段EAST, WEST, NORTH, SOUTH。
enum关键字用于创建枚举类型,跟class有点类似。另外,枚举常量都是static和final的。
更多关于枚举请阅读java enum.
关于Java注解
Java注解提供了与代码相关的信息,它们对代码没有直接影响。注解是在Java 5引入的。
注解是嵌入到程序中的元数据,它可以被注解解析工具或编译器解析。
我们也可以指定注解是在编译期可用还是运行期可用。
Java中内置的注解有@Override, @Deprecated 和@SuppressWarnings
更多关于注解的内容,请阅读java annotations.。
关于Java反射机制
Java反射API可以帮助我们观察和修改Java程序运行时行为,通过反射机制,我们可以获取一个Java类、接口或枚举的方法和属性信息。反射API属于Java的高级特性,在平时的编程中,除非特殊情况,一般是不推荐使用的。反射API的使用会破坏一些设计模式,如常见的单例模式,通过反射可以调用私有构造方法,违反了访问修饰符的规则。
虽然在平时的编程中,我们很少使用反射API,但是反射机制的存在非常重要。现在,基本上任何一个框架都离不开反射API,如常见的Spring、Hibernate或者Tomcat。
更多详细信息,请阅读Java Reflection Tutorial。
关于Java中的组合
组合是一种设计技巧,用于实现类之间的has-a关系,我们可以使用对象组合实现代码复用。
Java使用对象引用变量来实现组合,使用组合的好处是我们可以控制其它对象对客户端类的可见性,并且只复用我们需要复用的代码。
更多Java组合的内容,请阅读Java Composition。
太多了,未完待续...