Java面试基础知识点
第一章 Java核心基础语法
1.1 基本数据类型与包装类
1.1.1 8种基本数据类型
1.1.2 自动装箱与拆箱
自动装箱(Autoboxing):编译器自动将基本类型转换为对应的包装类对象。
自动拆箱(Unboxing):编译器自动将包装类对象转换为基本类型。
// 自动装箱:编译器会调用 Integer.valueOf(100)Integera=100;// 自动拆箱:编译器会调用 a.intValue()intb=a;// 实际编译后等价于:Integera=Integer.valueOf(100);intb=a.intValue();1.1.3 Integer缓存机制(高频面试题)
Integer 内部维护了一个 IntegerCache 缓存数组,默认缓存范围是 -128 ~ 127。当调用 Integer.valueOf() 或自动装箱时,会先检查缓存,如果值在范围内则直接返回缓存对象,否则 new 一个新对象。`// 源码(JDK 8)
// 源码(JDK 8)publicstaticIntegervalueOf(inti){if(i>=IntegerCache.low&&i<=IntegerCache.high)returnIntegerCache.cache[i+(-IntegerCache.low)];returnnewInteger(i);}// 面试常见陷阱题Integera=100,b=100;System.out.println(a==b);// true — 在缓存范围内,同一对象Integerc=200,d=200;System.out.println(c==d);// false — 超出缓存,不同对象Integere=newInteger(100);Integerf=newInteger(100);System.out.println(e==f);// false — new 一定创建新对象// 可通过JVM参数调整缓存上限// -Djava.lang.Integer.IntegerCache.high=500面试技巧:回答时要说清楚三点:① 缓存范围默认 -128~127 ② valueOf() 方法会先查缓存 ③ new Integer() 不经过缓存,一定创建新对象。
1.2 String / StringBuilder / StringBuffer
1.2.1String / StringBuilder / StringBuffer的区别
1.2.2 String不可变的原因与好处
●安全性:String 被广泛用作参数(如网络连接、文件路径),不可变防止被篡改
●字符串常量池:不可变使得同一个字符串可以被多个引用共享,节省内存
●HashMap的key:不可变保证了 hashCode 不变,如果 String 可变,放入 HashMap 后修改会导致数据丢失
●线程安全:不可变对象天然是线程安全的,不需要同步
// JDK 8 底层实现:final char[] valuepublicfinalclassString{privatefinalcharvalue[];// final修饰,不可变}// JDK 9+ 底层实现:final byte[] value + coder 标识编码// 优化:Latin1字符用1字节,中文用2字节,节省空间publicfinalclassString{privatefinalbyte[]value;// JDK9改用byte[]privatefinalbytecoder;// LATIN1=0, UTF16=1}1.2.3 字符串常量池
字符串常量池(String Pool)是 JVM 在堆中开辟的一块区域(JDK7+从方法区移到堆),用于存储字符串字面量,实现字符串的复用。
Strings1="hello";// 字面量,放入常量池Strings2="hello";// 从常量池取出同一个对象,s1 == s2 为 trueStrings3=newString("hello");// 在堆中创建新对象,s1 != s3Strings4=s3.intern();// intern() 返回常量池中的引用,s1 == s4 为 true// 重要:JDK7+ intern() 如果常量池没有,会在常量池记录堆中对象的引用(而非复制)Strings5=newStringBuilder("ja").append("va").toString();System.out.println(s5.intern()==s5);// true(JDK7+)1.2.4 String拼接的性能差异
// ❌ 反例:每次循环创建新的String对象,产生大量垃圾Stringresult="";for(inti=0;i<10000;i++){result+=i;// 等价于 result = new StringBuilder(result).append(i).toString();}// ✅ 正例:使用StringBuilder,只创建一个对象StringBuildersb=newStringBuilder();for(inti=0;i<10000;i++){sb.append(i);}Stringresult=sb.toString();// 编译优化:单个表达式的+拼接会自动优化为StringBuilderStrings="a"+"b"+"c";// 编译器优化 → "abc"1.3 面向对象(封装、继承、多态)
1.3.1 封装(Encapsulation)
封装是将对象的属性和行为包装在一起,通过访问修饰符隐藏内部实现细节,只暴露必要的接口。
publicclassBankAccount{privatedoublebalance;// 私有属性,外部不能直接访问// 通过公有方法控制访问,可以加入业务逻辑校验publicdoublegetBalance(){returnbalance;}publicvoiddeposit(doubleamount){if(amount<=0)thrownewIllegalArgumentException("金额必须大于0");balance+=amount;}publicvoidwithdraw(doubleamount){if(amount>balance)thrownewIllegalArgumentException("余额不足");balance-=amount;}1.3.2 继承(Inheritance)
继承是子类获得父类的属性和方法,实现代码复用。Java 只支持单继承(一个类只能有一个直接父类),但支持多重实现(实现多个接口)。
// 父类classAnimal{protectedStringname;publicvoideat(){System.out.println(name+" is eating");}}// 子类继承父类classDogextendsAnimal{publicvoidbark(){System.out.println(name+" is barking");}@Overridepublicvoideat(){// 方法重写System.out.println("Dog "+name+" is eating");}}// super 关键字classPuppyextendsDog{publicvoidshow(){super.eat();// 调用父类方法}}1.3.3 多态(Polymorphism)—— 核心重点
多态是指同一个行为具有多个不同表现形态。Java中多态分为两种:
- 编译时多态(静态绑定)——方法重载(Overload)
同一个类中,方法名相同,参数列表不同(类型、数量、顺序),返回值可以不同但不能仅靠返回值区分。
classCalculator{publicintadd(inta,intb){returna+b;}publicdoubleadd(doublea,doubleb){returna+b;}// 参数类型不同publicintadd(inta,intb,intc){returna+b+c;}// 参数个数不同}- 运行时多态(动态绑定)——方法重写(Override)
子类重写父类方法,父类引用指向子类对象,实际调用的是子类的方法。这是面试考察的重点。
classAnimal{publicvoidsound(){System.out.println("Animal sound");}}classCatextendsAnimal{@Overridepublicvoidsound(){System.out.println("Meow");}}classDogextendsAnimal{@Overridepublicvoidsound(){System.out.println("Woof");}}// 多态体现:父类引用指向子类对象Animala1=newCat();Animala2=newDog();a1.sound();// 输出 Meow — 运行时确定调用Cat的方法a2.sound();// 输出 Woof — 运行时确定调用Dog的方法// 多态的实际应用:工厂模式、策略模式、依赖注入等