java基础面试题(2022)

目录

1.JDK、JRE、JVM三者的关系?

2.Java的基本数据类型?

3.在进行小数计算的时候,可以使用double吗?

4.什么是逻辑与和短路与(&和&&)?

5.switch...case判断条件可以使用字符串类型吗?

6.如何定义一个方法?

7.你能说明方法中return的用法吗?

8.请你说一下面向对象的特征?那什么是封装、什么是继承、什么是多态?

9.重写和重载有什么区别?

10.抽象类和接口有什么区别?

11.Java中常用的循环方式有哪些?你能说说他们的区别吗?

12.break和continue有什么区别?

13.什么是嵌套循环?如何跳出嵌套循环?你觉得嵌套循多了有什么样的问题?

14.不写类的构造方法可以吗?如果写了类的有参构造方法,还会有缺省构造方法吗?

15.类的构造器可以被重写吗?那可以被重载吗?

16.基本类型画“==”号和引用类型画“==”号有什么区别?那引用类型要判断内容是否相等应该怎么办?

17.你能说说java中的this和super关键字吗?

18.请你说一下java中的final关键字?

19.请你说一下java中的static关键字?

20.什么是内部类?内部类分类有哪些?

21.通过字面量创建字符串和new一个字符串对象有什么区别?那什么是常量池呢?

22.做字符串拼接的时候可以用String吗?StringBuilder和StringBuffer有什么区别呢?

23.子类重写父类含有抛出异常的方法时,有哪些要求?

24.final、finally、finalize有什么区别?

25.List集合和Set集合有什么区别?

26.集合中的泛型有什么用?

27.常用的List集合有哪些呢?有什么区别?

28.什么是队列?什么是栈?它们遵循什么原则?

29.HashMap的底层数据结构是什么?那什么时候变为红黑树呢?

30.HashMap、HashTable、ConcurrentHashMap有什么区别?

31.什么是CAS算法?

32.HashMap的初始长度是多少?在什么时候进行扩容?

33.我们能否使用任何类作为HashMap的key?

34.你能说说sleep、wait、notify的作用吗?

35.你有用过java中的线程池吗?Java中的线程池(创建线程池的方式)有哪些?那你最常用的线程池是哪种?

36.你能介绍一下ThreadPoolExcutor各参数的含义吗?你觉得核心线程数设置多大比较合理?

37.什么是字节码?采用字节码的好处是什么?

38.有了解过Java类加载器

39.线程的生命周期?线程有几种状态

40.Thread、Runable的区别

41.对守护线程的理解

42.并发、并行、串行的区别

43.线程池中阻塞队列的作用?为什么是先添加列队而不是先

创建最大线程?

44.线程池中线程复用原理

45.用最有效率的方法计算 2 乘以 8

.46.Math.round(11.5) 等于多少?Math.round(-11.5)等于多少

47.访问修饰符 public,private,protected,以及不写(默认)时的区别

 48.面向对象五大基本原则是什么

 49.对象实例与对象引用有何不同?

50.java 中 IO 流分为几种?

51.synchronized和lock区别

52.synchronized实现原理

53.ThreadLocal使用场景与原理


1.JDK、JRE、JVM三者的关系?

JVM是Java虚拟机,是虚拟出来的一个系统,我们常说的hotsport是JVM的一种实现;JRE是Java的最小运行环境,它包含JVM和系统类库;JDK是Java的最小开发环境,它包含JRE+编译运行工具。

2.Java的基本数据类型?

byte(1个字节)

short(2个字节)

char(2个字节)

int(4个字节)

long(8个字节)

double(8个字节)

float(4个字节)

boolean(1个字节)

3.在进行小数计算的时候,可以使用double吗?

如果是对精确度要求不高的时候可以使用double进行小数计算,但如果是对精度要求高的时候则不能使用,例如在银行项目中对资金的一些计算,如果使用double可能会丢失精度,导致结果不正确。(我们可以使用JDK提供的BigDecimal进行计算)

4.什么是逻辑与和短路与(&和&&)?

逻辑与和短路与都是需要整个判断都为true的时候表达式才为true,当某一个判断为false时逻辑与会继续执行后续判断,短路与则不会再继续执行了。(逻辑或和短路或也是如此)

