9. java知识点

光说面试难,9张思维导图,总结Java面试核心知识点,你是否也复习到这样 各位老铁,面试了吗?有没有找工作啊,小编没有找工作,但是公司通知,马上要开启一个新的项目----脑瓜子嗡嗡的,果然长时间的假期不是白放的,老boss憋着大招呢,正好趁着这段时间,反正早晚要用,就把自己的知识体系整理了一下,最先整理的是自己认为的9大核心知识点。并且用 9 个思维导图来记录这些知识,我觉得这些知识,都是大概率会问到的,具体是哪 9 门,大家可以往下看,最后的思维导图,也会送给大家。 1、计算机网络 在校招的面试中,计算机网络的知识,问的是真的多,而且涉及到的协议也是真的多,例如 http, 阅读详情

1. HashMap

在这里插入图片描述
1.7:头插法(多线程扩容时会形成循环链表,产生死循环),数组+链表,
1.8:尾插法,数组+链表+红黑树
在这里插入图片描述

扩容 重hash

JAVA7扩容后的rehash过程使用了单链表的头插法方式,同一位置上新元素总会被放在链表的头部位置;这样如果发生了hash冲突的话先放在一个索引上的元素终会被放到Entry链的尾部,这一点和JAVA8有区别。

JAVA8在rehash算法利用了下面的一个特性:
HashMap的扩容使用的是2次幂的扩展(指长度扩为原来2倍),所以,元素的位置要么是在原位置,要么是在原位置再移动2次幂的位置。什么意思呢? 我们举个例子说明。

假设原数组长度 capacity 为 16,扩容之后 new capacity 为 32:
下标的计算方法,对于一个 Key,如原Hash值 key1 = 0001 1001 key2 = 0000 1001
扩容前 hash & (length - 1) :
key1 : 0001 1001 & 0000 1111 -> 0000 1001
key2 : 0000 1001 & 0000 1111 -> 0000 1001

扩容后 hash & (length - 1) :
key1 : 0001 1001 & 0001 1111 -> 0001 1001
key2 : 0000 1001 & 0001 1111 -> 0000 1001

因此,我们在扩充HashMap的时候,不需要像JDK1.7的实现那样重新计算hash,

只需要看原来的hash值在扩容后新增的那一位是1还是0,如果是0的话索引没变,是1的话索引变成“原索引+oldCap

因此,我们在扩充HashMap的时候,不需要像JDK1.7的实现那样重新计算hash,

LinkedHashMap(有序,加上了双向链表)

LinkedHashMap就是HashMap+双向链表
在这里插入图片描述
LinkedHashMap是有序的,且默认为插入顺序

ConcurrentHashMap的底层实现:

​ JDK1.7的 ConcurrentHashMap 底层采⽤ 分段的数组+链表 实现;采用 分段锁(Sagment) 对整个桶数组进⾏了分割分段(Segment默认16个),每⼀把锁只锁容器其中⼀部分数据,多线程访问容器⾥不同数据段的数据,就不会存在锁竞争,提⾼并发访问率。
在这里插入图片描述

​ JDK1.8的 ConcurrentHashMap 采⽤的数据结构跟HashMap1.8的结构⼀样,数组+链表/红⿊树;摒弃了Segment的概念,⽽是直接⽤ Node 数组+链表+红⿊树的数据结构来实现,通过并发控制 synchronized 和CAS来操作保证线程的安全。

2. 异常

除了error和runtimeException其他都为必检异常在这里插入图片描述

  1. 尽量不要捕获类似Exception这样的通用异常,而是应该捕获特定异常
  2. 不要生吞(swallow)异常。这是异常处理中要特别注意的事情,因为很可能会导致非常难以诊断的诡异情况
  3. 不要e.printStackTrace();,不好确认输出到哪里了
  4. Throw early, catch late(提前抛出能早点定位到问题,晚点catch,在更高层面,因为有了清晰的(业务)逻辑,往往会更清楚合适的处理方式是什么)
  5. try-catch代码段会产生额外的性能开销,或者换个角度说,它往往会影响JVM对代码进行优化,所以建议仅捕获有必要的代码段,尽量不要一个大的try包住整段的代码;与此同时,利用异常控制代码流程,也不是一个好主意,远比我们通常意义上的条件语句(if/else、switch)要低效
  6. Java每实例化一个Exception,都会对当时的栈进行快照,这是一个相对比较重的操作。如果发生的非常频繁,这个开销可就不能被忽略了。

3. final、finally(关闭的连接等资源)、 finalize(垃圾回收关联)

在这里插入图片描述
finally里面的代码可不会被执行的哦

finalize ,jdk9已废除,无法保证fnalize什么时候执行,执行的是否符合预期,不推荐使用,降低垃圾回收效率,Java平台目前在逐步使用java.lang.ref.Cleaner来替换掉原有的fnalize实现。Cleaner的实现利用了幻象引用

