Boolean ? 结果a : Boolean ? 结果b : 结果c;
(1)from
(3) join
(2) on
(4) where
(5)group by(开始使用select中的别名,后面的语句中都可以使用)
(6) avg,sum…
(7)having
(8) select
(9) distinct
(10) order by
SpringBoot+SpringDataJPA:操作简单的增删改查+Mybatis:多表联查等
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:自动配置的核心注解,是否自动配置的开关)
解决方案 使用string存储数据 若查询不到那么将请求参数设置null值并存入缓存,同时设置过期时间,那么在过期时间内将不会再访问数据库
所有的请求不会访问数据库,只访问redis,设置定时任务,定期更新redis中的数据
高并发情况下,缓存失效,造成大量请求瞬间请求数据库
设置条件,同样的请求只能有一个线程去访问数据库,再使用互斥锁(trylock)
大量的高并发的缓存同时失效,造成的数据库压力过大(整点抢购活动)
解决方案:设置不同的过期时间,
只查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、一般采用异步方式。顺序执行可能会导致系统卡壳
静态内部类才可以声明静态方法
静态方法不可以使用非静态变量
抽象方法不可以有函数体
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();
}
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. 从任一节点到其每个叶子的所有路径都包含相同数目的黑色节点。
1)没有测试之前不要写任何功能代码
2)只编写恰好能够体现一个失败情况的测试代码
3)只编写恰好能通过测试的功能代码
在实际开发过程中,可能并不需要严格遵守这三个原则。即便只是大体上应用TDD到复杂功能开发,就能发挥很大的作用。
具体来说,首先在开发前期,按照TDD的原则不断在添加测试用例和开发功能代码之间切换。
在这个循环迭代过程中,不断地通过重构和面向对象思想,完善代码设计。
并且可以引入业界公认的设计模式使自己的代码更加专业、优美。
这样做的优点:
一是帮助思考。对于很复杂的功能需要迭代开发,不可能一下子就把逻辑实现全想明白。于是可以先实现最简单功能,再逐步完善;
二是快速调试。有了单元测试,可以通过失败的用例直接找到对应出问题的代码,几乎不需要太多调试了;
三是通过TDD不断迭代出的代码,设计比较合理,后期更加容易维护。
当然凡事都是有利有弊的,TDD也有它的缺点和局限:
一是前期进开发稍慢一些,因为需要编写单元测试(但是TDD往往在开发中后期会让你的开发进度越来越快,
TDD节省下来的时间将远远超过编写和维护测试用例的时间。这就好比玩即时战略游戏,前期的精心布局将在中后期看到效果);
二是对于简单功能并不适用,要注意应用场景。
? 应用:自旋锁
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);