Java基础面试题(一)
Java基础
1、数据类型
基本数据类型在声明时自动分配空间,引用数据类型声明时只是分配了引用空间,只有在创建对象时才会开辟 空间。
2、标识符命名规则
标识符的含义
类的名字、方法以及变量名称
命名规则(硬性要求)
标识符可以包含英文字母,0-9,$,_;
标识符不能以数字开头;
标识符不能是关键字。
命名规范(非硬性要求)
类名规范:大驼峰式
变量名、方法名规范:小驼峰式
3、instanceof 关键字的作用
其中 obj 为一个对象,Class 表示一个类或者一个接口,当 obj 为 Class 的对象,或者是其直接或 间接子类, 或者是其接口的实现类,结果result 都返回 true,否则返回false。 注意:编译器会检查 obj 是否能转换成右 边的class类型,如果不能转换则直接报错,如果不能确定 类型,则通过编译,具体看运行时定。
1 //false ,在 JavaSE规范 中对 instanceof 运算符的规定就是:如果 obj 为 null,那么将返回 2 false。 3 System.out.println(null instanceof Object);
4、Java自动装箱与拆箱
装箱就是自动将基本数据类型转换为包装类型(int-->Integer)
拆箱就是自动将包装类型转换为基本数据类型(Integer-->int)
IntegerCache类
1 private static class IntegerCache { 2 static final int low = -128; 3 static final int high; 4 static final Integer cache[]; 5 6 static { 7 // high value may be configured by property 8 int h = 127; 9 String integerCacheHighPropValue = 10 sun.misc.VM.getSavedProperty("java.lang.Integer.IntegerCache.high"); 11 if (integerCacheHighPropValue != null) { 12 try { 13 int i = parseInt(integerCacheHighPropValue); 14 i = Math.max(i, 127); 15 // Maximum array size is Integer.MAX_VALUE 16 h = Math.min(i, Integer.MAX_VALUE - (-low) -1); 17 } catch( NumberFormatException nfe) { 18 // If the property cannot be parsed into an int, ignore it. 19 } 20 } 21 high = h; 22 23 cache = new Integer[(high - low) + 1]; 24 int j = low; 25 for(int k = 0; k < cache.length; k++) 26 cache[k] = new Integer(j++); 27 28 // range [-128, 127] must be interned (JLS7 5.1.7) 29 assert IntegerCache.high >= 127; 30 } 31 32 private IntegerCache() {} 33 }
在通过valueOf方法创建Integer对象的时候,如果数值在[-128,127]之间,便返回指向IntegerCache.cache中 已经存在的对象的引用;否则创建一个新的Integer对象。
在某个范围内的整型数值的个数是有限的,而浮点数却不是。
5、重写和重载
重写(Override):
1.发生在父类与子类之间
2.方法名,参数列表,返回类型(除过子类中方法的返回类型是父类中返回类型的子类)必须相同
3.访问修饰符的限制一定要大于被重写方法的访问修饰符(public>protected>default>private)
4.重写方法一定不能抛出新的检查异常或者比被重写方法申明更加宽泛的检查型异常
重载(Overload):
1.重载是一个类中多态性的一种表现
2.重载要求同名方法的参数列表不同(参数类型、参数个数、参数顺序)
3.重载的时候,返回值类型可以相同也可以不相同,无法以返回值类型作为重载方法的区分标准
6、equals与==的区别
==比较的是变量在栈内存中存放的对象的堆内存地址,用来判断两个对象的地址是否相同;如果是具体的阿拉 伯数字,值相等则返回true,如:int a = 10;long b = 10L;double c = 10.0都是相同的,返回true,因为它们都 指向地址为10的堆。
equals用来比较的是两个对象的内容是否相等,由于所有的类都是继承自java.long.Object类的,所以适用于所 有对象。
(如果是Object类的equals方法,没区别,都比较的是虚地址;如果是String类的equals方法,==比较的是虚 地址,equals方法比较的是字符串的内容。)
7、HashCode的作用
HashCode方法:它返回的就是根据对象的内存地址换算出的一个值。这样一来,当集合要添加新的元素时,先 调用这个元素的HashCode方法,就一下子能确定到它应该放置的物理位置上。如果这个位置上没有元素,它就 可以直接存储在这个位置上,不用再进行比较了;如果这个位置上已经有元素了,就调用它的equals方法与新 元素进行比较,相同的话就不存储,不相同就散列在其它的地址。这样一来实际调用equals方法的次数就大大 的降低了,几乎只需要一两次。
8、String、StringBuffer和StringBuilder的区别是什么
String就是只读字符串,是一个对象。从底层源码看就是一个final类型的字符数组,所引用的字符串不能被改变,一经定义无法再增删改。每次对String的操作都会生成新的String对象。
1 private final char value[];
StringBuffer和StringBuilder它们两都继承了AbstractStringBuilder抽象类。它们底层源码都是可变的字符数组。StringBuffer对方法加了同步锁或者对调用的方法加了同步锁,所以是线程安全的。StringBuilder并没有对方法进行加同步锁,所以是非线程安全的可以调用append(),replace(),delete()方法。
1 char[] value;
9、ArrayList和LinkedList的区别
Array(数组)是基于索引(index)的数据结构,它是使用索引在数组中搜索和读取数据是很快的。
缺点:数组初始化必须指定初始化的长度,否则报错。
List是一个有序的集合,可以包含重复的元素,提供了按照索引访问的方式,它继承Collection;它有两个实现类:ArrayList和LinkedList。
ArrayList:可以看作是能够自动增长容量的数组
LinkedList是一个双链表,在添加和删除元素是具有比ArrayList更好的性能
10、HashMap和HashTable的区别
两者父类不同: HashMap是继承自AbstractMap类,而Hashtable是继承自Dictionary类。不过它们都实现了同时实现 了map、Cloneable(可复制)、Serializable(可序列化)这三个接口。
对外提供的接口不同 :Hashtable比HashMap多提供了elments() 和contains() 两个方法。 elments() 方法继承自Hashtable的父类Dictionnary。elements() 方法用于返回此Hashtable中的 value的枚举。 contains()方法判断该Hashtable是否包含传入的value。它的作用与containsValue()一致。事实上, contansValue() 就只是调用了一下contains() 方法。
对null的支持不同 Hashtable:key和value都不能为null。 HashMap:key可以为null,但是这样的key只能有一个,因为必须保证key的唯一性;可以有多个key 值对应的value为null。
安全性不同 :HashMap是线程不安全的,在多线程并发的环境下,可能会产生死锁等问题,因此需要开发人员自己 处理多线程的安全问题。 Hashtable是线程安全的,它的每个方法上都有synchronized 关键字,因此可直接用于多线程中。 虽然HashMap是线程不安全的,但是它的效率远远高于Hashtable,这样设计是合理的,因为大部分的 使用场景都是单线程。当需要多线程操作的时候可以使用线程安全的ConcurrentHashMap。 ConcurrentHashMap虽然也是线程安全的,但是它的效率比Hashtable要高好多倍。因为 ConcurrentHashMap使用了分段锁,并不对整个数据进行锁定。
初始容量大小和每次扩充容量大小不同
计算hash值的方法不同
11、Collection包结构与Collections的区别
Collection是集合类的上级接口,子接口有 Set、List、LinkedList、ArrayList、Vector、Stack、Set;
Collections是集合类的一个帮助类, 它包含有各种有关集合操作的静态多态方法,用于实现对各种集 合的搜索、排序、线程安全化等操作。此类不能实例化,就像一个工具类,服务于Java的Collection框 架。
12、泛型常用特点
“泛型”:泛指的类型。ArrayList作为集合可以存放各种元素,如Integer、String、自定义的各种类型等。例如:只存放Integer类型的元素
1 List<Integer> iniData = new ArrayList<>();
13、Java创建对象的四种方式
new创建新对象
通过反射机制
采用clone(克隆)机制
通过序列化机制
14、两个不相等的对象有相同的hashCode
当hash冲突产生时,一般有以 下几种方式来处理
拉链法:每个哈希表节点都有一个next指针,多个哈希表节点可以用next指针构成一个单向链表,被 分配到同一个索引上的多个节点可以用这个单向链表进行存储;
开放定址法:一旦发生了冲突,就去寻找下一个空的散列地址,只要散列表足够大,空的散列地址总能找 到,并将记录存入;
再哈希:又叫双哈希法,有多个不同的Hash函数.当发生冲突时,使用第二个,第三个….等哈希函数计算 地址,直到无冲突。
15、深拷贝和浅拷贝
浅拷贝:复制基本类型的属性;引用类型的属性复制,复制栈中的变量和变量指向对内存中的对象的指针,不复制堆内存中的对象。
16、final的用法
被final修饰的类不可以被继承;
被final修饰的方法不可以被重写;
被final修饰的变量不可以被改变,如果修饰引用,那么表示引用不可变,引用指向的内容可变;
被final修饰的方法,JVM会尝试将其内联,以提高运行效率;
被final修饰的常量,在编译阶段会存入常量池中。
被final修饰的对象,对象的地址值是不变的。
除此之外,编译器对final域要遵守的两个重排序规则更好:
在构造函数内对一个final域的写入,域随后把这个被构造对象的引用赋值给一个引用变量,这两个操作之间不能重排序;
初次读一个包含final域的对象的引用,与随后初次读这个final域,这两个操作之间不能重排序。
17、静态修饰符static(静态结构)
静态结构不能被垃圾回收机制回收;
静态结构不依赖于某一个对象;
静态结构依赖于类存在的;
静态结构优先于对象加载。
(代码块创建几个对象就执行几次,静态块只在加载类的时候执行一次)、
(执行顺序:静态块 --->实例块---->构造器 继承的时候:父静--->子静---->父实----->父构--->子实---->子构)
1 public class Father { 2 static { 3 System.out.println("父类静态块执行了..."); 4 } 5 6 { 7 System.out.println("父类实例块执行了..."); 8 } 9 10 public Father(){ 11 System.out.println("父类构造器执行了..."); 12 } 13 } 14 public class Son extends Father { 15 static { 16 System.out.println("子类静态块执行了..."); 17 } 18 19 { 20 System.out.println("子类实例块执行了..."); 21 } 22 23 public Son(){ 24 System.out.println("子类构造器执行了"); 25 } 26 27 public static void main(String[] args) { 28 new Son(); 29 } 30 } 31 父类静态块执行了... 32 子类静态块执行了... 33 父类实例块执行了... 34 父类构造器执行了... 35 子类实例块执行了... 36 子类构造器执行了 37 38 Process finished with exit code 0
静态修饰符static 被类的所有对象共享,是判断是否使用静态关键字的条件; 可以通过类名调用,也可以通过对象名调用;
static访问特点:
静态成员方法只能访问静态成员;
在静态方法中不能使用this关键字;
局部变量不可以使用static关键字声明;
只有内部类可以使用static关键字声明;
主方法必须使用static声明。
此外static也多用于修饰内部类,此时称之为静态内部类。
还有一种用法就是静态导包,即import static。
1 import static java.lang.Math.*; 2 public class Test{ 3 public static void main(String[] args){ 4 //System.out.println(Math.sin(20));传统做法 5 System.out.println(sin(20)); 6 } 7 }
18、3*0.1 == 0.3返回值是什么
false,因为有些浮点数不能完全精确的表示出来。
19、a = a + b 与 a += b有什么区别
a += b隐式的将操作的结果类型强制转换为持有结果的类型,而a = a + b则不会自动进行类型转换。
20、try catch finally ,try里有return,finally还执行么
不管有没有出现异常,finally块中代码都会执行;
当try和catch中有return时,finally仍然会执行;
finally是在return后面的表达式运算后执行的(此时并没有返回运算后的值,而是先把要返回的值保 存起来,管finally中的代码怎么样,返回的值都不会改变,任然是之前保存的值),所以函数返回值是 在finally执行前确定的;
finally中最好不要包含return,否则程序会提前退出,返回值不是try或catch中保存的返回值。
21、Exception与Error包结构
运行异常
Java可抛出(Throwable)的结构分为三种类型:被检查的异常(CheckedException),运行时异常 (RuntimeException),错误(Error)。
除数为零时产生的 ArithmeticException异常,数组越界时产生的IndexOutOfBoundsException异常,fail-fast机制产生 的ConcurrentModificationException异常。
线程1通过Iterator在遍历集合A中的元素,在某个时候线程2修改了集合A的结构(是结构上面的 修改,而不是简单的修改集合元素的内容),那么这个时候程序就会抛出ConcurrentModificationException 异常,从而产生fail-fast机制,这个错叫并发修改异常。
常见的五种运行时异常:
ClassCastException(类转换异常)
IndexOutOfBoundsException(数组越界)
NullPointerException(空指针异常)
ArrayStoreException(数据存储异常,操作数组是类型不一致)
BufferOverflowException(写入长度超过允许的长度)
被检查异常
当通过clone()接口 去克隆一个对象,而该对象对应的类没有实现Cloneable接口,就会抛出 CloneNotSupportedException异常。被检查异常通常都是可以恢复的。如:IOException 、FileNotFoundException 、SQLException。
错误
定义:Error类及其子类。
当资源不足、约束失败、或是其它程序无法继续运行的条件发生时,就产生错误。程序本身无法修复这 些错误的。例如,VirtualMachineError就属于错误。出现这种错误会导致程序终止运行。 OutOfMemoryError、ThreadDeath。
22、OOM和SOF的的情况
OutOfMemoryError异常
Java Heap 溢出:
java.lang.OutOfMemoryError:Java heap spacess;
先分清是因为内存泄漏(Memory Leak)还是 内存溢出(Memory Overflow)。
虚拟机栈和本地方法栈溢出
线程请求的栈深度大于虚拟机所允许的最大深度,将抛出StackOverflowError异常;
虚拟机在扩展栈是无法申请到足够的内存空间,将抛出OutOfMemoryError异常;
(注意栈的大小越大可分配空间的线程数就越少)
运行时常量池溢出
java.lang.OutOfMemoryError:PermGenspace
由于常量池分配在方法区内,我们可以通过过-XX:PermSize和-XX:MaxPermSize限制方法区的大小,从而间接限制其中常量池的容量。
方法区溢出
java.lang.OutOfMemoryError:PermGenspace
一个类如果要被垃圾收集器回收,判定条件是很苛刻的。
SOF(堆栈溢出StackOverflow)
StackOverflowError 的定义:当应用程序递归太深而发生堆栈溢出时,抛出该错误。 因为栈一般默认为1-2m
栈溢出原因:递归调用,大量死循环或死循环,全局变量是否过多,数组、List、map数据过大。
23、线程、程序、进程的基本概念及联系
线程:轻量级进程
进程:进程是动态的
程序:含有指令和数据的文件,被存储在磁盘或其他的数据存储设备中,也就是说程序是静态的代码
联系:一个进程就是一个执行中的程序,它在计算机中一个 指令接着一个指令地执行着,同时,每个进程还占有某些系统资源如 CPU 时间,内存空间,文件,输 入输出设备的使用权等等。换句话说,当程序在执行时,将会被操作系统载入内存中。 线程是进程划分 成的更小的运行单位。线程和进程最大的不同在于基本上各进程是独立的,而各线程则不一定,因为同 一进程中的线程极有可能会相互影响。从另一角度来说,进程属于操作系统的范畴,主要是同一段时间 内,可以同时执行一个以上的程序,而线程则是在同一程序内几乎同时执行一个以上的程序段。
24、线程基本状态
新建状态(NEW)
就绪状态(Runnable)
运行状态(Running)
阻塞状态(Blocked)
死亡状态(Dead)
25、Java序列化中如果有些字段不想被序列化,怎么办
对于不想进行序列化的变量,使用 transient 关键字修饰。
transient 关键字的作用是:阻止实例中那些用此关键字修饰的的变量序列化;当对象被反序列化时, 被 transient 修饰的变量值不会被持久化和恢复。
transient 只能修饰变量,不能修饰类和方法。
26、Java中IO流
流的流向分:输入流和输出流
操作单元划分:字节流和字符流
流的角色分:节点流和处理流
InputStream/Reader: 所有的输入流的基类,前者是字节输入流,后者是字符输入流。
OutputStream/Writer: 所有输出流的基类,前者是字节输出流,后者是字符输出流。
https://pic1.zhimg.com/80/v2-eb408ac849a679b09941be7ebd734768_720w.webp(Java IO的图 )
27、Java IO与NIO的区别
实现方式不同,NIO主要用到的是块,所以NIO的效率要比IO高很多。
Java API中提供了两套NIO,一套是针对标准输入输出NIO,另一套就是网络编程NIO。
28、Java反射的作用原理
定义:
反射机制在Java中,只要给定类的名字,就可以通过反射机制来获得类的所有信息。动态获取的信息以及动态调用对象的方法的功能称为Java语言的反射机制。
用到反射的地方:
jdbc就是典型的反射,如hibernate,struts等框架使用反射机制实现的。
反射的实现:第一步:获取Class对象,有4中方法:
1)Class.forName(“类的路径”);
2)类名.class
3)对象名.getClass()
4)基本类型的包装类,可以调用包装类的Type属性来获得该包装类的Class对象
实现Java反射的类:
1)Class:表示正在运行的Java应用程序中的类和接口 注意: 所有获取对象的信息都需要Class类来实现。
2)Field:提供有关类和接口的属性信息,以及对它的动态访问权限。
3)Constructor:提供关于类的单个构造方法的信息以及它的访问权限
4)Method:提供类或接口中某个方法的信息
反射机制的优缺点:
优点:
1)能够运行时动态获取类的实例,提高灵活性;
2)与动态编译结合
缺点:
1)使用反射性能较低,需要解析字节码,将内存中的对象进行解析。
解决方案:
1、通过setAccessible(true)关闭JDK的安全检查来提升反射速度;
2、多次创建一个类的实例时,有缓存会快很多
3、ReflectASM工具类,通过字节码生成的方式加快反射速度
2)相对不安全,破坏了封装性(因为通过反射可以获得私有方法和属性)
29、List、Set、Map三者的区别
List(对付顺序的好帮手): List接口存储一组不唯一(可以有多个元素引用相同的对象),有序的 对象
Set(注重独一无二的性质): 不允许重复的集合。不会有多个元素引用相同的对象。
Map(用Key来搜索的专家): 使用键值对存储。Map会维护与Key有关联的值。两个Key可以引用相 同的对象,但Key不能重复,典型的Key是String类型,但也可以是任何对象。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· AI技术革命,工作效率10个最佳AI工具