4. 强引用、软引用(缓存)、弱引用、虚引用(检测对象被回收)

  1. 强引用(“Strong” Reference),就是我们最常见的普通对象引用,只要还有强引用指向一个对象,就能表明对象还“活着”
  2. 软引用(SoftReference),是一种相对强引用弱化一些的引用,可以让对象豁免一些垃圾收集,只有当JVM认为内存不足时,才会去试图回收软引用指向的对象,软引用通常用来实现内存敏感的缓存,如果还有空闲内存,就可以暂时保留缓存,当内存不足时清理掉,
    使用:浏览器的后退按钮。按后退时,这个后退时显示的网页内容是重新进行请求还是从缓存中取出
  3. 弱引用(WeakReference)并不能使对象豁免垃圾收集,仅仅是提供一种访问在弱引用状态下对象的途径,如果试图获取时对象还在,就使用它,否则重现实例化。它同样是很多缓存实现的选择。
  4. 虚引用,你不能通过它访问对象。幻象引用仅仅是提供了一种确保对象被fnalize以后,做某些事情的机制,比如,通常用来做所谓的Post-Mortem清理机制,它主要用来跟踪对象被垃圾回收的活动。

方法的内部有一个强引用,这个引用保存在Java栈中,而真正的引用内容(Object)保存在Java堆中。 当这个方法运行完成后,就会退出方法栈,则引用对象的引用数为0,这个对象会被回收

软引用可以和一个引用队列(ReferenceQueue)联合使用。如果软引用所引用对象被垃圾回收,JAVA虚拟机就会把这个软引用加入到与之关联的引用队列中。
弱引用可以和一个引用队列,
虚引用必须和一个引用队列联合使用,当 GC 准备回收一个对象,如果发现它有虚引用,就会在回收之前,把这个 虚引用 加入到与之关联的 ReferenceQueue 中

    ReferenceQueue<String> referenceQueue = new ReferenceQueue<>();
    String str = new String("abc");
    SoftReference<String> softReference = new SoftReference<>(str, referenceQueue);

    str = null;//软引用中的对象引用置为null
    // Notify GC
    System.gc();

    System.out.println(softReference.get()); // abc

    Reference<? extends String> reference = referenceQueue.poll();
    System.out.println(reference); //null

5. String、StringBufer、StringBuilder

String是典型的Immutable类
StringBufer是为解决上面提到拼接产生太多中间对象的问题而提供的一个类(线程安全)
StringBuilder(线程不安全)

为了实现修改字符序列的目的,StringBufer和StringBuilder底层都是利用可修改的(char,JDK 9以后是byte)数组
在JDK 8中,字符串拼接操作会自动被javac转换为StringBuilder操

6. 不同字符占用空间与编码有关

中文在不同编码是不定长的 2-4个字节,英文一般是1个,只有Unicode编码下是2个字节

ASCII码:英文字母 1个字节的空间
UTF-8编码:英文字符 1个字节(含标点),中文字符 3个字节(含标点)
UTF-16编码,通常汉字占2个字节
Unicode编码:英文中文都是2个字节
GBK编码,一个汉字占2个字节。

字符 不等于 字节。

字符(char)是 Java 中的一种基本数据类型,由 2 个字节组成,
java一个 int 占 4 个字节,一个 double 占 8个字节 等等。

8bit(位)=1Byte(字节) 1024Byte(字节)=1KB 1024KB=1MB 1024MB=1GB 1024GB=1TB

7. 写时复制

解释:
Copy-On-Write简称COW,是一种用于程序设计中的优化策略。其基本思路是,
如果有多个调用者(callers)同时请求相同资源(如内存或磁盘上的数据存储),他们会共同获取相同的指针指向相同的资源,直到某个调用者试图修改资源的内容时,系统才会真正复制一份专用副本(private copy)给该调用者,而其他调用者所见到的最初的资源仍然保持不变。这过程对其他的调用者都是透明的

使用

  • linux 的fock(),exec()
  • java容器

8. @Transactional

事务传播属性

传播特性是作用于内层方法上

PROPAGATION_REQUIRED:如果不存在外层事务,就主动创建事务;否则使用外层事务(默认)
PROPAGATION_SUPPORTS:如果不存在外层事务,就不开启事务;否则使用外层事务(内外一致)
PROPAGATION_MANDATORY:如果不存在外层事务,就抛出异常;否则使用外层事务
PROPAGATION_REQUIRES_NEW:总是主动开启事务;如果存在外层事务,就将外层事务挂起
PROPAGATION_NOT_SUPPORTED:总是不开启事务;如果存在外层事务,就将外层事务挂起
PROPAGATION_NEVER:总是不开启事务;如果存在外层事务,则抛出异常
PROPAGATION_NESTED:如果不存在外层事务,就主动创建事务;否则创建嵌套的子事务(内依赖外,外不希望被内影响,外层catch住内层的异常,外层就不会回滚)

rollbackFor

注解不生效

注解只是个标记,实际作用于注解对应的切面,需要在切面中识别注解中定义的如@Order才能生效

  1. try catch掉了,没抛出
    2. 没有开启对注解的解析(@EnableTransactionManagement )
    3. @Transactional只能作用域public方法上(因为,被aop增强的方法都应该是public的,而不能是private的)
    4. 默认只对非必检异常处理,必检的IOException,SQLException,FileNotFoundException异常等无法回滚,(rollbackFor = Exception.class即可解决)
    5. 数据库引擎要支持事务,如myisam不行
    6. 分布式事务不支持

9. 泛型擦除