5.switch...case判断条件可以使用字符串类型吗?

在jdk1.7之前只能使用整形,在jdk1.7开始可以使用字符串类型。

6.如何定义一个方法?

修饰词,返回值类型,方法名,参数列表,方法体

7.你能说明方法中return的用法吗?

无返回值方法时,return用于结束方法;有返回值方法时,return用于结束方法并返回值给调用方。

8.请你说一下面向对象的特征?那什么是封装、什么是继承、什么是多态?

封装、继承、多态;

我们把一些具有相同属性或行为的类抽取出来,就是封装;对类的封装,就是封装的对象的属性和行为;对方法的封装,封装的是具体的功能。

继承是为了代码的重用,Java中的继承是单继承的,一旦继承子类就具有父类+子类的属性和行为;

我们声明一个父类型的引用指向子类型的对象,就是多态。多态的主要表现形式就是重写和重载。

9.重写和重载有什么区别?

重写发生在父子类中,方法名称相同,参数列表相同;

重载发生在同一个类中,方法名称相同,参数列表不同;

10.抽象类和接口有什么区别?

接口只能包含常量和抽象方法,接口之间可以继承,接口可以被多实现

抽象类可以包含抽象方法,也可以包含非抽象方法,必须被继承,因为java是单继承的,所以在继承一个类时我觉得应该要慎重考虑。

11.Java中常用的循环方式有哪些?你能说说他们的区别吗?

while循环、do...while循环、for循环,while循环可能一次都不执行、do...while循环至少会执行一次,for循环也有可能一次都不执行,但是我们最常用的循环方式。

12.break和continue有什么区别?

break用于结束循环,continue用于跳过本次循环。

13.什么是嵌套循环?如何跳出嵌套循环?你觉得嵌套循多了有什么样的问题?

嵌套循环就是循环中套循环,外层循环控制行,内层循环控制列,运行规则遵循外层循环走一次,内层循环走所有次;当我们想跳出整个嵌套循环的时候,可以使用outer:标签来定义循环,使用break outer来跳出整个循环;嵌套循环我觉得一般需要控制在3层以内,如果嵌套太多可读性不好,并且可能存在设计问题。

14.不写类的构造方法可以吗?如果写了类的有参构造方法,还会有缺省构造方法吗?

不写类的构造方法,java编译器默认会有缺省无参构造方法;如果写了类的有参构造方法,不会生成缺省方法。

15.类的构造器可以被重写吗?那可以被重载吗?

类的构造器不可以被重写,但可以被重载。

16.基本类型画“==”号和引用类型画“==”号有什么区别?那引用类型要判断内容是否相等应该怎么办?

基本类型画“==”号是判断两个值是否相等;

引用类型画“==””号是判断两个对象在堆的内存地址是否相同;

如果引用类型需要判断内容是否相等,应该使用equals方法;

17.你能说说java中的this和super关键字吗?

java中的this代表的是指向对象本身的一个指针,super是发生在继承关系中的,代表的是指向父类对象的一个指针。

this.成员变量名,是访问本类的成员变量;如果参数super.成员变量名,是访问的父类的成员变量。

this.方法名,是访问本类的方法,我们在调用方法时,可以不写this,编译器会自动生成一个隐式的this;super.方法名,是访问父类的方法。

this(),是访问的本类的构造方法;super()是访问父类的构造方法,并且在初始化子类时,一定会先初始化父类。默认子类中的构造器会隐式的调用super()方法。

18.请你说一下java中的final关键字?

final关键字用于修饰变量、方法、类;

被final修饰的变量,不可以被重新赋值;

被final修饰的类不可被继承;

被final修饰的方法不能被重写。

19.请你说一下java中的static关键字?

static修饰的变量,称为静态变量,存在于方法区(元空间)中;通过类名.变量来访问,当所有对象数据都一样时使用。

static修饰的方法,称为静态方法,存在于方法区(元空间)中;通过类名.方法名来访问,当方法的操作仅与参数有关而与对象无关时使用,例如咱们常写的工具类当中的方法。

还有一种static静态块,在被类加载时自动执行,存在于方法区(元空间)中,常常用于加载静态资源,例如图片,音频,读取文档等。

