前言:前几天有粉丝问我,网上java面试题总是参差不齐,希望我为他整理一套全面的java面试题,并且这套java面试题有个要求,必须能够让他20天就能看完这些面试题,他说现在很多面试题我看都得看3个月才能看完,然后我才能去找工作,但是自己得时间有限所以想让我帮他总结一套万能面试java求职笔记。接下来我将会至少分为12个章节进行阐述这套Java求职笔记,感兴趣的可以坚持看完!觉得不错的可以点个赞。 1为什么写这套Java求职笔记很早的时候我就想写一些Java求职方向的一些文章,由于很长时间耽搁了加上,有粉丝后台问我,可不可以帮他总结一些java求职笔记,他看了很多Java技术有很多技术,很迷茫不知道学哪些,我笑着说,不要着急,无论你到什么时候你都会迷茫,因为技术一直在更新,谢谢你信任我,解救你的迷茫唯一办法就是多看LRyab博客,就是这样我带着粉丝的问题,开始编写了这套Java求职笔记,看完这套求职笔记,我相信很多人都会找到属于自己的心仪工作。 2一套知识大纲技术图思来想去,本来不想放这套思维大纲技术图,但是很多大佬都喜欢放思维导图,那么我也放一张思维大脑图,方便大家以后学习,在java求职的时候可以带上这张脑图。
3那些年不能忘记的JAVA基础3.1面向对象(一切皆对象)
封装:封装就是把对象的属性和实现细节隐藏起来,仅对外提供公共的访问方法。 将个对象的属性和行为代码封装到一个模块中,也就是一个类中,属性用变量定义,行为用方法定义,方法可以直接访问同一个对象中的属性。 将对象的属性和方法结合一个独立的整体,隐藏其细节,并提供对外访问的接口。 封装优点:1隐藏实现细节 2安全性 3增加代码的复用性:比如在工具类中封装的各种方法,可以任意调用,而不用每处去实现细节。 4模块化:分模块去封装属性、方法等等。有利于代码调试,相互配合。 继承:多个类中存在相同的属性和行为时,将这些相同的内容抽取到一个单独类中,那么多类无需再定义这些属性和行为,只需要继承这个类即可。继承这个类的为新类,新类称之为原始类的派生类(子类)而原始类称之为新类的基类(父类),派生类可以从它的那里继承方法和实例变量,并且类可以修改或者增加新的方法使之更适合特殊的需求。可通过extends关键字实现继承。 从已知的一个类中派生出来的一个新类叫子类。子类实现了父类所有非私有化的属性和方法,并且根据实际需求扩展出新的行为。 继优点:1、继承是传递的,易于在其基础上构造和扩充。 2、简化对事物的描绘,使得层次更加清晰。 3、减少代码冗余。 4、提高可维护性。 多态:多态性是指允许不同类的对象对同一消息作响应,多态性语言具有灵活、抽象、行为共享,代码共享的优势,很好的解决了应用程序函数同名的问题。 多个不同对象对同一消息作出响应。同一个消息根据不同的对象而采用各种不同的方法。 多态的好处:主要是利于代码扩展。 多态的表现形式: 方法重载和方法重写:方法重载通常指一个类中,相同的方法名对应着不同的方法实现,这些方法名相同的方法其区别在于他们需要的参数不同。 方法重写主要用于父类和子类间,子类重写父类的方法,只是对应的方法实现不同,其方法名和参数都相同。
抽象类:在java语言中,一个类中的方法只给出类的标准。而没有给出具体实现的方法,这样的类就是抽象类。 接口:在多态机制中接口比抽象类使用起来更加方便。而抽象类组成的集合就是接口。
抽象类是为了代码的复用,接口是为了实现多态性。 接口可以进行多实现类似于多继承,抽象类无法实现多继承。 抽象类特征: 抽象类必须有abstract来修饰 抽象类可以不含有抽象方法 如果一个类包含抽象方法,那该类就必须是抽象类。 3.2面试中常见的IO流IO分为字节流和字符流 字节流和字符流有入输出 字节流分为:inputStream和OutputStream InputStrean 常用输入流:FileInputStream ByteArrayInputStream OutputStream 常用输出流:FiLe0utPutStrean ByteArrayOutputstrean 字符流分为:Reader和Writer Reader常用入流:BufferReader、InputStreamReader(FileReader) Writer常用输出点:Bufferaríter·OutputStreaniriter(F1LeWriter) PrintWriter 输入输出流是相对于内存而言的。
以文件上传为例? 首先创建一个目标文件路径FiLe 构建一个BufferedOutputStream输出流 获取上传文件的输入流BufferedInputStrean输入流 使用whiLe循环只要输入流的字节长度不为-1,就向输出流内写入字符。
字节流和字符流· 字节流继承inputstrean和outputstrean,字符流继承InputstreamReader和outputStreamWriter
输入流就是从外部文件输入到内存,输出流就是从内存输出到文件 字节流有抽象类inputstream和outputstream他们的子类有,FileoutPutStrean,BufferedoutPutstrean等字符流有BufferReader和Writer。 它们都实现了CLoseabLe,FLushabLe、Appendeble这些接口·程序中输入输出全是以流的形式保存。流中实际保存的实际上全是字节文件。
Java中阻塞方法是指程序调用改方法时,必须等待输入数据可用或者检测到输入结束或者抛出异常,否则程序会一直停留在改语句上,不会执下面的语句比如read()和readL.ine()方法
计算机中的一切都是二进制的字节形式存在,底层设备永远只按受字节数据,有时候写字符到底层设备,需要将人眼看的懂得字符转换为字节再进行写入字符流时,字节流得包装,字符流则是直接接收字符串,它内部将传转化为字节,再写入属出设备。
传统IO流是阻塞式的,会一直监听一个ServerScoket,再调用reader方法时,他会一直等待缓存区满才返回。 NIO是非阻塞式核心类: Buffer为所有原始类型提供Buffer缓存支持 Charset字符集编码解码解决方案 Channel一个新的原始I/0抽象,用于读写Buffer类型。
数据需要读取使用InputStream、Reader 数据需要写入使用OutPutStream,Writer 操作数据如果是纯文本:使用Reader和Writer 不是则使用Inputstreem和outputstream 操作案例:递归读取文件夹下的文件 文件的上传下载(看我其他博文) 3.3你应该知道的多线程线程和进程: 当一个程序被运行,就开启了一个进程, 比如启动了qq,word 程序由指令和数据组成,指令要运行,数据要加载,指令被cpu加载运行,数据被加载到内存,指令运行时可由cpu调度硬盘、网络等设备。 线程:一个进程内可分为多个线程 一个线程就是一个指令流,cpu调度的最小单位,由cpu一条一条执行指令 并行和并发 并发:单核cpu运行多线程时,时间片进行很快的切换。线程轮流执行cpu 并行:多核cpu运行 多线程时,真正的在同一时刻运行 为什么要用多线程? 多线程能实现的都可以用单线程来完成,那单线程运行的好好的,为什么java要引入多线程的概念呢? 多线程的好处: 程序运行的更快!快!快! 充分利用cpu资源,目前几乎没有线上的cpu是单核的,发挥多核cpu强大的能力 多线程难在哪里? 单线程只有一条执行线,过程容易理解,可以在大脑中清晰的勾勒出代码的执行流程 多线程却是多条线,而且一般多条线之间有交互,多条线之间需要通信,一般难点有以下几点 多线程的执行结果不确定,受到cpu调度的影响 多线程的安全问题 线程资源宝贵,依赖线程池操作线程,线程池的参数设置问题 多线程执行是动态的,同时的,难以追踪过程 多线程的底层是操作系统层面的,源码难度大 Java多线程的基本使用:定义任务,创建和运行线程 定义任务 继承Thread类 (可以说是 将任务和线程合并在一起) 实现Runnable接口 (可以说是 将任务和线程分开了) 实现Callable接口 (利用FutureTask执行任务) Thread实现任务的局限性 任务逻辑写在Thread类的run方法中,有单继承的局限性 创建多线程时,每个任务有成员变量时不共享,必须加static才能做到共享 Runnable和Callable解决了Thread的局限性 但是Runbale相比Callable有以下的局限性 任务没有返回值 任务无法抛异常给调用方 创建线程的方式 通过Thread类直接创建线程 利用线程池内部创建线程 启动线程的方式 调用线程的start()方法 守护线程: 默认情况下,java进程需要等待所有线程都运行结束,才会结束,有一种特殊线程叫守护线程,当所有的非守护线程都结束后,即使它没有执行完,也会强制结束。默认的线程都是非守护线程。垃圾回收线程就是典型的守护线程。 线程阻塞: 线程的阻塞可以分为好多种。 BIO阻塞,即使用了阻塞式的io流 sleep让线程休眠进入阻塞状态 a.join() 调用该方法的线程进入阻塞 同步锁阻塞 同步锁等待产生阻塞 sleep() 使线程休眠,会将运行中的线程进入阻塞状态。当休眠时间结束后,重新争抢cpu的时间片继续运行 join() join是指调用该方法的线程进入阻塞状态,等待某线程执行完成后恢复运行 interrupt() 中断线程 线程分为哪几种状态? 初始状态、可运行状态、运行状态、阻塞状态、终止状态。 Thread类中的核心方法? Object类中与线程有关的方法? wait() notify()方法 随机唤醒被wait的一个线程。 notifyAll() native 装饰的方法为本地方法,调用非java语言编写的ddl接口。称之为本地方法。 线程安全: 多线程调用同一个对象的临界区的方法时,对象的属性值一定不会发生错误,这就是保证了线程安全。 synchronized 同步锁也叫对象锁,是锁在对象上的,不同的对象就是不同的锁,保证线程安全的,是阻塞式的解决方案。 当一个线程执行完synchronized的代码块后 会唤醒正在等待的线程 加锁是加在对象上,一定要保证是同一对象,加锁才能生效 线程通信: 线程间通信可以通过共享变量+wait()¬ify()来实现 wait()将线程进入阻塞状态,notify()将线程唤醒 wait()和sleep()的区别 二者都会让线程进入阻塞状态,有以下区别 wait是Object的方法 sleep是Thread的方法 wait会立即释放锁 sleep不会释放锁 wait后线程的状态是Watting sleep后线程的状态为 Time_Waiting 生产者消费者模型案例 生产者来生产数据,消费者来消费数据,生产者生产满了就不生产了,通知消费者取,等消费了再进行生产。 同步锁生活银行取钱案例 死锁:死锁会导致程序无法运行下去 线程池: java开发中经常有池子的思想,如数据库连接池、Redis连接池。 线程池的好处:降低资源消耗,通过池化思想,减少创建线程和销毁线程的消耗,控制资源 提高响应速度,任务到达时,无需创建线程即可运行 提供更多更强大的功能,可扩展性高 3.4常见的底层性能调优方案
3.5常见设计模式案例java设计模式: 顾名思义java中一些代码被固定写法形成了一种模式给这个模式起了个名字。所以叫设计模式 java中的设计模式分为23种,但是你至少会这三种并且能举例说明哪些地方用到了。 (1)单例模式、代理模式、工厂模式、观察者模式、装饰者模式、适配器模式 单例模式又分为:懒汉式和饿汉式 单例保证一个对象在JVM种只能有一个实例 struts2是多例的每次属性渲染都得重新生成新得对象。 spring bean id是唯一生成得所以是单例得 常用:获取数据库得conn链接可以使用单例设计模式。 (2)代理模式 静态代理和动态代理 jdk自带得动态代理和cglib,javaaassist(字节码操作库) 动态代理是基于反射原理。需要使用反射机制实现匿名代理类 spring Aop切面就是使用CGLIB动态代理,实现日志切面。asm、cglib jar包 spring 会自动在jdk动态代理和CGLIB之间切换 (3)工厂模式 工厂模式创建对象大大增加了创建对象封装得层次 mybaties中的事务模块和数据源模块都使用了工厂模式 (4)观察者模式 定义了对象之间的一对多,这样一来,一个对象的改变所有的依赖对象都会接收到通知并且自动更新。 (5)装饰者模式和适配器模式 java IO到处都是装饰者模式:bufferReader和BufferedWriter增强了Reader和Writer对象,增强了单个对象的能力。 3.6java中你不知道的容器集合技术
集合就是一个放数据的容器,准确的说是放数据对象引用的容器 集合类存放的都是对象的引用,而不是对象的本身 集合类型主要有3种:set(集)、list(列表)和map(映射)。
集合用于存储对象的容器,对象是用来封装数据,对象多了也需要存储集中式管理。 和数组对比对象的大小不确定。因为集合是可变长度的。数组需要提前定义大小
数组是固定长度的;集合可变长度的。 数组可以存储基本数据类型,也可以存储引用数据类型;集合只能存储引用数据类型。 数组存储的元素必须是同一个数据类型;集合存储的对象可以是不同数据类型。
Collection接口的子接口包括:Set接口和List接口 Map接口的实现类主要有:HashMap、TreeMap、 Hashtable、ConcurrentHashMap以及Properties等 Set接口的实现类主要有:HashSet、TreeSet、LinkedHashSet等 List接口的实现类主要有:ArrayList、LinkedList、Stack以及Vector等
Collection集合的子接口有Set、List、Queue三种子接口。 List:一个有序的容器,元素可以重复,可以插入多个null元素,元素都有索引。ArrayList、LinkedList。 Set:一个无序,不可以存储重复元素,只允许存入一个null元素,必须保证元素唯一性。
List子类:ArrayList Object数组 LinkedList双向循环链表 Set子类:HashSet 基于HashMap实现的 TreeSet红黑树 自平衡的排序二叉树 Map子类:HashMap数组+链表 解决哈希冲突。LinkedHashMap 数组、链表或者红黑树 HashTable 数组和链表组成的。treeMap红黑树。
Vector、hashTable、ConcurrentHashMap因为内部含有synchronized所以线程安全。
假设2个线程,线程1通过Iterator在遍历A集合的元素,在某一个时刻,线程2修改了集合A的结构,那么这个时候就会抛出:ConcurrentModifyicationException异常从而产生fail-fast机制。
可以使用 Collections. unmodifiableCollection(Collection c) 方法来创建一个只读集合,这样改变集合的任何 操作都会抛出 Java. lang. UnsupportedOperationException 异常。、
Iterator 接口提供遍历任何 Collection 的接口。我们可以从一个 Collection 中使用迭代器方法来获取迭代器实例,迭代器允许调用者在迭代过程中移除元素。
Iterator<String> it = list. iterator(); while(it. hasNext()){ String obj = it. next(); System. out. println(obj); } Iterator 的特点是只能单向遍历,但是更加安全,因为它可以确保,在当前遍历的集合元素被更改
一边遍历一边修改 Collection 的唯一正确方式是使用 Iterator.remove() 方法,Java 一般不允许一个线程在遍历 Collection 时另一个线程修改它。
遍历方式有以下几种 for循环遍历、迭代器遍历、foreach循环遍历 最佳实践:ArrayList使用for循环遍历
ArrayList 底层以数组实现,是一种随机访问模式。 ArrayList 在顺序添加一个元素的时候非常方便。 ArrayList 比较适合顺序添加、随机访问的场景。
数组转 List:使用 Arrays. asList(array) 进行转换。 List 转数组:使用 List 自带的 toArray() 方法。
数据结构:一个数组,一个双向链表 随机访问:ArrayList比LinkedList在随机访问的时候效率高,增加删除元素效率linkedlist链表效率要高于数组 内存占用:Linkedlist比arrayList要占用内存 2者都不能保证线程安全
vector线程安全一些 性能:ArrayList在性能方便优于Vector 扩容:ArrayList每次扩容只会增加50%,而Vector每次会增加1倍
ArrayList 不是线程安全的,如果遇到多线程场景,可以通过 Collections 的 synchronizedList 方法将其转换成线程安全的容器后再使用。
transient关键词修饰的变量不参与序列化,每次之序列化ArrayList中的非transient元素,然后遍历Element打他,只序列化已存入的元素,这样既加快了序列化的速度,又减少了序列化之后的文件大小。
List支持for循环,也就是通过下标来遍历,也可以使用迭代器,但是set只能用迭代,因为它是无序,无法用下标来取得想要的值。
HashSet 是基于 HashMap 实现的,HashSet的值存放于HashMap的key上,HashMap的value统一为present,因此 HashSet 的实现比较简单,基本上都是直接调用底层HashMap 的相关方法来完成,HashSet 不允许重复的值。
链表是可以将物理地址上不连续的数据连接起来,通过指针来对物理地址进行操作,实现增删改查等功能。 链表大致分为单链表和双向链表。 单链表:每个节点包含两部分,一部分存放数据变量的data,另一部分是指向下一节点的next指针 双向链表:除了包含单链表的部分,还增加的pre前一个节点的指针 链表的优点 插入删除速度快、内存利用率高,不会浪费内存(可以使用内存中细小的不连续空间),大小没有固定,拓展很灵活。 链表的缺点 不能随机查找,必须从第一个开始遍历,查找效率低
HashMap的数据结构:在java编程语言中,最基本的结构就2种,一个数组,另外一个是模拟指针(引用),所有的数据结构都可以使用者2个基本结构构造的。 HashMap实际上是一个链表散列的数据结构,即数组和链表的结合体。 HashMap是基于Hash算法实现的 放值和取值:过程,Hash冲突,将冲突的放入链表做进一步的比较,拉链法解决了hash冲突。
resize扩容优化 引了红黑树链表过长影响查询效率 多线程数据丢失问题
平衡二叉树(一种特殊的二叉树) 红黑树添加和删除,最常用到旋转和变色,因为可以使这棵树重新变成红黑树
当两个不同的输入值,根据同一散列函数计算出相同的散列值的现象,我们就把它叫做碰撞(哈希碰撞)。 我们将数组和链表结合在一起,发挥两者各自的优势,就可以使用俩种方式:链地址法和开放地址法可以解决哈希冲突。
能够有效的减少Hash碰撞的几率
HashTable已经淘汰
TreeMap是有序的基于红黑树实现
TreeMap适合遍历,HashMap适合集合元素添加和删除
最大的区别是线程安全
HashTable全表锁,ConcurrentHashMap分段锁,效率高
4结束语混社会这么久,越来越觉得思考的重要性,没有思考就没有成就,现在社会内卷严重,大多数人都知道去努力,但是大多数的人没有养成思考的习惯,如果你学会思考,你整个人就会很爽,就好比你在沙漠里面找到了一瓶水,现在社会谎言、潜规则、利益太多,如果你不思考,只能跟着别人的思想走。 5个人说明 |
|