nginx中的if和后面的()中间必须有空格
查找阿里有关的Java视频资料
三目运算符多条件使用
Boolean ? 结果a : Boolean ? 结果b : 结果c;
SQl的执行顺序
(1)from
(3) join
(2) on
(4) where
(5)group by(开始使用select中的别名,后面的语句中都可以使用)
(6) avg,sum…
(7)having
(8) select
(9) distinct
(10) order by
CMS接口开发
文件上传
MySQL读写分离
SpringCloud+SpringBoot
RabbitMQ搭建
SpringSecurity Oauth2
课程管理
SpringBoot+SpringDataJPA:操作简单的增删改查+Mybatis:多表联查等
搜索
媒资管理
SpringSecurity
分布式事务
反射
SpringBoot如何创建一个新项目
分布式事务
SpringCloud
数据库范式
JS&JQ对象转化
SpringJPA
DOM BOM
泛型
四种引用
MySQL视图
SpringMVC的工作流程
- 请求发送到服务器之后,被封装为request对象(tomcat封装)进入到之后DispatcherServlet(springmvc的入口)
- 接下来到达HanlderMapping(处理器映射器)之后来选择映射
- 根据注解@RequestMapping注解的路径和tomcat封装好的请求路径来进行匹配
- 接下来进入到处理器执行链(HandlerExecutionChain)
- 调用控制器对应的拦截器
- 接下来调用处理器适配器(HandlerAdapter)
- 通过处理器适配器来调用我们写的controller
- 然后统一返回modelandview对象
- 在转发前,会把model中的数据存入request作用域中
- 再由视图解析器(viewResolver)将视图名转换为最终的jsp路径,并转发到jsp
- 如果执行过程中出现了异常:
- 异常解析器(exceptionhandlerexceptionresolver)进行处理
- jsp动态生成html代码并返回响应
九种域对象
SpringBoot
1).所有的模块都要继承spring-boot-starter-parent
@SpringBootApplication注解,是核心注解,具有包扫描的作用,默认扫描当前包及其子包,标识当前类是引导类,若需要扫描其他包,那么在此注解下添加@ComponentScan(basePackage=("需要扫描的全包名","com.lzh..."))
借助main执行SpringApplication.run方法,表示要运行SpringBoot的引导类,run方法的参数就是SpringBoot引导类的字节码对象(谁有注解谁是引导类)
2).热部署:在pom.xml中添加spring-boot-devtools坐标
3).**起步依赖** parent:依赖于dependencies(通过<dependencyManagement>来统一管理依赖的版本)
4).起步依赖 web:依赖传递,依赖于parent,parent依赖于dependencies
5).**自动配置**:@SpringBootApplication由三个注解组成(@SpringBootConfiguration:声明当前类是Spring的一个配置类
@ComponentScan:进行包扫描的注解,默认扫描当前包及其子包
@EnableAutoConfiguration:自动配置的核心注解,是否自动配置的开关)
Redis的穿透
解决方案 使用string存储数据 若查询不到那么将请求参数设置null值并存入缓存,同时设置过期时间,那么在过期时间内将不会再访问数据库
所有的请求不会访问数据库,只访问redis,设置定时任务,定期更新redis中的数据
Redis的击穿
高并发情况下,缓存失效,造成大量请求瞬间请求数据库
设置条件,同样的请求只能有一个线程去访问数据库,再使用互斥锁(trylock)
Redis的雪崩
大量的高并发的缓存同时失效,造成的数据库压力过大(整点抢购活动)
解决方案:设置不同的过期时间,
只查redis,通过定时任务定时更新redis
设计模式
设计模式五大原则和一法则
-
单一职责原则(Single Responsibility Principle)(高内聚,低耦合):一个类只负责一项职责,对一个类而言,只能有一个引起他变化的原因
-
里氏替换原则(LSP liskov substitution principle):子类可以扩展父类的功能,但不能改变父类原有的功能(增强程序的健壮性)
-
依赖倒置原则(dependence inversion principle)**:面向接口编程,上层模块不应该依赖下层模块,两者应依赖其抽象
-
接口隔离(interface segregation principle)**:建立单一接口,类之间的依赖关系应该建立在最小的接口上,客户端不应该依赖不需要的接口【接口粒度越小,系统越灵活,但复杂性越高,维护性降低】
-
迪米特原则(law of demeter LOD):最少知道原则,尽量降低类于类之间的耦合;一个对象应该对其他对象有最少的了解
-
总:开闭原则(open closed principle):用抽象构建架构,用实现扩展原则
1.工厂模式:****
类别:创建型模式;
功能:提供了一种创建对象的最佳方式;
优点:1、一个调用者想创建一个对象,只要知道其名称就可以了。 2、扩展性高,如果想增加一个产品,只要扩展一个工厂类就可以。 3、屏蔽产品的具体逻辑实现,调用者只关心产品的接口;
缺点:适合复杂对象适合工厂模式,使得系统中的类的个数成倍增加会增加系统复杂度和具体类的依赖;
使用场景:1、日志记录器:记录可能记录到本地硬盘、系统事件、远程服务器等,用户可以选择记录日志到什么地方。
2、数据库访问,当用户不知道最后系统采用哪一类数据库,以及数据库可能有变化时。 3、设计一个连接服务器的框架,需要三个协议,"POP3"、"IMAP"、"HTTP",可以把这三个作为产品类,共同实现一个接口。
2.抽象工厂模式:*****
类别:创建型模式;
功能:提供了一种创建对象的最佳方式;
优点:当一个产品族中的多个对象被设计成一起工作时,它能保证客户端始终只使用同一个产品族中的对象;
缺点:产品族扩展非常困难,要增加一个系列的某一产品,既要在抽象的 Creator 里加代码,又要在具体的里面加代码。
3.单例模式:****
类别:创建型模式;
功能:提供了一种创建对象的最佳方式;
优点:1、在内存里只有一个实例,减少了内存的开销,尤其是频繁的创建和销毁实例(比如管理学院首页页面缓存)。2、避免对资源的多重占用(比如写文件操作);
缺点:没有接口,不能继承,与单一职责原则冲突,一个类应该只关心内部逻辑,而不关心外面怎么样来实例化。;
使用场景:
1、要求生产唯一序列号。
2、WEB 中的计数器,不用每次刷新都在数据库里加一次,用单例先缓存起来。
3、创建的一个对象需要消耗的资源过多,比如 I/O 与数据库的连接等。
4.建造者模式:**
类别:创建型模式
功能:使用多个简单的对象一步一步构建成一个复杂的对象
优点:建造者独立,易于扩展,便于控制细节风险
缺点:产品需有共同点,范围有限制,内部变化复杂,辉有很多的建造类
使用场景:
1、需要生成的对象具有复杂的内部结构
2、需要生成的对象内部属性本身相互依赖
**与工厂模式的区别是:建造者模式更加关注零件装配的顺序。
5.原型模式:***
类别:创建型模式
功能:用于创建重复的对象,同时又能保证性能。提供了创建对象的最佳方式,在运行期建立和删除原型
关键代码:继承Cloneable重写clone()方法
优点:性能提高,避开构造函数的约束
缺点:对于已有的类不支持串行化的间接对象或含有循环结构,需实现Cloneable接口
使用场景:
1、资源优化场景
2、类的初始化需要消耗非常多的资源
3、性能和安全要求的场景
4、通过new产生一个对象需要非常多的数据准备或,访问权限
5、一个对象或多个修改者的场景
6、一个对象需要被多个对象访问且修改时可以拷贝多个对象给他们用
7、原型模式一般结合工厂方法模式一起出现,通过clone的方法创建一个对象,通过工厂方法提供给调用者,
======((((这个模式和volatile有啥区别))))=====
6.适配器模式(转换器)****
类别:结构型模式
功能:将一个类的接口转换成另一个接口,使不兼容的类可以一起工作
关键代码:适配器继承或依赖已有对象,实现想要的目标接口
优点:可以让两个没有关联的类一起运行,提高了类的复用,增加了类的透明度,灵活性好
缺点:过多使用会让系统零乱,不易整体把握。Java单继承,最多适配一个适配者类
使用场景:有动机的修改一个正常运行的系统的接口,可以考虑使用适配器模式
**适配器是解决正在服役的项目问题
7.桥接模式***
类别:结构型模式
功能:使实体类的功能独立于接口实现类,这两种类型的类可被结构化改变而互不影响。(将抽象部分和实现部分分离,使他们可以独立变化)
关键代码:抽象类依赖实现类
优点:抽象和实现的分离,扩展能力强,实现细节对客户透明
缺点:因聚合关联关系建立在抽象层,要求开发者针对抽象进行设计与变成
使用场景:1、一个系统需要在构件的抽象化角色和具体化角色之间增加灵活性,避免在两个层次之间建立静态的继承联系,通过桥接模式可以使他们在抽象层建立一个关联关系2、对于不希望使用继承,或因多层次继承导致系统类的个数增加过多的系统3、一个类存在两个独立变化的纬度且这两个类都需要进行扩展
**对于两个独立变化的维度,使用桥接模式非常合适
8.过滤器模式(或标准模式)
类别:结构型模式
功能:获得符合多个条件的对象
使用场景:对一组数据进行分组的情况下,可以定义一个接口,通过实现接口重写过滤方法,比如传入一个集合,将集合中姓刘的人筛选出来,定义方法,遍历传入的集合,将符合条件的数据加入新的集合并返回,总的来说就是传入数据,去掉不符合条件的并返回
9.组合模式(部分整体模式)****
类别:结构型模式
功能:使客户程序与复杂元素的内部结构解耦(动态的给一个对象添加一些额外的职责)
关键代码:树枝和叶子实现统一接口,数值内部组合该接口
实例:算术表达式包括[操作数,操作符,另一个操作数],另一个操作符也可以是操作数、操作符和另一个操作数。
优点:高层模块调用简单,节点自由增加
缺点:其叶子和树枝的声明都是实现类,而不是接口,违反了依赖倒置原则
使用场景:部分,整体场景,树形菜单,文件,文件夹的管理
10.装饰器模式***
类别:结构型模式(创建了一个装饰类用来包装原有的类)
功能:保持类方法签名完整性的前提下,提供了额外的功能
关键代码:
1.Component类充当抽象角色,不应该具体实现
2.修饰类引用和继承Component类,具体扩展类重写父类的方法
实例:孙悟空72变,本质还是猴子
优点:装饰类和被装饰类可以独立发展,不会相互耦合,装饰模式是继承的一个替代模式,可以动态的扩展一个实现类的功能
缺点:多层装饰比较复杂
使用场景:扩展一个类的功能,动态的增加功能,动态撤销
11.外观模式*****
类别:结构型模式
功能:为子系统中的一组接口提供一个一致的界面,降低访问复杂系统的内部子系统的复杂度,简化客户端与其的接口
关键代码:在客户端和复杂系统之间再加一层,在这一层将调用顺序和依赖关系处理好
实例:西京医院便民门诊(ps:哈哈哈哈秀emmm虽然便民关了)
优点:减少系统相互依赖,提高灵活性,安全性
缺点:不符合开闭原则,若要改东西,那么将会很麻烦
使用场景:1.为复杂的模块或子系统提供外界访问的模块
2.子系统相对独立
3.预防低水平人员带来的风险
12.享元模式*
类别:结构型模式
功能:尝试重用现有的同类对象,若无则创建新对象
关键代码:用HashMap存储这些对象
实例:String类型的字符串,如果有那么返回,如果没有,那么创建一个字符串保存在字符串缓存池里;数据库的数据池
优点:大大减少了对象的创建,降低系统的内存,使效率提高
缺点:提高了系统的复杂度,需要分离出外部状态和内部状态,否则可能会引起线程安全问题,这些类需要有一个工厂对象加以控制.
使用场景:系统有大量相似对象,需要缓冲池的场景
我的问题:为什么需要分离外部状态和内部状态,为什么会引起线程安全问题,为什么需要工厂对象加以控制,如string创建时的过程,工厂是谁?怎么分离的状态
13.代理模式****
类别:结构型模式
功能:为其他对象提供一种代理以控制对这个对象的访问,
关键代码:实现与被代理类组合
实例:应用的快捷方式,spring aop,火车票代售点,kfc甜品站(emm)
优点:职责清晰,扩展性高,智能化
缺点:有些类型的代理模式可能会造成请求的处理速度变慢,某些代理模式特别复杂
使用场景:1、远程代理。2、虚拟代理。3、copy-on-write代理。4、保护代理。5、cache代理。6、防火墙代理。7、同步化代理。8、只能引用代理。
注意:1、和适配器模式的区别:适配器模式主要考虑对象的接口,而代理模式不能改变所代理类的接口。2、和装饰器模式的区别:装饰器模式为了增强功能,而代理模式是为了加以控制。
14.责任链模式**
类别:行为模式
功能:让多个对象都有可能接受请求,责任链上的处理者负责处理请求,客户只需要将请求发送到责任链上即可,无需关心请求的处理细节和请求的传递,所以责任链将请求的发送者和请求的处理者解耦了,一般用在处理消息时过滤很多道
关键代码:Handler里面聚合它自己,在HandlerRequest里判断是否合适,若妹达到条件则向下传递,向谁传递之前set进去
实例:Javaweb中tomacat对encoding的处理,jsp servlet的filter
优点:
1、降低请求的发送者和接收者的耦合度
2、简化对象,使对象不需要知道链的结构
3、增强给对象指派职责的灵活性,通过改变链内的成员或调动他们的次序,允许动态地增加或删除责任
4、增加新的请求处理类很方便(实现接口就好??)
缺点:影响系统性能,不能保证请求一定被接受,不容易观察运行时的特征影响除错
使用场景:
1、多个对象处理同一个请求
2、在不明确指定接收者的情况下,想多个对象中的一个提交一个请求
3、可动态制定一组对象处理请求
15.命令模式****
类别:行为模式
功能:将一个请求封装成一个对象,传给调用对象,调用对象寻找可以处理该命令的合适的对象,并将该命令传给响应的对象,该对象执行传入的请求对象。
关键代码:定义三个角色:
1、received真正的命令执行对象
2、Command
3、invoker使用命令对象的入口
优点:降低了系统耦合度,新的命令可以很容易的添加到系统中
缺点:可能导致系统由过多的具体命令类
使用场景:需要对行为进行记录、撤销/重做、事务等处理,需要将行为请求者和行为实现者解耦,那么就需要将一组行为抽象为对象从而实现松耦合
实例:springmvc中doget,dopost;实现一个控制器转发到多个模型,定义接口,让所有模型实现这个接口那么就可以转发过去;
16.解释器模式*
类别:行为模式
功能:该接口解释一个特定的上下文
关键代码:构建环境类,包含解释器之外的一些全局信息,一般是使用hashmap
优点:扩展性好,易于实现简单文法
缺点:可利用场景较少,难维护,一般采用的递归调用
使用场景:将解释执行的语言中的句子表示为一个抽象语法树,重复出现的问题可以用一种简单的语言来表达
**在Java中可以用expression4j代替
17.迭代器模式*****
类别:行为模式
功能:顺序访问集合对象的元素,不需要知道集合对象的底层表示
关键代码:定义接口hasNext,next
优点:
1、支持不同的方式遍历一个聚合对象
2、迭代器简化了聚合类
3、在同一个聚合上可以有多个遍历
4、增加新的聚合类和迭代器类都很方便,无需修改原有代码
缺点:增加了系统的复杂性。
使用场景:
1、访问一个聚合对象的内容而无须暴露它的内部表示。
2、需要为聚合对象提供多种遍历方式。
3、为遍历不同的聚合结构提供一个统一的接口。
实例:iterator
18.中介者模式**
类别:行为模式
功能:降低多个对象和类之间的通信复杂性,使代码易于维护
关键代码:对象之间的通信封装到一个类中单独处理
优点:降低了类的复杂度,解耦,符合迪米特原则
缺点:中介者复杂庞大难以维护
使用场景:对象之间存在比较复杂的引用关系,难以复用
实例:MVC框架 controller是model和view的中介者
19.备忘录模式**
类别:行为模式
功能:保存一个对象的某个状态,用于适当的时候恢复对象
关键代码:客户不与备忘录耦合,与备忘录管理类耦合
优点:方便的找回历史状态,实现了信息的封装,不需要关心状态的保存细节
缺点:消耗资源
使用场景:需要恢复数据的场景,提供回滚的操作
实例:数据库事务,ctrl+z
20.策略模式****
类别:行为模式
功能:随着策略对象的改变从而使用不同的算法
关键代码:实现同一个接口
优点:算法可以自由切换,避免使用多重条件判断,扩展性好
缺点:策略类会增多,所有策略类都需要对外暴露服务
使用场景:动态的让一个对象在许多行为中选择一个,系统需要动态的在集中算法中选择一种
实例:webmagic,java AWT中的LayoutManager
**若策略多于四个需要考虑使用混合模式
21.访问者模式*
类别:行为模式
功能:将数据结构和数据操作分离
关键代码:在数据基础类里有一个方法接受访问者,将自身传入访问者
优点:符合单一职责原则,优秀的扩展性,灵活性
缺点:
1、具体元素对访问者公布细节,违反了迪米特原则
2、具体元素变更比较困难
3、违反了依赖倒置原则,依赖了具体类,没有依赖抽象
使用场景:对象结构中对象对应的类很少改变,需要对对象结构中的对象进行很多不同且不相关的操作
实例:报表,UI,拦截器,过滤器
22.模板模式***
类别:行为模式
功能:一些方法通用,却在每一个子类都重写了这个方法
关键代码:在抽象类实现,其他不通用的方法在子类实现
优点:
1、封装不变的部分,扩展可变部分
2、提取公共代码,便于维护
3、行为又父类控制,子类实现
缺点:每一个不同的实现都需要一个子类来实现,类会过多
使用场景:重要的复杂的方法可以考虑作为模板方法
实例:spring对hibernate的支持
**为防止恶意操作,一般模板方法都加上 final 关键词
23.状态模式***
类别:行为模式
功能:允许对象在内部状态发生改变时改变他的行为,对象看起来好像修改了他的类
关键代码:状态模式的接口中有一个或者多个方法
优点:
1、封装了转换规则
2、枚举可能的状态
3、将所有与某个状态有关的行为放到一个类中,并且可以方便的增加新的状态,只需要改变对象状态就可以改变对象的行为
4、允许状态逻辑转换与状态对象合成一起
5、可以让多个环境对象共享一个状态对象,从而减少系统中对象的个数
缺点:
1、会增加系统类和对象的个数
2、对开闭原则的支持并不友好
使用场景:行为随状态改变而改变的场景,条件分支语句的代替者
实例:比赛时的状态,一般,及格,超长
24.观察者模式***
类别:行为模式
功能:当一个对象被修改时,自动通知他的依赖对象
关键代码:在抽象类中有一个ArrayList存放观察者
优点:观察者和被观察者是抽象耦合的,建立了一套触发机制
缺点:
1、若观察者过多,消耗资源会过多
2、若观察者和观察目标之间有依赖循环的话,可能导致循环调用(类似递归无出口)
3、没有相应的机制让观察者知道目标是怎么发生变化的
使用场景:一个对象的改变将导致其他一个多个对象也发生改变,a影响b,b影响c
注意:
1、java中已经有对观察者模式支持的类
2、避免循环引用
3、一般采用异步方式。顺序执行可能会导致系统卡壳
java内部类的特点
静态内部类才可以声明静态方法
静态方法不可以使用非静态变量
抽象方法不可以有函数体
1.为什么使用内部类?
使用内部类最吸引人的原因是:每个内部类都能独立地继承一个(接口的)实现,所以无论外围类是否已经继承了某个(接口的)实现,
对于内部类都没有影响
1.1.使用内部类最大的优点就在于它能够非常好的解决多重继承的问题,使用内部类还能够为我们带来如下特性:
(1)、内部类可以用多个实例,每个实例都有自己的状态信息,并且与其他外围对象的信息相互独。
(2)、在单个外围类中,可以让多个内部类以不同的方式实现同一个接口,或者继承同一个类。
(3)、创建内部类对象的时刻并不依赖于外围类对象的创建。
(4)、内部类并没有令人迷惑的“is-a”关系,他就是一个独立的实体。
(5)、内部类提供了更好的封装,除了该外围类,其他类都不能访问。
2.内部类分类:
(一).成员内部类:
public class Outer{
private int age = 99;
String name = "Coco";
public class Inner{
String name = "Jayden";
public void show(){
System.out.println(Outer.this.name);
System.out.println(name);
System.out.println(age);
}
}
public Inner getInnerClass(){
return new Inner();
}
public static void main(String[] args){
Outer o = new Outer();
Inner in = o.new Inner();
in.show();
}
}
1.Inner 类定义在 Outer 类的内部,相当于 Outer 类的一个成员变量的位置,Inner 类可以使用任意访问控制符,
如 public 、 protected 、 private 等
2.Inner 类中定义的 show() 方法可以直接访问 Outer 类中的数据,而不受访问控制符的影响,
如直接访问 Outer 类中的私有属性age
3.定义了成员内部类后,必须使用外部类对象来创建内部类对象,而不能直接去 new 一个内部类对象,
即:内部类 对象名 = 外部类对象.new 内部类( );
4.编译上面的程序后,会发现产生了两个 .class 文件: Outer.class,Outer$Inner.class{}
5.成员内部类中不能存在任何 static 的变量和方法,可以定义常量:
(1).因为非静态内部类是要依赖于外部类的实例,而静态变量和方法是不依赖于对象的,仅与类相关,
简而言之:在加载静态域时,根本没有外部类,所在在非静态内部类中不能定义静态域或方法,编译不通过;
非静态内部类的作用域是实例级别
(2).常量是在编译器就确定的,放到所谓的常量池了
★★友情提示:
1.外部类是不能直接使用内部类的成员和方法的,可先创建内部类的对象,然后通过内部类的对象来访问其成员变量和方法;
2.如果外部类和内部类具有相同的成员变量或方法,内部类默认访问自己的成员变量或方法,如果要访问外部类的成员变量,
可以使用 this 关键字,如:Outer.this.name
(二).静态内部类: 是 static 修饰的内部类,
1.静态内部类不能直接访问外部类的非静态成员,但可以通过 new 外部类().成员 的方式访问
2.如果外部类的静态成员与内部类的成员名称相同,可通过“类名.静态成员”访问外部类的静态成员;
如果外部类的静态成员与内部类的成员名称不相同,则可通过“成员名”直接调用外部类的静态成员
3.创建静态内部类的对象时,不需要外部类的对象,可以直接创建 内部类 对象名 = new 内部类();
public class Outer{
private int age = 99;
static String name = "Coco";
public static class Inner{
String name = "Jayden";
public void show(){
System.out.println(Outer.name);
System.out.println(name);
}
}
public static void main(String[] args){
Inner i = new Inner();
i.show();
}
}
(三).方法内部类:其作用域仅限于方法内,方法外部无法访问该内部类
(1).局部内部类就像是方法里面的一个局部变量一样,是不能有 public、protected、private 以及 static 修饰符的
(2).只能访问方法中定义的 final 类型的局部变量,因为:
当方法被调用运行完毕之后,局部变量就已消亡了。但内部类对象可能还存在,
直到没有被引用时才会消亡。此时就会出现一种情况,就是内部类要访问一个不存在的局部变量;
==>使用final修饰符不仅会保持对象的引用不会改变,而且编译器还会持续维护这个对象在回调方法中的生命周期.
局部内部类并不是直接调用方法传进来的参数,而是内部类将传进来的参数通过自己的构造器备份到了自己的内部,
自己内部的方法调用的实际是自己的属性而不是外部类方法的参数;
防止被篡改数据,而导致内部类得到的值不一致
/*
使用的形参为何要为 final???
在内部类中的属性和外部方法的参数两者从外表上看是同一个东西,但实际上却不是,所以他们两者是可以任意变化的,
也就是说在内部类中我对属性的改变并不会影响到外部的形参,而然这从程序员的角度来看这是不可行的,
毕竟站在程序的角度来看这两个根本就是同一个,如果内部类该变了,而外部方法的形参却没有改变这是难以理解
和不可接受的,所以为了保持参数的一致性,就规定使用 final 来避免形参的不改变
*/
public class Outer{
public void Show(){
final int a = 25;
int b = 13;
class Inner{
int c = 2;
public void print(){
System.out.println("访问外部类:" + a);
System.out.println("访问内部类:" + c);
}
}
Inner i = new Inner();
i.print();
}
public static void main(String[] args){
Outer o = new Outer();
o.show();
}
}
(3).注意:在JDK8版本之中,方法内部类中调用方法中的局部变量,可以不需要修饰为 final,匿名内部类也是一样的,主要是JDK8之后增加了 Effectively final 功能
http://docs.oracle.com/javase/tutorial/java/javaOO/localclasses.html
反编译jdk8编译之后的class文件,发现内部类引用外部的局部变量都是 final 修饰的
(四).匿名内部类:
(1).匿名内部类是直接使用 new 来生成一个对象的引用;
(2).对于匿名内部类的使用它是存在一个缺陷的,就是它仅能被使用一次,创建匿名内部类时它会立即创建一个该类的实例,
该类的定义会立即消失,所以匿名内部类是不能够被重复使用;
(3).使用匿名内部类时,我们必须是继承一个类或者实现一个接口,但是两者不可兼得,同时也只能继承一个类或者实现一个接口;
(4).匿名内部类中是不能定义构造函数的,匿名内部类中不能存在任何的静态成员变量和静态方法;
(5).匿名内部类中不能存在任何的静态成员变量和静态方法,匿名内部类不能是抽象的,它必须要实现继承的类或者实现的接口的所有抽象方法
(6).匿名内部类初始化:使用构造代码块!利用构造代码块能够达到为匿名内部类创建一个构造器的效果
public class OuterClass {
public InnerClass getInnerClass(final int num,String str2){
return new InnerClass(){
int number = num + 3;
public int getNumber(){
return number;
}
}; /* 注意:分号不能省 */
}
public static void main(String[] args) {
OuterClass out = new OuterClass();
InnerClass inner = out.getInnerClass(2, "chenssy");
System.out.println(inner.getNumber());
}
}
interface InnerClass {
int getNumber();
}
常用Linux指令
1.ps 查看当前服务器上的进程 -ef | grep xxx -- color 查看xxx是否在进程中
2.top查看资源
3.tail 显示文件尾部 通常配合 -f /logs/catalina.out 查看日志文件
4.free 查看当前服务器的内存总数 -m 是将结果已m的形式展示
5.查看磁盘剩余空间 desk
反射的特点
反射指的是在运行时能够分析类的能力的程序。
反射机制可以用来:
1.在运行时分析类的能力--检查类的结构--所用到的就是java.lang.reflect包中的Field、Method、Constructor,分别用于描述类的与、方法和构造器。A中的Class类在java.lang中。
2.在运行时查看对象。
3.实现通用的数组操作代码。
反射机制的功能:
在运行时判断任意一个对象所属的类;在运行时构造任意一个类的对象;在运行时判断任意一个类所具有的成员变量和方法;在运行时调用任意一个对象的方法;生成动态代理。
反射机制常见作用:
动态加载类、动态获取类的信息(属性、方法、构造器);动态构造对象;动态调用类和对象的任意方法、构造器;动态调用和处理属性;获取泛型信息(新增类型:ParameterizedType,GenericArrayType等);处理注解(反射API:getAnnotationsdeng等)。
反射机制性能问题:
反射会降低效率。
void setAccessible(boolean flag):是否启用访问安全检查的开关,true屏蔽Java语言的访问检查,使得对象的私有属性也可以被查询和设置。禁止安全检查,可以提高反射的运行速度。
可以考虑使用:cglib/javaassist操作。
红黑树的基本原则
性质1. 节点是红色或黑色。
性质2. 根节点是黑色。
性质3. 每个叶子的子节点都是黑色的空节点
性质4. 每个红色节点的两个子节点都是黑色。(从每个叶子到根的所有路径上不能有两个连续的红色节点)
性质5. 从任一节点到其每个叶子的所有路径都包含相同数目的黑色节点。
TDD的三个原则
1)没有测试之前不要写任何功能代码
2)只编写恰好能够体现一个失败情况的测试代码
3)只编写恰好能通过测试的功能代码
在实际开发过程中,可能并不需要严格遵守这三个原则。即便只是大体上应用TDD到复杂功能开发,就能发挥很大的作用。
具体来说,首先在开发前期,按照TDD的原则不断在添加测试用例和开发功能代码之间切换。
在这个循环迭代过程中,不断地通过重构和面向对象思想,完善代码设计。
并且可以引入业界公认的设计模式使自己的代码更加专业、优美。
这样做的优点:
一是帮助思考。对于很复杂的功能需要迭代开发,不可能一下子就把逻辑实现全想明白。于是可以先实现最简单功能,再逐步完善;
二是快速调试。有了单元测试,可以通过失败的用例直接找到对应出问题的代码,几乎不需要太多调试了;
三是通过TDD不断迭代出的代码,设计比较合理,后期更加容易维护。
当然凡事都是有利有弊的,TDD也有它的缺点和局限:
一是前期进开发稍慢一些,因为需要编写单元测试(但是TDD往往在开发中后期会让你的开发进度越来越快,
TDD节省下来的时间将远远超过编写和维护测试用例的时间。这就好比玩即时战略游戏,前期的精心布局将在中后期看到效果);
二是对于简单功能并不适用,要注意应用场景。
CAS(比较并交换)
应用:自旋锁
public class SpinLock {
private AtomicReference<Thread> sign =new AtomicReference<>();
public void lock(){
Thread current = Thread.currentThread();
while(!sign .compareAndSet(null, current)){
}
}
public void unlock (){
Thread current = Thread.currentThread();
sign .compareAndSet(current, null);
}
}
AtomicInteger 的 incrementAndGet()
public final int getAndAddInt(Object var1, long var2, int var4) {
int var5;
do {
var5 = this.getIntVolatile(var1, var2);
} while(!this.compareAndSwapInt(var1, var2, var5, var5 + var4));
return var5;
}
复制代码
与自旋锁有异曲同工之妙,就是一直while,直到操作成功为止。
令牌桶限流器
所谓令牌桶限流器,就是系统以恒定的速度向桶内增加令牌。每次请求前从令牌桶里面获取令牌。如果获取到令牌就才可以进行访问。当令牌桶内没有令牌的时候,拒绝提供服务。我们来看看 eureka
的限流器是如何使用 CAS 来维护多线程环境下对 token 的增加和分发的。
public class RateLimiter {
private final long rateToMsConversion;
private final AtomicInteger consumedTokens = new AtomicInteger();
private final AtomicLong lastRefillTime = new AtomicLong(0);
@Deprecated
public RateLimiter() {
this(TimeUnit.SECONDS);
}
public RateLimiter(TimeUnit averageRateUnit) {
switch (averageRateUnit) {
case SECONDS:
rateToMsConversion = 1000;
break;
case MINUTES:
rateToMsConversion = 60 * 1000;
break;
default:
throw new IllegalArgumentException("TimeUnit of " + averageRateUnit + " is not supported");
}
}
//提供给外界获取 token 的方法
public boolean acquire(int burstSize, long averageRate) {
return acquire(burstSize, averageRate, System.currentTimeMillis());
}
public boolean acquire(int burstSize, long averageRate, long currentTimeMillis) {
if (burstSize <= 0 || averageRate <= 0) { // Instead of throwing exception, we just let all the traffic go
return true;
}
//添加token
refillToken(burstSize, averageRate, currentTimeMillis);
//消费token
return consumeToken(burstSize);
}
private void refillToken(int burstSize, long averageRate, long currentTimeMillis) {
long refillTime = lastRefillTime.get();
long timeDelta = currentTimeMillis - refillTime;
//根据频率计算需要增加多少 token
long newTokens = timeDelta * averageRate / rateToMsConversion;
if (newTokens > 0) {
long newRefillTime = refillTime == 0
? currentTimeMillis
: refillTime + newTokens * rateToMsConversion / averageRate;
// CAS 保证有且仅有一个线程进入填充
if (lastRefillTime.compareAndSet(refillTime, newRefillTime)) {
while (true) {
int currentLevel = consumedTokens.get();
int adjustedLevel = Math.min(currentLevel, burstSize); // In case burstSize decreased
int newLevel = (int) Math.max(0, adjustedLevel - newTokens);
// while true 直到更新成功为止
if (consumedTokens.compareAndSet(currentLevel, newLevel)) {
return;
}
}
}
}
}
private boolean consumeToken(int burstSize) {
while (true) {
int currentLevel = consumedTokens.get();
if (currentLevel >= burstSize) {
return false;
}
// while true 直到没有token 或者 获取到为止
if (consumedTokens.compareAndSet(currentLevel, currentLevel + 1)) {
return true;
}
}
}
public void reset() {
consumedTokens.set(0);
lastRefillTime.set(0);
}
}
复制代码
所以梳理一下 CAS 在令牌桶限流器的作用。就是保证在多线程情况下,不阻塞线程的填充token 和消费token。
归纳
通过上面的三个应用我们归纳一下 CAS 的应用场景:
- CAS 的使用能够避免线程的阻塞。
- 多数情况下我们使用的是 while true 直到成功为止。
CAS 缺点
- ABA 的问题,就是一个值从A变成了B又变成了A,使用CAS操作不能发现这个值发生变化了,处理方式是可以使用携带类似时间戳的版本AtomicStampedReference
- 性能问题,我们使用时大部分时间使用的是 while true 方式对数据的修改,直到成功为止。优势就是相应极快,但当线程数不停增加时,性能下降明显,因为每个线程都需要执行,占用CPU时间。
总结
CAS 是整个编程重要的思想之一。整个计算机的实现中都有CAS的身影。微观上看汇编的 CAS 是实现操作系统级别的原子操作的基石。从编程语言角度来看 CAS 是实现多线程非阻塞操作的基石。宏观上看,在分布式系统中,我们可以使用 CAS 的思想利用类似Redis
的外部存储,也能实现一个分布式锁。
从某个角度来说架构就将微观的实现放大,或者底层思想就是将宏观的架构进行微缩。计算机的思想是想通的,所以说了解底层的实现可以提升架构能力,提升架构的能力同样可加深对底层实现的理解。计算机知识浩如烟海,但是套路有限。抓住基础的几个套路突破,从思想和思维的角度学习计算机知识。不要将自己的精力花费在不停的追求新技术的脚步上,跟随‘start guide line’只能写一个demo,所得也就是一个demo而已。
停下脚步,回顾基础和经典或许对于技术的提升更大一些。
vue中获取url的参数 this.$rote.使用params.参数名,可以获取到参数 获取问号左边参数使用query获取问号右边参数
Angular教程
概述:SoC关注点分离,拆解,分块处理
SOLID:面向对象的五个原则
MVC:面向架构
框架基本都灌输了上述两个设计:通过设计理解框架
MDN来学习CSS,理解CSS设计思路
主语言是TypeScript
完善的类型系统,严格的语法检查,强力的IDE支持
设计很像Spring
可以复用自己的经验,起步较容易
风格更重严谨而不是灵活
灵活意味着失控
可以看一下angular的风格指南
一件起步Angular CLI不用关webpack,一条命令生成项目组件和服务
一步到位,angular选择了TypeScript和RxJs
学习路线
angular.cn
快速上手->搭建环境->开发中按需查API
IDE(需安装插件);Chrome插件:Augury;NodeJS最新版
组件库
Angular Material
ng-zorro-antd
lonic(移动端,h5应用)
扩展文档(阅读被angular依赖,MQ的设计和rxjs比较像)
RxJS:http://rxjs.dev
深度剖析Angular(Angular In Depth)
阅读源码的话从Angular Material或CDK组件开发工具的源码
接口定义
目的是实现需求
1.了解接口请求什么,响应什么
2.定义出模型类,最终使用统一模型类响应结果
Dockers
组件:
客户端,服务端,镜像,容器,注册中心
启动:systemctl start/stop/restart/status/enable(开机自启) docker
镜像:
查看docker images
网上查找镜像 docker search 关键字
下载 docker pull 关键字
删除镜像 docker rmi 镜像名称/镜像id
查看运行状态 docker ps
进入容器(交互式) docker run/exit -it --name=mycentos01 centos:7 /bin/bash
创建容器 docker exec -it mycentos02 centos:7
进入容器(守护式) docker exec -it mycentos02 /bin/bash
开启容器 docker start/stop mycentos01
端口映射 docker run -di --name=my_mysql -p 33306:3306 -e MYSQL_ROOT_PASSWORD=root mysql
目录映射 docker run -di --name=my_tomacat -p 8080:8080 -v /usr/local/webapps:usr/local/tomcat/webapps --privileged=true tomcat:7-jre7
文件复制
docker op /usr/local/1.txt my_tomcat:/usr/local
查看ip docker inspect my_tomc
Docker的备份和迁移:容器(commit)-镜像(save)-.tar(load)-镜像容器(docker run)
springmvc的controller线程安全吗?怎么解决
不安全,默认情况,也就是单例模式下需要线程安全的话必须使用ThreadLocal来封装变量ThreadLocal<Integer> tl = new ThreadLocal<>(); 才能保证线程安全
若是多例在controller上添加@Scope(value = "prototype"),使controller变成多例的那么,在没有静态成员变量的情况下他是线程安全的,但是若使用了静态成员变量,那么因为静态成员变量的创建时跟随类的加载而加载的所以无法保证线程安全,所以要想保证线程安全须使用ThreadLocal来封装这个变量
long类型对应mysql里的哪种类型
Long型id数据对应MySQL数据库中 bigint或numeric 数据类型;
java类 mysql数据库
java.lang.Byte byte TINYINT
java.lang.Short short SMALLINT
java.lang.Integer integer INGEGER
java.lang.Long long BIGINT
java.lang.Float float FLOAT
java.lang.Double double DOUBLE
java.lang.BigDecimal big_decimal NUMERIC
java.lang.Boolean boolean BIT
java.lang.String string VARCHAR
java.lang.Boolean yes_no CHAR(1)('Y'或'N')
java.lang.Boolean true_false CHAR(1)(‘Y’或'N')
java.uitl/sql.Date date DATE
java.sql.Time time TIME
java.sql.Timestamp timestamp TIMESTAMP
java.uitl.Calendar celendar TIMESTAMP
java.uitl.Calendar calendar TIMESTAMP
java.io.Serializable serializable VARBINARY/BLOB
java.sql.Clob clob CLOB
java.sql.Blob blob BLOB
java.lang.Class class VARCHAR
java.uitl.Locale locale VARCHAR
java.uitl.TimeZone timezone VARCHAR
java.uitl.Currency currency VARCHAR
类加载器
JVM中的类的加载器主要有三种:启动类加载器,拓展类加载器,应用类加载器。
启动类加载器(Bootstrap classLoader):又称为引导类加载器,由C++编写,无法通过程序得到。主要负责加载JAVA中的一些核心类库,主要是位于<JAVA_HOME>/lib/rt.jar中。
拓展类加载器(Extension classLoader):主要加载JAVA中的一些拓展类,位于<JAVA_HOME>/lib/ext中,是启动类加载器的子类。
应用类加载器(System/Application classLoader): 又称为系统类加载器,主要用于加载CLASSPATH路径下我们自己写的类,是拓展类加载器的子类。
算数运算符优先级排名
口诀:淡云一笔安洛三福 单目>算数运算符>移位>比较>按位>逻辑>三目>赋值;单运移比按逻三赋
SQL中的行转列,成绩转换使用CASE WHEN 列名 THEN ELSE END
jdk1.8支持的锁有:读写锁,自旋锁,乐观锁
1、Mysql中存储过程和存储函数的区别?
- 存储过程(Stored Procedure)
- 是一组为了完成特定功能的SQL语句集,经编译后存储在数据库中,用户通过指定存储过程的名字并给定参数(如果该存储过程带有参数)来调用执行它,存储过程是可编程的函数,在数据库中创建并保存,也可以由SQL语句和控制结构组成.简单点说就是一堆有逻辑控制的SQL的合并
- 一般使用在比较复杂的业务中,使用存储过程的系统更加稳定
- 存储过程只在创造时进行编译,以后每次存储过程都不需要重新编译,所以使用存储过程也可以提高数据库执行速度
- 当对数据库进行复杂操作时(入对多个表进行增删改查时),可以将此复杂操作用存储过程封装起来域数据库提供的事物处理结合一起使用.这些操作如果不结合起来的话需要多次链接数据库,如果传承存储过程那么只需要连接一次数据库
- 安全性高,可设定只有此用户才具有对指定存储过程的使用权
- 是一组为了完成特定功能的SQL语句集,经编译后存储在数据库中,用户通过指定存储过程的名字并给定参数(如果该存储过程带有参数)来调用执行它,存储过程是可编程的函数,在数据库中创建并保存,也可以由SQL语句和控制结构组成.简单点说就是一堆有逻辑控制的SQL的合并
-
存储函数(stored function)
transient和volatile
transient用于序列化对象时标记此对象不被序列化
volatile修饰的成员变量每次被线程访问时都会使线程强迫去在共享内存中读取该成员变量的值,当成员变量变化时,该变量修饰符会强迫线程将变化值写回到共享内存, 结论:任何时刻不同的线程看到的成员变量都是最新的值
Java关键字和保留字
-
关键字列表 (依字母排序 共50组):
- abstract, assert, boolean, break, byte, case, catch, char, class, const(保留关键字), continue, default, do, double, else, enum, extends, final, finally, float, for, goto(保留关键字), if, implements, import, instanceof, int, interface, long, native, new, package, private, protected, public, return, short, static, strictfp, super, switch, synchronized, this, throw, throws, transient, try, void, volatile, while
-
保留字列表 (依字母排序 共14组),Java保留字是指现有Java版本尚未使用,但以后版本可能会作为关键字使用:
- byValue, cast, false, future, generic, inner, operator, outer, rest, true, var, goto (保留关键字) , const (保留关键字) , null
java中控制数字精度
使用BigDecimal类来控制精度
HashMap
ConcurrentHashMap
使用segment来分段和管理锁,segment继承自ReentrantLock,因此ConcurrentHashMap使用ReentrantLock来保证线程安全。
类的加载顺序
首先,需要明白类的加载顺序。
(1) 父类静态代码块(包括静态初始化块,静态属性,但不包括静态方法)
(2) 子类静态代码块(包括静态初始化块,静态属性,但不包括静态方法 )
(3) 父类非静态代码块( 包括非静态初始化块,非静态属性 )
(4) 父类构造函数
(5) 子类非静态代码块 ( 包括非静态初始化块,非静态属性 )
(6) 子类构造函数
其中:类中静态块按照声明顺序执行,并且(1)和(2)不需要调用new类实例的时候就执行了(意思就是在类加载到方法区的时候执行的)
2.其次,需要理解子类覆盖父类方法的问题,也就是方法重写实现多态问题。
Base b = new Sub();它为多态的一种表现形式,声明是Base,实现是Sub类, 理解为 b 编译时表现为Base类特性,运行时表现为Sub类特性。
当子类覆盖了父类的方法后,意思是父类的方法已经被重写,题中 父类初始化调用的方法为子类实现的方法,子类实现的方法中调用的baseName为子类中的私有属性。
由1.可知,此时只执行到步骤4.,子类非静态代码块和初始化步骤还没有到,子类中的baseName还没有被初始化。所以此时 baseName为空。 所以为null。
Request中的方法
- 设置字符编码格式:request.setCharacterEncoding(“UTF-8”)
- 获取请求方式:request.getMethod()
- 获取http协议版本:request.getProtocol
- 获取请求的URL和URI:request.getRequestURL
URI()(URI统一资源标识符的子集是URL是具体的URI提供了定位该资源的信息和URN用特定命名空间的名字标识资源) - 获取请求头字段名列表:Request.getHeaderNames()
- 获取请求头字段值:Request.getHeader(headerName)
- 获取请求参数值:Request.getParameter(parameterName)
- 获取某个请求参数的多个值:Request.getParameterValues(“参数名”);会返回一个数组
- 获取实体内容,适用于POST方法的请求:Request.getInputStream()
Restful风格
-
如果通过表单只能提交get和post请求
-
如果通过ajax那么可以指定多种请求类型
-
@RequestParam是把请求中指定名称的参数给控制器中的形参赋值
@RequestBody是获取请求体
@RequestHeader是获取指定请求头
@PathVariable:
用于绑定 url 中的占位符。例如:请求 url 中 /delete/{id},这个{id}就是 url 占位符
url 支持占位符是 spring3.0 之后加入的。是 springmvc 支持 rest 风格 URL 的一个重要标志
-
tomcat中的编码问题
- get请求tomcat7以下
- [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-3vJdaRIj-1597217156795)(/C:/Users/Administrator/AppData/Roaming/Typora/typora-user-images/1566634597144.png)]
- post请求需要在web.xml中配置全局过滤器
- [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-QB4Qzlgi-1597217156797)(/C:/Users/Administrator/AppData/Roaming/Typora/typora-user-images/1566634648019.png)]
禁用cookie的情况下session怎样工作
cookie每次都会携带在请求中不禁用时jsessionid携带在cookie中- 如果禁止了cookie那么需要将jsessionid携带在地址后面,需要在响应时使用response.encodeRedirectURL("/index.jsp"),将session的关联从请求头中放到请求地址中[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-pt4IkWaP-1597217156799)(/C:/Users/Administrator/AppData/Roaming/Typora/typora-user-images/1566625926555.png)]
Timer不建议用,建议使用Excutorsquartz企业级定时任务建议使用的框架
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-I66Njdz8-1597217156801)(/C:/Users/Administrator/AppData/Roaming/Typora/typora-user-images/1566626116260.png)]
间隔一秒钟,执行上述控制台的输出.
建议使用Excutors.newScheduledThreadPool(2)创建延时执行线程
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ejkFWunG-1597217156802)(/C:/Users/Administrator/AppData/Roaming/Typora/typora-user-images/1566626413924.png)]
类之间的几种关系>
**USES-A:**依赖关系,A类会用到B类,这种关系具有偶然性,临时性。但B类的变化会影响A类。这种在代码中的体现为:A类方法中的参数包含了B类。
**关联关系:**A类会用到B类,这是一种强依赖关系,是长期的并非偶然。在代码中的表现为:A类的成员变量中含有B类。
HAS-A:聚合关系,拥有关系,是关联关系的一种特例,是整体和部分的关系。比如鸟群和鸟的关系是聚合关系,鸟群中每个部分都是鸟。
**IS-A:**表示继承。父类与子类,这个就不解释了。
要注意:还有一种关系:组合关系也是关联关系的一种特例,它体现一种contains-a的关系,这种关系比聚合更强,也称为强聚合。它同样体现整体与部分的关系,但这种整体和部分是不可分割的。
java 中\n\r\t\f的区别
符号 | 意义 |
---|---|
\n | 光标换行 |
\r | 光标回到第一个字符 |
\t | 相当于tab |
\f | 换页,print中木有意义 |
相对路径和绝对路径的理解
在资源文件前加上/叫做绝对路径,总是以webapp目录为起点
在资源文件前不加/叫做相对路径,相对于访问时的路径列如
重定向和转发
相应头中包含信息:302和location=地址(告诉浏览器去访问这个地址再次发送请求)
mybatis中的#{},${}的区别
Mybatis中 映射文件中使用#{}和${}占位符的区别 推荐使用#{}
${} 不会使用占位符而是直接使用字符串进行拼接
#{}会将其变为?占位符 底层使用where first_name=? preparedStatment.setString
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-NOeOJUHS-1597217156806)(C:/Users/Administrator/AppData/Roaming/Typora/typora-user-images/1566119062232.png)]
#更安全,
有
s
q
l
注
入
风
险
<
/
f
o
n
t
>
<
f
o
n
t
c
o
l
o
r
=
r
e
d
>
有sql注入风险</font> <font color = red>
有sql注入风险</font><fontcolor=red>可以拼接sql中的任意部分,如:
select *from KaTeX parse error: Expected 'EOF', got '&' at position 22: …name} order by &̲{column} 可以将其中…{}括号内可以进行运算,#{}括号中不能进行运算
列如分页时计算limi后面的索引和每页显示条数[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-SAVyFDn3-1597217156806)(/C:/Users/Administrator/AppData/Roaming/Typora/typora-user-images/1566453255998.png)]
$可以在映射文件中使用(mapper)也可以在核心配置文件中使用#{}只能在映射文件中使用
xml解析
dom 一次解析完
sax 以流的方式一行一行的读
Java中vector和ArrayList的相关特性
1、vector线程安全Arraylist线程不安全
2、当集合中使用的数据量较大时使用vector会比较有优势,因为扩容时vector增加一倍而ArrayList只增加一半
3、当查找一个指定位置的数据他们所用的时间是相同的
JVM
常量池的数据结构是hashtable 在开源的jdk中有一个vm文件下的class文件中的c++文件中实现的,string是,string创建时按照设计模式所说是new了一个再去比较,若无那么复制到常量池中,
j*.exe
java,exe是java虚拟机
javadoc.exe用来制作java文档
jdb.exe是java的调试器
javaprof,exe是剖析工具
JVM内存的组成及其作用
分类两大块 Java内存和非Java内存(外堆)
Java内存有
方法区(共享):
虚拟机栈(私有):线程内调用一次方法就会产生一个栈帧(一个方法就是一个栈帧,正在运行的叫活动栈帧),栈帧内包含方法内的局部变量,方法参数,返回地址等
本地方法栈(私有):其他语言写的用native
程序计数器(私有):记录代码执行到哪一行
堆空间(共享):
非Java内存(堆外内存)
元空间:运行时常量池,类对象,类加载器,静态变量,
直接内存:NIO进行IO操作时用到的数据缓冲内存
字节长度
字节类型 | 长度 |
---|---|
byte | 1 |
short | 2 |
int | 4 |
long | 8 |
double | 8 |
float | 4 |
boolean | 2 |
char | 1 |
对于JVM内存配置参数:
-Xss设置虚拟机栈
-Xmx10240m -Xms10240m -Xmn5120m -XXSurvivorRatio=3
-Xmx:最大堆内存大小
-Xms:最小堆内存大小
-Xmn:堆内存中年轻代大小
-XXSurvivorRatio:年轻代中Eden区和Survivor区的大小比值
年轻代中Survivor区有两个
常见的代码优化技术
复写传播,删除死代码,强度削弱,归纳变量删除
复写传播:
- 复写语句:形式为f = g 的赋值
- 优化过程中会大量引入复写
- 复写传播变换的做法是在复写语句f = g后,尽可能用g代表f
- 复写传播变换本身并不是优化,但它给其他优化带来机会
- 常量合并(编译时可完成的计算)
- 死代码删除
死代码删除
- 死代码是指计算的结果决不被引用的语句
- 一些优化变换可能会引起死代码
代码外提
- 代码外提是循环优化的一种
- 循环优化的其它重要技术
- 归纳变量删除
- 强度削弱
- hash值计算时使用31是31的乘法可以使用移位和减法替换
例:
`while``(i <= limit - ``2``) ...``// 代码外提后变成``t = limit - ``2``;``while``(i <= t) ...`
归纳变量删除
`j = j - ``1``t4 = ``4` `* j``t5 = a[t4]``if` `t5 > value ``goto` `B3`
- j和t4的值步伐一致地变化,这样的变量叫作归纳变量
- 在循环中有多个归纳变量时,也许只需要留下一个
- 这个操作由归纳变量删除过程来完成
- 对本例可以先做强度削弱,它给删除归纳变量创造机会
强度削弱
- 强度削弱的本质是把强度大的运算换算成强度小的运算,例如将乘法换成加法运算。
线程安全
成员变量和静态成员变量
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-x2BVkHmp-1597217156808)(/C:/Users/Administrator/AppData/Roaming/Typora/typora-user-images/1566193874731.png)]
线程安全的类
Vector,Hashtable,Stack
线程不安全的类
ArrayList Hashmap
数组不是原生类
控制切面通知的执行顺序
首先先将通知分为多个切面,每个切面一个通知,使用order来控制
对于前置通知,order小的在前面,对于后置通知,order小的在后面
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-eEP7pFlB-1597217156809)(C:/Users/Administrator/AppData/Roaming/Typora/typora-user-images/1566124159206.png)]
用注解配置声明式事务
xml
事务管理器
1、事务管理器
2、tx:annotation-driven/
在代码中
@Transactional可以加在方法或者类上 有很多属性
Mybatis
持久层
ORM mapping
开发步骤
1、导入坐标
2、表,实体类
3、映射文件(sqlmapconfig配置文件)
<mapper namespace=命名空间>
<select id=唯一标识 resulttype=对应的java类型 parameterType=参数类型>select。。from 。。where
</select>
</mapper>
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-r4OxvMsi-1597217156810)(C:/Users/Administrator/AppData/Roaming/Typora/typora-user-images/1566175653671.png)]
4、核心配置文件
数据源
<mapper resource=映射文件路径></mapper>
<typeAliases><package name=包名> </typeAliases>
将数据库中的下划线变为java中的驼峰命名法
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-2eJvNQUP-1597217156811)(C:/Users/Administrator/AppData/Roaming/Typora/typora-user-images/1566175930789.png)]
$时直接拼接字符串有sql注入的风险
sql中出现特殊字符
使用<![CDATA[出现特殊字符的语句]]>
这样就不会将特殊字符进行转义 如sql语句中有小于号大于号
分页查询
逻辑分页
sql语句是查询所有 java中 public Listfindbypage(RowBounds rb);
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-0jPZst3u-1597217156811)(C:/Users/Administrator/AppData/Roaming/Typora/typora-user-images/1566184127921.png)]
物理分页
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-TlCaHRoJ-1597217156812)(C:/Users/Administrator/AppData/Roaming/Typora/typora-user-images/1566184091021.png)]
mybatis generator插件的使用
第一步导入依赖[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-xvNZVvRZ-1597217156813)(/C:/Users/Administrator/AppData/Roaming/Typora/typora-user-images/1566204555197.png)]
第二步 编写配置文件
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-wYxGcxxh-1597217156815)(/C:/Users/Administrator/AppData/Roaming/Typora/typora-user-images/1566204697848.png)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-u2V0tMVW-1597217156816)(/C:/Users/Administrator/AppData/Roaming/Typora/typora-user-images/1566204716002.png)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-fa3CbKK5-1597217156817)(/C:/Users/Administrator/AppData/Roaming/Typora/typora-user-images/1566204829215.png)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-guAhH9Qv-1597217156817)(/C:/Users/Administrator/AppData/Roaming/Typora/typora-user-images/1566204837090.png)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-QWoLBe5L-1597217156818)(/C:/Users/Administrator/AppData/Roaming/Typora/typora-user-images/1566204941059.png)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-lRs6BVIT-1597217156819)(/C:/Users/Administrator/AppData/Roaming/Typora/typora-user-images/1566205064579.png)]
sql查询时使用模糊查询尽量不写前%,这样就能使用索引来告诉查询
多表查询
property是属性对应的是类中的属性
association是关联标签
要是有对象那么就用assocation标签将查出来的数据封装在对象中
主键使用id标签其他使用result标签 标签的属性colum是表中查出来的值 property是类中的属性名 association标签中的property是类中的属性名
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-PN33cFnq-1597217156820)(/C:/Users/Administrator/AppData/Roaming/Typora/typora-user-images/1566358095210.png)]
使用autoMapping标签属性时,可以省略标签中的result中属性名与列名一样的result标签
jdk1.7中抽象类和接口的区别
接口(interface)可以说成是抽象类的一种特例,接口中的所有方法都必须是抽象的。接口中的方法定义默认为public abstract类型,接口中的成员变量类型默认为public static final。另外,接口和抽象类在方法上有区别:
- 抽象类中可以包含静态方法,接口中不能包含静态方法
- 抽象类和接口中都可以包含静态成员变量,抽象类中的静态成员变量的访问类型可以任意,但接口中定义的变量只能是public static final类型,并且默认即为public static final类型
- 一个类可以实现多个接口,但只能继承一个抽象类。二者在应用方面也有一定的区别:接口更多的是在系统架构设计方法发挥作用,主要用于定义模块之间的通信契约。而抽象类在代码实现方面发挥作用,可以实现代码的重用,例如,模板方法设计模式是抽象类的一个典型应用,假设某个项目的所有Servlet类都要用相同的方式进行权限判断、记录访问日志和处理异常,那么就可以定义一个抽象的基类,让所有的Servlet都继承这个抽象基类,在抽象基类的service方法中完成权限判断、记录访问日志和处理异常的代码,在各个子类中只是完成各自的业务逻辑代码。
- 抽象类中的抽象方法的访问类型可以是public,protected和默认类型
- 抽象类中可以有普通成员变量,接口中没有普通成员变量
- 抽象类中可以包含非抽象的普通方法,接口中的所有方法必须都是抽象的,不能有非抽象的普通方法。
- 抽象类可以有构造方法,接口中不能有构造方法。
Mybatis中多对多查询流程
数据库中有三个表abc,其中b表中的内容时a的id对应的c的id,比如a是一个人,c是这个人所拥有的技能:语数英;所以说可以有多个人有多种技能,此时b表就展示了多个人对应的多个技能,比如李青精通语数,薇恩精通英数,蔚精通语数英.这三张表就是一种多对多的表关系;在这种多表查询中我们应该先使用左外连接查出来这个人所拥有的技能的编号,再使用内连接查询这个编号对应的技能
select a.*,b.* from a left join b on a.id=b.a_id
inner join c on c_id=c.id
第一行sql就是使用左外连接查询出来这个人对应的技能编号,第二行sql就是将查询出来的这个技能编号的id作为内连接的查询条件来查询具体的技能是什么.
mybatis注解开发
第一步在测试类中添加成员方法上边添加@Before 来加载资源文件,获取session mapper
第二部进行数据测试 将接口中对应的crud方法上添加对应的注解
@Insert:实现新增
@Update:实现更新
@Delete:实现删除
@Select:实现查询
注解括号中写入sql字符串代表需要该接口的抽象方法实现时的方法
多对一 一对一使用@ONE
一对多多对多使用@Many
集合封装使用@Result({多个@Result(Colum="",property="")})注解
@Result:实现结果集封装
@Results:可以与@Result 一起使用,封装多个结果集
@One:实现一对一结果集封装
@Many:实现一对多结果集封装
使用注解一对一查询时相当于第一次查询结果的结果集中有一个对象这个对象通过第一次查询的结果的一列数据作为条件再去查询第二张表;就是a表和b表,a表中有一个数据是匹配的b表的id 通过这个id再区查询b这就是一对一
mybatis的sql一级缓存优化
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-qRzlHf5V-1597217156821)(/C:/Users/Administrator/AppData/Roaming/Typora/typora-user-images/1566377664918.png)]
弄了个map 键为sql语句 值为sql的结果,map随着session的关闭而消失
mybatis的sql二级缓存优化
配置:添加@CacheNamespace
或在xml中添加标签
注解添加在需要使用的接口上
在user对象上添加序列化接口
是所有sqlsession共享的
前端学习
信息
样式
交互
查:MDN-HTML/CSS/JS的一切知识
练:实践出真知-Chrome DevTools
想:理解架构-MVC->MVVM
换:切换思维方式
HTML
把html想象成word文档
区分内容与非内容
列如面包屑中的大于号应该是CSS中的
HTML不是只共屏幕显示使用
a11y,可能是给盲人翻译阅读,所以需要区分内容和非内容
CSS
从粗糙到精致的递进式还原:相当于建楼
做CSS框架的使用者
MDN和《CSS设计指南》
理解CSS的思维模型:
如同画画:构图->物体->着色
CSS:布局->组件->定制
CSS原理
为什么叫层叠样式表:先看到细部规则(若无规则)->局部规则(若无规则)->全局规则>
为什么需要选择器:只有选择器才能确定他是什么规则
样式继承是怎么回事:通常出现在文字样式如字体
总之:责任链模式:
实践 - Chrome DevTools;与UX协作
不建议使用!important 病毒特性,若此处定义了优先级,其他地方若是需要高于此优先级那么也需要使用!important
JS和TS
动态语言中常见的鸭子类型
如果两个类型的形态和行为一致,那么他们两个可以被称为一个类型但java不行
静态语言中常见的类型系统
优点:自文档化,对读者友好,类型信息,对IDE友好,模块化,对团队友好;外挂类型信息,对遗留代码友好;Anders和HejLsberg,对…粉丝友好(hhh)
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-0cofn8GQ-1597217156822)(…/桌面背景/1572525503510.png)]
docker的两种不同的导出命令
- export->import–>容器的导入导出
- 仅保存容器导出时的状态
- docker commit 将容器变为镜像
- docker images --tree 仅有当前层的数据
- load->save–>镜像的导入导出:
- 会保存镜像的所有历史纪录(包含历史层)
- docker images --tree 有所有可以回滚的数据