20.什么是内部类?内部类分类有哪些?

在Java中,可以将一个类的定义放在另外一个类的定义内部,这就是内部类

内部类可以分为四种成员内部类、局部内部类、匿名内部类和静态内部类

21.通过字面量创建字符串和new一个字符串对象有什么区别?那什么是常量池呢?

内存的分配方式不一样,通过字面量创建的字符串对象会分配到常量池中,通过new一个字符串对象会分配到堆中。常量池我的理解是,它存在于方法区(元空间中),使用字面量创建的字符串会直接缓存到常量池中,若再次使用该字面量创建新字符串时,不再创建新对象,而是从常量池中获取。

22.做字符串拼接的时候可以用String吗?StringBuilder和StringBuffer有什么区别呢?

不建议直接用String做拼接,最好使用StringBuilder或者StringBuffer来做拼接。StringBuilder是非线程安全的,效率更高。StringBuffer是线程安全的,效率低一些,但安全。

23.子类重写父类含有抛出异常的方法时,有哪些要求?

不再抛出任何异常;

仅抛出部分异常;

抛出子类异常;

不可以抛出额外异常;

不可以抛出父类异常;

24.final、finally、finalize有什么区别?

final用于修饰类、变量、方法,修饰类表示该类不可被继承,修饰方法表示该方法不可被重写,修饰变量表示变量不可被重新赋值。

finally一般作用在try-catch捕获异常代码块中,不论代码是否发生异常,finally中的代码一定会被执行,通常用来关闭一些资源时使用。

finalize属于Object类中的一个方法,当对象被回收的时候,会调用此方法。

25.List集合和Set集合有什么区别?

List集合是可重复集,而且有序。Set集合是不可重读集,而且无序。

26.集合中的泛型有什么用?

集合中的泛型是用来约束元素的类型的。

27.常用的List集合有哪些呢?有什么区别?

常用的List集合有ArrayList、LinkedList、Vector。ArrayList底层是数组,它的查询速度快,增删速度慢;LinkedList底层是链表,它查询速度慢,增删速度快。ArrayList和LinkedList都是非线程安全的,Vector底层是数组,是线程安全的。

28.什么是队列?什么是栈?它们遵循什么原则?

队列是用于存储一组元素的数据结构,但是存取元素必须遵循先进先出原则。

栈也是用于存储一组元素,存取必须遵循先进后出原则。

29.HashMap的底层数据结构是什么?那什么时候变为红黑树呢?

在JDK1.7的时候是数组+链表;在JDK1.8的时候是数组+链表+红黑树;当链表的长度大于8的时候,就会变为红黑树。

30.HashMap、HashTable、ConcurrentHashMap有什么区别?

HashMap是线程不安全的;HashTable是线程安全的,其内部使用synchronized关键字进行加锁;ConcurrentHashMap结合了HashMap和HashTable,是线程安全的,在JDK1.7其内部使用了分段锁的思想来进行加锁,每一把锁只锁容器中的一部分数据,降低了锁的力度,提高了效率。在JDK1.8的时候使用了CAS+synchronized来保证并发安全

31.什么是CAS算法?

CAS算法的全称是:compareAndSwap的意思,是能保证当操作的线程安全和原子性的算法。CAS算法将预期值和更新值传入方法中进行比较,如果内存值和预期值不同,那么此次操作失败,继续循环获取新的内存值,预期值,更新值,直到这次操作成功,我们称这种操作为线程的自旋,其中的算法我们称为CAS算法。

32.HashMap的初始长度是多少?在什么时候进行扩容?

HashMap的初始长度是16。当容量达到加载因子0.75的时候进行扩容,扩容后的大小一定是2的N次方。

33.我们能否使用任何类作为HashMap的key?

可以,但需要注意的是,如果类重写了equals方法,我们就应当连同重写hashcode方法;因为hashcode的值应当与equals的结果相对应,两个对象若equals比较为true,hashcode值应当相同。两个对象equals比较结果为false,hashcode值最好不同。若依然相同,那么作为key存入HashMap中时会产生链表情况,影响HashMap查询性能。

扩充:认识树

算法动画演示:

https://www.cs.usfca.edu/~galles/visualization/Algorithms.html

二叉搜索树