Java的泛型基本上都是在编译器这个层次上实现的,在生成的字节码中是不包含泛型中的类型信息的,使用泛型的时候加上类型参数,在编译器编译的时候会去掉,这个过程成为类型擦除。
如List等类型,在编译之后都会变成 List。JVM 看到的只是 List,而由泛型附加的类型信息对 JVM 来说是不可见的。

ArrayList<String> list1 = new ArrayList<String>();
        list1.add("abc");

        ArrayList<Integer> list2 = new ArrayList<Integer>();
        list2.add(123);

			//true
        System.out.println(list1.getClass() == list2.getClass());
        

先检查再编译,类型检查就是针对引用的

泛型类型变量不能是基本数据类型
泛型类中的静态方法和静态变量不可以使用泛型类所声明的泛型类型参数

public class Test2<T> {    
    public static T one;   //编译错误    
    public static  T show(T one){ //编译错误    
        return null;    
    }    
}

因为类型擦除的问题,所以所有的泛型类型变量最后都会被替换为原始类型。

既然都被替换为原始类型,那么为什么我们在获取的时候,不需要进行强制类型转换呢

假设泛型类型变量为Date,虽然泛型信息会被擦除掉,但是会将(E) elementData[index],编译为(Date) elementData[index]。所以我们不用自己进行强转。

10. fail-fast ,fail-safe(它是Java集合的一种错误检测机制)

fail-fast主要是体现在当我们在遍历集合元素的时候,经常会使用迭代器,但在迭代器遍历元素的过程中,如果集合的结构(modCount)被改变的话,就会抛出异常ConcurrentModificationException,防止继续遍历。这就是所谓的快速失败机制

采用安全失败机制的集合容器,在遍历时不是直接在集合内容上访问的,而是先复制原有集合内容,在拷贝的集合上进行遍历。由于在遍历过程中对原集合所作的修改并不能被迭代器检测到,所以不会触发ConcurrentModificationException。

11. Object

toString,equals,hashcode,clone(浅拷贝,对象里面的对象只拷贝引用),wait,notify,getClass,finalize

12. 创建对象的步骤

步骤:类加载检查、分配内存、初始化零值、设置对象头、执行init方法

①类加载检查:

​ 虚拟机遇到 new 指令时,⾸先去检查是否能在常量池中定位到这个类的符号引⽤,并且检查这个符号引⽤代表的类是否已被加载过、解析和初始化过。如果没有,那必须先执⾏相应的类加载过程。

②分配内存:

​ 在类加载检查通过后,接下来虚拟机将为新⽣对象分配内存,分配⽅式有 “指针碰撞” 和 “空闲列表” 两种,选择那种分配⽅式由 Java 堆是否规整决定,⽽Java堆是否规整⼜由所采⽤的垃圾收集器是否带有压缩整理功能决定。

③初始化零值:

​ 内存分配完成后,虚拟机需要将分配到的内存空间都初始化为零值,这⼀步操作保证了对象的实例字段在 Java 代码中可以不赋初始值就直接使⽤,程序能访问到这些字段的数据类型所对应的零值。

④设置对象头:

​ 初始化零值完成之后,虚拟机要对对象进⾏必要的设置,例如这个对象是那个类的实例、如何才能找到类的元数据信息、对象的哈希吗、对象的 GC 分代年龄等信息。 这些信息存放在对象头中。 另外,根据虚拟机当前运⾏状态的不同,如是否启⽤偏向锁等,对象头会有不同的设置⽅式。

⑤执⾏ init ⽅法:

​ 从虚拟机的视⻆来看,⼀个新的对象已经产⽣了,但从Java 程序的视⻆来看, ⽅法还没有执⾏,所有的字段都还为零。所以⼀般来说(除循环依赖),执⾏ new 指令之后会接着执⾏ ⽅法,这样⼀个真正可⽤的对象才算产⽣出来。

13. 内存泄漏(释放不掉)

内存泄漏指你申请了一块内存,但是没有内存释放,导致这块内存一直处于占用状态。(无用的被引用的对象)

长生命周期的对象持有短生命周期对象的引用就很可能发生内存泄漏

  1. 静态集合类引起内存泄漏,单例对象持有外部的引用(例子:HashMap做缓存)
  2. 各种连接(例子:关于文件处理器的应用,在读取或者写入一些文件之后,由于发生了一些异常,close 方法又没有放在 finally 块里面)
    数据库连接的connection,Connection一旦回收,Resultset 和Statement 对象就会立即为NULL。
    数据库连接池,必须显式地关闭Resultset Statement 对象

内存溢出(内存不够)

14. spring设计模式

单例:线程池,私有构造方法+两段锁获取instance

双重检测锁,第一次减少锁的开销、第二次防止重复、volatile防止重排序导致实例化未完成
两段锁

public static aaThreadPool getInstance() {
            if(instance == null){
                synchronized (aaThreadPool.class){
                    if(instance == null){
                         instance = new aaThreadPool();;
                    }
                }
            }
            return instance;
        }

1.分配内存空间
2.在这块内存上初始化对象
3.将内存地址赋值给earth变量
重排序后:
1.分配内存空间
2.将内存地址赋值给earth变量
3.在这块内存上初始化对象
并发下:线程A执行到2,实例未初始化完毕,线程b获取到锁,发现不为null,返回对象使用,此时对象未初始化

工厂: Spring使⽤⼯⼚模式通过 BeanFactory 、 ApplicationContext 创建bean 对象。

