Java基础笔试核心知识点详解 Java基础是技术笔试的首要考察内容,涵盖了集合框架、反射机制、字符串操作、异常处理、设计模式等核心领域。本文将深入剖析这些知识点,帮助读者系统掌握Java基础的核心内容。
1. 集合框架深度解析 1.1 HashMap与ConcurrentHashMap的实现原理 HashMap实现原理 HashMap基于哈希表实现,采用数组+链表+红黑树的复合结构:
存储结构 :使用Node数组存储键值对,每个Node包含key、value、hash、next四个字段
哈希计算 :通过key的hashCode()计算哈希值,然后通过(n-1) & hash
确定数组索引
冲突处理 :采用链地址法解决哈希冲突,当链表长度≥8且数组长度≥64时转为红黑树
扩容机制 :当元素数量超过阈值(容量×负载因子0.75)时触发扩容,容量变为原来的2倍
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 final V putVal (int hash, K key, V value, boolean onlyIfAbsent, boolean evict) { Node<K,V>[] tab; Node<K,V> p; int n, i; if ((tab = table) == null || (n = tab.length) == 0 ) n = (tab = resize()).length; if ((p = tab[i = (n - 1 ) & hash]) == null ) tab[i] = newNode(hash, key, value, null ); else { Node<K,V> e; K k; if (p.hash == hash && ((k = p.key) == key || (key != null && key.equals(k)))) e = p; else if (p instanceof TreeNode) e = ((TreeNode<K,V>)p).putTreeVal(this , tab, hash, key, value); else { for (int binCount = 0 ; ; ++binCount) { if ((e = p.next) == null ) { p.next = newNode(hash, key, value, null ); if (binCount >= TREEIFY_THRESHOLD - 1 ) treeifyBin(tab, hash); break ; } if (e.hash == hash && ((k = e.key) == key || (key != null && key.equals(k)))) break ; p = e; } } } }
ConcurrentHashMap线程安全机制 ConcurrentHashMap在JDK1.8中采用CAS+synchronized保证线程安全:
存储结构 :与HashMap类似,但Node的val和next字段使用volatile修饰保证可见性
并发控制 :
插入时使用CAS操作保证原子性
当发生哈希冲突时,使用synchronized锁住链表头节点
扩容时支持多线程协助扩容(ForwardingNode机制)
size计算 :使用baseCount和CounterCell数组来统计元素数量,避免全局锁
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 final V putVal (K key, V value, boolean onlyIfAbsent) { if (key == null || value == null ) throw new NullPointerException (); int hash = spread(key.hashCode()); int binCount = 0 ; for (Node<K,V>[] tab = table;;) { Node<K,V> f; int n, i, fh; if (tab == null || (n = tab.length) == 0 ) tab = initTable(); else if ((f = tabAt(tab, i = (n - 1 ) & hash)) == null ) { if (casTabAt(tab, i, null , new Node <K,V>(hash, key, value, null ))) break ; } else if ((fh = f.hash) == MOVED) tab = helpTransfer(tab, f); else { V oldVal = null ; synchronized (f) { if (tabAt(tab, i) == f) { } } } } addCount(1L , binCount); return null ; }
1.2 Vector与ArrayList的线程安全比较
特性
Vector
ArrayList
线程安全
是,所有方法使用synchronized修饰
否,非线程安全
扩容策略
扩容为原来的2倍
扩容为原来的1.5倍
性能
较低,方法级同步开销大
较高,无同步开销
初始容量
10
10
遍历方式
支持Enumeration和Iterator
仅支持Iterator
1 2 3 4 5 6 7 8 9 10 11 12 13 14 public synchronized boolean add (E e) { modCount++; ensureCapacityHelper(elementCount + 1 ); elementData[elementCount++] = e; return true ; } public boolean add (E e) { ensureCapacityInternal(size + 1 ); elementData[size++] = e; return true ; }
1.3 LinkedList的实现机制与适用场景 实现机制 LinkedList基于双向链表实现:
节点结构 :每个节点包含prev、next、item三个字段
头尾指针 :维护first和last指针,支持快速头尾操作
队列特性 :实现了Deque接口,支持队列和栈的操作
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 private static class Node <E> { E item; Node<E> next; Node<E> prev; Node(Node<E> prev, E element, Node<E> next) { this .item = element; this .next = next; this .prev = prev; } } private void linkFirst (E e) { final Node<E> f = first; final Node<E> newNode = new Node <>(null , e, f); first = newNode; if (f == null ) last = newNode; else f.prev = newNode; size++; modCount++; }
适用场景
频繁插入删除 :在中间位置插入删除元素时性能优于ArrayList
队列/栈实现 :作为队列或栈使用时效率很高
内存敏感 :不需要连续的内存空间
2. 反射机制详解 2.1 反射基本原理 反射机制允许程序在运行时获取类的信息并操作类或对象的属性、方法等:
Class对象 :每个类在JVM中都有对应的Class对象,包含了类的完整结构信息
获取方式 :
Class.forName("全限定类名")
类名.class
对象.getClass()
2.2 反射的应用场景 获取类信息 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 Class<?> clazz = Class.forName("java.util.ArrayList" ); System.out.println("类名:" + clazz.getName()); System.out.println("简单类名:" + clazz.getSimpleName()); Package pkg = clazz.getPackage();System.out.println("包名:" + pkg.getName()); Class<?> superClass = clazz.getSuperclass(); System.out.println("父类:" + superClass.getName()); Class<?>[] interfaces = clazz.getInterfaces(); for (Class<?> iface : interfaces) { System.out.println("接口:" + iface.getName()); }
创建对象 1 2 3 4 5 6 7 Class<?> clazz = Class.forName("java.util.ArrayList" ); Object obj = clazz.newInstance(); Constructor<?> constructor = clazz.getConstructor(int .class); Object obj = constructor.newInstance(10 );
调用方法 1 2 3 4 5 6 7 8 9 10 11 Class<?> clazz = Class.forName("java.util.ArrayList" ); Object list = clazz.newInstance();Method addMethod = clazz.getMethod("add" , Object.class);addMethod.invoke(list, "Hello" ); Method sizeMethod = clazz.getMethod("size" );int size = (int ) sizeMethod.invoke(list);
访问字段 1 2 3 4 5 6 7 8 Class<?> clazz = Student.class; Field nameField = clazz.getDeclaredField("name" );nameField.setAccessible(true ); Student student = new Student ();nameField.set(student, "张三" ); String name = (String) nameField.get(student);
2.3 反射的性能优化
缓存Class对象 :避免重复获取Class对象
setAccessible(true) :关闭安全检查提高性能
MethodHandle :JDK7引入的轻量级反射机制
3. 字符串操作深度分析 3.1 String、StringBuilder、StringBuffer区别
特性
String
StringBuilder
StringBuffer
可变性
不可变
可变
可变
线程安全
是(不可变天然线程安全)
否
是
性能
低(频繁修改时)
高
中等
使用场景
字符串常量
单线程字符串操作
多线程字符串操作
String不可变性原理 1 2 3 4 5 6 7 8 9 public final class String { private final char value[]; private final int hash; public String (String original) { this .value = original.value; this .hash = original.hash; } }
StringBuilder实现原理 1 2 3 4 5 6 7 8 9 10 11 12 13 14 abstract class AbstractStringBuilder { char [] value; int count; public AbstractStringBuilder append (String str) { if (str == null ) str = "null" ; int len = str.length(); ensureCapacityInternal(count + len); str.getChars(0 , len, value, count); count += len; return this ; } }
3.2 字符串常量池机制 JVM为了提升性能和减少内存消耗,维护了一块特殊的内存区域——字符串常量池:
1 2 3 4 5 6 7 8 9 10 11 String s1 = "hello" ; String s2 = "hello" ; String s3 = new String ("hello" ); System.out.println(s1 == s2); System.out.println(s1 == s3); String s4 = s3.intern(); System.out.println(s1 == s4);
4. 异常处理体系 4.1 Java异常体系结构 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 Throwable ├── Error(系统级错误,程序无法处理) │ ├── OutOfMemoryError │ ├── StackOverflowError │ └── VirtualMachineError └── Exception(程序可处理的异常) ├── RuntimeException(运行时异常,非受检异常) │ ├── NullPointerException │ ├── ArrayIndexOutOfBoundsException │ ├── ClassCastException │ └── IllegalArgumentException └── 非RuntimeException(受检异常) ├── IOException ├── SQLException └── ClassNotFoundException
4.2 自定义异常实现 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 public class BusinessException extends Exception { private String errorCode; public BusinessException (String message, String errorCode) { super (message); this .errorCode = errorCode; } public String getErrorCode () { return errorCode; } } public class SystemException extends RuntimeException { public SystemException (String message) { super (message); } public SystemException (String message, Throwable cause) { super (message, cause); } }
4.3 异常处理最佳实践 try-with-resources语法 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 BufferedReader br = null ;try { br = new BufferedReader (new FileReader ("file.txt" )); return br.readLine(); } catch (IOException e) { e.printStackTrace(); } finally { if (br != null ) { try { br.close(); } catch (IOException e) { e.printStackTrace(); } } } try (BufferedReader br = new BufferedReader (new FileReader ("file.txt" ))) { return br.readLine(); } catch (IOException e) { e.printStackTrace(); }
异常捕获顺序 1 2 3 4 5 6 7 8 9 10 11 12 try { } catch (FileNotFoundException e) { log.error("文件未找到" , e); } catch (IOException e) { log.error("IO异常" , e); } catch (Exception e) { log.error("未知异常" , e); }
5. 设计模式精讲 5.1 单例模式详解 饿汉式单例 1 2 3 4 5 6 7 8 9 10 public class HungrySingleton { private static final HungrySingleton INSTANCE = new HungrySingleton (); private HungrySingleton () {} public static HungrySingleton getInstance () { return INSTANCE; } }
懒汉式单例(双重检查锁) 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 public class LazySingleton { private volatile static LazySingleton INSTANCE; private LazySingleton () {} public static LazySingleton getInstance () { if (INSTANCE == null ) { synchronized (LazySingleton.class) { if (INSTANCE == null ) { INSTANCE = new LazySingleton (); } } } return INSTANCE; } }
静态内部类单例(推荐) 1 2 3 4 5 6 7 8 9 10 11 12 public class StaticInnerSingleton { private StaticInnerSingleton () {} private static class SingletonHolder { private static final StaticInnerSingleton INSTANCE = new StaticInnerSingleton (); } public static StaticInnerSingleton getInstance () { return SingletonHolder.INSTANCE; } }
枚举单例(最推荐) 1 2 3 4 5 6 7 8 public enum EnumSingleton { INSTANCE; public void doSomething () { } }
5.2 工厂模式 简单工厂模式 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 public interface Car { void run () ; } public class Benz implements Car { @Override public void run () { System.out.println("奔驰在跑..." ); } } public class Bmw implements Car { @Override public void run () { System.out.println("宝马在跑..." ); } } public class SimpleCarFactory { public static Car createCar (String type) { switch (type) { case "benz" : return new Benz (); case "bmw" : return new Bmw (); default : throw new IllegalArgumentException ("未知车型" ); } } }
工厂方法模式 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 public interface CarFactory { Car createCar () ; } public class BenzFactory implements CarFactory { @Override public Car createCar () { return new Benz (); } } public class BmwFactory implements CarFactory { @Override public Car createCar () { return new Bmw (); } }
5.3 观察者模式 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 public interface Subject { void registerObserver (Observer o) ; void removeObserver (Observer o) ; void notifyObservers () ; } public interface Observer { void update (float temperature, float humidity, float pressure) ; } public class WeatherData implements Subject { private List<Observer> observers; private float temperature; private float humidity; private float pressure; public WeatherData () { observers = new ArrayList <>(); } @Override public void registerObserver (Observer o) { observers.add(o); } @Override public void removeObserver (Observer o) { observers.remove(o); } @Override public void notifyObservers () { for (Observer observer : observers) { observer.update(temperature, humidity, pressure); } } public void measurementsChanged () { notifyObservers(); } public void setMeasurements (float temperature, float humidity, float pressure) { this .temperature = temperature; this .humidity = humidity; this .pressure = pressure; measurementsChanged(); } }
6. 高频面试题总结 6.1 集合框架相关
HashMap的put过程是怎样的?
计算key的hash值
通过(n-1)&hash计算索引位置
如果位置为空,直接插入
如果位置不为空,判断key是否相同,相同则覆盖
不同则判断是否为树节点,是则插入红黑树
否则插入链表,链表长度≥8时转为红黑树
HashMap为什么线程不安全?
多线程put可能导致数据丢失
扩容时可能导致链表成环(JDK1.7)
非原子操作导致的数据不一致
ConcurrentHashMap如何实现线程安全?
使用CAS操作保证原子性
synchronized只锁定链表头节点
使用volatile保证可见性
扩容时支持多线程协助
6.2 反射机制相关
反射的优缺点?
优点:动态性、灵活性、框架设计基础
缺点:性能开销、安全限制、代码复杂
如何防止反射破坏单例?
在构造方法中检查实例是否已存在
使用枚举实现单例
使用SecurityManager检查权限
6.3 字符串相关
String为什么设计成不可变?
线程安全
支持字符串常量池
作为HashMap的key安全
避免被恶意修改
StringBuilder和StringBuffer的区别?
StringBuilder非线程安全,性能高
StringBuffer线程安全,方法使用synchronized
6.4 异常处理相关
finally块一定会执行吗?
正常情况下会执行
System.exit()时不会执行
JVM崩溃时不会执行
线程被中断时可能不执行
try-with-resources原理?
编译器自动生成close方法调用
要求资源实现AutoCloseable接口
异常抑制机制
6.5 设计模式相关
单例模式的实现方式?
工厂模式的作用?
解耦对象的创建和使用
统一管理对象的创建
符合开闭原则
参考资料
《Java编程思想》
《Effective Java》
《Java并发编程实战》
JDK 1.8源码
《设计模式:可复用面向对象软件的基础》
本文档会持续更新,如有疑问或建议,欢迎留言讨论!