特点:左子树的键值小于根的键值,右子树的键值大于根的键值;

对该二叉树的节点进行查找发现深度为1的节点的查找次数为1,深度为2的查找次数为2,深度为3的查找次数为3,深度为n的节点的查找次数为n,因此查找时间复杂度依赖于节点深度,如果节点很深,则查找效率降低;

平衡二叉查找树(AVL树)

为了提高二叉查找树的的查找效率,人们又引入了平衡二叉查找树

1.在满足二叉查找树的条件下,还需满足任何节点的两个子树的高度最大差为1,所以它呈现出是一种左右平衡的状态;

下图中左边的是AVL树,它的任何节点的左右两个子树的高度差<=1;而右边的不是AVL树,其根节点的左子树高度为3,而右子树高度为1,两个子树的高度差为2;

2.当我们向平衡二叉树(AVL Tree)插入新的节点(或者删除新的节点),有可能打破它原有的平衡,那么它会通过旋转使其恢复平衡;

3.当插入新节点,失去平衡的二叉树可以概括为四种状态:LL(左左)、RR(右右)、LR(左右)、RL(右左):

4.LL: LeftLeft,也称“左左”,插入或删除一个节点后,根节点的左孩子(Left Child)的左孩子(Left Child)还有非空节点,导致根节点的左子树高度比右子树高度高2,AVL树失去平衡;

5.RR: RightRight,也称“右右”,插入或删除一个节点后,根节点的右孩子(Right Child)的右孩子(Right Child)还有非空节点,导致根节点的右子树高度比左子树高度高2,AVL树失去平衡;

6.LR: LeftRight,也称“左右”,插入或删除一个节点后,根节点的左孩子(Left Child)的右孩子(Right Child)还有非空节点,导致根节点的左子树高度比右子树高度高2,AVL树失去平衡;

7.RL:RightLeft,也称“右左”,插入或删除一个节点后,根节点的右孩子(Right Child)的左孩子(Left Child)还有非空节点,导致根节点的右子树高度比左子树高度高2,AVL树失去平衡;

红黑树

为了解决AVL树需要维护平衡的条件而导致的每次进行增加、删除和修改后对树的结构调整较大,较为耗时的情况,所以红黑树的平衡条件就没有那么的苛刻,这样既降低了增删改对树的结构的调整的耗时,但是也是相对来说是平衡的,所以其也需要旋转。如下图就是一个标准的红黑树

红黑树的性质:

1.每个节点不是红色就是黑色

2.不可能有连在一起的红色节点

3.根节点都是黑色

4.每个红色节点的两个子节点都是黑色

旋转和颜色变换规则:

变色

条件:

(1)当前节点的父亲节点是红色

(2)当前节点的叔叔节点也是红色

步骤:

把父亲节点设置为黑色

把叔叔也设置为黑色

把爷爷节点设为红色

左旋:

条件:

当前节点的父亲节点是红色

当前节点的叔叔节点是黑色

当前节点是右子树

步骤

当前父亲节点是红色,

叔叔是黑色的时候,且当前节点是右子树。

以父亲节点作为左旋。

右旋:当前父亲节点是红色,叔叔是黑色的时候,且当前节点是左子树,进行右旋。

把父亲节点变为黑色

把爷爷节点变为红色

以爷爷节点旋转

34.你能说说sleep、wait、notify的作用吗?

Sleep(Thread的方法)用于线程的休眠,可以指定休眠的时长,如果在一个同步块中,sleep不会释放锁。

wait是Object提供的一个方法,可以对象来进行线程的休眠,如果在一个同步块中,wait会释放锁。

notify也是Object提供的一个方法,可以唤醒处于wait状态的线程,如果在一个同步块中,wait不会释放锁。

35.你有用过java中的线程池吗?Java中的线程池(创建线程池的方式)有哪些?那你最常用的线程池是哪种?

有用过,java中的线程池有4种:

动态的线程池:newCachedThreadPool

固定线程数的线程池:newFixedThreadPool

固定只有一条线程的线程池:newSingleThreadExecutorPool

以固定频率执行的线程池:newScheduledThreadPool

一般来说,这4种线程池都不使用,一般使用ThreadPoolExecutor来自定义线程池。

