mahaonan 的个人博客   >   分类   >   个人笔记

java细节知识整理 有更新!

2022-07-18

java细节知识整理 java基础 普通for循环和增强for循环都需要判断是否为null list移除类型为int的元素,不能直接写,这样会默认移除下标,应该按如下写 list.remove(new Integer(1)); spring相关 HandlerMethodArgumentResolver 可以对controller的参数进行处理,用来做验证,自动赋值等等操作,详细引用参考springboot-practice中的CurrentUserIdMethodArgumentResolver

3.表,栈,队列

2022-07-18

3.表,栈,队列 ##关于ListIterator接口 ListIterator扩展了List的Iterator功能. 新增了以下方法 boolean hasPrevious() E previous(); void add(E x); void set(E newVal) 注意ListIterator接口中当前项的概念是一个抽象概念,是在next调用所给出的项和previous的调用所给出的项之间抽象出来的 对list的开头使用previous是不合法的,同样对最后一项使用next是非法的

java数据结构

2022-07-18

java数据结构 自信,坚定信念,throw 数据结构 逻辑结构 线性结构 集合结构 树形结构 图形结构 物理结构(存储结构) 顺序存储结构 链式存储结构 数据类型 一组性质相同的值的集合及定义在此集合上的一些操作的总称 比如说基本数据类型int,自定义的类 抽象数据类型 一个数字模型及定义在该模型上的一组操作 比如说抽象类 线性表(List) ] 特征:一一对应的关系 顺序存储方式线性表 ArrayList 内层为数组结构 (增删改查) 链式存储方式线性表 用一组任意的存储单元存储线性表的数据元素,这组存储单元可以是连续的,也可以是不连续的。 里面有一个属性data,用来存储当前元素的对象,还有一个属性next,存放下一个元素的地址(即指向下一个元素的对象) 还有一个属性previous存放上一个元素的地址(即指向上一个元素的对象)(双向链表) 栈(Stack) 栈底就是第一个进栈的数据,栈顶就是最后一个进栈的数据。 波兰表达式(中缀表达式)标准四则运算表达式 逆波兰表达式(后缀表达式)计算机采用的方式 例如:931-3*+10 2/ + 第一步:923*+10 2/....

1.引论

2022-07-18

1.引论 递归(recursive) 四个基本法则如下 基准情形(base case) 必须总要有某些基准的情形,它们不用递归就能求解 不断推进(making progress) 对于那些要递归求解的情形,递归调用必须总能够朝着一个基准情形推进。 设计法则(design rule) 假设所有的递归调用都能运行 当设计递归程序时一般没有必要知道细节,不必去追踪大量的递归调用。从整体上去考虑就可以。 合成效益法则(compound interest rule) 在求解一个问题的同一实例时,切勿在不同的递归调用中做重复性的工作。 取余运算是非常耗时的,因为n%10 = n-[n/10]*10 类似的 n%m = n-[n/m]*m [x]是小于或等于x的最大整数 泛型 协变性 即是否能用is a来描述,如果可以,则具有协变性 java中数组是协变的,所以Teacher [] is-a person[] 集合也是协变的,但是泛型集合不是协变的。使用泛型的意义就在于产生编译器错误而不是运行时的类型不匹配异常 因此Collection 不能够传入参数为Collection的方法中 ....

2.算法分析 有更新!

2022-07-18

