final
1.被final修饰的变量值必须要有初始值,如果被修饰的成员变量是基本类型,则这个变量的值不能改变,如果被修饰的成员变量是引用类型,则表示这个引用的地址值不能改变,内容可以改变
2.被final修饰的方法不能重写,但可以被继承
3.被final修饰的类不能被继承
4.在jdk中被设计为final类有String,System,Intering等
static
1.被static修饰的类或方法可以在没有创建对象的情况下进行调用,只要类被加载了就可以通过类名直接访问
2.static可以用来修饰类的成员方法,变量
3.static代码快可以优化程序性能
try/ catch/ finally
被try包裹的代码异常会执行catch代码
finally代码是那种情况都会执行
8中数据类型
整形: byte short int long
浮点型: float double
布尔型:boolean
字符型:char
==和equals()
==:比较的是内存地址是否相等属于数值比较
equals()比较的是内容是否相等,属于内容比较
String的常用方法有哪些
indexOf():返回指定字符的索引。
charAt():返回指定索引处的字符。
replace():字符串替换。
trim():去除字符串两端空白。
split():分割字符串,返回一个分割后的字符串数组。
getBytes():返回字符串的 byte 类型数组。
length():返回字符串长度。
toLowerCase():将字符串转成小写字母。
toUpperCase():将字符串转成大写字符。
substring():截取字符串。
equals():字符串比较。
常见的数据结构
1.数组:是最常用的数据结构,数组的特点是长度固定,数组的大小固定后就无法扩容了 ,数组只能存储一种类型的数据 ,添加,删除的操作慢,因为要移动其他的元素。
2.栈:是一种基于先进后出的数据结构,是一种只能在一端进行插入和删除操作的特殊线性表。它按照先进后出的原则存储数据,先进入的数据被压入栈底,最后的数据在栈顶,需要读数据的时候从栈顶开始弹出数据。
3.队列:是一种基于先进先出的数据结构,是一种只能在一端进行插入,在另一端进行删除操作的特殊线性表,它按照先进先出的原则存储数据,先进入的数据,在读取数据时先被读取出来。
4.链表:是一种物理存储单元上非连续、非顺序的存储结构,其物理结构不能只表示数据元素的逻辑顺序,数据元素的逻辑顺序是通过链表中的指针链接次序实现的。链表由一系列的结节组成,结点可以在运行时动态生成。根据指针的指向,链表能形成不同的构,例如单链表,双向链表,循环链表等。
5.树:是我们计算机中非常重要的一种数据结构,有二叉树、平衡树、红黑树、B 树、B+树。
6.散列表:也叫哈希表,是根据关键码和值 (key 和 value) 直接进行访问的数据结构,通过 key 和 value来映射到集合中的一个位置,这样就可以很快找到集合中的对应元素。
7.堆:是计算机学科中一类特殊的数据结构的统称,堆通常可以被看作是一棵完全二叉树的数组对象。
8.图:图是由一组顶点和一组能够将两个顶点相连的边组成的
String,Stringbuffer,Stringbuilder
string:字符串常量,每次操作字符串都会生成新的
Stringbuilder字符串变量,线程不安全,单线程操作
Stringbuffer字符串变量,对方法施加了同步锁,线程安全.支持多线程操作每次创建时都会分配一定的内存,当字符串大于容量时会自动扩容
垃圾回收机制
第一步如何发现垃圾:
1.引用计数算法:堆中对象每被引用一次,则计数器加1,每减少一个引用就减一,当对象的引用计数为0时可以被当作垃圾收集
2.根搜索算法/可达性分析: 从一个GC ROOT(引用对象)开始寻找对应的引用节点,找到这个节点后继续寻找这个节点的引用系欸但,当所有的引用节点寻找完毕之后,剩余的节点被认为没有引用到的节点,即可当作垃圾
第二部进行垃圾回收:
1.标记清除算法:分为标记和清除两个阶段,首先标记出所有需要回收的对象,在标记完成后同意回收所有被标记的对象
2.标记整理算法:是标记清除算法基础上做了改进,标记出所有需要回收的对象,让存活的对象都像一端移动,在移动过程中清理掉可回收的对象
3.复制算法:将可用内存按容量分成大小相等的两块,每次只使用其中一块,这块使用完了就将存活的对象复制到另一块内存上去,然后把使用过的内存一次清理掉
4.分代收集算法:当前主流的JVM都采用分代收集算法,这种算法会根据对象存活周期的不同将内存划分为年轻代,年老代,永久代,不同生命周期的对象可以采用不同的回收算法,以便提高效率
(1)年轻代(YoungGeneration)
1.所有新生成的对象首先都是放在年轻代的。
2.新生代内存按照8:1:1的比例分为一个eden区和两个Survivor(survivor0,survivor1)区。大部分对象在Eden区中生成。回收时先将eden区存活对象复制到一个survivor0区,然后清空eden区,当这个survivor0区也存放满了时,则将eden区和survivor0区存活对象复制到另一个survivor1区,然后清空eden和这个survivor0区,此时survivor0区是空的,然后将survivor0区和survivor1区交换,即保持survivor1区为空,如此往复。
3.当survivor1区不足以存放eden和survivor0的存活对象时,就将存活对象直接存放到老年代。若是老年代也满了就会触发一次FullGC,也就是新生代、老年代都进行回收。
4.新生代发生的GC也叫做MinorGC,MinorGC发生频率比较高(不一定等Eden区满了才触发)
(2)年老代(OldGeneration)
1.在年轻代中经历了N次垃圾回收后仍然存活的对象,就会被放到年老代中。因此,可以认为年老代中存放的都是一些生命周期较长的对象。
2.内存比新生代也大很多(大概是2倍),当老年代内存满时触发MajorGC即FullGC,FullGC发生频率比较低,老年代对象存活时间比较长,存活率比较高。
(3)持久代(PermanentGeneration)用于存放静态文件,如Java类、方法等。持久代对垃圾回收没有显著影响,从JDK8以后已经废弃,将存放静态文件,如Java类、方法等这些存储到了元数据区.
Get和Post的区别
1.get是不安全的,因为在传输过程中,数据都被放在请求的URL中Post的所有操作都是对用户不可见的
2.get传输的数据量比较小,一般传输数据大小超不过2-4k
3.get限制fron表单的数据集必须为ASCLL字符,而POst支持整个ISO10646字符集
4.get效率比post好
${}和#{}区别
${}不安全的是拼接符
#{}可以防止sql注入占位符预编译的
JWT token
token的执行流程:当用户认证后,服务端生成一个token发送给客户端,客户端放到cookie中存储,每次请求时带上token,服务端收到token通过验证身份后即可确认用户身份
token的组成
第一部分头部:为令牌的类型及使用的哈希算法
第二部分时负载是一个json对象,可以存放有效信息去的地方
第三部分是防止被篡改,把第一部分和第二部分使用base64进行编码然后加上自定义的签名组成
分布式锁
分布式锁应该具备的条件
1.在分布式系统环境下,一个方法同一时间只能被一个机器的一个线程执行
2,高可用的获取锁和释放锁
3.高性能的获取锁与释放锁
4.具备可重入特性
5.具备锁失效机制,防止死锁
6.具备非阻塞锁特性,即没有获取到锁 直接放回获取锁失败
分布式锁的三种实现方式
1.基于数据库实现排他锁
创建一张实现锁的表,对表单字段做唯一约束,如果有多个请求同时提交到数据库的话,数据库只会保证一个操作可以成功
2.基于redis实现
一:获取锁的时候使用setnx加锁,并使用expire命令为锁添加一个超时时间,超过该使劲按自动释放锁,锁的value值为一个随机生成的uuid,通过此在释放锁的时候进行判断
二:获取锁的时候设置一个获取的超时时间,若超过这个时间则放弃获取锁
三:释放锁的时候,通过uuid判断是不是该锁,若是该锁则执行delete进行锁释放
3.基于zookeeper实现
在zookeeper当中创建一个持久节点ParentLock,当第一个客户端想要获取锁时,需要在持久节点下面创建一个临时节点,然后临时节点查找持久节点下边所有的临时节点并排序,判断自己是不是最靠前的一个,如果时第一个节点就获取到锁,如果客户端2前来获取锁则在持久节点下创建临时节点并继续监听排队