36.你能介绍一下ThreadPoolExcutor各参数的含义吗?你觉得核心线程数设置多大比较合理?

corePoolSize:核心线程数,指线程池不关闭就一直存活的线程数。maximumPoolSize:最大线程数,指线程池能同时存活的最大线程数。
keepAliveTime:空闲的线程保留的时间,指非核心线程空闲的最大时间,超过这个时间就会将这些空闲的非核心线程销毁掉。
unit:空闲线程的保留时间单位。
workQueue:工作的阻塞队列,存储等待执行的任务。
threadFactory:线程工厂,指定了线程池中的线程的创建方式和销毁方式。
handler:拒绝策略{CallerRunsPolicy(调用者运行策略),AbortPolicy(中止策略),DiscardPolicy(丢弃策略),DiscardOldestPolicy(弃老策略)},指线程池在达到上限(达到最大线程数且任务队列也满了)的情况下的执行逻辑。

最大核心线程数设置为:CPU的核心数 * 2 +1 最为合适

37.什么是字节码?采用字节码的好处是什么?

字节码 Java 源代码经过虚拟机编译器编译后产生的文件(即扩展为 .class 的文件),它不面向任
何特定的处理器,只面向虚拟机。
采用字节码的好处
Java 语言通过字节码的方式,在一定程度上解决了传统解释型语言执行效率低的问题,同时又保留
了解释型语言可移植的特点。所以 Java 程序运行时比较高效,而且,由于字节码并不专对一种特定
的机器,因此, Java 程序无须重新编译便可在多种不同的计算机上运行。

38.有了解过Java类加载器

JDK 自带有三个类加载器: bootstrap ClassLoader ExtClassLoader AppClassLoader
BootStrapClassLoader ExtClassLoader 的父类加载器,默认负责加载 %JAVA_HOME%lib 下的 jar 包和 lass文件。
ExtClassLoader AppClassLoader 的父类加载器,负责加载 %JAVA_HOME%/lib/ext 文件夹下的 jar 包和 class类。
AppClassLoader 是自定义类加载器的父类,负责加载 classpath 下的类文件。系统类加载器,线程上下 文加载器 继承ClassLoader 实现自定义类加载器

39.线程的生命周期?线程有几种状态

1. 线程通常有五种状态,创建,就绪,运行、阻塞和死亡状态。
2. 阻塞的情况又分为三种:
(1) 、等待阻塞:运行的线程执行 wait 方法,该线程会释放占用的所有资源, JVM 会把该线程放入 等待 池” 中。进入这个状态后,是不能自动唤醒的,必须依靠其他线程调用 notify notifyAll 方法才能被唤 醒,wait object 类的方法
(2) 、同步阻塞:运行的线程在获取对象的同步锁时,若该同步锁被别的线程占用,则 JVM 会把该线程放 入“ 锁池 中。
(3) 、其他阻塞:运行的线程执行 sleep join 方法,或者发出了 I/O 请求时, JVM 会把该线程置为阻塞状 态。当sleep 状态超时、 join 等待线程终止或者超时、或者 I/O 处理完毕时,线程重新转入就绪状态。 sleep是 Thread 类的方法
1. 新建状态( New ):新创建了一个线程对象。
2. 就绪状态( Runnable ):线程对象创建后,其他线程调用了该对象的 start 方法。该状态的线程位于 可运行线程池中,变得可运行,等待获取CPU 的使用权。
3. 运行状态( Running ):就绪状态的线程获取了 CPU ,执行程序代码。
4. 阻塞状态( Blocked ):阻塞状态是线程因为某种原因放弃 CPU 使用权,暂时停止运行。直到线程进 入就绪状态,才有机会转到运行状态。
5. 死亡状态( Dead ):线程执行完了或者因异常退出了 run 方法,该线程结束生命周期。

40.Thread、Runable的区别

Thread Runnable 的实质是继承关系,没有可比性。无论使用 Runnable 还是 Thread ,都会 new
Thread ,然后执行 run 方法。用法上,如果有复杂的线程操作需求,那就选择继承 Thread ,如果只是简单的执行一个任务,那就实现runnable

41.对守护线程的理解

