1. 为什么说Java是一门平台无关语言?
平台无关实际的含义是“一次编写到处运行”。Java 能够做到是因为它的字节码(byte code)可以运行在任何操作系统上,与底层系统无关。
2. 为什么 Java 不是100%面向对象?
Java 不是100%面向对象,因为它包含8个原始数据类型,例如 boolean、byte、char、int、float、double、long、short。它们不是对象。
3. 什么是 singleton class,如何创建一个 singleton class?
Singleton class 在任何时间同一个 JVM 中只有一个实例。可以把构造函数加 private 修饰符创建 singleton。
4. 什么是多态?
多态简单地说“一个接口,多种实现”。多态的出现使得在不同的场合同一个接口能够提供不同功能,具体地说可以让变量、函数或者对象能够提供多种功能。下面是多态的两种类型:
- 编译时多态
- 运行时多态
编译时多态主要是对方法进行重载(overload),而运行时多态主要通过使用继承或者实现接口。
什么是运行时多态,也称动态方法分配?
在 Java 中,运行时多态或动态方法分配是一种在运行过程中的方法重载。在这个过程中,通过调用父类的变量引用被重载的方法。下面是一个例子:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
|
class Car { void run() { System.out.println(“car is running”); } } class Audi extends Car { void run() { System.out.prinltn(“Audi is running safely with 100km”); } public static void main(String args[]) { Car b= new Audi(); //向上转型 b.run(); } } |
5. Java类加载器包括几种?它们之间的关系是怎么样的?
Java 类加载器有:
- 引导类加载器(bootstrap class loader):只加载 JVM 自身需要的类,包名为 java、javax、sun 等开头。
- 扩展类加载器(extensions class loader):加载 JAVA_HOME/lib/ext 目录下或者由系统变量 -Djava.ext.dir 指定位路径中的类库。
- 应用程序类加载器(application class loader):加载系统类路径 java -classpath 或 -Djava.class.path 下的类库。
- 自定义类加载器(java.lang.classloder):继承 java.lang.ClassLoader 的自定义类加载器。
注意:-Djava.ext.dirs 会覆盖 Java 本身的 ext 设置,造成 JDK 内建功能无法使用。可以像下面这样指定参数:
1
|
-Djava.ext.dirs=./plugin:$JAVA_HOME/jre/lib/ext。 |
它们的关系如下:
- 启动类加载器,C++实现,没有父类。
- 扩展类加载器(ExtClassLoader),Java 实现,父类加载器为 null。
- 应用程序类加载器(AppClassLoader),Java 实现,父类加载器为 ExtClassLoader 。
- 自定义类加载器,父类加载器为AppClassLoader。
7. 什么是JDBC驱动?
JDBC Driver 是一种实现 Java 应用与数据库交互的软件。JDBC 驱动有下面4种:
- JDBC-ODBC bridge 驱动
- Native-API 驱动(部分是 Java 驱动)
- 网络协议驱动(全部是 Java 驱动)
- Thin driver(全部是 Java 驱动)
8. 使用 Java 连接数据库有哪几步?
- 注册驱动类
- 新建数据库连接
- 新建语句(statement)
- 查询
- 关闭连接
9. 列举Spring配置中常用的重要注解。
下面是一些重要的注解:
- @Required
- @Autowired
- @Qualifier
- @Resource
- @PostConstruct
- @PreDestroy
10. Spring中的Bean是什么?列举Spring Bean的不同作用域。
Bean 是 Spring 应用的骨架。它们由 Spring IoC 容器管理。换句话说,Bean 是一个由 Spring IoC 容器初始化、装配和管理的对象。
下面是 Spring Bean 的5种作用域:
- Singleton:每个容器只创建一个实例,也是 Spring Bean 的默认配置。由于非线程安全,因此确保使用时不要在 Bean 中共享实例变量,一面出现数据不一致。
- Prototype:每次请求时创建一个新实例。
- Request:与 prototype 相同,区别在于只针对 Web 应用。每次 HTTP 请求时创建一个新实例。
- Session:每次收到 HTTP 会话请求时由容器创建一个新实例。
- 全局 Session:为每个门户应用(Portlet App)创建一个全局 Session Bean。
11. Object 类包含哪些方法?
这是一个非常常见的问题,用来确定你对基础知识的熟悉程度。以下是每个对象都具有的方法:
在 java.lang
包中,Object
类位于类层次结构的顶端。每个类都是 Object
类直接或间接的子类。你使用或编写的每个类都继承了 Object
类中的实例方法。你并不需要使用这些方法中的任何一种,但是,如果你选择这样做,则可能需要用你的类的特定代码来重写这些方法。以下是本节所讨论的从 Object
类中继承的方法:
protected Object clone() throws CloneNotSupportedException
创建并返回此对象的副本。public boolean equals(Object obj)
判断另一对象与此对象是否「相等」。protected void finalize() throws Throwable
当垃圾回收机制确定该对象不再被调用时,垃圾回收器会调用此方法。public final Class getClass()
返回此对象的运行时类。public int hashCode()
返回此对象的散列码值。public String toString()
返回此对象的字符串表示形式。
Object
类的 notify
,notifyAll
和 wait
方法都在同步程序中独立运行线程的活动方面发挥了作用,这将在后面的课程中讨论,在此不做介绍。其中有五种方法:
public final void notify()
public final void notifyAll()
public final void wait()
public final void wait(long timeout)
public final void wait(long timeout, int nanos)
12. 为什么 String 对象是不可变的?
- 字符串池之所以可能,就是因为字符串在 Java 中是不可变的。由此 Java 运行时环境节省了大量堆空间,因为不同的 String 变量可以引用池中的同一 String 变量。如果 String 不是不可变的, 则字符串驻留(String interning)将是不可能的,因为一旦任一变量更改所引用的String对象的值,它也会反映在其他变量中。
- 如果字符串不是不可变的,那么它可能会对应用程序造成严重的安全威胁。例如,数据库用户名和密码都作为 String 传递以获取数据库连接,Socket 编程的主机和端口信息也是如此。由于字符串是不可变的,因此其值不能被更改。否则,任何黑客都可以篡改其引用的值,这会导致应用程序中的安全问题。
- 由于 String 是不可变的,因此它对与多线程处理来说是安全的,并且可以在不同的线程之间共享单个 String 实例。这避免了为线程安全使用同步;字符串是隐式线程安全的。
- 字符串被用在 Java 类加载器中,其不可变性为类加载器加载正确的类提供了安全性。否则的话,请考虑这样一个危险的情况,在你尝试加载
java.sql.Connection
类时,你引用的值却被更改为myhacked.Connection
,并且它能对数据库执行你不需要的操作。 - 由于 String 是不可变的,因此在它被创建时其散列码就被缓存,不需要再次计算。这使得它成为映射中键的理想对象,它的处理速度比其他
HashMap
键类型快。这就是为什么 String 是HashMap
中最常用的键类型。
为什么 Java 中的字符串不可变?点击这里了解更多。
13. final,finally,和 finalize 三者之间有什么不同?
这是我最喜欢的问题。
final
关键字用于在多个语境下定义只能分配一次的实体。finally
代码块是用于执行重要代码 (如关闭连接、流等) 的代码块。无论是否处理异常,finally
代码块总会被执行。finally
代码块紧随try
代码块或catch
代码块。- 这是在删除或销毁对象之前垃圾回收器总会调用的方法,该方法使得垃圾回收机制能够执行清理活动。
14. 什么是菱形继承问题?
菱形继承问题反映了为什么在 Java 中我们不被允许实现多继承。如果有两个类共同继承一个有特定方法的超类,那么该方法会被两个子类重写。然后,如果你决定同时继承这两个子类,那么在你调用该重写方法时,编译器不能识别你要调用哪个子类的方法。
我们把这个问题称为 菱形继承问题 。上图对它作了说明,它也得名于此。
15. 如何使一个类不可变?
我认为这是一个相当困难的问题。您需要对类进行多次修改,以实现不可变性:
- 将类声明为
final
,使其无法被继承。 - 所有域都用
private
修饰,不允许直接访问。 - 不提供变量的
setter
方法。 - 所有可变域都用
final
修饰, 使它的值只能分配一次。 - 通过构造函数执行深克隆初始化所有域。
- 对
getter
方法获取的对象执行克隆以返回副本,而不是返回实际的对象引用。
16. 什么是单例模式?
单例模式是指一个类仅允许创建其自身的一个实例,并提供对该实例的访问权限。它包含静态变量,可以容纳其自身的唯一和私有实例。它被应用于这种场景——用户希望类的实例被约束为一个对象。在需要单个对象来协调整个系统时,它会很有帮助。
17. 什么是依赖注入?
这是你必须知道的首要问题, 无论你是使用 Java EE 还是 Spring 框架。你可以看看我的文章,其中进一步地解释了这一点: 什么是依赖注入?
总结
在本文中,我们讨论了最常见的十个 Java 面试题——在我看来这是根据我的经验总结出的时下最重要的问题。如果你了解这些问题,我相信你能在面试中获得很大的优势。