文章目录
- Java基础学习(7/3-7/4)
-
- 数据类型
- 泛型、反射、注释、序列化(加例)
-
- 1、reflect类方法
- 2、泛型
- 3、反射原理
-
- 这里补充java四大引用类型:
- **总结反射获取方法**
- 反射使用方法invoke
- 4、注解原理
-
- 顺便说一句Java动态代理机制:
- 5.序列化原理
- 6、Clone的原理?
- 7、BigInteger高精度
- 数据结构 java 操作系统 网络(查漏补缺)
-
- 完全定义二叉树
- 2、Inode元信息
- java序列化原理
- 插入排序
- udp到达tcp功能
- 拥塞控制-发送窗口大小问题
- 7、Linux的inode
- 8.线程阻塞-不包括时间片切换
- 9、instanceof运算符 statement
- 如果你想列出当前的目录和子目录,所有的扩展都被称为.txt下面哪个命令可以用于文件?
- 访问主存上的数据需要多少个机器时钟?
- 12、进程进入等待状态有哪几种方式
- 13.同一过程下的线程可过程中共享
- 14、正则表达式
- 15、docker底层隔离机制
- 16.分析递归的时间复杂性
- 17.程序流程控制
- 谈谈你对Java的理解
-
- 一、final关键词注意事项(9/17)
- 二、finally注意点(9/17)
- 三、static关键字的初始化顺序(9/17)
- 四、Java8学习(9/18)
-
- 1、接口默认方法(Default Methods for Interfaces)
- 2、Lambda表达式
-
- (1)函数接口(Functional Interfaces):
- (2)Lambda作用域:
- (3)访问对象的字段和静态变量
- 3.引用方法和构造函数(Method and Constructor References)
- 4、Streams(流)
- Java 集体学习(7/16)
-
- ArrayList
- Vector
- CopyOnWriteArrayList
- LinkedList
- HashMap
- LinkedHashMap
- JVM 学习(7/17)
-
- 一、总结常见配置
- 二、java内存模型
-
- Volatile如何实现内存可见性?
- Synchronized实现可见性?
- 三、java跨平台文件
- 四、JVM如何加载.class文件
-
- **2020/08/29整合**了解整个类加载过程:
- loadClass和forName的区别?
- 五、JVM内存模型
-
- 1、程序计数器:
- 2、Java虚拟机栈(Stack)
- **3.本地方法栈**:
- 4.方法区(元空间)
- 5、Java堆(Heap)
- 6.常量池运行
- 六、GC-java垃圾回收机制
-
- 判断垃圾是否需要回收?
- 2.垃圾回收算法
- 3.分代回收算法
-
- 老年和年轻:
-
- (1)年轻一代:尽快收集生命周期短的对象。
-
- 年轻时垃圾回收工艺演示:
- 常用调优参数:
- (2)老年:存放生命周期长的对象。
-
- 触发Full GC的条件:
- 4.垃圾收集器
-
- 1、Stop-the-World
- 2、Safepoint:
- 3、JVM运行模式:
- 四、垃圾收集器:
-
- Serial收集器:(-XX:UseSerialGC,复制算法表示启用GC
- ParNew收集器(-XX: UseParNewGC,复制算法)
- Parallel Scavenge收集器(-XX: UseParallelGC,复制算法)
- Serial Old收集器(-XX: UseSerialOld,标记-整理算法
- Parallel Old收集器(-XX: UseParallelOldGC,标记-整理算法
- CMS收集器(-XX: UseConcMarkSweepGC,标记-清除算法
- G1收集器(-XX: UseG1GC,复制 标记-整理算法
- GC相关面试题:
-
- 1、Object的finalize()方法的作用是否与C 同样的分析函数。
- 2.强引用、软引用、弱引用、虚引用。
- 七、如何检查线程状态,线程卡在那个地方。(检测死锁位置?
- 八、Java创建对象的过程
- Redis学习(7/20)
-
- 一、基础知识
-
- 1、Redis为什么单线程这么快?
- 2.分布式锁?
- 一、单机redis中间,加时任务给出了不完美的方案:
- 二、edis集群中分布式锁
- 3、bitmap运用场景
- 二、Redis 与 Memcached比较
- 三、LRU算法
- redis中海量数据查询key前缀
- 五、如何实现异步队列
- 六、redis回收进程如何工作
-
- 1、为了防止同一时间有过多的过期key进行删除。我们可以手动在key的过期时间的基准上+random.randomint(86400)(一天的随机时间)
- 2、近似lru算法(只有惰性处理)
- zset有序列表实现
-
- 1、Zset的使用命令:
- 2、查找节点思路:
-
- 时间复杂度:
- 空间复杂度:
- 3、跳表索引动态更新问题:
- 4、跳表的rank排名如何实现的?
- 5、为什么Zset使用skiplist不使用红黑树?
-
- zset实现延时队列:
- redis应用
-
- 1、缓存穿透:
- 2、缓存雪崩:
- 3、缓存击穿:
- redis持久化
-
- 1、RDB机制(快照,全量存储)
- 2、AOF机制(默认是关闭的)
- 双写一致性问题
- 十一、Redis集群
-
- 1、是否使用过Redis集群,集群的高可用怎么保证,集群的原理是什么?
- 2、一致性哈希算法(9/20)
-
- **(1)一致性hash的容错性和扩展性**:
- (2)数据倾斜问题
- (3)redis集群中一致性hash算法的使用
- MySQL学习(7/22没看成,7/29号上午11点)
-
- MVCC多版本并发控制
-
- 版本号、隐式字段:
- Undo日志:
- ReadView(读视图)
- 快照读与当前读
- 参考:
- 间隙锁gap lock类
-
- 1、Record Locks记录锁
- 2、Gap Locks间隙锁
- 3、Next-Key Locks(包括record和gap锁)
- (总结)InnoDB中的record锁、gap锁、next-key锁。
- 4、意向锁
- 隔离级别
- 四、MySQL45讲学习(8/10、8/11、8/14)
-
- 01基础架构:一条SQL查询语句是如何执行的?
- 02基础架构:一条SQL更新语句执行流程?
- 03事务隔离:为什么你改了我还看不见?
-
- \*(补充)MySQL如何实现事务的ACID特性的?
-
- 1、原子性(事务当中操作要么都做,要么都不做)
- 2、一致性(事务只会从一个一致性状态,到另一个一致性状态,也就是说事务从始至终都该是维护数据一致性的)
- 3、隔离性(事务之间互不相干,不可以操作另一个事务中的数据)
- 4、持久性(数据从内存中持久化到磁盘)
- 04索引
-
- 基于主键索引和普通索引查询有什么区别?
- 面试题:数据量大,二级索引搜索会快?
- 自增主键or不使用自增主键?
- 补充:为什么B+树可以减少磁盘访问?
- 1、联合索引B+树(非叶节点上也是按顺序排列的索引字段)
- 1.1覆盖索引是啥?
- 2、利用最左匹配原则,可以减少为特定查询建立冗余索引。
- 06索引、慢查询、锁等补充
-
- 1、为什么要使用索引
- 2、B树、B+树:
- 3、聚集、非聚集索引:(cluster聚簇索引、聚集索引翻译区别,一个意思。)
- 4、密集索引和稀疏索引区别:
- 5、慢查询优化:
- 6、索引建立越多越好?
- 7、联合索引的最左匹配原则
- 8、数据库锁的分类
- 9、数据库索引不命中情况
- 10、内连接和外连接和等值连接的区分?
- 11、MyISAM与InnoDB关于锁方面的区别是什么?
- Java中IO学习(10/16)
-
- 一、概览
- 二、磁盘操作
- HTTP相关协议学习(7/29)
-
-
- 一、HttpServletRequest
- 二、HTTP、RESTful
-
- HTTPS
- HTTP2.0
-
- 1、为什么说HTTP是无连接?
- 2、为什么说HTTP的是无状态的?
- 3、HTTP2 可以提高网页的性能。
- 4、HTTP响应头keep-alive如何实现长连接(连接保活)?
- 输入url发生了什么?
-
- 计算机网络学习(8/4)
-
- TCP滑动窗口
- 二、流量控制
- TCP拥塞控制
- 四、SSL(Security Sockets Layer,安全套接字)
-
-
- 1、HTTPS数据传输流程:
- 2、HTTPS和HTTP的区别?
- 3、GET请求和POST请求的区别?
- 4、Session和Cookie的区别?
-
- Rocketmq学习(8/4-8/5)
-
- RocketMQ-概念模型
-
- 使用消息中间件之前需要先了解“同步”调用、“异步”调用?
- 消息重复消费问题(幂等性)
- 二、如何保证消息的可靠性传输?或者说,如何处理消息丢失的问题?(漏消费)
- 三、RocketMQ保证消息顺序
-
-
- (单独说)消费者和topic以及其中的queue对应关系。
-
- 四、消息积压如何处理?
- 五、设计一个消息队列的思路?
-
- 其实聊到这个问题,一般面试官要考察两块:
- 设计解答:
- 六、常用消息中间件区别,使用场景?
- 七、分布式事务(8/24补充)
-
- 1、2pc(两段式提交)
- 2、半消息事务(最终一致性)【事务型消息?正解!】
- 数据结构学习(8/9)
-
- 一、红黑树学习
-
- 红黑树的调整
- 插入操作的平衡调整
- 删除操作的平衡调整
- 二、全排列、IP地址复原-DFS(回溯算法)
- 哈希树
- 四、各类排序算法时间复杂度及稳定性
- 五、各种简单dp题目(类似爬楼梯的变形题)
- 六、力扣刷题遇到的java语法问题
- 七、链表排序为什么归并比快速排序更优?
- 设计模式学习(8/14)
-
- 一、设计模式六大原则
- 二、设计模式
-
- 1、UML统一建模语言学习:
- 2、常用设计模式
-
- 设计模式分类:
- 单例模式:
- 装饰器模式:
- 策略模式:
- 责任链模式:
- 适配器模式:
- 并发进阶面试题复习(9/10-)
-
- 一、ThreadLocal结构
- 二、Java内存模型
- 三、yield和sleep,wait和sleep的区别?
- 四、线程和协程(9/16)
-
- 1、首先比较单线程和多线程的区别?
-
-
- 创建合适的线程数量?
- 实际项目中对多线程的使用?
-
- **2、协程是什么**?
- Spring面试题复习(8/17)
-
- 一、Spring IOC原理
-
- 小结:
- 二、Spring AOP(面向切面编程)
-
- AOP的使用:(使用\@AspectJ注解开发AOP)
- AOP的实现原理:
- 三、Spring容器对象可以用jvm自己创建的对象吗,并说明理由。
- 四、Spring创建的对象和jvm创建的对象有什么不同?
- 五、Bean的生命周期
- 六、Spring 框架中都用到了哪些设计模式?
- 七、SpringMVC原理
- 八、Spring事务
- 九、如何使用JPA在数据库中非持久化一个字段?
- RPC介绍,RPC原理是什么?(9/16)
Java基础篇学习(7/3-7/4)
数据类型
注:包装类型中一般设有缓冲池,比如Integer、String。
1、Integer缓存池范围-128~127都是同一个地址,在缓存池范围内赋值不会创建新的对象,且不开辟新内存空间。该缓存池由源码Integer.class中的IntegerCache这个私有静态内部类定义。该缓存池与jvm关系是:缓存池创建缓存数据,jvm会在常量池中直接找到该值引用。不用创建新的对象。还可以在jvm中设置缓存池hi最大值。
String integerCacheHighPropValue =
sun.misc.VM.getSavedProperty(“java.lang.Integer.IntegerCache.high”);
2、String也有缓存池
String不可变性:所谓不可变性就是不可以手动修改已经分配内存空间的String。
// String使用+拼接,不能改变原来的String,会创建新的String对象。创建和分配空间,所以+号耗时。
String str1 = “java”;
str1.concat(“c++”);
System..println("str1: " + str1);//仍然为java
:1、可以缓存hash值,不用重复计算hash值,例如String常被用于map的键key。2、String pool中应用了String不可变性。3、安全性。String通常作为参数,例如,网络地址不需要被改变。4、线程安全性。String 不可变性天生具备线程安全,可以在多个线程中安全地使用。
String Pool字符串缓存池:
String缓存池中保存所有字符串字面量(literal strings),这些在编译时就确定。可以使用intern()方法在运行时,将字符串加入到String Pool中。**Intern()**方法就是将String Pool中没有的字符串加入,返回String Pool中引用。如果已经存在直接返回String Pool中引用。
:例如,String str = new String(“x”)+new String(“x“);str.inern();如果String Pool之前没存在“xx”,调用的str引用会指向String Pool中字面量。【。】
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Bc7X1hrO-1606109192015)(media/ef627310e25938ebef4d94734a2ad132.png)]
Intern()方法详解:
https://tech.meituan.com/2014/03/06/in-depth-understanding-string-intern.html
注:包装类的自动装箱、自动拆箱。
1、下表列出了原始类型及其对应的包装类,Java编译器将其用于自动装箱和拆箱:
boolean | Boolean |
byte | Byte |
char | Character |
float | Float |
int | Integer |
long | Long |
short | Short |
double | Double |
2、(1)自动装箱,发生于存储在集合类中,基本数据类型不满足要求。或者基本数据类型传参给包装类方法。
(2)自动拆箱,容器中取出基本数据类型。传参给需要基本数据类型的方法。
泛型、反射、注解、序列化(加实例)
1、reflect类方法
Class 和 java.lang.reflect 一起对反射提供了支持,java.lang.reflect 类库主要包含了以下三个类:
-
:可以使用 get() 和 set() 方法读取和修改 Field 对象关联的字段;
-
:可以使用 invoke() 方法调用与 Method 对象关联的方法;
-
:可以用 Constructor 的 newInstance() 创建新的对象。
2、泛型
白话:
(1)让数据类型变得参数化(不支持基本类型),代替一部分参数类型。
(2)在编译期运用<?extends List<Integer>>限定容器中存储的参数类型。而且限定类型之后能在编译之前就发现类型错误。List.add(“123”)是加不进去字符串的。
这里属于向上转型(子类对象(小范围)转化为父类对象(大范围)),java中自动转换。
向下转型(父类对象强制转换为子类对象)
把类型明确的工作推迟到创建对象或调用方法的时候才去明确特殊的类型。
容器编译时类型检查。
好处:
(1)通过泛型的语法定义,编译器可以在编译期提供一定的类型安全检查,过滤掉大部分因为类型不符而导致的运行时异常。//可以对参数进行类型限定。
(虽然类型不确定,但是必须是同一种类型的,防止在编译期能发现的问题,要运行时才发现)
(2)泛型可以让程序代码的可读性更高,并且由于本身只是一个语法糖,所以对于 JVM 运行时的性能是没有任何影响的
基本使用:泛型类、泛型方法、泛型变量。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-nC8PUFeW-1606109192018)(media/a55440b93e525e376310e9ac3630f817.png)]
类型变量的限定
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-FTeZNFRM-1606109192021)(media/45931fa23c6ab225339a514253561a3d.png)]
有如下用法
<T extends Comparable> //一个类型变量的一个类型限定
<T extends Comparable & Serializable> //一个类型变量的两个类型限定
<T extends Comparable,U extends Serializable> //两个类型变量的类型限定
<? extends T>:是指 “上界通配符(Upper Bounds Wildcards)”
<? super T>:是指 “下界通配符(Lower Bounds Wildcards)
基本原理:
编译器和虚拟机对泛型的处理是不一样的
(1)虚拟机不存在“泛型”概念
(2)只有编译器识别泛型,并对其操作。
泛型擦除(类型擦除):
Java中,无论定义了一个反型,在编译时都会自动生成一个相应的原始类型。
T变成Object,Integer擦除变成Object。但之后会插入一行checkcast指令用于强制类型转换。由Object到Integer成为泛型翻译。
注意:java默认泛型不可以向上转型,如果能够转型,说明类可以存储其他子类,这会造成逻辑上的混乱。List<List<Integer>> re = new ArrayList<ArrayList<Integer>>是非法的。
3、反射原理
通过Java的反射机制,可以在运行期间调用对象的任何方法
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-5ES8xLiw-1606109192024)(media/74b3d628f285e24b418354ee70174595.png)]
类加载的第一步即加载阶段,主要完成下面3件事情:
(1)通过全类名获取定义此类的二进制字节流。
(2)将字节流所代表的静态存储结构转化为方法区的运行时数据结构。
(3)在内存(堆)中生成一个代表该类的class对象,作为方法区这些数据的访问入口。
???cyc2018虚拟机类加载部分。类加载的第一个阶段加载阶段。
Class对象是加载的最终产品,类的方法代码,变量名,方法名,访问权限,返回值等都是方法区的。
Java中使用类java.lang.Class来指向一个类型信息,通过这个Class对象,我们可以得到该类的所有内部信息。
直接从clazz.getDeclaredMethod();方法入手
首先Class类里面有一个软引用类型的成员变量
SoftReference<Class.ReflectionData<T>> reflectionData;
ReflectionData是用来缓存从JVM方法区中读取的类型信息的,比如字段、方法等。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-lfYss5sl-1606109192026)(media/5a5bf2166bc9d681934c9e351bc7019b.png)]
该成员变量时SoftReference的,说明在内存紧张时会被GC回收,如果reflectionData被回收之后,又执行了反射方法,通过newReflectionData方法重新创建一个这样的对象。
这里补充java四大引用类型:
Java中根据其生命周期的长短,将引用分为4类:
1、强引用
最普遍的引用,通过new关键字创建的对象所关联的引用是强引用。当JVM内存空间不足,宁愿抛出OOM异常,也不会回收具有强引用对象。一个普通的对象,没有其他引用关系,或将强引用赋值为null,就代表可以GC了。
2、软引用
通过SoftReference类实现。软引用生命周期比强引用短一些。只有当JVM认为内存不足时,才会去回收软引用指向的对象,即JVM保证在抛出OOM之前回收软引用对象。
软引用用于内存敏感的缓存,没有空闲内存就需要被回收的。
3、弱引用
弱引用也是用来描述非必须对象的,他的强度比软引用更弱一些,被弱引用关联的对象,在垃圾回收时,如果这个对象只被弱引用关联(没有任何强引用关联他),那么这个对象就会被回收。
4、虚引用
如果一个对象仅持有虚引用,那么它就和没有任何引用一样,在任何时候都可能被垃圾回收器回收。
https://www.jianshu.com/p/825cca41d962
继续讲反射实现的重要方法getDeclaredMethod()方法源码
(1)getDeclaredMethod()
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-W1JiTAY0-1606109192027)(media/671d78081606f28a6f52a3451451dcb8.png)]
其中Method method = searchMethods(this.privateGetDeclaredMethods(false), name,
parameterTypes);为主要加载方法的步骤。
(2)SearchMethods
SearchMethods中调用的copyMethod每次返回新的method对象。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-afJa8LE1-1606109192029)(media/e2086d55c89fac6f787b7c5b7bf4c3d5.png)]
所次每次调用getDeclaredMethod方法返回的Method对象其实都是一个新的对象,且新对象的root属性都指向原来的Method对象,如果需要频繁调用,最好把Method对象缓存起来。
(3)privateGetDeclaredMethods()
里面又是Method[] privateGetDeclaredMethods() 方法很重要。源码为:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-NXa3go2V-1606109192030)(media/9fe730e59a8f7f12bec77cdca68efdbb.png)]
这个方法确定了ReflectionData的获取逻辑:
(1)先查看缓存中对否存在。存在直接返回rd。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-68Zngf8w-1606109192032)(media/9587877781ce302f2fe3cf951800e867.png)]
(2)不存在调用newReflectionData方法从JVM中获取。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-xB5W76wk-1606109192034)(media/1eb4c44bf9871fe711896fa917eda42c.png)]
反射获取方法:getDeclaredMethod方法获取本类声明过的public、private等方法。其中先searchMethod找到与所求方法名相同的方法,复制一份返回。而找方法需要调用privateGetDeclaredMethod查看软引用类型缓存的所有类的信息ReflectionData。由此又使用reflectionData()方法判断软引用类的缓存有没有被GC掉,如果没有直接返回,如果被GC了需要从JVM中获取类信息。
反射使用方法invoke
Method.invoke()
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-iI3fsi3S-1606109192036)(media/4add198be92a4e69e816314f35ae0ae4.png)]
最终执行的是 MethodAccessor.invoke(obj, args); 方法
4、注解原理
所有注解都继承自Annotation
如注解@Override 定义
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-zrvxrtWi-1606109192037)(media/1122105f5fa4e82cc92b60ed5e70dffe.png)]
本质上就是Override接口继承Annotation类
一个注解的意义准确来说,只不过是一种特殊的注释而已,如果没有解析它的代码,它可
能连注释都不如。
解析一个类或者方法的注解有两种方式
(1)编译期直接扫描
(2)运行时反射
JDK提供的几种注解
用来定义注解**(运行期反射)**
Target:注解的作用目标(方法、类、字段…)
Retention:注解的生命周期(编译器、类加载、运行期)
Documented:注解是否应当被包含在 JavaDoc 文档中
Inherited:是否允许子类继承该注解
Override:方法重写
Deprecated:方法已过时
SuppressWarnings:压制警告(不希望编译器检查)
虚拟机规范定义了一系列和注解相关的属性表, 如下:
RuntimeVisibleAnnotations:运行时可见的注解
RuntimeInVisibleAnnotations:运行时不可见的注解
RuntimeVisibleParameterAnnotations:运行时可见的方法参数注解
RuntimeInVisibleParameterAnnotations:运行时不可见的方法参数注解
AnnotationDefault:注解类元素的默认值
对于一个类或者接口来说,Class 类中提供了以下一些方法用于反射注解。
getAnnotation:返回指定的注解
isAnnotationPresent:判定当前元素是否被指定注解修饰
getAnnotations:返回所有的注解
getDeclaredAnnotation:返回本元素的指定注解
getDeclaredAnnotations:返回本元素的所有注解,不包含父类继承而来的
自定义注解Hello
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-YRVELYER-1606109192038)(media/8aa37a6a46ef2d598c0258f6d02fdebe.png)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-4dZAWuz2-1606109192039)(media/43b4b1865ee08588fbcd9f38c6339e44.png)]
注解本质上是继承了 Annotation 接口的接口,而当你通过反射,也就是我们这里的 getAnnotation 方法去获取一个注解类实例的时候,其实 JDK 是通过动态代理机制生成一个实现我们注解(接口)的代理类。
这里顺便提一句Java动态代理机制:
每一个动态代理类的调用处理程序都必须实现InvocationHandler接口,并且每个代理类的实例都关联到了实现该接口的动态代理类调用处理程序中,当我们通过动态代理对象调用一个方法时候,这个方法的调用就会被转发到实现InvocationHandler接口类的invoke方法来调用,看如下invoke方法:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-OkXwAyqT-1606109192040)(media/954686e949499d0d612894e1e8ce7f0d.png)]
客户端使用动态代理时,调用Proxy.newProxyInstance()获取代理对象,也可以封装在getAnnotation 方法中。当然还必须编写一个workhandler实际代理对象使用被代理对象Teacher的所有方法。(java动态代理是invocationhandler是一个接口,需要有实际代理类实现这个接口)(相当于新建的一个类,使用反射机制调用Teacher类的方法。。。)
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-zt0RXh4r-1606109192041)(media/f2f7e7d0204c963ab93bf66b95728840.png)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-iZvf6O5R-1606109192042)(media/f46cee1553cdcc72e1c75184502f6e18.png)]
在其他类使用时,创建workhandle对象调用它的invoke方法,就能既执行原来的方法,而且能执行其他扩展方法。
https://blog.csdn.net/yaomingyang/article/details/80981004
最后我们再总结一下整个反射注解的工作原理:
(1)首先,我们通过键值对的形式可以为注解属性赋值,像这样:@Hello(value = “hello”)。
(2)接着,你用注解修饰某个元素,编译器将在编译期扫描每个类或者方法上的注解,会做一个基本的检查,你的这个注解是否允许作用在当前位置,最后会将注解信息写入元素的属性表。
(3)然后,当你进行反射的时候,虚拟机将所有生命周期在 RUNTIME 的注解取出来放到一个 map 中,并创建一个 AnnotationInvocationHandler 实例,把这个 map 传递给它。
(4)最后,虚拟机将采用 JDK 动态代理机制生成一个目标注解的代理类,并初始化好处理器。
那么这样,一个注解的实例就创建出来了,它本质上就是一个代理类,你应当去理解好 AnnotationInvocationHandler 中 invoke 方法的实现逻辑,这是核心。一句话概括就是,通过方法名返回注解属性值。
5、序列化原理
概念:
序列化:把Java对象转换为字节序列的过程。
反序列化:把字节序列恢复为Java对象的过程。
如果一个类想被序列化,需要实现Serializable接口。否则将抛出NotSerializableException
异常,这是因为,在序列化操作过程中会对类型进行检查,要求被序列化的类必须属于
Enum、Array和Serializable类型其中的任何一种。
-
在变量声明前加上transient关键字,可以阻止该变量被序列化到文件中。
-
在类中增加writeObject() 和 readObject() 方法可以实现自定义序列化策略(ArrayList就是这么干的)
总结如下
序列化会通过反射调用无参数的构造方法创建一个新的对象。
在要序列化的类中实现readResolve()方法, 在该方法中返回单例实例
当被反序列化时就会判断, 该类中是否实现了readResolve()方法, 若实现了, 则反射调用该方法
6、Clone的原理?
Clone的浅拷贝、深拷贝。
浅拷贝是将变量引用传递给新变量,在修改新的变量时,旧的变量值会被改变。
深拷贝是重新开辟一片内存空间,复制属性值,然后传递新的引用给新变量。
Clone可以对基本数据类型进行深拷贝,对引用类型则需要重写clone方法。(直到对象clone的都是基本数据类型)才可以实现深拷贝。
new操作符的本意是分配内存。程序执行到new操作符时, 首先去看new操作符后面的类型,因为知道了类型,才能知道要分配多大的内存空间。分配完内存之后,再调用构造函数,填充对象的各个域,这一步叫做对象的初始化,构造方法返回后,一个对象创建完毕,可以把他的引用(地址)发布到外部,在外部就可以使用这个引用操纵这个对象。
而clone在第一步是和new操作符相似的,都是进行内存空间的分配,调用clone方法时分配的内存和源对象(即调用clone方法的对象)相同。然后再使用原对象中对应的各个域填充新对象的域,填充完成之后clone方法返回,一个新的相同的对象被创建,同样可以把这个新对象的引用发布到外部
https://www.cnblogs.com/shoshana-kong/p/10822379.html
7、BigInteger高精度
https://blog.csdn.net/sinat_34328764/article/details/79900883
API中描述:
不可变的任意精度的整数。所有操作中,都以二进制补码形式表示 BigInteger(如 Java 的基本整数类型)。BigInteger 提供所有 Java 的基本整数操作符的对应物,并提供 java.lang.Math 的所有相关方法。另外,BigInteger 还提供以下运算:模算术、GCD 计算、质数测试、素数生成、位操作以及一些其他操作。
其实我们所应该知道的就是BigInteger可以表示任意大小的整数,加减乘除的操作都换成了方法调用,Bigxxx类型的数都是不可变的,每次运算都会产生新的对象来进行计算,应该避免大规模的使用。
使用字符串来进行初始化操作String temp1 = “123”,BigInteger bg1 = new BigInteger(temp1);
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-bGocM6LE-1606109192043)(media/8c1ee3ec690308e8ddbde3ee5f9fdbde.png)]
数据结构+java+操作系统+网络(查漏补缺的)
1、完全二叉树定义
一棵深度为k的有n个结点的二叉树,对树中的结点按从上至下、从左到右的顺序进行编号,如果编号为i(1≤i≤n)的结点与满二叉树中编号为i的结点在二叉树中的位置相同,则这棵二叉树称为完全二叉树
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-0aSgslH3-1606109192044)(media/078d16082147d85484b32ed11612e487.jpeg)]
只需要节点都集中在左边就行,不需要节点个数为偶数。
2、Inode元信息
inode 和 block 概述#
文件是存储在硬盘上的,硬盘的最小存储单位叫做扇区sector,每个扇区存储512字节。操作系统读取硬盘的时候,不会一个个扇区地读取,这样效率太低,而是一次性连续读取多个扇区,即一次性读取一个块block。这种由多个扇区组成的块,是文件存取的最小单位。块的大小,最常见的是4KB,即连续八个sector组成一个block。
文件数据存储在块中,那么还必须找到一个地方存储文件的元信息,比如文件的创建者、文件的创建日期、文件的大小等等。这种存储文件元信息的区域就叫做inode,中文译名为索引节点,也叫i节点。因此,一个文件必须占用一个inode,但至少占用一个block。
题目参考标题8
元信息 → inode
数据 → block
参考链接:https://www.cnblogs.com/llife/p/11470668.html
java序列化原理
基本包装类一般实现了serializable接口,所以可以直接序列化为字节序列(字节数组),
自定义对象类需要实现该接口。序列化使用writeObject,反序列化使用readOject方法。
序列化就是使得在不同环境下,
插入排序
插入排序对于基本有序,或者已经有序的数组是效率最高的。(这里的有序不是指全部逆序)
for (int i = 1; i < nums.length; i++) {
if (nums[i - 1] > nums[i]) { // 只有右边数比左边数小时才排序,所以基本有序就占了优势。
int tmp = nums[i]; // 保存小的值
for (int j = i; j >= 0; j–) {
if (j > 0 && nums[j - 1] > tmp) {
nums[j] = nums[j - 1]; // 向后移动大值
} else {
// 找到j这个位置,它之前数要比tmp小,所以插入在这里
nums[j] = tmp;
break;
}
}
}
}
udp到达tcp功能
在网络7层协议中,如果想使用UDP协议达到TCP协议的效果,可以在哪层做文章?
从建立会话连接的角度去考虑。udp是无连接的,tcp通过三次握手建立连接。会话层可以为端到端建立连接,并且维护这个连接,结束时最后释放连接。所以在会话层做文章。
(1)应用层是应用程序与应用程序之间交互。
(2)表示层主要处理数据表示有关的,数据的加密、解密、压缩与解压缩。
(3)会话层主要利用传输层提供的服务,为会话实体之间建立连接、维持连接和释放连接。
(4)传输层提供了进程间的逻辑通信。控制交互通信功能。
(5)网络层向上只提供简单灵活的、无连接的、尽最大努力的交互的数据报服务。
(6)数据链路层以数据帧形式进行交互。
(7)物理层提供物理线路传输电信号。
拥塞控制-发送窗口大小问题
答案:
链接:https://www.nowcoder.com/questionTerminal/bf02156911654f2aaa146f8fd15bd9e0
来源:牛客网
从拥塞控制的角度出发,发生超时时,ssthresh被设定为8的一半,且拥塞窗口被设为1KB,此后再无拥塞,故而拥塞窗口经10个RTT依次变化为2、4(未超过ssthresh值之前以指数级增长)、5、6、7、8、9、10、11、12(超过ssthresh之后以数量级增长),最终达到12KB。
而流量控制的角度出发,接受窗口恒为10KB。
发送方的发送窗口取拥塞窗口和接收窗口的最小值,故最后答案是10KB。
7、Linux的inode
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-mtQFh3Vk-1606109192046)(media/4c13d0a47b1fb446dcd73c0ace33e4d7.png)]
解答:
文件名和inode号码是"一一对应"关系,每个inode号码对应一个文件名。但是,Unix/Linux系统允许,多个文件名指向同一个inode号码。这意味着,可以用不同的文件名访问同样的内容;对文件内容进行修改,会影响到所有文件名;但是,删除一个文件名,不影响另一个文件名的访问。这种情况就被称为"硬链接"(hard link)。 除了硬链接以外,还有一种特殊情况。文件A和文件B的inode号码虽然不一样,但是文件A的内容是文件B的路径。读取文件A时,系统会自动将访问者导向文件B。因此,无论打开哪一个文件,最终读取的都是文件B。这时,文件A就称为文件B的"软链接"(soft link)或者"符号链接(symbolic link)。 这意味着,文件A依赖于文件B而存在,如果删除了文件B,打开文件A就会报错:“No such file or directory”。这是软链接与硬链接最大的不同:文件A指向文件B的文件名,而不是文件B的inode号码,文件B的inode"链接数"不会因此发生变化。
8、线程阻塞-不包括时间片切换
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-bHKySnXh-1606109192047)(media/74ed197412b65b0097dd97799a3108de.png)]
一般线程中的阻塞:
A、线程执行了Thread.sleep(int millsecond);方法,当前线程放弃CPU,睡眠一段时间,然后再恢复执行
B、线程执行一段同步代码,但是尚且无法获得相关的同步锁,只能进入阻塞状态,等到获取了同步锁,才能回复执行。
C、线程执行了一个对象的wait()方法,直接进入阻塞状态,等待其他线程执行notify()或者notifyAll()方法。
D、线程执行某些IO操作,因为等待相关的资源而进入了阻塞状态。比如说监听system.in,但是尚且没有收到键盘的输入,则进入阻塞状态。
9、instanceof运算符+statement
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-T1WL6Xml-1606109192048)(media/b94c4e99d3b887c88ffb6e91648dc6cd.png)]
10、如果想列出当前目录以及子目录下所有扩展名为“.txt”的文件,那么可以使用以下哪个命令?
find . -name “*.txt”
11、访问主存上的数据,大概需要多少个机器时钟?
100个。
12、进程进入等待状态有哪几种方式
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-BmOVLkgh-1606109192049)(media/ced70090a023c57e2ea49ad55c3f3e9a.png)]
来源:牛客网
进程分为基本的三个状态:运行、就绪、阻塞/等待。
A. 高优先级的抢占CPU,使得原来处于运行状态的进程转变为就绪状态。
B. 阻塞的进程等待某件事情的发生,一旦发生则它的运行条件已经满足,从阻塞进入就绪状态。
C. 时间片轮转使得每个进程都有一小片时间来获得CPU运行,当时间片到时从运行状态变为就绪状态。
D. 自旋锁(spinlock)是一种保护临界区最常见的技术。在同一时刻只能有一个进程获得自旋锁,其他企图获得自旋锁的任何进程将一直进行尝试(即自旋,不断地测试变量),除此以外不能做任何事情。因此没有获得自旋锁的进程在获取锁之前处于忙等(阻塞状态)。
13、同一进程下的线程可以共享以下
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-gN4GxZ3r-1606109192050)(media/d7efbb19674f759758a75570a5820349.png)]
同一进程内的线程共享 1代码段 2数据段 3打开文件列表 4堆
线程私有 1线程id 2寄存器 (用于暂时存放数据)3工作栈
14、正则表达式
15、docker底层隔离机制
Docker的隔离性主要运用Namespace 技术
16、递归的时间复杂度分析
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-0OiviYQG-1606109192052)(media/121bd494a0c33dd1e2dc1c634017bee1.jpeg)]
//截止条件只有一个x
fun( x, y, z) {
(x <= 0) {
System..println(y + “,” + z);
;
}
fun(x - 1, y + 1, z);
fun(x - 1, y, z + 1);
}
只有一个调用fun(x - 1, y + 1, z);复杂度就是O(n)。
有两个调用fun(x - 1, y + 1, z);复杂度就是O(2^n)。
17、程序流程控制
1、流程控制三大结构:顺序、循环、分支!
2、改变程序执行方式:选择、循环、方法调用。
18、ThreadLocal的继承问题?
A、ThreadLocal继承自Thread
B、ThreadLocal实现了Runnable接口
C、ThreadLocal重要作用在于多线程间的数据共享
D、ThreadLocal是采用哈希表的方式来为每个线程都提供一个变量的副本
E、ThreadLocal保证各个线程间数据安全,每个线程的数据不会被另外线程访问和破坏
**答案:**D和E正确的
http://www.tilaile.com/question/12616
四、谈谈你对Java的理解
1、平台无关性
2、GC
3、语言特性
4、面向对象
5、类库
6、异常处理
1、平台无关性
编译时、运行时。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Akw2AAnc-1606109192053)(media/11a7b37aae183bcbe3c8abaf5ce2cd32.png)]
为什么JVM不直接将源码解析成机器码去执行?
1、如果直接解析源码,需要每次都编译,每次执行都需要各种检查
2、兼容性:也可将别的语言解析成字节码
一、final关键字的几点注意点(9/17)
(1)final修饰基本类型变量,代表该变量是常量不能被再次初始化。(final修饰成员变量一定要进行初始化,否则编译报错,修饰一般变量时,在使用之前需要进行初始化。)
【final修饰的变量-常量,在类加载的准备阶段,进行赋初始值,而且是赋常量的值。】
Static修饰变量表示该变量属于类变量,可以修改内容。类加载准备阶段,赋的是零值。
https://blog.csdn.net/zxd8080666/article/details/78087646
(2)final修饰引用类型变量,代表该引用不能指向其他引用变量。
,但是这种替换只有在编译期能够确定final修饰的变量的值,编译器才能对变量直接进行替换。
例1:
public static void main(String[] args) {
String a = “hello2”;
final String b = “hello”;
String d = “hello”;
String c = b + 2;
String e = d + 2;
System.out.println((a == c));
System.out.println((a == e));
}
结果: true,false
因为第一个b是final修饰的,编译期可以确定的值。
例2:
public static void main(String[] args) {
String a = “hello2”;
final String b = getHello();
String c = b + 2;
System.out.println((a == c));
}
public static String getHello() {
return “hello”;
}
结果: false,false
因为b在编译期无法确定值。
final修饰的方法,代表该方法在子类中不可以被重写。子类中有相同的函数签名也不是对父类方法的重写。(同函数名的方法重载不受影响。)
final修饰的类,不可以被继承。final不可以修饰abstract类,匿名内部类中所有变量必须是final变量。
Ps:
(1)final关键字容易与finalize()方法搞混,后者是在Object类中定义的方法,是在垃圾回收之前被JVM调用的方法。
(2)接口中声明的所有变量本身是final的。
(3)final和abstract这两个关键字是反相关的,final类就不可能是abstract的。
(4)final方法在编译阶段绑定,称为静态绑定(static binding)。
参考:https://www.jb51.net/article/157603.htm
二、finally的注意点(9/17)
首先,不管有没有异常抛出或者try-catch中有无return。finally中语句都会执行!
这是为了使得finally中的一些对资源的释放、关闭不受影响。
(1)finally中有return,编译器会有警告(finally block does not complete normally,finally语句块没有正常完成)那么try-catch中无论return还是抛异常,finally中的return都会覆盖返回值。只返回finally中的return的值。
(2)finally中没有return,try-catch中有return,那么return和抛异常是正常输出的。如果finally中对return的变量进行修改,那么不会影响到返回值的大小。
(1)try中执行到return(如果有return)之前所有语句,包括return中的运算语句。(相当于返回值已经确定了)。
(2)catch捕获try中运行语句的异常。程序执行catch块中return之前(包括return语句中的表达式运算)代码。
(3)执行finally中语句(没有return不能改变1、2的返回结果),如果有return覆盖1、2返回结果。
https://blog.csdn.net/u011277123/article/details/59074492
三、static关键字的初始化顺序(9/17)
静态变量和静态代码块初始化,先于实例变量和普通语句块。静态变量、静态代码块之间初始化顺序取决于自身的代码顺序。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-7oODlNUU-1606109192054)(media/8901b7e6f3eb375411a6e21e92e5bad8.png)]
最后才是构造函数的初始化。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-wJLZy7pU-1606109192055)(media/63239c268892ffb7fb56a6f7c5a59ff2.png)]
(1)父类的静态变量、静态代码块。
(2)父类的实例变量、普通语句块初始化。
(3)父类的构造函数初始化。
(4)子类的静态变量、静态代码块执行。
(5)子类的实例变量、普通语句块初始化。
(6)子类的构造函数初始化。
四、Java8学习(9/18)
1、接口的默认方法(Default Methods for Interfaces)
Java8使我们够通过default关键字向接口添加非抽象方法的实现。此功能也称为虚拟扩展方法。
不管是抽象类还是接口,都可以通过匿名内部类的访问方式访问。不能通过抽象类或者接口直接创建对象。对于匿名内部类方式访问接口,我们可以这样理解:一个内部类实现了接口里的抽象方法并且返回一个内部类对象,之后我们让接口的引用来指向这个对象。
2、Lambda表达式
-
List<String> names = Arrays.asList(“peter”, “anna”, “mike”, “xenia”);
-
Collections.sort(names, Comparator<String>() {
-
@Override
-
compare(String o1, String o2) {
-
o1.compareTo(o2);
-
}
-
});
-
names.sort((o1, o2) -> o1.compareTo(o2));
-
System.out.println(names);
(1)函数式接口(Functional Interfaces):
为了使现有函数友好地支持Lambda。最终采取的方法是:增加函数式接口的概念。“函数式接口”是指仅仅包含一个抽象方法,但是可以有多个非抽象方法(也就是上面提到的默认方法)的接口。像这样的接口,可以被隐式转换为Lambda表达式。
Java.lang.Runnable与java,util.concurrent.Callable是函数式接口最典型的两个例子。
Java 8增加了一种特殊的注解@FunctionalInterface,但是这个注解通常不是必须的(某些情况建议使用),只要接口只包含一个抽象方法,虚拟机会自动判断该接口为函数式接口。一般建议在接口上使用@FunctionalInterface 注解进行声明,这样的话,编译器如果发现你标注了这个注解的接口有多于一个抽象方法的时候会报错的,如下图所示
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-NQU8nod1-1606109192056)(media/f9fdb55ef3006988cb215fe9881e9cd8.png)]
-
@FunctionalInterface
-
Converter<F, T> {
-
T convert(F from);
-
}
-
// 函数式接口 将数字字符串转换为整数类型
-
Converter<String, Integer> converter = (from) -> Integer.valueOf(from);
-
Integer converted = converter.convert(“123”);
-
System.out.println(converted.getClass());// class java.lang.Integer
-
System.out.println(converted);
Lambda表达式无法访问接口的默认方法。
(2)Lambda作用域:
在lambda表达式中访问外层作用域和老版本的匿名对象中的方式很相似。你可以直接访问标记了final的外层局部变量,或者实例的字段以及静态变量。
-
// Lambda作用域,访问局部变量
-
// final int num = 1;
-
int num = 1;
-
// 函数式接口,将Integer->String
-
Converter<Integer, String> stringCovert = (from) -> String.valueOf(from + num);
-
System.out.println(stringCovert.convert(2));
-
// num = 3; 这里的num必须不可被后面的代码修改(即隐性的具有final的语义,在lambda表达式中修改num也是不对的)
(3)访问对象字段与静态变量
和本地变量不同的是,lambda内部对于实例的字段以及静态变量是即可读又可写。该行为和匿名对象是一致的:
testScopes() {
Converter<Integer, String> stringConverter1 = (from) -> {
outerNum = 23;