守护线程:为所有非守护线程提供服务的线程;任何一个守护线程都是整个 JVM 中所有非守护线程的保姆;
守护线程类似于整个进程的一个默默无闻的小喽喽;它的生死无关重要,它却依赖整个进程而运行;哪天其他线程结束了,没有要执行的了,程序就结束了,理都没理守护线程,就把它中断了;
注意: 由于守护线程的终止是自身无法控制的,因此千万不要把 IO File 等重要操作逻辑分配给它;因为它不靠谱;
守护线程的作用是什么?
举例, GC 垃圾回收线程:就是一个经典的守护线程,当我们的程序中不再有任何运行的 Thread, 程序就不会再产生垃圾,垃圾回收器也就无事可做,所以当垃圾回收线程是JVM 上仅剩的线程时,垃圾回收线程会自动离开。它始终在低级别的状态中运行,用于实时监控和管理系统中的可回收资源。
应用场景:(
1 )来为其它线程提供服务支持的情况;(
2 ) 或者在任何情况下,程序结束时,这个线程必须正常且立刻关闭,就可以作为守护线程来使用;反之,如果一个正在执行某个操作的线程必须要正确地关闭掉否则就会出现不好的后果的话,那么这个线程就不能是守护线程,而是用户线程。通常都是些关键的事务,比方说,数据库录入或者更新,这些操作都是不能中断的。
thread.setDaemon(true) 必须在 thread.start() 之前设置,否则会跑出一个
IllegalThreadStateException 异常。你不能把正在运行的常规线程设置为守护线程。
Daemon 线程中产生的新线程也是 Daemon 的。
守护线程不能用于去访问固有资源,比如读写操作或者计算逻辑。因为它会在任何时候甚至在一个操作的中间发生中断。
Java 自带的多线程框架,比如 ExecutorService ,会将守护线程转换为用户线程,所以如果要使用后台线程就不能用Java 的线程池。

42.并发、并行、串行的区别

串行在时间上不可能发生重叠,前一个任务没搞定,下一个任务就只能等着
并行在时间上是重叠的,两个任务在 同一时刻互不干扰 的同时执行。
并发允许两个任务彼此干扰。统一时间点、只有一个任务运行,交替执行

43.线程池中阻塞队列的作用?为什么是先添加列队而不是先

创建最大线程?

1 、一般的队列只能保证作为一个有限长度的缓冲区,如果超出了缓冲长度,就无法保留当前的任务了,阻塞队列通过阻塞可以保留住当前想要继续入队的任务。
阻塞队列可以保证任务队列中没有任务时阻塞获取任务的线程,使得线程进入 wait 状态,释放 cpu 资源。
阻塞队列自带阻塞和唤醒的功能,不需要额外处理,无任务执行时 , 线程池利用阻塞队列的 take 方法挂起,从而维持核心线程的存活、不至于一直占用cpu 资源
2 、在创建新线程的时候,是要获取全局锁的,这个时候其它的就得阻塞,影响了整体效率。
就好比一个企业里面有 10 个( core )正式工的名额,最多招 10 个正式工,要是任务超过正式工人数 task > core)的情况下,工厂领导(线程池)不是首先扩招工人,还是这 10 人,但是任务可以稍微积压一下,即先放到队列去(代价低)。10 个正式工慢慢干,迟早会干完的,要是任务还在继续增加,超过正式工的加班忍耐极限了(队列满了),就的招外包帮忙了(注意是临时工)要是正式工加上外包还是不能完成任务,那新来的任务就会被领导拒绝了(线程池的拒绝策略)。

44.线程池中线程复用原理

线程池将线程和任务进行解耦,线程是线程,任务是任务,摆脱了之前通过 Thread 创建线程时的
一个线程必须对应一个任务的限制。
在线程池中,同一个线程可以从阻塞队列中不断获取新任务来执行,其核心原理在于线程池对
Thread 进行了封装,并不是每次执行任务都会调用 Thread.start() 来创建新线程,而是让每个线程去 执行一个“ 循环任务 ,在这个 循环任务 中不停检查是否有任务需要被执行,如果有则直接执行,也就是调用任务中的 run 方法,将 run 方法当成一个普通的方法执行,通过这种方式只使用固定的线程就将所有任务的 run 方法串联起来。

