Java面试宝典:基础三
51. 基本类型为何不能作为HashMap键?注意事项
原因:
- HashMap的键值类型由泛型约束(
HashMap<K, V>
),泛型必须是对象类型(Object
的子类)。 - 基本类型(如
int
)会自动装箱为包装类(如Integer
)。
引用类型作键的注意事项:
- 重写
equals()
和hashCode()
:确保对象逻辑相等性(默认比较地址)。 - 不可变性:推荐使用不可变对象(如
String
、Integer
),防止键值被修改后哈希定位失效。 - 性能优化:
- 避免复杂对象作为键(计算哈希耗性能)。
- 解决哈希冲突:链表转红黑树(Java 8+)。
示例:
Map<String, Integer> map = new HashMap<>(); map.put("key", 10); // String为不可变对象,安全
52. Java多态实现
三大条件:
- 继承:子类继承父类(或实现接口)。
- 重写:子类重写父类方法。
- 向上转型:父类引用指向子类对象。
实现步骤:
class Animal { void sound() { System.out.println("Animal sound"); } }
class Dog extends Animal { @Override void sound() { System.out.println("Bark!"); } // 重写
} public class Test { public static void main(String[] args) { Animal myPet = new Dog(); // 向上转型 myPet.sound(); // 输出 "Bark!"(多态调用) }
}
53. 继承描述正误
题目:以下对继承的描述锚误的是?
A. Java中的继承允许一个子类继承多个父类
B. 父类更具有通用性,子类更具体
C. Java中的继承存在着传递性
D. 实例化子类会递归调用父类构造方法
答案:A
解析:
- Java单继承:一个类只能直接继承一个父类(但可实现多个接口)。
- 传递性:若
C extends B
,B extends A
,则C
拥有A
的成员。 - 构造链:子类构造必先调用父类构造(显式或隐式
super()
)。
54. Math.random() / Math.random() 的值
- 结果范围:
- 若两次随机值均非0,结果在
(0, +∞)
波动(多数情况)。 - 若除数为0(极小概率),结果为
NaN
(非数字)。
- 若两次随机值均非0,结果在
验证代码:
double result = Math.random() / Math.random(); System.out.println(result); // 可能输出 NaN 或极大值
55. Pair 与 Pair 的关系
- 无继承关系:
Pair<Manager>
和Pair<Employee>
是不同类型(泛型擦除后均为Pair
,但编译时独立)。
- 泛型不变性:
// 编译错误! Pair<Employee> pair = new Pair<Manager>(); // ❌ 不兼容类型
解决方法:使用通配符(
Pair<? extends Employee>
)。
56. 接口 vs 抽象类
维度 | 抽象类 | 接口 |
---|---|---|
方法实现 | 可包含具体方法 | Java 8+ 支持 default 方法 |
成员变量 | 可定义普通变量 | 只能是 public static final 常量 |
构造方法 | 有构造方法(子类初始化调用) | 无构造方法 |
继承/实现 | 单继承(extends ) | 多实现(implements ) |
设计理念 | “is-a”关系(代码复用) | “has-a”能力(行为规范) |
使用场景:
- 抽象类:共享通用逻辑(如
Animal
定义公共属性和方法)。 - 接口:定义跨类能力(如
Flyable
、Runnable
)。
57. 同步代码块 vs 同步方法
特性 | 同步方法 | 同步代码块 |
---|---|---|
语法 | 方法前加 synchronized | 代码块内加 synchronized(target) |
锁范围 | 整个方法(粒度大) | 自定义代码块(粒度小,性能更优) |
锁对象 | 实例方法锁 this ,静态方法锁类 | 可指定任意对象 |
示例:
// 同步方法
public synchronized void save() { /* 操作共享资源 */ } // 同步代码块
public void update() { synchronized (lockObject) { // 自定义锁对象 /* 操作共享资源 */ }
}
58. 静态内部类 vs 非静态内部类
特性 | 静态内部类 | 非静态内部类 |
---|---|---|
依赖外部实例 | 不需要(无隐式引用) | 需要(持有 外部类.this 引用) |
静态成员 | 可包含静态方法和属性 | 禁止包含静态成员 |
访问外部成员 | 仅能访问外部类静态成员 | 可访问外部类所有成员 |
实例化 | new Outer.StaticInner() | outerInstance.new NonStaticInner() |
内存泄漏风险:非静态内部类隐含外部类引用,长期持有易导致内存泄漏。
59. 反射机制详解
概念:运行时动态获取类信息并操作类的能力。
核心API:
Class.forName("全类名")
:获取类对象。clazz.getDeclaredFields()
:获取所有属性。clazz.getMethod("方法名", 参数类型)
:获取方法。method.invoke(obj, args)
:调用方法。
应用场景:
- 框架设计(如Spring IOC依赖注入)。
- 动态代理(如AOP实现)。
- 注解处理(如Lombok生成代码)。
缺点:
- 性能开销(反射调用慢于直接调用)。
- 破坏封装性(可访问私有成员)。
60. Java数据库访问包
题目:提供Java存取数据库能力的包是?
A. java.sql
B. java.awt
C. java.lang
D. java.swing
答案:A
解析:
java.sql
:提供JDBC API(Connection
、Statement
等)。java.awt
/javax.swing
:GUI编程。java.lang
:基础类(如String
、Object
)。
61. 合法运算符
题目:下列运算符合法的是?
A. &&
B. <>
C. if
D. =
答案:A、D
解析:
&&
:逻辑与(短路与)。=
:赋值运算符。<>
:Java中表示不等于应为!=
。if
:是关键字,非运算符。
62. 循环代码输出结果
题目:以下代码输出什么?
public class Test { public static void main(String[] args) { int a = 0; int c = 0; do { --c; a = a - 1; } while (a > 0); System.out.println(c); // 输出? }
}
答案:C(-1)
解析:
- 执行
--c
→c = -1
。 - 执行
a = -1
。 - 判断
a > 0
为false
,退出循环。
63. 抽象方法规则
题目:下列哪一种叙述是正确的?
A. abstract可修饰字段、方法和类
B. 抽象方法必须有{}
C. 声明抽象方法,{}
可有可无
D. 声明抽象方法不可写{}
答案:D
解析:
abstract
只能修饰类和方法,不能修饰字段。- 抽象方法无方法体(禁止写
{}
)。
64. 形式参数特性
题目:下列语句正确的是?
A. 形式参数可被视为局部变量(local variable)
B. 形式参数可被字段修饰符修饰
C. 形式参数是方法调用时真正传递的参数
答案:A
解析:
- 形参本质是局部变量:作用域仅限于方法内。
- 修饰符限制:仅可用
final
(防止重赋值)。 - 实参才是真正传递的值:形参是方法定义的占位符。
65. 方法调用权限
题目:下列哪种说法正确?
A. 实例方法可直接调用超类实例方法
B. 实例方法可直接调用超类类方法
C. 实例方法可直接调用其他类实例方法
D. 实例方法可直接调用本类类方法
答案:D
解析:
- D正确:实例方法可调用本类的静态方法(类方法)。
- A/B错误:需考虑访问权限(如父类私有方法不可调用)。
- C错误:需通过对象实例调用其他类实例方法。
66. Java程序类型
题目:Java程序的种类有?
答案:B、C、D
解析:
- Applet:嵌入网页运行的小程序(已淘汰)。
- Application:独立运行的桌面应用(含
main()
方法)。 - Servlet:服务器端程序(处理HTTP请求)。
- 类(Class)是程序的基本单位,但不是程序类型。
67. 编译与环境变量
题目:下列说法正确的有?
答案:B、C、D
解析:
- B:编译时可通过
-classpath
指定路径(覆盖环境变量)。 - C:
javac File1.java File2.java
同时编译多个文件。 - D:
javac -d bin src/*.java
指定输出目录。 - A错误:环境变量在操作系统级别配置,非编译时指定。
68. 非法标识符
题目:下列标识符不合法的有?
答案:A、C、D
解析:
- A:
new
是关键字。 - C:数字开头(违反规则)。
- D:包含非法字符
.
。 - B合法:
$
开头允许(如$Usdollars
)。
69. 数组特性错误说法
题目:下列说法错误的有?
答案:B、C、D
解析:
- A正确:数组是对象(继承
Object
)。 - B错误:Java原生类只有8种基本类型。
- C错误:数组初始化应为
{}
而非()
。 - D错误:数组长度固定不可变。
70. 接口修饰符限制
题目:不能用来修饰interface的有?
答案:A、C、D
解析:
- 接口仅支持
public
或默认(包访问)。 private
/protected
:违反接口开放性原则。static
:接口本身是隐式静态(无需显式声明)。
71. 参数传递规则
题目:下列正确的有?
答案:A、C、D
解析:
- Java只有值传递:
- 基本类型:传递值副本(不影响原值)。
- 引用类型:传递引用副本(不影响原引用地址,但可修改对象内容)。
- D正确:通过引用副本修改对象内容(如集合增删)。
72. 类方法(静态方法)限制
题目:下列说法错误的有?
答案:A、C、D
解析:
- A错误:静态方法中不能使用
this
(无实例)。 - B正确:静态方法可直接调用同类静态方法。
- C错误:可调用其他类的静态方法(如
Math.max()
)。 - D错误:通过实例对象可调用实例方法。
73. 方法存在形式错误说法
题目:下列说法错误的有?
答案:A、B、C
解析:
- A/B错误:Java所有方法必须属于类或对象(无全局函数)。
- C错误:方法属于类的成员(静态方法属于类,实例方法属于对象)。
- D正确:方法调用形式类似函数(
obj.method()
)。
74. 程序运行错误说法
题目:下列说法错误的有?
答案:B、C、D
解析:
- A正确:
java.exe
执行需main()
方法。 - B错误:J2SDK是开发工具包,Java API是类库。
- C错误:
Appletviewer
只运行HTML嵌入的Applet。 - D错误:Applet无需
main()
(由浏览器或Appletviewer
调用生命周期方法)。
75. 小数默认类型
题目:0.3332
的数据类型是?
答案:B(double)
解析:
- Java中小数默认为
double
类型。 - 需显式加
f
后缀表示float
(如0.3332f
)。
76. 接口修饰符
题目:Java接口的修饰符可以为?
答案:D(abstract)
解析:
- 接口默认为
abstract
(可显式声明,通常省略)。 public
或默认包访问也可,但private
/protected
/static
非法。
77. 绕过构造方法创建对象
题目:不通过构造函数也能创建对象吗?
答案:A(是)
解析:
- 反射:
Class.newInstance()
(过时)或Constructor.newInstance()
。 - 克隆:
clone()
(需实现Cloneable
)。 - 反序列化:
ObjectInputStream.readObject()
。
78. 数值溢出问题
题目:存在使 i + 1 < i
的数吗?
答案:存在
解析:
int i = Integer.MAX_VALUE; // 2147483647
System.out.println(i + 1 < i); // true(-2147483648 < 2147483647)
原理:整型溢出后变为最小值。
79. 接口与抽象类关系
问题:
- 接口可否继承接口?
- 可以(支持多继承):
interface A {} interface B extends A {} interface C extends A, B {} // 多继承
- 可以(支持多继承):
- 抽象类是否可实现接口?
- 可以(需实现全部抽象方法或保持抽象):
abstract class MyClass implements Runnable { // 可不实现run(),但类需声明为abstract }
- 可以(需实现全部抽象方法或保持抽象):
- 抽象类是否可继承实体类?
- 可以:
class Concrete {} abstract class AbstractClass extends Concrete {}
- 条件:实体类需有可访问的构造方法(非
private
)。
- 可以: