2024 Java核心知识点精心整理(全是精华)

最后

看完上述知识点如果你深感Java基础不够扎实,或者刷题刷的不够、知识不全面

小编专门为你量身定制了一套<Java一线大厂高岗面试题解析合集:JAVA基础-中级-高级面试+SSM框架+分布式+性能调优+微服务+并发编程+网络+设计模式+数据结构与算法>

image

针对知识面不够,也莫慌!还有一整套的<Java核心进阶手册>,可以瞬间查漏补缺

image

全都是一丢一丢的收集整理纯手打出来的

更有纯手绘的各大知识体系大纲,可供梳理:Java筑基、MySQL、Redis、并发编程、Spring、分布式高性能架构知识、微服务架构知识、开源框架知识点等等的xmind手绘图~

image

image

本文已被CODING开源项目:【一线大厂Java面试题解析+核心总结学习笔记+最新讲解视频+实战项目源码】收录

需要这份系统化的资料的朋友,可以点击这里获取

实例变量和实例方法的特点:

都必须通过实例对象才可以访问。(实例变量位于堆中,生命周期取决于实例的生命周期)

12、Java编译后的.class文件包含了哪些内容?

编译后的.class文件是一组以8位字节为基础单位的二进制流,各个数据项目严格按照顺序紧凑地排列在.class文件之中,中间没有添加任何分隔符;

根据Java虚拟机规范的规定,.class文件格式采用一种类似于C语言的伪结构来存储数据,包含无符号数和表:

无符号数:以u1、u2、u4、u8来分别代表1个字节、2个字节、4个字节和8个字节的无符号数,无符号数可以用来描述数字、索引引用、数量值或者按照UTF-8编码构成的字符串值;

:由多个无符号数或者其他表作为数据项构成的复合数据类型,所有表都习惯性的以”_info“结尾。

Class文件的结构没有分隔符,无论你是数量还是顺序,都是严格规定的,哪个字节代表什么含义、长度多少、先后顺序如何,都不允许改变。

详见.class文件剖析

13、简述zset实现原理

一两句话说不清楚,就是一种数据结构,打个比方

1、2、3、4、5、6、7、8、9

要找到8,我得遍历8次

如果我把1、3、5、7、9拎出来作为一个类似索引的东西

找8的时候,先在索引里面找,8在7和9中间,找到7以后再遍历1次就找到了8,总共遍历5次

而这个1、3、5、7、9的索引还可以拎个1、5、9出来,以此类推

回到zset,它维护了两个元素,一个是 dict,用来维护数据到分数的关系,一个是zskiplist,用来维护分数所在链表的关系

14、简述协程的优缺点

协程是一种轻量级线程

优点:

跨平台

跨体系架构

无需线程上下文切换的开销

无需原子操作锁定及同步的开销

方便切换控制流,简化编程模型

高并发+高扩展性+低成本:一个CPU支持上万的协程都不是问题。所以很适合用于高并发处理。

缺点:

无法利用多核资源,协程的本质是个单线程,它不能同时将 单个CPU 的多个核用上,协程需要和进程配合才能运行在多CPU上.当然我们日常所编写的绝大部分应用都没有这个必要,除非是cpu密集型应用。

进行阻塞(Blocking)操作(如IO时)会阻塞掉整个程序,这一点和事件驱动一样,可以使用异步IO操作来解决

15、如何判断一个hash函数好不好?

1、计算性能

2、离散性

hash算法一定要把数据哈希均匀,不能全部挤在一坨,对hash算法不太清楚的必须看看这篇文章,我以前花了整整一天时间写的,举了很多例,真正搞懂hashCode和hash算法

16、http中get和post的区别?

GET在浏览器回退时是无害的,而POST会再次提交请求。

GET产生的URL地址可以被Bookmark,而POST不可以。

GET请求会被浏览器主动cache,而POST不会,除非手动设置。

GET请求只能进行url编码,而POST支持多种编码方式。

GET请求参数会被完整保留在浏览器历史记录里,而POST中的参数不会被保留。

GET请求在URL中传送的参数是有长度限制的,而POST么有。

对参数的数据类型,GET只接受ASCII字符,而POST没有限制。

GET比POST更不安全,因为参数直接暴露在URL上,所以不能用来传递敏感信息。

GET参数通过URL传递,POST放在Request body中。

(本标准答案参考自w3schools)

然而实际上,它们的本质都是 TCP 连接,并无区别。上面的答案纯粹是为了应付面试官。真正导致产生区别的原因是 HTTP 的规定以及浏览器/服务器的限制,这才导致它们在应用过程中可能会有所不同。

17、解决hash冲突的方式?

拉链法

代表作:hashMap

原理:把所有hash值相同的元素放到链表中

再哈希法

原理:产生冲突时,对结果再进行一次hash,直到没有hash冲突,一般没人用,太鲁莽了,而且治标不治本,理论上永远不能彻底解决hash冲突

开放地址法

1、线性探测法

2、线性补偿探测法

3、伪随机探测

18、简述装饰者模式和适配器模式

装饰者模式

概括:在不改变现有对象结构的情况下,动态地给该对象增加一些职责(即增加其额外功能),它属于结构型模式,mybatis-plus的QueryWrapper就是装饰者模式的体现

适配器模式

概况:将一个接口转换成用户需要的另一个接口,使接口不兼容的那些类可以一起工作,也属于结构型模式,SpringMvc中的HandlerAdapter就是适配器模式的体现

19、hashCode和equals方法的联系

java规定:

如果两个对象的hashCode()相等,那么他们的equals()不一定相等。

如果两个对象的equals()相等,那么他们的hashCode()必定相等。

对hash算法不太清楚的同学必须看看这篇文章,我以前花了整整2天时间写的,举了很多例,真正搞懂hashCode和hash算法

20、什么是重写和重载?

1、重写是在子类存在方法与父类的方法的名字相同,而且参数的个数与类型一样,返回值也一样的方法,就称为重写(Override)

2、重载是一个类中定义了多个方法名相同,而他们的参数的数量不同或数量相同而类型和次序不同,则称为方法的重载(Overload)

3、重载是一个类的多态性表现,而重写是子类与父类的一种多态性表现

21、Java有几种基本数据类型?分别占用多少字节?

| 数据类型 | 占用字节 |

| — | — |

| byte | 1 |

| short | 2 |

| int | 4 |

| long | 8 |

| char | 2(c语言是1字节,可以存储一个汉字) |

| float | 4 |

| double | 8 |

| boolean | 1/8 |

22、Java异常有哪些类型?

Java所有的异常都继承至Throwable,分为Error和Exception两大类,其中:

Error是系统级错误,在代码层无法处理,常见的有StackOverflowError、OutOfMemoryError等;

Exception是异常,通常可以在代码层处理,常见的有NullpointerException、ClassCaseException、IndexOutOfBoundsException等

23、简述jvm内存模型?

程序计数器:线程私有,各线程之间独立储存,互不影响,若当前执行的是Java方法,则记录的就是当前执行指令的地址,若是native方法,则为空;

java虚拟机栈:线程私有,每个方法在执行时都会创建一个栈帧,方法执行过程就是栈帧在虚拟机栈中从入栈到出栈的过程,入栈表示方法开始被调用,出栈表示方法执行完毕,栈帧用于保存方法内部局部变量、操作数、方法返回值、动态链接;我们平时说的栈其实一般就是指局部变量区:用于存放方法参数、方法内定义的局部变量,还有已知的八大基本数据类型、对象引用、返回值地址;

本地方法栈:线程私有,和虚拟机栈相似,区别在于虚拟机栈的服务对象是java方法,而本地方法栈是本地方法;

堆:线程共享,在虚拟机启动的时候创建,用于存放对象实例,堆是GC管理的主要区域;

方法区:线程共享,其实方法区也是堆的物理组成部分,用于存放常量、静态变量 、 类信息(构造方法/接口定义) 、运行时常量池;注意, 实例变量在堆内存中,和方法区无关。