45.用最有效率的方法计算 2 乘以 8

2 << 3 (左移 3 位相当于乘以 2 3 次方,右移 3 位相当于除以 2 3 次方)。

.46.Math.round(11.5) 等于多少?Math.round(-11.5)等于多少

Math.round(11.5) 的返回值是 12 Math.round(-11.5) 的返回值是 -11 。四舍五入的原理是在参数
上加 0.5 然后进行下取整。

47.访问修饰符 public,private,protected,以及不写(默认)时的区别

private : 在同一类内可见。使用对象:变量、方法。 注意:不能修饰类(外部类)
default ( 即缺省,什么也不写,不使用任何关键字) : 在同一包内可见,不使用任何修饰符。
使用对象:类、接口、变量、方法。
protected : 对同一包内的类和所有子类可见。使用对象:变量、方法。 注意:不能修饰类
(外部类)。
public : 对所有类可见。使用对象:类、接口、变量、方法
java基础面试题(2022)_第1张图片

 48.面向对象五大基本原则是什么

单一职责原则 SRP(Single Responsibility Principle) 类的功能要单一,不能包罗万象,跟杂货铺似的。
开放封闭原则 OCP(Open Close Principle) 一个模块对于拓展是开放的,对于修改是封闭的,想要增加功能热烈欢迎,想要修改,哼,一万 个不乐意。
里式替换原则 LSP(the Liskov Substitution Principle LSP) 子类可以替换父类出现在父类能够出现的任何地方。比如你能代表你爸去你姥姥家干活。哈哈~~
依赖倒置原则 DIP(the Dependency Inversion Principle DIP) 高层次的模块不应该依赖于低层次的模块,他们都应该依赖于抽象。抽象不应该依赖于具体实 现,具体实现应该依赖于抽象。就是你出国要说你是中国人,而不能说你是哪个村子的。比如说中 国人是抽象的,下面有具体的xx 省, xx 市, xx 县。你要依赖的抽象是中国人,而不是你是 xx 村 的。
接口分离原则 ISP(the Interface Segregation Principle ISP) 设计时采用多个与特定客户类有关的接口比采用一个通用的接口要好。就比如一个手机拥有打电话,看视频,玩游戏等功能,把这几个功能拆分成不同的接口,比在一个接口里要好的多。

 49.对象实例与对象引用有何不同?

对象引用指向对象实例(对象引用存放 在栈内存中)。一个对象引用可以指向0 个或 1 个对象(一根绳子可以不系气球,也可以系一个气 球); 一个对象可以有 n 个引用指向它(可以用 n 条绳子系住一个气球)

50.java 中 IO 流分为几种?

按照流的流向分,可以分为输入流和输出流;
按照操作单元划分,可以划分为字节流和字符流;
按照流的角色划分为节点流和处理流。
InputStream/Reader: 所有的输入流的基类,前者是字节输入流,后者是字符输入流。
OutputStream/Writer: 所有输出流的基类,前者是字节输出流,后者是字符输出流。

51.synchronized和lock区别

区别:1、lock是一个接口,而synchronized是java的一个关键字。2、synchronized在发生异常时会自动释放占有的锁,因此不会出现死锁;而lock发生异常时,不会主动释放占有的锁,必须手动来释放锁,可能引起死锁的发生。在分布式开发中,锁是线程控制的重要途径。Java为此也提供了2种锁机制,synchronized和lock。

52.synchronized实现原理


Java中每一个对象都可以作为锁,这是synchronized实现同步的基础:

普通同步方法,锁是当前实例对象

静态同步方法,锁是当前类的class对象

同步方法块,锁是括号里面的对象

53.ThreadLocal使用场景与原理

ThreadLocal 用作保存每个线程独享的对象,为每个线程都创建一个副本,这样每个线程都可以修改自己所拥有的副本, 而不会影响其他线程的副本,确保了线程安全。
ThreadLocal 用作每个线程内需要独立保存信息,以便供其他方法更方便地获取该信息的场景。每个线程获取到的信息可能都是不一样的,前面执行的方法保存了信息后,后续方法可以通过 ThreadLocal 直接获取到,避免了传参,类似于全局变量的概念。
 

你可能感兴趣的:(java,面试,开发语言)