一、反射机制
1、什么是反射机制
正在运行,动态获取类的信息。
2、反射机制的作用
a.反编译:.class-->.java;
b.使用反射机制获取类的属性、方法、实例化对象;
c.不使用new 可以获取对象
3、反射机制创建对象
//使用java的反射机制创建对象 类的完整路径
Class<?> class=Class.forName("com.a.User");
//使用反射 创建对象
User user=(User)class.newInstance();
//调用有参构造函数
Constructor<?> constructor=class.getConstructor(String.class);
User user2=(User)constructor.newInstance("张三");
4、怎么防止被反射
a
5、反射机制应用场景
a. jdbc 连接
b. SpringIOC底层使用反射机制+DOM4J
c.框架Hibernate、mybatis
二、设计模式
创建型模式:工厂方法模式、抽象工厂模式、单例模式、建造者模式、原型模式。
结构型模式:适配器模式、装饰器模式、代理模式、外观模式、桥接模式、组合模式、享元模式。
行为型模式:策略模式、模板方式模式、观察者模式、迭代子模式、责任链模式、命令模式、备忘录模式、状态模式、访问者模式、中介者模式、解释器模式。
三、单例设计模式
1、什么是单例设计模式?
保证在一个jvm中,只能存在一个实例,保证对象唯一性。
2、单例设计模式应用场景?
servlet、spring、sruts2、springmvc、连接池、线程池、枚举、常用
3、单例的好处与缺点
好处:节约内存,重复利用,方便管理
缺点:线程安全问题
4、单例创建方式
a.饿汉式:类初始化时,会立即加载该对象,线程天生安全,调用效率高。
public class User01 {
//类初始化时就会创建对象,调用效率高,但不调用时会浪费内存
private static final User01 user=new User01();
//私有化构造函数
private User01(){}
//定义获取对象静态方法
public static User01 getInstance(){
return user;
}
//调用 获取对象
public static void main(String[] args){
User01 user01=User01.getInstance();
}
}
b.懒汉式:类初始化时,不会初始化该对象,真正需要使用的时候才会创建该对象,具备懒加载功能。
public class User02{
//类初始化的时候 不生成对象
private static User02 user02;
//私有化构造函数
private User02(){}
//在调用时,先判断是否为空对象,若为空再生成对象。但此处会有线程安全问题,如是多线程可能会创建多个对象。所以最好加上synchronized
public static synchronized User02 getInstance(){
if(null==user02){
user02=new User02();
}
return user02;
}
}
c.静态内部方式:结合了懒汉式和饿汉式各自的优点,真正需要对象的时候才会加载,加载类是线程安全。
public class User03{
private User03(){}
public static class SingletonUserInstance{
private static final User03 user03=new User03();
}
public static User03 getInstance(){
return new SingletonUserInstance.user03;
}
}
d.枚举单例:使用枚举实现单例模式 优点:实现简单,调用效率高,枚举本身就是单例,由jvm从根本上提供保障 避免通过反射和反序列化的漏洞,缺点:没有延迟加载。
public class User04{
private User04(){}
public static User04 getInstance(){
return SingletonUserEnum.INSTANCE.getInstance();
}
//枚举本来就是单例
static enum SingletonUserEnum{
INSTANCE;
private User04 user04;
//此方法只会执行一次
private SingletonUserEnum(){
user04=new User04();
}
public User04 getInstance(){
return this.user04;
}
}
}
e.双重检测锁方式:
public class User05{
private static volatile User05 user05;
private User05(){}
public static getInstance(){
if(null==user05){
synchronized(this){
if(null==user05){
user05=new User05();
}
}
}
return user05;
}
}
四、工厂模式
1、简单工厂(用来生产同一等级结构中的任意产品。不支持拓展增加产品)
简单工厂模式相当于是一个工厂中有各种产品,创建在一个类中,客户无需知道具体产品的名称,只需要知道产品类所对应的参数即可。但是工厂的职责过重,而且当类型过多时不利于系统的扩展维护。
//car interface
public interface Car{
void run();
}
//Car object 1
public class BydCar implements Car{
public void run(){
System.out.println("比亚迪");
}
}
//Car object 2
public class JiliCar implements Car{
public void run(){
System.out.println("吉利");
}
}
//Car Factory
public class CarFactory{
public static createCar(String name){
if("比亚迪".equals(name)){
return new BydCar();
}
if("吉利".equals(name)){
return new JiliCar();
}
return null;
}
}
//client
public class Client{
public static void main(String[] args){
Car byd=CarFactory.createCard("比亚迪");
}
}
2、工厂方法设计模式(用来生产同一等级结构中的固定产品。支持拓展增加产品)
工厂方法模式Factory Method,又称多态性工厂模式。在工厂方法模式中,核心的工厂类不再负责所有的产品的创建,而是将具体创建的工作交给子类去做。该核心类成为一个抽象工厂角色,仅负责给出具体工厂子类必须实现的接口,而不接触哪一个产品类应当被实例化这种细节。
//car factory interface
public interface CarFactory{
Car createCar(String name);
}
public class BydCaryFactory implements CarFactory{
public Car createCar(String name){
return new BydCar();
}
}
public class JiliCaryFactory implements CarFactory{
public Car createCar(String name){
return new JiliCar();
}
}
3、抽象工厂(用来生产不同产品族的全部产品。不支持拓展增加产品;支持增加产品族)
抽象工厂简单地说是工厂的工厂,抽象工厂可以创建具体工厂,由具体工厂来产生具体产品。
五、代理设计模式
1、什么是代理模式
通过代理控制对象的访问,可以详细访问某个对象的方法,在这个方法调用之前或调用后处理。既(AOP微实现) ,AOP核心技术面向切面编程。
2、代理模式应用场景
SpringAOP,事务原理,日志打印,权限控制,远程调用,安全代理,可以隐蔽真实角色。
3、静态代理
由程序员创建或工具生成代理类的源码,再编译代理类。所谓静态也就是在程序运行前就已经存在代理类的字节码文件,代理类和委托类的关系在运行前就确定了。
public interface UserDao{
void save();
}
public class UserDaoImpl implements UserDao{
public void save(){
System.out.println("保存.....");
}
}
//代理类
public class UserDaoProxy implements UserDao{
private UserDaoImpl userDao;
public UserDaoProxy(UserDaoImpl userDao){
this.userDao=userDao;
}
public void save(){
System.out.println("开启事务.....");
userDao.save();
System.out.println("提交事务.....");
}
}
4、动态代理
a.什么是动态代理
代理对象,不需要实现接口。
代理对象的生成,是利用JDK的API,动态的在内存中构建代理对象(需要我们指定创建代理对象/目标对象实现的接口的类型)。
动态代理也叫做:JDK代理,接口代理。
b.实现方式:JDK代理
通过实现InvocationHandler接口创建自己的调用处理器 IvocationHandler handler = new InvocationHandlerImpl(…);
通过为Proxy类指定ClassLoader对象和一组interface创建动态代理类Class clazz = Proxy.getProxyClass(classLoader,new Class[]{…});
通过反射机制获取动态代理类的构造函数,其参数类型是调用处理器接口类型Constructor constructor = clazz.getConstructor(new Class[]{InvocationHandler.class});
通过构造函数创建代理类实例,此时需将调用处理器对象作为参数被传入Interface Proxy = (Interface)constructor.newInstance(new Object[] (handler));
//每次生成动态代理类对象时,实现了InvocationHandler接口的调用处理器对象
public class InvocationHandlerImpl implements InvocationHandler{
private Object target;//这其实业务实现类对象,用来调用具体的业务方法
// 通过构造函数传入目标对象
public InvocationHandlerImpl(Object target){
this.target=target;
}
public Object invoke(Object proxy,Method method,Object[] args) throws Throwable{
Object result=null;
System.out.println("开启事务");
result=method.invoke(target,args);
System.out.println("关闭事务");
return result;
}
public static void main(String[] args) throws NoSuchMethodException,SecurityException, InstantiationException,
IllegalAccessException, IllegalArgumentException, InvocationTargetException {
// 被代理对象
UserDao userDao = new UserDao();
InvocationHandlerImpl invocationHandlerImpl = new InvocationHandlerImpl(userDao);
ClassLoader loader = userDao.getClass().getClassLoader();
Class<?>[] interfaces = userDao.getClass().getInterfaces();
// 主要装载器、一组接口及调用处理动态代理实例
UserDao newProxyInstance = (IUserDao) Proxy.newProxyInstance(loader, interfaces, invocationHandlerImpl);
newProxyInstance.save();
}
}
c.CGLIB代理
不要求委托类实现接口,底层使用ASM字节码生成框架生成代理类的字节码。
//引用包
<dependency>
<groupId>cglib</groupId>
<artifactId>cglib</artifactId>
<version>3.1</version>
</dependency>
public class CglibProxy implements MethodInterceptor{
private Object target;
public Object getInstance(Object target){
this.target=target;
Enhancer enhancer=new Enhancer();
enhancer.setSuperclass(target.getClass());
enhancer.setCallback(this);
return enhancer.create();
}
public Object intercept(Object obj,Method method,Object[] args,MethodProxy proxy){
System.out.println("开启事务");
Object invoke=proxy.invoke(obj,arges);
System.out.println("提交事务");
return invoke;
}
public static void main(String[] args){
CglibProxy proxy=new CglibProxy();
UserDaoImpl userDao=(UserDaoImpl)proxy.getInstance(new UserDaoImpl());
userDao.add();
}
d.CGLIB动态代理与JDK动态代理的区别
JDK代理是利用反射机制生成一个实现代理接口的匿名类,在调用具体方法前调用InvokeHandler来处理。CGLIB代理 是利用asm开源包,对代理对象类的class文件加载进来,通过修改字节码生成子类来处理。
JDK动态代理只能对实现了接口的类生成代理,而不能针对类 。
CGLIB是针对类实现代理,主要是对指定的类生成一个子类,覆盖其中的方法 。
五、建造者模式
将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示。就是将各种产品集中起来进行管理,用来创建复合对象。使用场景:需要生成的对象具有复杂的内部结构。需要生成的对象内部属性本身相互依赖。与工厂模式的区别是:建造者模式更加关注与零件装配的顺序。
六、模板方法模式
处理某个流程的代码已经都具备,但是其中某个节点的代码暂时不能确定。因此,我们采用模板方法模式,将这个节点的代码实现转移给子类完成。即:处理步骤在父类中定义好,具体的实现延迟到子类中定义。
应用场景:数据库访问的封装、Junit单元测试、servlet中关于doGet/doPost方法的调用、Hibernate中模板程序、spring中JDBCTemplate,HibernateTemplate等等。
七、适配器模式
适配器模式一般是用来解决兼容的问题。分为类适配器、对象适配器、接口适配器,类适配器方式采用继承方式,对象适配方式使用构造函数传递。
使用场景:
1、我们在使用第三方的类库,或者说第三方的API的时候,我们通过适配器转换来满足现有系统的使用需求。
2、我们的旧系统与新系统进行集成的时候,我们发现旧系统的数据无法满足新系统的需求,那么这个时候,我们可能需要适配器,完成调用需求。
3、我们在使用不同数据库之间进行数据同步。(我这里只是分析的是通过程序来说实现的时候的情况。还有其他的很多种方式[数据库同步])。
4、OutputStreamWriter:是Writer的子类,将输出的字符流变为字节流,即:将一个字符流的输出对象变为字节流的输出对象。InputStreamReader:是Reader的子类,将输入的字节流变为字符流,即:将一个字节流的输入对象变为字符流的输入对象。
八、外观模式
隐藏系统的复杂性,并向客户端提供了一个客户端可以访问系统的接口。这种类型的设计模式属于结构型模式,它向现有的系统添加一个接口,来隐藏系统的复杂性。
使用场景:在Spring 中使用最广泛。
九、原型模式
原型模式是一个创建型的模式。原型二字表明了改模式应该有一个样板实例,用户从这个样板对象中复制一个内部属性一致的对象,这个过程也就是我们称的“克隆”。被复制的实例就是我们所称的“原型”,这个原型是可定制的。原型模式多用于创建复杂的或者构造耗时的实例,因为这种情况下,复制一个已经存在的实例可使程序运行更高效。
原型模式分为浅复制和深复制,浅复制仅是复制基本类型的数据,而引用类型数据,只是复制内存地址。深复制指的是在内存开辟一块新的内存地址用于存放复制的对象。
使用场景:
(1) 类初始化需要消化非常多的资源,这个资源包括数据、硬件资源等,通过原型拷贝避免这些消耗。
(2) 通过new产生的一个对象需要非常繁琐的数据准备或者权限,这时可以使用原型模式。
(3)一个对象需要提供给其他对象访问,而且各个调用者可能都需要修改其值时,可以考虑使用原型模式拷贝多个对象供调用者使用,即保护性拷贝。