A.Core Java
1.Java 8 的重要特性有哪些?
2014年3月发布的Java8,是Java面试中热门的问题之一。如果你回答的清晰,表明你对Java最新技术是与时俱进。
Java8是自Java5注解和泛型功能以来变化最大的版本。一些重要的特性诸如:
1. Interface changes with default and static methods
2. Functional interfaces and Lambda Expressions
3. Java Stream API for collection classes
强烈推荐访问以上链接了解每个具体的细节,或者阅读Java 8 Features。
2.Java的跨平台特性指的什么?
跨平台意味着你能在任何操作系统运行同样的Java程序。例如,你可以将在Windows平台写的Java程序放到Max OS系统运行。
3.什么是JVM?它可以跨平台否?
Java虚拟机是Java程序语言的核心。JVM负责将字节码机器可读的代码。JVM是非跨平台的,这也就是你需要在不同的操作系统上安装不同的JVM。我们也可以定制JVM配置,比如设置最小和最大分配内存。它是虚拟的,而且不受底层操作系统依赖。
4.JDK和JVM有什么区别?
Java开发套件(JDK)的目的是为开发服务的,JVM是其中一部分,它旨在运行Java程序。JDK提供所有的开发工具,需要编译的可执行二进制文件,调试和执行Java应用程序。可执行部分由JVM处理,来提供机器独立运行。
5.JVM和JRE有什么区别?
Java运行时环境(JRE)是JVM的具体实现。JRE由JVM和Java二进制还有其他classes类组成,以保证正确执行Java程序。JRE不包含任何开发工具,比如Java编译器,测试工具等。如果你要执行任何Java程序,你必须安装JRE。
6.Java中所有类的父类是什么?
java.lang.Object是所有Java类的父类,使用的时候不需要继承它。
7.为什么Java不支持多继承?
Java不支持类的多继承是因为存在“钻石问题”。了解“钻石问题”的例子可以查看文章Multiple Inheritance in Java。
然后多继承关系可以通过接口来实现。一个接口可以继承多个接口,因为他们只声明了方法,而具体的实现放在实现类里面,所以接口中不会存在“钻石问题”。
8.为什么Java不是纯面向对象语言?
因为Java原始类型,例如:int,byte,short,long等,所以Java不是纯面向对象语言。我认为它给我们在编写代码时提供了便捷。
显然Java可以用封装对象给原始对象提供展示,但他们没有任何好处。
众所周知,所有的原始对象都有封装对象,例如:Integer,Long等,封装对象中会有额外的一些方法。
9.path和classpath变量有什么区别?
PATH是操作系统使用的环境变量,用于放置执行相关的文件。这就是为什么我们安装完Java,想让操作系统找到执行文件,我们需要把Java目录位置加到PATH环境变量中。
Classpath是Java特定用的,用于Java执行文件放置class文件。我们可以在Java应用运行时提供classpath路径,可以是个目录,ZIP文件,JAR文件等。
10.Java中main方法有什么重要性?
main()方法是任何独立Java应用的入口。main方法的语法如下:
public static void main(String args[])
main方法是public和static修饰的,所以Java不用初始化类就能够访问它。方法参数是String数组,我们可以在运行程序时候传进来,查看这篇文章可以进一步了解how to compile and run java program。
11.Java中方法重载和方法重写有什么区别?
当我们在一个class类中想使用同一个方法名称实现多个方法而且参数不同时,这时候就可以用方法重载。
方法重写的概念来自于继承的情况,当我们有两个方法用了同一个方法签名,一个是在父类,另一个是在子类。我们可以在子类中使用@Override注解重写方法实现,这样可以确保父类中方法改变了,子类中也跟着变。
重载体现的类内部的多态性,重写体现的是父、子类继承间的多态性。
12.是否可以重载main方法?
是的,我们可以在同一个class类中写多个名称是"main"的方法。然后当Java虚拟机运行时候会根据public static void main(String args[])语法来找对应的main方法。
13.是否可以在Java源文件中写多个public classes?
Java不允许在一个源文件中写多个public class。一个源文件可以含有多个非public声明的class。
14.什么是Java的Package,哪些包是默认引入的?
包是Java中有效组织类分组的机制。分组逻辑可以基于设计的功能也可以基于模块。完全区分一个Java类包括包路径和类名称。例如java.lang.Object,完全区分是由类名称Object加上包路径java.lang。
java.lang下的包是默认引入的,所以我们的程序里面无需引入该包下的类。
15.什么Java访问修饰符
Java通过public, private and protected访问修饰词提供访问控制。当没有任何修饰词时,属于默认访问修饰。
Java类只能包含public或者默认修饰词。阅读Java Access Modifiers了解更多细节。
16.什么是final关键字?
类上使用final关键词修饰为了确保没有其他类可以继承它,例如String类是final修饰,所以我们无法继承String。
方法上使用final关键词修饰为了确保子类无法重写该方法。
变量上使用final关键词修饰为了确保其只能分配一次。然后变量的状态可以改变,例如可以给一个object分配final变量,但是object变量后面还可以修改。
17.什么是static关键字?
static关键词可以修饰class 层级的变量,使其变成全局共享变量。
static关键词也可以修饰方法。静态方法只能访问静态变量,同时也只能调用类的静态方法。
阅读java static keyword了解更多。
18.Java中finally和finalize的区别?
finally代码块用在try-catch中,用以确保改部分代码始终会执行,即便是任何异常抛出的情况。
finally代码块经常用来处理try代码块中创建的资源进行回收。
finalize()是Object类中特定的方法,可以在基础的类中进行重写。当object准备垃圾回收时,这个方法会被垃圾回收调用。这个方法经常重写用于在垃圾回收时释放系统资源。
19.是否可以声明一个静态类?
不能声明顶层类为静态类,然后一个内部类可以声明成静态static。如果内部类被声明为静态类,它被叫做静态嵌套类。内部静态类和其他顶层类是一样的,嵌套只是为了打包方便。
阅读java inner class了解更多。
20.什么是静态引用?
如果我们使用其他类中的静态变量或静态方法,通常我们先引入该类,然后使用该类的方法/变量。
import java.lang.Math;
//inside class
double test = Math.PI * 5;
当只需要用某个方法或变量时,我们也可以同样的引入静态方法或变量
import static java.lang.Math.PI;
//no need to refer class now
double test = PI * 5;
使用静态引入会产生混淆,所以需要尽量避免这种方式。过渡使用静态引用会导致你的程序可读性差和可维护性低。
21.什么是try-with-resources?
Java7的一个特性是try-with-resources声明,用于动态资源管理。Java7之前没有动态资源管理,我们需要明确需要关闭的资源。通常会在try-catch声明的finally代码块中实现。当我们忘记关闭资源时这种方法会导致内存不足。
从Java7开始,我们可以在try代码块中创建资源和使用它,当try-catch代码块结束时,Java会马上处理好资源的。阅读Java Automatic Resource Management了解更多。
22.什么是multi-catch块?
多个异常块捕获代码是Java7的一个改善,我们可以捕获多个异常在同一个catch块中。当每一个catch块中都是相似代码的时候,这样的处理会让代码变得简洁。
如果一个catch块处理多个异常,可以使用管道符"|",这种情况下异常参数是final修饰,所以无法改变它。阅读Java multi catch block了解更多。
23.什么是静态块?
Java静态代码块是通过Java ClassLoader把类加载到内存时候的一组可执行的声明。它被用来初始化类中的静态变量。大多数情况当类加载时创建静态资源。
24.什么是接口?
接口是Java程序语言的核心部分,不仅广泛用于JDK,而且在Java设计模式中,大多数框架中,工具类中都有使用。接口给Java提供了一种抽象化的途径,而且用于约定在子类中的实现。
接口有利于定义类型和在我们代码里创建集成关系的顶层逻辑。由于Java类可以实现接口的多继承,所以在大多数情况下最好使用超类当接口。阅读java interface了解更多。
25.什么是抽象类?
抽象类用在Java中为子类们创建一个超类且含有具体的方法实现。一个抽象类可以有不含方法体的抽象方法,也可以有具体实现的抽象方法。
abstract关键字用于创建抽象类。抽象类不能被实例化,通常用在提供子类继承和实现基础的抽象方法和重写或者用抽象类中的方法。阅读java abstract class了解更多。
26.Java中抽象类和接口的区别?
abstract关键词创建抽象类而interface关键词创建的是接口;
抽象类可以有具体的方法实现而接口没有;
一个类只能继承一个抽象类,但是可以实现多个接口;
我们可以运行含有main()方法的抽象类,而接口不行;
27.接口是否可以实现或继承另一个接口?
接口无法实现另一个接口,他们是继承关系。因为接口没有方法实现,所以不存在“diamond”问题,这就是为什么会允许多接口继承,一个接口也可以继承多个接口。
28.什么是Marker interface?
Java中Marker interface是指一个空的接口没有任何方法,但在一些功能设计的类里面强制实现。我们熟知的一些marker interfaces例如Serializable、Cloneable。
29.什么是Wrapper classes?
Java的嵌套类是Object对八种原始类型的展示。Java中所有嵌套类都是不可变和final修饰的。Java5中自动装箱和拆箱允许一种便捷的方式转换原始类型和它们对应的封装类型。
阅读Wrapper classes in Java了解更多。
30.什么是Java中的枚举?
枚举是Java1.5中引入的新类型,它的filed是固定的常量Set集合。例如我们可以创建方向的枚举集合:东、西、南、北。
同类类似,创建枚举的关键词是enum。枚举常量是隐形的静态和final。
阅读java enum了解更多。
31.什么是Java注解?
Java注解提供关于代码的信息,它们对注解的代码块没有直接影响。注解是Java5引入的。注解是嵌入在程序中关于程序的元数据。注解的语法解析可以被注解解析工具或者编译器解析。我们也可以指定注解是编译时有效或运行时有效。Java内置的注解有@Override, @Deprecated,@SuppressWarnings。
阅读java annotations了解更多。
32.什么是Java反射API?为何它非常重要?
Java反射API是检查和修改Java应用运行时行为的一种方式。我们可以检查类、接口、枚举,获取它们的方法和成员变量的细节。反射API是高级技能,我们应该避免在平时编码时使用。反射API的用法可以打破设计模式,比如单例模式,通过调用私有构造器等可以违反Java里访问修饰的规则。
即便我们不在普通应用编码时使用反射API,但它还是有其重要意义。在一些框架中,比如Spring,Hibernate或容器应用例如Tomcat,Jobss里不能没有反射API。它们通过反射API调用合适的方法和实例化对象,在其他程序处理中也应用广泛。
阅读Java Reflection Tutorial深入了解反射API。
33.什么是Java复合Composition?
复合/组合是Java类中实现has-a关系的设计技术,我们可以使用对象组合来实现代码重用。
我们可以针对其他的对象实例化成变量来实现Java组合,其好处是我们可以控制类中其他对象的可见性,在我们需要的时候重用。
阅读Java Composition了解复合/组合示例。
34.复合优于继承的好处有哪些?
Java程序中最佳实践之一是“复合优于继承”原则,一些原因如下:
a.任何父类的变化可能都会影响子类,及时我们不会用到的父类方法。例如,我们在子类中有一个test()方法,突然有人在其父类也写了个test()方法,会导致子类编译错误。复合就绝不会有这种问题,因为我们只使用我们需要的方法。
b.继承暴露了所有父类的方法和变量给继承者们,如果我们掌握不好父类的设计,会导致安全漏洞。复合允许我们提供严格的方法访问,因此更加安全。
c.我们可以在运行时进行复合绑定,然后继承绑定需要在编译时期。这样复合提供更加灵活的方法调用。
阅读java composition vs inheritance了解更多组合优于继承的好处。
35.如何对customer对象集合排序?
需要实现Comparable接口来支持customer集合的排序。Comparable接口有compareTo(T obj)方法,用来做排序的方法,也提供了它的实现。我们可以使用默认的方式来对集合中customer对象来排序。
36.什么是Java中内部类?
我们可以在类的内部定义一个类,叫做嵌套类。任何非静态嵌套类叫内部类。内部类和类对象关联,它可以访问外层类的所有变量和方法。由于内部类和实例有关联,所以不能含有静态变量。我们可以有局部内部类或匿名内部类。
阅读java inner class了解更多。
37.什么是匿名内部类?
局部内部类如果没有名称,就是匿名内部类。一个匿名类的定义和实例化都是一条声明。匿名内部类通常继承一个类或者实现一个接口。
由于匿名内部类没有名字,所以无法定义构造方法。匿名内部类可访问域是它的定义位置。
38.什么是Classloader?
Java Classloader是一个我们需要访问类时加载程序字节码到内存的程序。我们也可以扩展Classloader类,重写loadClass(String name)方法来创建自己的classloader。
阅读java classloader了解更多。
39.有哪些不同类型的Classloader?
Java中内置了三种类型类加载器:
1.Bootstrap Class Loader – 它加载JDK的内部类,典型的有rt.jar和其他核心类;
2.Extensions Class Loader – 它加载JDK扩展目录的类,通常是$JAVA_HOME/lib/ext目录;
3.System Class Loader – 它加载当前classpath的类,可以在调用程序是命令行指定-cp或者-classpath命令来设置。
40.什么是三元运算符?
Java条件运算符仅指的条件运算,例如三元运算。它在Java程序应用广泛,是内部替代if-then-else语句用的。我们可以用条件运算符 if-else语句或者switch条件。
阅读java ternary operator了解更多。
41.super关键字有什么作用?
super关键字可以用来访问父类的方法,当你在子类重写了该方法时用的。
我们可以在子类构造器通过super关键字调用父类构造器但是这种情况需要将第一条声明写在构造器方法里。
package com.journaldev.access;
public class SuperClass {
public SuperClass(){
}public SuperClass(int i){}
public void test(){
System.out.println("super class test method");
}}
使用super关键字的例子可以参考下面子类的实现:
package com.journaldev.access;
public class ChildClass extends SuperClass {
public ChildClass(String str){
//access super class constructor with super keyword
super();
//access child class method
test();
//use super to access super class method
super.test();
}
@Override
public void test(){
System.out.println("child class test method"); }
}
}
42.说明下break和continue声明的用途?
我们可以使用break语句终止for,while,或者do-while循环。可以在switch语句中退出switch条件。你可以看下break的例子java break。我们可以使用break当作标签来退出内部循环。
continue语句是在for,while或者do-while循环中跳过当次循环。我们可以使用continue语句当作标签来跳过当次循环。
43.this关键字有什么用?
this关键字提供了当前类的引用,它常用来确保一个类里面的变量是被调用,而不是局部同名变量被调用了。
44.什么是默认构造器?
类的无参构造函数就是默认的构造函数。当我们没有写无参类,Java编译器会自动给类创建一个默认的无参构造器。如果有其他的构造器定义了的话,编译器就不会创建默认的了。
45.是否可以在try中不写catch代码块?
可以,我们可以写try-finally语句而没有catch代码块。
46.什么是垃圾回收?
垃圾回收是在堆内存中回收没有被使用的对象的进程。在Java中,分配内存的过程是自动由garbage collector处理的。
我们可以在代码中写Runtime.getRuntime().gc()来运行垃圾回收,或者使用System.gc()。查看更多分析堆内存和垃圾回收机制的,阅读Java Garbage Collection。
47.什么是序列化和反序列化?
我们把Java对象转换成流的过程叫做序列化。一旦Java对象被转换成流,它就能被保存到文件或者发送到网络传输或者用到socket连接中。
对象在实现序列化接口后,我们可以用java.io.ObjectOutputStream来讲对象写到文件或者任何OutputStream对象中。阅读Java Serialization了解更多。
进程通过序列化将流数据转换成对象的过程叫反序列化。阅读Java Deserialization了解更多。
48.如何在cmd窗口运行JAR文件
我们如果要在命令行运行JAR文件,它需要有mainfest文件定义Main-Class入口。Main-Class是JAR文件的入口,命令行运行时需要用到。
49.System类有哪些用途?
Java的System类是核心类之一,调试时候最早记录日志信息就是通过System.out.print()方法来实现的。
System类是final的,所以它不能有子类,也不能通过继承来重写。System类不提供任何公共构造器,所以我们无法实例化这个类,这就是为什么它所有的方法都是静态方法。
System的一些有用的方法有数组复制,获取当前系统时间,读取系统环境变量等。
阅读Java System Class了解更多。
50.instanceof关键字有什么作用?
instanceof关键字用来检查一个对象是否是某个类的类型。我们赢尽可能避免使用它。用法示例:
public static void main(String args[]){
Object str = new String("abc");
if(str instanceof String){
System.out.println("String value:"+str);
}
if(str instanceof Integer){
System.out.println("Integer value:"+str);
}
}
由于str在运行时是String类型,第一个if语句计算的值是true而第二个计算值是false。
51.switch case中是否可以用String?
Java7的一个特性是改进了switch case允许使用String。所以如果使用Java7或者更高版本,你可以在switch-case语句中使用String。
阅读Java switch-case String example了解更多。
52.Java是值传递还是引用传递?
这是个容易混淆的问题,我们知道对象变量包含对象到堆的引用。当我们调用任何方法时,这些变量被传递而且存储在方法栈内存中。我们可以通过简单的方法交换对所有语言测试到底是引用传递还是值传递,了解更多请阅读Java is Pass by Value and Not Pass by Reference。
53.堆和栈内存的区别?
以下是堆和栈内存的主要区别:
∆堆内存被应用所有部分使用而栈内存只被一个线程执行时使用;
∆无论一个对象是否创建,它总是存储在堆内存栈内存包含它的引用。栈内存包含局部原始变量,对象的引用变量在堆内存区。
∆栈内存管理由LIFO管理完成,然而堆内存管理则更加复杂,因为它是全局的。
通过一个简单的程序了解更多细节,阅读Java Heap vs Stack Memory。
54.Java编译的文件存在JDK,JRE还是JVM?
Java编译器的任务是将程序转换为字节码,我们有javac来执行编译。所以它一定存在于JDK,我们在JRE不需要而JVM只是规范。
55.下面的程序输出结果是什么?
1.类的静态方法
package com.journaldev.util;
public class Test {
public static String toString(){
System.out.println("Test toString called");
return "";
}
public static void main(String args[]){
System.out.println(toString());
}
}
答案:代码编译会失败,因为Object类方法不能用static关键词修饰。你会得到一个编译错误“This static method cannot hide the instancemethod from Object”。理由是静态方法属于类,所有类的基类是Object,我们不能像在类中一样在实例里面有相同名称的方法。
2.静态方法调用
package com.journaldev.util;
public class Test {
public static String foo(){
System.out.println("Test foo called");
return "";
}
public static void main(String args[]){
Test obj = null;
System.out.println(obj.foo());
}
}
答案:这是个异常的情形。当我们调用对象的方法为空时会报NullPointerException空指针异常。编译器会给出“The static method foo() from the type Test should be accessed in a static way”,但是当执行时会打印“Test foo called”。
理想的情况是当对象静态方法调用时Java API应该给出错误而不是警告,但我认为这样强制的太晚了。大多数异常是即使对象这里为空,但调用静态方法是还是能运行。我认为这里可以运行是因为Java运行时计算出foo()是一个静态方法,而且在类加载到内存中调用,而且不会用这个对象,所以没有空指针异常。