在这里插入图片描述

代理 : Spring AOP 功能的实现。

观察者: Spring 事件驱动模型就是观察者模式很经典的⼀个应⽤。

适配器:Spring AOP 的增强或通知(Advice)使⽤到了适配器模式、Spring MVC 中也是⽤到了适配器模式适配 Controller 。

将一个类的接口转换成客户希望的另外一个接口

15.创建对象步骤

步骤:类加载检查、分配内存、初始化零值、设置对象头、执行init方法

初始化零值完成之后,虚拟机要对对象进⾏必要的设置,例如这个对象是那个类的实例、如何才能找到类的元数据信息、对象的哈希吗、对象的 GC 分代年龄等信息。 这些信息存放在对象头中。 另外,根据虚拟机当前运⾏状态的不同,如是否启⽤偏向锁等,对象头会有不同的设置⽅式。

16. spring cloud

Spring Cloud是一套非常完善的分布式框架,目前很多企业开始用微服务、Spring Cloud的优势是显而易见的 ,利用Spring Boot的开发便利性巧妙地简化了分布式系统基础设施的开发,如服务发现注册、配置中心、智能路由、消息总线、负载均衡、断路器、数据监控等,都可以用Spring Boot的开发风格做到一键启动和部署;Spring Cloud的子项目,大致可分成两类,一类是对现有成熟框架"Spring Boot化"的封装和抽象,也是数量最多的项目;第二类是开发了一部分分布式系统的基础设施的实现

springcloud 不是一个开发框架,而是一整套的解决方案,而 dubbo 仅仅是一个 rpc 的框架

Spring Boot 是 Spring 的一套快速配置脚手架,可以基于Spring Boot 快速开发单个微服务,Spring Cloud是一个基于Spring Boot实现的云应用开发工具。Spring -> Spring Boot > Spring Cloud 这样的关系

SpringBoot是Spring推出用于解决传统框架配置文件冗余,装配组件繁杂的基于Maven的解决方案,旨在快速搭建单个微服务

springboot:约定大于配置,内置容器,自动装配:**Spring Boot 会根据某些规则对所有配置的 Bean 进行初始化。可以减少了很多重复性的工作

spring cloud的组成
路由route: ⽹关最基础的⼯作单元。路由由⼀个ID、⼀个⽬标URL、⼀系列的断⾔(匹配条件判断)和Filter过滤器组成。如果断⾔为true,则匹配该路由。

Eureka (ap)/ Zookeeper(cp)

Hystrix / Sentinel
在这里插入图片描述
在这里插入图片描述

Hystrix(调用方,熔断降级,快速失败) / Sentinel(提供方,流量控制)
线程池隔离(受线程池中线程数量的限制,线程切换开销大)/信号量隔离(开销相对较小,并发请求受信号量的个数的限制)

Config / Nacos(配置中心)
Bus / Stream(mq)
Sleuth / Zipkin(全链路追踪)

作用域

名称 作用域
singleton 单例对象,默认值的作用域
prototype 每次获取都会创建⼀个新的 bean 实例
request 每⼀次HTTP请求都会产⽣⼀个新的bean,该bean仅在当前HTTP request内有效。
session 在一次 HTTP session 中,容器将返回同一个实例(用户多次请求,可以理解是客户端同一个IE窗口发出的多个请求)
global-session 将对象存入到web项目集群的session域中,若不存在集群,则global session相当于session

循环依赖

​ 循环依赖其实就是循环引用,也就是两个或者两个以上的 Bean 互相持有对方,最终形成闭环。比如A 依赖于B,B又依赖于A

解决方案:多级缓存

这三级缓存分别指:
singletonFactories : 单例对象工厂的cache
earlySingletonObjects :提前暴光的单例对象的Cache
singletonObjects:单例对象的cache

在这里插入图片描述

17. spi(Service Provider Interface)

用来启用框架扩展和替换组件。 SPI的作用就是为这些被扩展的API寻找服务实现。
使用场景:数据库连接,dubbo框架的拓展,日志接口类对不同厂商的加载
特点:基于接口编程,桥接模式,避免 直接引入实现类,或者通过反射引入以及dubbo远程调用,而是通过插件的方式,在引入的jar包中的META-INF/services目录下的配置文件(配置文件名和接口路径一直)指定实现类的路径,来找到实现类;懒加载,缺点是遍历的方式所有实现类都会被加载

  1. 不需要改动源码就可以实现扩展,解耦。
  2. 实现扩展对原来的代码几乎没有侵入性。
  3. 只需要添加配置就可以实现扩展,符合开闭原则。
    使用方式:工程1定义接口;工程2实现接口,并创建META-INF/services/接口名 的文件,内容为实现类的路径,然后打包;工程3引入工程1和工程2的包,即可基于接口来使用实现类,ServiceLoader来load方法加载实现类(扫描META-INF目录,获取文件名,反射生成对象缓存)
    (ServiceLoader shouts = ServiceLoader.load(IShout.class))

18. ratelimiter(预消费)