2.算法分析 算法(algorithm) 是为求解一个问题需要遵循的,被清除指定的简单指令的集合 运行时间计算的一般法则 for循环 1个for循环的运行时间至多是该for循环内部那些语句(包含测试)的运行时间乘以迭代的次数 嵌套的for循环 从里向外分析这些循环,在一组嵌套循环内部的一条语句总的运行时间为该语句的运行时间乘以该组所有的for循环的大小的乘积 顺序语句 将各个语句的运行时间求和即可(这意味着,其中的最大值就是所得的运行时间) if/else语句 一个if/else语句的运行时间从不超过判断的运行时间再加上S1和S2中运行时间长者的总的运行时间 递归需要具体分析 斐波那契数列(3/2)的N次方<=fib(n)<(5/3)的N次方 最大子序列和问题的求解 算法1:穷举式地尝试所有可能的结果 public static int maxSubSum(int [] a) { int maxSum = 0; /* i控制从哪里开始加,0时从-2开始加,1时从11开始加 j控制加到哪里结束,i=0,j=0时加到-2,i=0,j=1时加到11 ....

02-java反射(一) 有更新!

2022-07-18

02-java反射(一) java反射(一) 一. 反射的基本操作原理 1.1 实例化Class对象的方法 Object类中的getClass()方法 public final Class<?> getClass() 此方法不能被子类所重写,且所有类的实例化对象都可以使用 利用包.类.class的形式实例化Class对象 例如java.util.Date.class,在一些开源框架中会大量使用 利用Class类中的forName()方法 主要可以用在工厂类上,jdbc驱动加载 1.2 Class对象的应用 newInstance() public T newInstance() throws InstantiationException, IllegalAccessException InstantiationException -> 没有无参构造,类名错误 IllegalAccessException -> 构造方法私有化 该方法只能调用类中的无参构造方法,相当于使用new进行对象的实例化操作- 面试题: new实例化....

07-java8剖析(一) 有更新!

2022-07-18

07-java8剖析(一) java8剖析(一) 一. lambda表达式 1.1 lambda表达式 在java中,我们无法将函数作为参数传递给一个方法,也无法声明返回一个函数的方法 基本结构 (param1, param2, param3) -> { } lamda表达式仍然是对象 lambda表达式传递行为,而不仅仅是值 提升抽象层次 API重用性更好 更加灵活 1.2 函数式编程 函数式编程的核心在于,由方法内部实现的业务逻辑改为由调用者声明。方法内部仅提供公用的逻辑。 是一种更高层次的抽象 1.3 方法引用 是一种语法糖,对lamda表达式语法的一种简写 List<String> list = Arrays.asList("mhn", "nhh"); list.forEach(System.out:: println); 类名:: 静态方法名 引用名::实例方法名 类名:: 实例方法名 构造方法引用 类名::new 二. 函数式接口 如果一个接口只有一个抽象方法,那么该接口就是一个函数式接口 如果我们....

03-java反射(二) 有更新!

2022-07-18

03-java反射(二) java反射(二) 一. 利用反射操作简单java类 1.1 定义实体类 company类 package entity; import java.io.Serializable; import java.util.Date; public class Company implements Serializable { private String name; private String address; private Date creatDate; public String getName() { return name; } public void setName(String name) { this.name = name; } public String getAddress() { return address; } public void setAddress(String address) { this.address = address; } public Date getCreatDate() { return creatDate....

05-java并发编程(进阶) 有更新!

2022-07-18

05-java并发编程(进阶) java并发编程(进阶篇) 一. volatile关键字 1.1 作用 强制线程到共享内存中读取数据,而不从线程工作内存中读取,从而使变量在多个线程间可见 一般意义上,一个共享变量会有一个共享内存,然后每个线程都有各自的工作内存,当操作数据时,线程会将共享变量从共享内存中读取到自己的工作内存,因此在操作期间,各个线程之间是不可见的,这样就会引发线程安全问题。 使用volatile关键字,则会忽略从共享内存读取到工作内存,在工作内存中进行独立操作的步骤。而是直接从共享内存中拿数据,操作,然后写入。 不使用volatile: 从共享内存读取到工作内存-> 在工作内存中读取到程序并操作-> 写入工作内存-> 写入共享内存 使用volatile: 从共享内存中读取到程序并操作-> 写入到共享内存 因此,解决了线程可见性的问题 例子 package base; import java.util.ArrayList; import java.util.List; public class DemoThread13{ p....

04-java并发编程(基础) 有更新!

2022-07-18

04-java并发编程(基础) java并发编程(基础篇) 一. 线程安全是如何产生的 多个线程操作同一对象 没有达成原子性,即操作是各自独立的,不是一个整体 当多个线程并发运行操作同一数据时,由于线程切换的时机不可控,可能会导致操作该数据时的过程未按照程序设计的执行顺序运行,导致操作出现混乱,严重时可能会导致系统瘫痪. 二. 认识线程安全与Synchronized 2.1 线程安全 概念 当多个线程访问某一个类,对象或者方法时,这个类,对象或方法都能表现出与单线程一致的行为,那么这个类,对象或方法就是线程安全的. 缘由 线程安全问题都是由全局变量及静态变量引起的 注意事项 若只有读操作,无写操作,那么一般而言是线程安全的 若有多个线程同时写,一般都要考虑线程安全问题 2.2 synchronized 普通方法上使用synchronized(对象锁) 当一个方法是用synchronized修饰后,那么该方法变为"同步方法",多个线程不能同时进入方法内容运行.而必须有顺序的一个一个运行.这样就可以避免并发安全问题. 在方法上使用synchro....

08-字符串常量池

2022-07-18

08-字符串常量池 字符串常量池 一. String基础知识 1.1 定义 String:字符串,使用一对 “” 引起来表示 String s1 = "mahaonan" ; // 字面量的定义方式 String s2 = new String("hello"); // new 对象的方式 String被声明为final的,不可被继承 String实现了Serializable接口:表示字符串是支持序列化的。实现了Comparable接口:表示String可以比较大小 String在jdk8及以前内部定义了final char value[]用于存储字符串数据。JDK9时改为byte[] 1.2 基本特征 String:代表不可变的字符序列。简称:不可变性。 当对字符串重新赋值时,需要重写指定内存区域赋值,不能使用原有的value进行赋值。 当对现有的字符串进行连接操作时,也需要重新指定内存区域赋值,不能使用原有的value进行赋值。 当调用String的replace()方法修改指定字符或字符串时,也需要重新指定内存区域赋值,不能使用原有的value进行....

06-对象的实例化内存布局与访问定位

2022-07-18

06-对象的实例化内存布局与访问定位 对象的实例化内存布局与访问定位 一. 对象的实例化 1.1 对象创建的方式 new:最常见的方式、单例类中调用getInstance的静态类方法,XXXFactory的静态方法 Class的newInstance方法:在JDK9里面被标记为过时的方法,因为只能调用空参构造器,并且权限必须为 public Constructor的newInstance(Xxxx):反射的方式,可以调用空参的,或者带参的构造器 使用clone():不调用任何的构造器,要求当前的类需要实现Cloneable接口中的clone方法 使用序列化:从文件中,从网络中获取一个对象的二进制流,序列化一般用于Socket的网络传输 第三方库 Objenesis 1.2 对象创建的步骤 从字节码的角度看对象创建的步骤 public class ObjectTest { public static void main(String[] args) { Object obj = new Object(); } } public static void main(java.la....

04-堆

2022-07-18

04-堆 JVM之运行时数据区(三)-- 堆 一. 堆的核心概述 1.1 堆与进程 堆针对一个JVM进程来说是唯一的。也就是一个进程只有一个JVM实例,一个JVM实例中就有一个运行时数据区,一个运行时数据区只有一个堆和一个方法区。 但是进程包含多个线程,他们是共享同一堆空间的。 1.2 基本特性 一个JVM实例只存在一个堆内存,堆也是Java内存管理的核心区域。 Java堆区在JVM启动的时候即被创建,其空间大小也就确定了,堆是JVM管理的最大一块内存空间,并且堆内存的大小是可以调节的。 《Java虚拟机规范》规定,堆可以处于物理上不连续的内存空间中,但在逻辑上它应该被视为连续的。 所有的线程共享Java堆,在这里还可以划分线程私有的缓冲区(Thread Local Allocation Buffer,TLAB)。 《Java虚拟机规范》中对Java堆的描述是:所有的对象实例以及数组都应当在运行时分配在堆上。(The heap is the run-time data area from which memory for all class instances and array....

05-方法区

2022-07-18

05-方法区 JVM之运行时数据区(四)-- 方法区 一. 基本认识 1.1 方法区初识 从一句简单的Person person = new Person()来认识方法区。 Person 类的 .class 信息存放在方法区中 person 变量存放在 Java 栈的局部变量表中 真正的 person 对象存放在 Java 堆中 在 person 对象中,有个指针指向方法区中的 person 类型数据,表明这个 person 对象是用方法区中的 Person 类 new 出来的。 1.2 方法区位置 《Java虚拟机规范》中明确说明:尽管所有的方法区在逻辑上是属于堆的一部分,但一些简单的实现可能不会选择去进行垃圾收集或者进行压缩。 但对于HotSpotJVM而言,方法区还有一个别名叫做Non-Heap(非堆),目的就是要和堆分开。 所以,方法区可以看作是一块独立于Java堆的内存空间 1.3 方法区的基本理解 方法区主要存放的是 Class,而堆中主要存放的是实例化的对象 方法区(Method Area)与Java堆一样,是各个线程共享的内存区域。多个线程同时加载同一个类....

03-虚拟机栈

2022-07-18

03-虚拟机栈 JVM之运行时数据区(二)-- 虚拟机栈 一. 简介 1.1 内存中的栈和堆 栈是运行时的单位,而堆是存储的单位。 栈解决程序的运行问题,即程序如何执行,或者说如何处理数据。堆解决的是数据存储的问题,即数据怎么放,放哪里。 1.2 虚拟机栈初识 Java虚拟机栈(Java Virtual Machine Stack),早期也叫Java栈。每个线程在创建时都会创建一个虚拟机栈,其内部保存一个个的栈帧(Stack Frame),对应着一次次的Java方法调用,栈是线程私有的。 Java虚拟机是以方法作为最基本的执行单元,一个方法对应一个"栈帧"。 虚拟机栈生命周期和线程一致,也就是线程结束了,该虚拟机栈也销毁了。 虚拟机栈的作用 主管Java程序的运行,它保存方法的局部变量(8 种基本数据类型、对象的引用地址)、部分结果,并参与方法的调用和返回。 局部变量,它是相比于成员变量来说的(或属性) 基本数据类型变量 VS 引用类型变量(类、数组、接口) 1.3 虚拟机栈的特点 栈是一种快速有效的分配存储方式,访问速度仅次于程序计数器。 JVM直接对Java栈的操作只有两....

01-JVM初识

2022-07-18

01-JVM初识 JVM之类加载子系统 一. 内存结构概述 JVM内存结构如下图所示: JVM的整个内存模型主要分为如下几部分: 类加载子系统:主要负责类的加载,链接以及初始化 运行时数据区:包括堆,虚拟机栈,本地方法栈,pc寄存器,方法区 执行引擎:包括解释器,即时编译器,垃圾回收器 本地方法接口 本地方法库 二. 类加载的过程 2.1 类加载子系统的作用 类加载器子系统负责从文件系统或者网络中加载Class文件,class文件在文件开头有特定的文件标识。 ClassLoader只负责class文件的加载,至于它是否可以运行,则由Execution Engine决定。 加载的类信息存放于一块称为方法区的内存空间。除了类的信息外,方法区中还会存放运行时常量池信息,可能还包括字符串字面量和数字常量(这部分常量信息是Class文件中常量池部分的内存映射)、 2.2 Loading 通过一个类的全限定名获取定义此类的二进制字节流 将这个字节流所代表的静态存储结构转化为方法区的运行时数据结构 在内存中生成一个代表这个类的java.lang.Class对象,作为方法区这个类的各种数....

02-JVM之运行时数据区

2022-07-18

02-JVM之运行时数据区 JVM之运行时数据区(一) 一. 前言 运行时数据区主要包括程序计数器,本地方法栈,方法区,堆,虚拟机栈。 当我们通过前面的:类的加载 --> 验证 --> 准备 --> 解析 --> 初始化,这几个阶段完成后,就会用到执行引擎对我们的类进行使用,同时执行引擎将会使用到我们运行时数据区 对于一个线程来说,有些内存区域是独有的,有些内存区域是共享的 线程独有:程序计数器、栈、本地方法栈 线程间共享:堆、堆外内存(永久代或元空间、代码缓存) JVM系统线程 虚拟机线程:这种线程的操作是需要JVM达到安全点才会出现。这些操作必须在不同的线程中发生的原因是他们都需要JVM达到安全点,这样堆才不会变化。这种线程的执行类型括"stop-the-world"的垃圾收集,线程栈收集,线程挂起以及偏向锁撤销 周期任务线程:这种线程是时间周期事件的体现(比如中断),他们一般用于周期性操作的调度执行 GC线程:这种线程对在JVM里不同种类的垃圾收集行为提供了支持 编译线程:这种线程在运行时会将字节码编译成到本地代码 信号调度线程:这种线程接收信号并发....

如何利用 Arthas 热更新线上代码

2022-07-18

如何利用 Arthas 热更新线上代码 前言 本文是Arthas 系列文章的第一篇。 一般线上问题比开发环境的问题更难解决,一个主要的原因便在于开发态可以任意 debug 断点调试,而线上环境一般不允许远程调试,所以在实践中,我一般习惯用 Arthas 来定位线上的问题。 Arthas 是阿里巴巴开源的 Java 应用诊断利器 Arthas 可以完成很多骚操作,今天给大家介绍的 Arthas 诊断技巧便是 -- 热更新线上代码。在生产环境热更新代码,并不是很好的行为,可能会引发一些问题 黑屏化的操作可能会导致误操作 不符合安全生产的规范,不满足可监控、可回滚、可降级 但有时候也有一些场景可以考虑使用 Arthas 来热更,例如开发环境无法复现的问题、找到修复思路后临时验证等。 本文以 Arthas 3.1.7 版本为例,主要使用到 jad/mc/redefine 三个指令。 示例 在 arthas-demo 示例中,一共有两个类,一个 HelloService 类,sayHello 方法负责不断的打印 hello world: public class HelloService....

03-JVM运行时参数

2022-07-18

03-JVM运行时参数 一. JVM参数选项类型 1.1 标准参数选项 比较稳定,后续版本基本不会变化 以-开头 -cp <目录和 zip/jar 文件的类搜索路径> -classpath <目录和 zip/jar 文件的类搜索路径> --class-path <目录和 zip/jar 文件的类搜索路径> 使用 : 分隔的, 用于搜索类文件的目录, JAR 档案 和 ZIP 档案列表。 -p <模块路径> --module-path <模块路径>... 用 : 分隔的目录列表, 每个目录 都是一个包含模块的目录。 --upgrade-module-path <模块路径>... 用 : 分隔的目录列表, 每个目录 都是一个包含模块的目录, 这些模块 用于替换运行时映像中的可升级模块 --add-modules <模块名称>[,<模块名称>...] 除了初始模块之外要解析的根模块。 <模块名称> 还可以为 ALL-DEFAULT, ALL-SYSTEM, ALL-MODULE-PA....