(jdk1.8之前,方法区的实现是永久代,从1.8开始,用元空间代替了永久代,注意一点,方法区还是那个方法区

这一坨内容请酌情观看,我怕把你绕晕~

再细分的话还有运行时常量池和字符串常量池:jdk1.6的时候,两者都是属于方法区,1.7开始,字符串常量池被移到了堆内存;运行时常量池用于存放编译期生成的各种常量(“abc”,123等)和符号引用;而字符串常量池是为了提高jvm效率单独用来存放字符串的,因为字符串不同于其他数据类型,它可以很长很长很长很长很长很长很长很长很长很长很长很长~;

24、简述GC机制,新生代和老年代的区别?

垃圾回收是java管理内存的一种机制,作用是清理无用对象避免内存泄漏,gc主要发生在java堆上,而堆可以细分为新生代和老年代(分代是为了提高gc效率,其实不分代也可以完成gc,只不过gc机制会对堆的所有区域进行扫描,浪费资源),新生代还可以细分为三个虚拟的区,Eden区、FromSurvivor区、ToSurvivor区,一开始对象都在Eden区,Eden区的对象经过一次新生代gc(复制算法)后若还能存活,就会移动到survivor区(ToSurvivor区),在此次新生代gc时,在survivor发生的改变就是,From区中的对象会根据年龄来决定去留,达到阈值,会移动到老年代,没达到就移动到To区,经过此次新生代gc,Eden和From区都已被清空,From区和To区会互换;

新生代gc(Minor GC)触发时机:当Eden区没有足够空间进行分配时;

老年代gc(Major GC/Full GC)触发时机:当老年代中没有足够的内存空间来存放对象时,虚拟机会发起一次Major GC/Full GC。只要老年代的连续空间大于新生代对象总大小或者历次晋升的平均大小就会进行Minor GC,否则将进行Full GC。

25、如何优化JVM频繁Minor GC?

最简单的就是适当扩大堆内存太小

26、简述类加载机制,什么是双亲委派?

1、加载:将源文件(代码)编译成.class文件,传递给类加载器

2、验证:类加载器拿到这些字节码文件后开始执行检查(通过本地类库),确保加载进来的字节流格式符合java虚拟机要求

3、准备:对类变量(不是实例变量)分配内存,并且给一个默认初始化的值(0或者null)

4、解析:将常量池中的符号引用加载成直接引用(如string str = new string(“123”),str就是符号引用,123是直接引用)

5、初始化:对类的静态变量初始化为指定的值,执行静态代码块

双亲委派机制:如果一个类加载器收到了类加载的请求,它首先不会自己去尝试加载这个类,而是把这个请求委派给父类加载器去完成,每一个层次的类加载器都是如此。

因此所有的加载请求最终都应该传送到顶层的启动类加载器中,只有当父加载器反馈自己无法完成这个加载请求(它的搜索范围中没有找到所需的类)时,子加载器才会尝试自己去加载。

27、synchronized底层实现原理?它与lock相比有什么优缺点?

首先那些说看过synchronized源码的基本都是大聪明,synchronized根本点不进去,想弄懂它的实现原理,我们只能通过看编译好的字节码文件

原理:

基于对象的监视器(ObjectMonitor),我们在字节码文件里面可以看到,在同步方法执行前后,有两个指令,方法前monitorenter,方法后monitorexit;

关于字节码一两句话说不清楚,我单独写了篇synchronized底层实现原理,保证你五分钟看懂

与lock对比:

1、synchronized不需要手动释放锁,lock需要在锁用完后进行unlock;

2、synchronized只能是默认的非公平锁,lock可以指定使用公平锁或者非公平锁;

3、lock提供的Condition(条件)可以指定唤醒哪些线程,而synchronized只能随机唤醒一个或者全部唤醒;

28、jvm指令重排原因?怎么避免?

原因:计算机内存操作速度远慢于CPU运行速度,所以就造成CPU空置,为了将提高CPU利用率,虚拟机会按照自己的一些规则会跳过执行慢的代码,去执行快的代码(即对代码重新排序),从而提升jvm的整体性能。

怎么避免:给关键的代码加上volatile关键字,所谓关键,就是会被执行顺序影响结果。

volatile关键字的三个特征是:线程可见、不具备原子性、禁止指令重排,volatile 的读性能消耗与普通变量几乎相同,但是写操作稍慢,因为它需要在本地代码中插入许多内存屏障指令来保证处理器不发生乱序执行。

29、ReentrantLock是什么?有什么用?怎么用?和synchronized的区别?

ReentrantLock是Lock的一个子类

在这里插入图片描述

作用:

用来给资源加锁,避免高并发造成的数据异常问题;

使用:

public void lockTest() {

int i = 0;

//创建lock实例,可传参数true或者false,表示是否是公平锁,默认是非公平锁

ReentrantLock lock = new ReentrantLock();

//在需要保证同步的代码前lock

lock.lock();

i++;

//代码后unlock

lock.unlock();

}

与synchronized主要区别,lock需要手动释放锁,可以指定公平锁或者非公平锁

这里只是为了便于理解,实际使用时我们会把代码块try起来,把unlock丢在finally里面

30、volatile关键字解决了什么问题?实现原理是什么?

解决了什么问题:

1、保证了变量的可见性

2、禁止指令重排

比如i=i+1,单线程操作没问题,如果使用多线程,比如两个线程,执行这段代码后(i初始值为0),i应该等于2,但是如果不用volatile修饰变量i,结果会等于1,初始时,两个线程分别读取i的值存入各自所在的CPU的高速缓存当中,然后线程1进行加1操作,然后把i的最新值1写入到内存。此时线程2的高速缓存当中i的值还是0,进行加1操作之后,i的值为1,然后线程2把i的值写入内存。

实现原理

基于内存屏障,关于内存屏障,搞java开发的同学在开发中不可能接触到,所以不用关心太多,知道内存屏障有什么作用,面试官问到你能唬住他就行了,因为面试官自己也不懂

(1)它确保指令重排序时不会把其后面的指令排到内存屏障前面,也不会把前面的指令排到内存屏障后面,总之一句话,他能保证指令按照我们希望的顺序执行

(2)它会强制将对缓存的修改操作立即写入主存,使得其它线程能立马发现;

31、ThreadLocal实现原理?

ThreadLocal中文名叫线程变量,它底层维护了一个map,key就是当前的ThreadLocal对象(可以理解为当前执行该段代码的线程),value就是你set的值,这个map保证了各个线程的数据互不干扰

想进一步了解ThreadLocal的同学请移步我凭ThreadLocal唬住了京东面试官

32、线程池实现原理?

要说实现原理,必须得把线程池的几个参数彻底搞懂,不要死记硬背

1、corePoolSize(必填):核心线程数。

2、maximumPoolSize(必填):最大线程数。

3、keepAliveTime(必填):线程空闲时长。如果超过该时长,非核心线程就会被回收。

4、unit(必填):指定keepAliveTime的时间单位。常用的有:TimeUnit.MILLISECONDS(毫秒)、TimeUnit.SECONDS(秒)、TimeUnit.MINUTES(分)。

5、workQueue(必填):任务队列。通过线程池的execute()方法提交的Runnable对象将存储在该队列中。

6、threadFactory(可选):线程工厂。一般就用默认的。

7、handler(可选):拒绝策略。当线程数达到最大线程数时就要执行饱和策略。

贴心的博主单独给你们写了篇讲线程池的,五分钟就能看懂的那种,请移步线程池实现原理吐血总结

33、java是如何实现线程安全的?哪些数据结构是线程安全的?

1、锁机制:用synchronize、lock给共享资源加锁;

2、使用java提供的安全类:java.util.concurrent包下的类自身就是线程安全的,在保证安全的同时还能保证性能;

线程安全的数据结构:

常见的有Atomicinteger、ConcurrentHashMap,太多了,截个图吧,大家可以自己去java.util.concurrent包下看

在这里插入图片描述

34、java线程间通信方式

1、基于synchronized+wait() 和 notify()

2、基于reentrantLock的Condition

3、基于volatile

4、基于CountDownLatch

一两句话说不清楚,单独写了篇,每个方式我都给了demo,复制就能运行,请移步java线程间通讯的几种方式

35、springMvc的controller是单例还是多例?

默认是单例,可以通过@Scope(“prototype”)注解指定成多例,但一般没人这么干

36、什么是redis缓存穿透、缓存击穿、缓存雪崩?如何解决?

从事态严重性来讲:穿透 > 雪崩 > 击穿

缓存穿透:请求数据库中根本就不存在的数据,既然数据库中都没有,缓存中更没有,导致每次请求直接怼到数据库;

缓存雪崩:缓存大面积失效;

缓存击穿:请求了很多缓存中没有但是数据库中真实存在的数据,一般是缓存过期导致,也导致请求直接怼到数据库;

解决办法:

缓存穿透:最简单的就是利用布隆过滤器过滤非法key,我写了个 demo来分析具体原理,请移步布隆过滤器原理

缓存雪崩:设置key过期时间的时候加上一个随机数,关键点就在于让key错开时间失效;

缓存击穿:延长热点数据过期时间,或者直接设置永远不过期;

37、说说数据库设计三范式?

第一范式

属性(字段)的原子性约束,要求属性具有原子性,不可再分割; 比如个人信息,个人信息不能作为一个字段,它可以再分为姓名、name、age等;

第二范式

记录的惟一性约束,要求记录有惟一标识,每条记录需要有一个属性来做为实体的唯一标识;

第三范式

字段冗余性的约束,即任何字段不能由其他字段派生出来;主键没有直接关系的数据列必须消除,消除的办法就是再创建一个表来存放他们,当然外键除外;

误区:

并不是非得严格按照三范式来设计,好的数据库设计一定不是这样的,而是根据实际情况柔性处理;

38、简单阐述Java中的io、nio、bio

i/o即input/output,就是指读写操作

面试官经常问io和nio的区别,如果把io和nio放一起比较的话,那这里的io其实可以理解为bio,即blocking-io:

bio:同步阻塞

bio是java传统的io模型,他是同步阻塞io,一个线程触发io操作后,必须等待这个io操作执行完成,期间不能去做其他事情;

nio:同步非阻塞

nio(non-blocking-io)是同步非阻塞io,一个线程触发io操作后它可以立即返回,但是他需要不断地轮询去获取返回结果;

aio:异步非阻塞

aio(Asynchronous-io)是异步非阻塞io,一个线程触发io操作后她可以立马返回去做其他事情,内核系统将io操作执行完成后会通知线程;

多路复用io:异步阻塞

io多路复用:可以理解为异步阻塞io,但官方没这么叫,一个线程可以管理多个连接,不用来回切换;

39、什么是内存泄漏,怎么确定内存泄漏?

概念:内存泄漏就是指jvm内存没有及时释放,用人话说就是使用完的对象没有被及时回收

怎么确认:linux有个工具叫valgrind,一两句话说不清楚,单独拎出来讲,移步使用valgrind来检查内存泄漏

40、实现单例设计模式(懒汉、饿汉)

//懒汉,顾名思义比较懒,在用的时候才实例化

public class Singleton {

//创建实例,注意,此时没有new

private static volatile Singleton instance = null;

//构造方法私有化,无法在外部获取实例,只能通过下方的公有静态方法

private Singleton() {}

//公有的静态方法,返回实例对象

public static synchronized Singleton getInstance() {

//先看下是否存在实例,有的话就不再new了

if (instance == null) {

//这里才new

instance = new Singleton();

}

return instance;

}

}

//饿汉,顾名思义很饥饿,创建对象的时候就直接new

public class Singleton {

//创建实例的时候就new

private static Singleton instance = new Singleton();

// 私有化构造方法,外部不能new

private Singleton() {}

//公有的静态方法,返回实例对象

public static Singleton getInstance() {

//直接将事先new好的实例返回

return instance;

}

}

41、手写生产者消费者模型

生产者消费者是并发编程很经典的一个模型

牵涉三个对象:仓库、生产者、消费者

仓库:代表共享变量

生产者:表示在仓库生产货物

消费者:表示从仓库拿出货物

实现思路:线程间通信

具体demo请见一看就懂的生产者消费者模型

42、int和Integer有什么区别?

int是基本数据类型,默认值为0,integer是其包装类型,默认值为null

  • 原始类型: boolean,char,byte,short,int,long,float,double
  • 包装类型:Boolean,Character,Byte,Short,Integer,Long,Float,Double

java实体类尽量都用integer,假设一个学生类,有个考试成绩属性,如果学生缺考,该属性不应该有值,应该为null,你用int的话默认值为0,考试成绩为0和缺考是两码事

43、String和StringBuilder、StringBuffer的区别?

Java平台提供了两种类型的字符串:String和StringBuffer/StringBuilder,它们可以储存和操作字符串。其中String是只读字符串,也就意味着String引用的字符串内容是不能被改变的。而StringBuffer/StringBuilder类表示的字符串对象可以直接进行修改。StringBuilder是Java 5中引入的,它和StringBuffer的方法完全相同,区别在于它是在单线程环境下使用的,因为它的所有方面都没有被synchronized修饰,因此它的效率也比StringBuffer要高。

44、常见的运行时异常

  • ArithmeticException(算术异常)
  • ClassCastException (类转换异常)
  • IllegalArgumentException (非法参数异常)
  • IndexOutOfBoundsException (下标越界异常)
  • NullPointerException (空指针异常)
  • SecurityException (安全异常)

45、事务的ACID是指什么?

  • 原子性(Atomic):事务中各项操作,要么全做要么全不做,任何一项操作的失败都会导致整个事务的失败;
  • 一致性(Consistent):事务结束后系统状态是一致的;
  • 隔离性(Isolated):并发执行的事务彼此无法看到对方的中间状态;
  • 持久性(Durable):事务完成后所做的改动都会被持久化,即使发生灾难性的失败,通过日志和同步备份可以在故障发生后重建数据。

46、事务隔离级别

1、READ_UNCOMMITTED

读未提交,即能够读取到没有被提交的数据,无法解决脏读、不可重复读、幻读

2、READ_COMMITED

读已提交,即能够读到那些已经提交的数据,能够防止脏读,但是无法限制不可重复读和幻读

3、REPEATABLE_READ

可重复读,即在数据读出来之后加锁,类似"select * from XXX for update",明确数据读取出来就是为了更新用的,所以要加一把锁,防止别人修改它。REPEATABLE_READ的意思也类似,读取了一条数据,这个事务不结束,别的事务就不可以改这条记录,这样就解决了脏读、不可重复读的问题,但是幻读的问题还是无法解决

4、SERLALIZABLE

串行化,最高的事务隔离级别,不管多少事务,挨个运行完一个事务的所有子事务之后才可以执行另外一个事务里面的所有子事务,解决了脏读、不可重复读和幻读

表格总结

在这里插入图片描述

47、悲观锁和乐观锁的原理以及应用场景

悲观锁:

顾名思义,比较悲观,每次去拿数据都认为别人会修改,所有每次在操作前都会加锁,如:读写锁、行锁、表锁等,synchronized的原理也是悲观锁;适用于多写操作

乐观锁:

每次拿数据都认为别人不会修改,所以不会加锁,但是在更新的时候,会先判断在此期间有没有人更新该数据,如果有,返回冲突报错信息,让用户决定怎么操作;适用于多读操作

48、对spring IOC和AOP的理解

IOC(控制反转)

也叫DI(依赖注入),是一种思想,不是一种技术,IOC主张把对象的控制权交由spring,底层实现是反射+工厂方法模式,IOC容器实际上就是个Map,存放各种对象;

AOP

面向切面编程,把一些能共用、冗余、繁琐的功能提取出来,AOP能在不改变原有业务逻辑的情况下,增强横切逻辑代码,根本上解耦合,避免横切逻辑代码重复;常见使用场景有事务管理、日志、全局异常处理、用户鉴权;

49、简述java内存模型

注意和本文23点的jvm内存模型区分开,这是两种截然不同的内存模型

以下是本人总结的概念,别看字多,都是精华,我想过删些,一句都没找到,阅读一遍应该理解的差不多了

  • java内存模型的由来:这和cpu和内存技术发展有关,当代cpu运算速度太快,以至于被内存拉低了程序运行的整体效率

  • 应对措施:为了不被内存影响性能,cpu厂商给cpu加了一级二级甚至三级高速缓存,cpu读取数据时先从一级缓存中找,没有的话找二级,再没有就找三级或者主存;java内存模型规定了变量都是存储在主存中,程序运行时操作的是高速缓存中的数据,操作完之后再同步到主存;

  • 后遗症及规范:在cpu和主存之间增加了一个高速缓存固然提升了程序运行效率,但是在多线程并发操作同一个变量时,就可能造成数据不一致的问题,所以就有了JMM(java内存模型,也可叫JMM规范),它保证了并发编程中数据的正确性(正确性可细分为原子性、可见性、有序性),底层具体实现方式比较复杂,好在JMM为我们日常编程提供了一些用于保证数据正确性的关键字,如synchronized(原子性、有序性)、volatile(可见性、有序性);

50、什么是泛型擦除?

泛型只是为了在编码过程中,我的理解是泛型存在的意义有两个:一是为了让我们更快地发现错误,比如你把User放进了ArrayList< Dog >中,编译器立马会报错;二是避免类型检查,从而避免在运行时抛出 classCastException;泛型擦除就是指泛型会在编译时被消除

ArrayList users = new ArrayList<>();

ArrayList dogs = new ArrayList<>();

System.out.println(users.getClass() == dogs.getClass());

//true

如上,运行结果表面两个list是相等的,因为经过编译后,泛型被擦除,两个list当然也就相等;

51、你能想到几种方法实现两数交换?

1、第三变量

public void swapOne(){

int a = 4;

int b = 5;

int c = a;

a = b;

b = c;

System.out.println(“a:”+a); //a:5

System.out.println(“b:”+b); //a:4

}

2、数学计算

public void swapTwo(){

int a = 4;

int b = 5;

a=a+b;

b=a-b;

a=a-b;

System.out.println(“a:”+a); //a:5

System.out.println(“b:”+b); //a:4

}

3、异或运算

public void swapThree(){

int a = 4;

int b = 5;

a = a ^ b; // 0101 ^ 0100 ===> 0001,此时a的值为1

b = a ^ b; // 0001 ^ 0100 ===> 0101,此时b的值为5

a = a ^ b; // 0001 ^ 0101 ===> 0100,此时a的值为4

System.out.println(“a:”+a); //a:5

System.out.println(“b:”+b); //a:4

}

52、什么是CAS操作?什么ABA问题?如何解决?

CAS全称compare and swap(比较并交换),作用是保证原子性

CAS操作包含三个操作数 —— 内存位置、预期原值、新值。 如果内存位置的值和预期原值相等,就把该值更新为新值,如果不相等,则什么都不做;

ABA问题:CAS操作存在的一个并发问题,打个比方,有两个线程A、B同时操作变量x,A读取到的预期原值是1,此时线程B先将x设置为2,再设置为1,等线程A再来操作的时候,x变量的预期原值和当前值相等,但是x在整个过程中的值是发生过变化的,这在某些业务场景下是不允许的;

解决:利用版本号,给变量x增加版本号,每次操作增加对本版好的判断和修改;

53、什么是回表查询?如何避免?

对于mysql数据库的InnoDB引擎,它的非主键索引是非聚簇索引,索引文件和数据文件分开存储,索引文件B+树的叶节点只保存主键,在进行查询时,需要先去索引文件找到id,再根据id去数据文件查找具体数据,这种现象就叫回表查询

如何避免:索引覆盖

将查询sql中的字段添加到联合索引里面,只要保证查询语句里面的字段都在索引文件中,就无需进行回表查询;

更多索引知识点请移步mysql索引总结

54、什么是CAP理论?

CAP理论是分布式系统架构设计中的一种猜想,或者说是一种理论

  • 一致性(Consistence) : 所有节点访问的数据都是一致的;
  • 可用性(Availability): 非故障的节点在合理的时间内返回合理的响应(不是错误或者超时的响应);
  • 分区容错性(Partition tolerance) : 分布式系统出现网络分区的时候,仍然能够对外提供服务。网络分区指的是网络设备出现的丢包、阻塞、超时等问题。

误区:我发现很多人说到CAP时,都知道分布式系统中这三者不能同时兼顾,只能满足其二,这种说法不严谨,并不是简单的三选二,而是在一致性和可用性二者中只能选其一,分区容错性是我们必须保证的,不能因为出现网络分区导致系统瘫痪,而一致性和可用性可以根据我们的业务来舍弃其一,即我们只能实现AP方案或者CP方案;

55、什么是BASE理论?

BASE理论由CAP理论演化而来,因为CAP对系统设计的要求过高,实现CAP的代价太大;

BASE实质上是对CAP 中 AP 方案的一个补充。

BA:Basically Available(基本可用)

S:Soft-state(软状态) E:Eventually

Consistent(最终一致性)

BASE理论核心思想

牺牲强一致性,通过某些逻辑来达到数据的最终一致性

因为大多数系统对强一致性的依赖没那么强,抛开分区容错性不谈,一致性和可用性这两者,可用性才是我们应该保证的,而对于一致性,我们往往只需要保证最终的数据一致即可;

56、@Autowire和@Resource区别?

都是用来装配java bean

  • @Autowired:按类型注入,这是spring的注解,可以搭配@Qualifie实现按名称注入;

  • @Resource:默认情况下是按照名称进行匹配,如果没有找到相同名称的Bean,则会按照类型进行匹配,这是java自己的注解;

注意事项:

@Autowired有个弊端,打个比方,有个userService,然后它有两个实现类userServiceA和userServiceB,这时候用@Autowired就行不通了,因为它不知道找谁,但是你也不能因为这个一上来就直接用@Resource,这玩意儿性能没@Autowired好,因为@Resource要匹配两次

57、什么是可重入锁?实现原理?

可重入锁:不是一种锁,它是锁的一种性质,代表该锁是否可重入,可重入意思就是**任意线程在获取到锁后能够再次获取该锁,不会被锁阻塞**,这个锁知道它属于谁,其它线程来了就会阻塞等待;

原理:锁的内部维护了线程计数器state和当前持有锁的线程对象,当线程A获取锁资源后,锁会记录下A线程,并且state+1,此时如果有其它线程来获取锁,会被封装成node节点插到队列尾部并且阻塞;而线程A再来获取锁资源时,会成功拿到锁,并且state+1;当线程退出同步代码块时,state-1,如果计数器为0,则释放锁;

58、synchronized可重入吗?ReentrantLock呢?

都是可重入锁,java的锁都可重入

59、RPC协议与HTTP协议的区别?

RPC:远程过程调用,一般用于一台计算机调用另一个计算机上的服务,rpc能让我们像调用本地方法一样调用远程方法;

HTTP:超文本传输协议,一般用于浏览器和服务器之间的通讯;

RPC效率更高,但是实现起来较复杂;

HTTP一般使用json传输数据,RPC一般采用二进制;

60、String有没有长度限制?

既然都这么问了那肯定是有的,分编译器和运行期,长度限制不一样

编译器2 ^ 16 - 1(65535)

运行期2 ^ 32 - 1(2147483647)

不管是编译器还是运行期,如果超出长度都会抛异常:常量字符串过长

61、算法 - 字符串压缩

两种压缩方式

  • 只统计字符出现次数,比如aabcccccaaa,压缩成a5b1c5,利用hashMap键的唯一性;

  • 统计相邻字符串出现次数,比如aabcccccaaa,压缩成a2b1c5a3,需要维护一个当前对比字符,一个字符出现次数,用第n个字符去和第n+1个字符对比

详细实现demo请移步Java字符串压缩

62、简述一下二叉树,有什么特点,以及它的三种遍历方式

一个递归的树形数据结构,每个节点最多有两个子节点;二叉树一般都是二分查找树,每个节点的值大于它左子节点的值,小于它右子节点的值

笔者福利

以下是小编自己针对马上即将到来的金九银十准备的一套“面试宝典”,不管是技术还是HR的问题都有针对性的回答。

有了这个,面试踩雷?不存在的!

回馈粉丝,诚意满满!!!




本文已被CODING开源项目:【一线大厂Java面试题解析+核心总结学习笔记+最新讲解视频+实战项目源码】收录

需要这份系统化的资料的朋友,可以点击这里获取

zed可重入吗?ReentrantLock呢?**

都是可重入锁,java的锁都可重入

59、RPC协议与HTTP协议的区别?

RPC:远程过程调用,一般用于一台计算机调用另一个计算机上的服务,rpc能让我们像调用本地方法一样调用远程方法;

HTTP:超文本传输协议,一般用于浏览器和服务器之间的通讯;

RPC效率更高,但是实现起来较复杂;

HTTP一般使用json传输数据,RPC一般采用二进制;

60、String有没有长度限制?

既然都这么问了那肯定是有的,分编译器和运行期,长度限制不一样

编译器2 ^ 16 - 1(65535)

运行期2 ^ 32 - 1(2147483647)

不管是编译器还是运行期,如果超出长度都会抛异常:常量字符串过长

61、算法 - 字符串压缩

两种压缩方式

  • 只统计字符出现次数,比如aabcccccaaa,压缩成a5b1c5,利用hashMap键的唯一性;

  • 统计相邻字符串出现次数,比如aabcccccaaa,压缩成a2b1c5a3,需要维护一个当前对比字符,一个字符出现次数,用第n个字符去和第n+1个字符对比

详细实现demo请移步Java字符串压缩

62、简述一下二叉树,有什么特点,以及它的三种遍历方式

一个递归的树形数据结构,每个节点最多有两个子节点;二叉树一般都是二分查找树,每个节点的值大于它左子节点的值,小于它右子节点的值

笔者福利

以下是小编自己针对马上即将到来的金九银十准备的一套“面试宝典”,不管是技术还是HR的问题都有针对性的回答。

有了这个,面试踩雷?不存在的!

回馈粉丝,诚意满满!!!

[外链图片转存中…(img-nIiOygfD-1715767019261)]
[外链图片转存中…(img-E1HDfJdt-1715767019261)]
[外链图片转存中…(img-DDbKM6v1-1715767019262)]
[外链图片转存中…(img-5EtJz2cq-1715767019262)]

本文已被CODING开源项目:【一线大厂Java面试题解析+核心总结学习笔记+最新讲解视频+实战项目源码】收录

需要这份系统化的资料的朋友,可以点击这里获取

  • 3
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值