两种模式,平滑模式和预热模式

 RateLimiter rateLimiter = RateLimiter.create(1);
        while (true){
            System.out.println("rate1:" + rateLimiter.acquire(1)); //阻塞
            System.out.println("rate3:" + rateLimiter.acquire(3)); //通过限制后面请求的等待时间,来支持一定程度的突发请求(预消费),此时等待1s
            System.out.println("rate5:" + rateLimiter.acquire(5));
            System.out.println("rate7:" + rateLimiter.acquire(7));
            System.out.println("rate try:" + rateLimiter.tryAcquire(3,1,TimeUnit.SECONDS));//设置等待超时时间
        }

令牌数,不是通过定时任务存放的方式,而是通过取令牌时延迟计算,有storedPermits,maxPermits,stableIntervalMicros,nextFreeTicketMicros(下次请求需要等待相应的时间到nextFreeTicketMicros时刻才可以获取令牌)来计算,其实现思路为,若当前时间晚于nextFreeTicketMicros,则计算该段时间内可以生成多少令牌,将生成的令牌加入令牌桶中并更新数据。这样一来,只需要在获取令牌时计算一次即可。

19. equals和hashcode

hashcode根据内存地址计算
两个对象相等其hash值一定相等(java规定,不重写hashcode的话集合类无法去重,集合类放入时先判断hashcode是否一样,再用equals,可以提高程序插入和查询的速度)
如果重写equals没写hashcode方法,equals判断相等,但是不同的内容用的Object的hashcode方法会出现不一样,所以要重写hashcode

20. dubbo

服务注册,服务发现,故障转移、路由转发、负载均衡
在这里插入图片描述
在这里插入图片描述
所谓路由机制,是指设置一定的规则对服务提供者列表进行过滤。负载均衡时,只在经过了路由机制的服务提供者列表中进行选择。

在这里插入图片描述
网络通信模型:包括通信协议(header和body,序列化,默认hessian2)和线程派发机制(请求在io线程还是业务线程执行,默认all,即除了心跳包和io之外都在业务线程池执行; io线程和业务线程,通信协议相关参数有threads,queues,iothreads,serialization),io线程中不能有阻塞操作,否则影响效率,简单的如心跳包都放在io线程中

拓展机制

基于spi理念,filter机制

泛化调用

dubbo调用方式两种,普通的反射调用和泛化调用(不用引入jar包,网关类,业务中很少使用)

普通接口调用 ->
反射调用(java反射,已知类名,方法名,参数,抽象出公共方法)->
泛化调用(采用一种统一的方式来发起对任何服务方法的调用,适用于网关,透传等没有很多业务逻辑的场景),依赖@DubboReference的ReferenceConfig关键类;使用GenericService的$invoker方法

当服务消费端发生调用时,我们使用 Map 来存储一个具体的请求参数对象,然后传输到服务提供方。由于服务提供方引入了模型相关的 Jar,服务提供方在执行业务方法之前,需要将 Map 转化成具体的模型对象,然后再执行业务逻辑。

21. 代理

代理方式:

  1. 静态代理:自己手写代理类,调用被代理类的方法,代理类和原始类的关系在运行前就已经确定
  2. 动态代理

动态代理实现方式

  1. jdk自身的代理,基于反射生成的代理对象(public final class $Proxy0 extends Proxy implements Interface)代理对象继承自Proxy对象实现了被代理的接口,由于java单继承,所以java代理只能代理接口(运行时生成对象,获取类信息,甚至可以修改类定义,Class、Field、Method、Constructor,反射能绕开限制) 实例化的是Proxy对象,依赖少,代码简单,需要实现InvocationHandler类加上增强逻辑,Proxy.newProxyInstance(classLoader, classes(被代理的接口), handler(增强类));缺点只能代理接口
  2. cglib(cglib基于ASM,底层是通过使用一个小而快的字节码处理框架ASM来转换字节码并生成新的类,不能对final修饰的类或方法进行增强)原理是:CGLIB来创建一个继承实现类的子类,用Asm库动态修改子类的代码来实现AOP效果;高性能;
  3. Instrument,实际上提供了 一种虚拟机级别支持的 AOP 实现方式

字节码增强工具(目标类都没有被提前加载到JVM中)

  1. ASM,它可以直接生产 .class字节码文件,也可以在类被加载入JVM之前动态修改类行为。ASM的应用场景有AOP(Cglib就是基于ASM)、热部署、修改其他jar包中的类等;ASM虽然可以达到修改字节码的效果,但是代码实现上更偏底层,是一个个虚拟机指令的组合,不好理解、记忆,和Java语言的编程习惯有较大差距。
  2. Javassist:编辑字节码,可以说更加简单、易懂,符合java编程习惯

Instrumentation接口来做运行时字节码文件的修改,是JVM提供的一个可以修改已加载类的类库
如需要运行时修改字节码(Arthas)
Attach API的loadAgent()方法,能够将打包好的Agent jar包动态Attach到目标JVM上

问题:
同一个类中的方法,调用有注解的方法,会使AOP注解失效
原因:Spring的动态代理帮我们动态生成了一个代理的对象,暂且叫他 U s e r S e r v i c e 。所以调用 h e l l o ( ) 方法实际上是代理对象 UserService。所以调用hello()方法实际上是代理对象 UserService。所以调用hello()方法实际上是代理对象UserService调用的。但是在hello()方法内调用同一个类的另外一个注解方法saveUser()时,实际上是通过this.saveUser()执行的, this 指的是UserService 对象,并不是$UserService代理对象调用的,没有走代理。所以注解失效。

注解

注解的本质就是一个继承了 Annotation 接口的接口,生成注解的实例,它本质上就是一个代理类,你应当去理解好 AnnotationInvocationHandler 中 invoke 方法的实现逻辑,这是核心。一句话概括就是,通过方法名返回注解属性值。

一般是自定义注解+aop实现如登陆校验,格式化输出,操作日志打印等功能
1,定义注解;2:方法中引用;3:定义切面(获取注解属性值等信息,根据属性值进行切面前后操作)

Instrument

Instrumentation接口来做运行时字节码文件的修改,是JVM提供的一个可以修改已加载类的类库
如需要运行时修改字节码
通过java agent实现
使用 Instrumentation,使得开发者可以构建一个独立于应用程序的代理程序(Agent),用来监测和协助运行在 JVM 上的程序,甚至能够替换和修改某些类的定义。有了这样的功能,开发者就可以实现更为灵活的运行时虚拟机监控和 Java 类操作了,这样的特性实际上提供了 一种虚拟机级别支持的 AOP 实现方式,使得开发者无需对 JDK 做任何升级和改动,就可以实现某些 AOP 的功能了。
Agent是JVMTI的一种实现,JVMTI 提供了一套”代理”程序机制,可以支持第三方工具程序以代理的方式连接和访问 JVM,并利用 JVMTI 提供的丰富的编程接口,完成很多跟 JVM 相关的功能。

22. 泛型(参数是匿名内部类)

public CompletableFuture<T> whenComplete(
        BiConsumer<? super T, ? super Throwable> action) {
        return uniWhenCompleteStage(null, action);
    }
使用
.whenComplete(
                        new BiConsumer<List<String>, Throwable>() {
                            @Override
                            public void accept(List<String> uid, Throwable throwable) {
                                System.out.println("whencomplate2");
                                System.out.println(uid);
                            }
                        }
                )
或者
.whenComplete(
                        (uid, e) -> {
                    System.out.println("whencomplate");
                    System.out.println(uid);

                }

泛型类:用< >括住,放在类名后面,类型参数可用于声明变量、形参、返回值、强制类型转换

public class Box<T> {
   
  private T t;
 
  public void add(T t) {
    this.t = t;
  }
 
  public T get() {
    return t;
  }
  }

泛型接口:用< >括住,放在接口名后面。

interface two<A>{

}

泛型方法:用< >括住,放在方法返回值前面。泛型参数可以被用到形参声明、方法返回值、方法定义中的变量声明和类型转换

// 比较三个值并返回最大值
   public static <T extends Comparable<T>> T maximum(T x, T y, T z)
   {                     
      T max = x; // 假设x是初始最大值
      if ( y.compareTo( max ) > 0 ){
         max = y; //y 更大
      }
      if ( z.compareTo( max ) > 0 ){
         max = z; // 现在 z 更大           
      }
      return max; // 返回最大对象
   }

23. try-catch性能

try块内禁止指令重排序优化,会影响性能(try块要小,try块范围尽量只覆盖抛出异常的地方)
for循环内try-catch需要处理catch内的逻辑,加上异常多的话,性能会差(for循环内不要try catch)

24. 事件驱动

需要

  1. 事件类,继承自EventObject,封装有事件源对象
  2. 监听器,实现EventListener,内部含事件类对象,定义回调方法
  3. 事件源,内部含有监听器类对象,并调用监听器回调方法

事件源变动 会调用回调用法,实现事件驱动

25. 缓存

只读缓存(读多)和读写缓存(读写比接近,只更新缓存,和缓存打交道,缓存和db打交道)
只读缓存更新策略:
要求没那么高的,设置key过期时间或者定期从数据库拉数据
要求高的,同步更新,通过事务保证一致性,降低性能

26.泛型

泛型方法(返回值前面➕泛型定义):
public void print(T t){
System.out.println(t);
}
泛型接口:
interface showInterface
{
public void show(T t);

}
泛型类:
class Test
{
public void show(T t){
System.out.println(t);
}
}

一般使用泛型方法和接口,不使用泛型类是因为类指定了泛型的类型后,这个对象只能使用该类型,不像泛型方法那么灵活

27. 微服务

服务描述,(接口设计规范,XML,RESTful api,postman上面能看到的各种格式规范)
服务框架(通信框架(http,socket),通信协议(http,socket),序列化)
服务注册(zk),
服务监控,
服务追踪,
服务治理(负载均衡,路由容错,删除故障节点)

mybatis #和$区别

#会加单引号,能防止sql注入,$不加,用于动态指定表名,变量名

JAVA知识点全面总结9:JVM调优 学习 阅读详情

相关推荐

基于STM32F4的NRF24L01驱动程序

基于STM32F4xx的NRF24L01驱动程序 提示:硬件平台基于STM32F427VIT6、NRF24L01模块 文章目录基于STM32F4xx的NRF24L01驱动程序前言一、NRF24L01简单介绍1,什么是NRF24L012,NRF24L01通信方法3,NRF24L01通信原理4,地址分配&通道分配问题二、STM32CubeMX配置三、添加底层文件1,添加.c/.h文件到工程中2,使用说明四,下载 前言 提示:本例程采用STM32CubeMX配置底层,采用硬件SPI方式驱动NRF24

qq_43603289的博客 2812

Java核心技术讲解学习二

LuckQI在这里你可以得到不只是技术,关注即可习得新技能 继续我们的Java核心知识点的学习。上面一篇说过虚拟机还有Java世界平台的简单知识,还顺便总结了Error和Exception相关内容看相关内容,请阅读Java核心技术讲解学习一。我们今天说点别的引用还有final,finally ,finalize三者相关的内容。final.finally,finalize    我们平常在使用的时候...

fengruiqi的博客 1042

基于Hadoop的NBA篮球球员大数据分析与可视化系统大数据分析系统python的项目(源码+lw+部署文档+讲解等)

本系统以 Hadoop 为基础,致力于对 NBA 篮球球员的海量数据进行深入分析与可视化呈现。它能够收集来自多个数据源的丰富数据,包括球员比赛统计数据、身体素质数据、技术特点数据等。利用 Hadoop 的分布式存储和计算能力,对这些大规模数据进行高效处理。通过数据分析算法,挖掘球员的潜在价值和特点,如球员的得分能力趋势、篮板球效率变化、不同位置球员的技术差异等。同时,借助先进的可视化技术,将分析结果以直观的图表、图形等形式展示出来。教练和球队管理层可以通过可视化界面清晰地了解球员的综合表现和发展态势,从而制

QQ3359892174的博客 1314

分享Java的9个知识点

关于java编程的知识,有人会问哪些是重要的知识点,不知道大家是否都知道呢? 现在兄弟连小编给大家分享以下9点内容,仔细看咯! 1.多线程并发 多线程是Java中普遍认为比较难的一块。多线程用好了可以有效提高cpu使用率, 提升整体系统效率, 特别是在有大量IO操作阻塞的情况下;但是它也是一柄双刃剑, 如果用不好,系统非但提升不大,或者没有提升,而且还会带来多线程之间的调...

diyi6539的博客 404

Streamlit安装避坑指南:从零到一键启动你的第一个数据可视化应用

本文提供了一份详尽的Streamlit安装避坑指南,帮助用户从零开始快速启动第一个数据可视化应用。文章深入剖析了安装过程中常见的网络超时、依赖冲突、环境变量缺失等核心问题,并给出了使用虚拟环境、配置国内镜像源、利用.whl文件离线安装等多种经过验证的解决方案,确保安装过程顺畅无阻。

weixin_29065015的博客 614

泛微OA集成阿里云短信(E9保姆教程)

泛微OA集成阿里云短信(E9保姆教程)

技术分享 515

初学Java必备9个重要的知识点

关于Java编程的知识,有人会问哪些是重要的知识点,不知道大家是否都知道呢?现在达妹给大家分享以下9点内容,仔细看咯!1.多线程并发多线程是Java中普遍认为比较难的一块。多线程用好了可以有效提高cpu使用率,提升整体系统效率,特别是在有大量IO操作阻塞的情况下;但是它也是一柄双刃剑,如果用不好,系统非但提升不大,或者没有提升,而且还会带来多线程之间的调试时等问题。在多线程中内容有很多,只是简单说...

IT技术交流分享 1786

NX二次开发 内部函数鼠标动态位置获取

内部函数鼠标动态位置获取

qq285503851的博客 3336

Java核心知识点整理大全9-笔记

而 LinkedBlockingQueue 之所以能够高效的处理并发数据,还因为其对于生产者 端和消费者端分别采用了独立的锁来控制数据同步,这也意味着在高并发的情况下生产者和消费 者可以并行地操作队列中的数据,以此来提高整个队列的并发性能。是一个不存储元素的阻塞队列。默认情况下 不保证访问者公平的访问队列,所谓公平访问队列是指阻塞的所有生产者线程或消费者线程,当 队列可用时,可以按照阻塞的先后顺序访问队列,即先阻塞的生产者线程,可以先往队列里插入 元素,先阻塞的消费者线程,可以先从队列里获取元素。

私信up主,有惊喜 6356

EtherCAT主站SOEM -- 18 --Qt-Soem通过CSV模式(周期同步速度模式)控制一个电机转圈圈

以上就是 EtherCAT主站SOEM – 18 --Qt-Soem通过CSV模式(周期同步速度模式)控制一个电机转圈圈 的内容。有不明白的地方欢迎留言;有建议欢迎留言,我后面编写文档好改进。创作不容,如果文档对您有帮助,记得给个赞。

常驻客栈的博客--嵌入式EtherCAT 1211

Java知识点9

什么时候定义静态成员呢?或者说:定义成员时,到底需不需要被静态修饰呢? 成员分两种: 1,成员变量。(数据共享时静态化)  该成员变量的数据是否是所有对象都一样:  如果是,那么该变量需要被静态修饰,因为是共享的数据。  如果不是,那么就说这是对象的特有数据,要存储到对象中。  2,成员函数。(方法中没有调用特有数据时就定义成静态)  如果判断成员函数是否需要被静态修饰呢?   只要参考,该

weizhentian624811的博客 297

【人工智能】国产开源大模型聊天 AquilaChat 快速开始上手实战&效果评测

Aquila语言大模型在技术上继承了GPT-3、LLaMA等的架构设计优点,替换了一批更高效的底层算子实现、重新设计实现了中英双语的tokenizer,升级了BMTrain并行训练方法,在Aquila的训练过程中实现了比Magtron+DeepSpeed zero-2将近8倍的训练效率。Aquila语言大模型是在中英文高质量语料基础上从0开始训练的,通过数据质量的控制、多种训练的优化方法,实现在更小的数据集、更短的训练时间,获得比其它开源模型更优的性能。

AI天才研究院 2万+

Java知识点整理 9 — JVM

Java知识点整理 6 — JVM部分,后续会持续更新整理。

konghaoran的博客 1187

霍尼韦尔SoftMaster使用说明

霍尼韦尔SoftMaster使用说明

老版QQ原生表情gif动态

这是老版的QQ表情,不过全是动态的的,Windows照片查看器是不会动的,可以右击用浏览器打开查看,再说一遍是老版的,只是分享给宁愿用老版也要动态的人。

java初级中的xml重要吗_java初级编程9个重要的知识点你知道几个?

原标题:java初级编程9个重要的知识点你知道几个?关于java编程的知识,有人会问哪些是重要的知识点,不知道大家是否都知道呢? 现在小编给大家分享以下9点内容,仔细看咯!1.多线程并发多线程是Java中普遍认为比较难的一块。多线程用好了可以有效提高cpu使用率, 提升整体系统效率, 特别是在有大量IO操作阻塞的情况下;但是它也是一柄双刃剑, 如果用不好,系统非但提升不大,或者没有提升,而且还会带...

weixin_29002191的博客 209

Camera2Demo

在Camera2 的基础上进行封装,使得Camera2一堆初始化逻辑与Activity分离,降低耦合度,完成预览拍照并保存的操作

java 9-期末复习知识点

9 Object 提供的常用方法equals()、toString()、hashCode()打印出所有的"水仙花数",所谓"水仙花数"是指一个三位数,其各位数字立方和等于该数本身。例如:153是一个"水仙花数",因为153=1的三次方+5的三次方+3的三次方。A、类体中只能有变量定义和成员方法的定义,不能有其他语句。5 字符串 (定义、比较、String提供的常用方法等)下面关于java中类的说法哪个是不正确的( )。5 捕获异常 try…5 final 关键字修饰类和方法的用法、涵义。

ebatudou的博客 159

visio安装包

Microsoft Office Visio 是一款专业的制图软件。利用经过更新的形状、协作工具和数据链接图表,创建专业级图表以简化复杂的信息。

Java的知识点9——this关键字

this关键字 构造方法是创建Java对象的重要途径,通过new关键字调用构造器时,构造器也确实返回该类的对象,但这个对象并不是完全由构造器负责创建。 创建一个对象分为如下四步:   1. 分配对象空间,并将对象成员变量初始化为0或空   2. 执行属性值的显式初始化   3. 执行构造方法   4. 返回对象的地址给相关的变量 this的本质就是“创建好的对象的地址”! 由于在构造...

qq_39368007的博客 341

Java初级编程9个重要的知识点你知道几个?

关于java编程的知识,有人会问哪些是重要的知识点,不知道大家是否都知道呢? 现在小编给大家分享以下9点内容,仔细看咯! 1.多线程并发 多线程是Java中普遍认为比较难的一块。多线程用好了可以有效提高cpu使用率, 提升整体系统效率, 特别是在有大量IO操作阻塞的情况下;但是它也是一柄双刃剑, 如果用不好,系统非但提升不大,或者没有提升,而且还会带来多线程之间的调试时等问题。 在多线...

java03_15的博客 238

java初级编程9个重要的知识点你知道几个?

关于java编程的知识,有人会问哪些是重要的知识点,不知道大家是否都知道呢? 现在小编给大家分享以下9点内容,仔细看咯! 1.多线程并发 多线程是Java中普遍认为比较难的一块。多线程用好了可以有效提高cpu使用率, 提升整体系统效率, 特别是在有大量IO操作阻塞的情况下;但是它也是一柄双刃剑, 如果用不好,系统非但提升不大,或者没有提升,而且还会带来多线程之间的调试时等问题。 在多线程中内容有很多,只是简单说明一下Java中初步使用多线程需要掌握的知识点,以后有机会单独再详细介绍一些高级特性的使用

142

Java学习【知识点及代码9】

10. 10.1 Calendar:它为特定瞬间与一组诸如 YEAR、MONTH、DAY_OF_MONTH、HOUR 等 日历字段之间的转换提供了一些方法Calendar(日历类) – 获取年,获取月,获取日,获取时,获取分,获取秒。 public int get(int field):返回给定日历字段的值 package com.edu.calendar;impor

huiyan_edu的博客 305

java学习知识点9

抽象类 接口 内部类

weixin_53176572的博客 91

java9中接口的知识点

qq_30312047的博客 145

java常用知识点系列-9

java常用知识点

weixin_53591856的博客 124

【Head First Java】知识点:Chapter 9

目录 一、所有变量 1 成员变量 1.1 实例变量 1.2 类变量 2 局部变量 二、内存分配 1 程序计数器(Program Counter Register) 2 虚拟机栈(VM Stack) 3 本地方法栈(Native Method Stack) 4 堆(heap) 5 方法区(Method Area) 三、构造器 一、所有变量 (注意:...

qq_35303117的博客 278
上一篇: 长连接
下一篇: 并发编程的艺术
big muscle
博客等级 码龄11年 145粉丝 71原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值