一、类加载器
类的加载:当程序使用某个类时,若该类未被加载到内存中,则系统会通过 加载、连接、初始化三步来实现类的初始化。
1.类加载的三个步骤
1.1加载(通过类加载器实现):
- 将class文件读入内存,并为它创建一个Class对象(任何类在使用时,系统都会为它创建一个Class对象)
1.2链接:
- 验证:内部结构是否正确。
- 准备:复制为类的静态变量分配内存,并设置默认值。
- 解析:将类的二进制数据中的符号引用替换为直接引用
1.3初始化:
- 类的初始化:类加载最后阶段,若该类具有超类,则对其进行初始化,执行静态初始化器和静态初始化成员变量(如前面只初始化了默认值的static变量将会在这个阶段赋值,成员变量也将被初始化)。
2.类加载的时机:
- 创建类实例
- 访问静态变量,为静态变量赋值,调用静态方法
- 初始化其子类
- 使用java.exe 命令运行某个类
- 使用反射方式来强制创建某个类或接口对应的对象
3.类加载器分类:
- 根类加载器:加载java核心类(jdk/jre/rt.jar 中的class文件)
- 扩展类加载器:加载jre中扩展目录中的jar包中的类(jdk/jre/lib/ext目录中的class文件)
- 系统类加载器:加载来自java命令的class文件以及classpath环境变量所指定的jar包和类路径下的class文件
二、反射
1.定义:
- 通过class文件对象,即Class类的对象(不是通过该类的对像),去使用该类的成员变量,构造方法,成员方法
2.Class类:
- 对应的成员变量,构造方法,成员方法都是类。(反射就是先得到Class类对象,再通过该对象获得它的成员变量/构造方法/成员方法,最后分别通过成员变量/构造方法/成员方法的对象调用对应的方法)
- 获取Class类的对象的方法
-
法一:
Person p=new Person(); Class c=p.getClass();
-
法二:
Class c=Person.class;
-
法三:
Class c=Class.forName(类的地址);
-
方法选择:
-
法二相对简单,但一般开发选择法三,因为法三参数时字符串,比较灵活,可通过配置文件加载,便于维护。
-
3.通过反射获取构造方法
Class c=Class.forName(Person类地址);//以Person类为例子
//获取所有构造方法,返回的cons 是类对象的集合
//获取所有公共构造方法
Constructor[] cons=c.getConstructors();
//获取所有构造方法(包括私有)
Constructor[] cons=c.getDeclaredConstructors();
//遍历构造方法
for(Constructor con:cons)System.out.println(con)
//获取单个构造方法
//获取有参构造方法(无参就不填参数即可)
Constructor con=c.getConstructor(String.class,int.class,String.class);//获取有参构造方法(无参就不填参数即可)
//获取任意单个构造方法(包括私有)
Constructor con=c.getDeclaredConstructor(String.class);
//取消java语言访问检测
con.setAccessible(true);
//通过构造方法创建类对象
Object obj=con.newInstance(“林青霞”,12,“重庆”);
4.通过反射获取成员变量并赋值
//先利用反射创建对象
Class c=Class.forName(person类地址)
Constructor con =c.getConstructor();
Object obj=con.newInstance();
//获取所有成员变量
//获取所有共有的成员变量
Field[] fields=c.getFields();
//获取所有的成员变量(包括私有)
Field[] fields=c.getDeclaredFields();
//获取单个成员变量
//获取共有的单个成员变量(名称记得打引号)
Field field=c.getField(“变量名称”);
//获取任意一个成员变量(包括私有)
Field field=c.getDeclaredField("变量名称“);
//取消java语言访问检测
field.setAccessible(true);
//给成员变量赋值
field.set(obj,变量值)//多个变量用逗号隔开
5.通过反射获取成员方法
//先利用反射创建对象
Class c=Class.forName(person类地址)
Constructor con =c.getConstructor();
Object obj=con.newInstance();
//获取所有成员方法
//获取所有共有的成员方法
Method[] methods=c.getMethods();
//获取所有的成员方法(包括私有)
Method[] methods=c.getDeclaredMethods();
//获取单个成员方法
//获取共有的单个成员方法(名称记得打引号)
Method method=c.getMethod(“方法名称”);
//获取任意一个成员方法(包括私有)
Method method=c.getDeclaredMethod("方法名称“,参数的class类型);//多个参数用空格隔开,参数的class类型如:String.class
//取消java语言访问检测
method.setAccessible(true);
//调用成员方法
method.invoke(obj,参数)//多个参数用逗号隔开
三、动态代理
1.含义:
- 在运行过程中产生某个对象,可以在运行的时候才切入改变类的方法,而不需要预先定义它。
- 在java的动态代理机制中,有两个重要的类和接口:Proxy(Class),InvocationHandler(Interface)通过这个类和接口就能生成一个动态代理对象(注意JDK提供的代理只能针对接口做代理,要对类做代理可以用cglib)。
- 每一个动态代理类都必须要实现InvocationHandler这个接口,并且每个代理类的实例都关联到了一个handler,当我们通过代理对象调用一个方法的时候,这个方法的调用就会被转发为由InvocationHandler这个接口的 invoke 方法来进行调用。
2.创建步骤
-
创建一个需要代理的接口
public interface StudentDao { abstract void identify(int s); abstract void dream(); }
-
实现代理接口
package proxy; public class StudentImpl implements StudentDao{ @Override public void identify(int s) { System.out.println("我是"+s+"年纪的"+"学生"); } @Override public void dream() { System.out.println("成绩高"); } }
-
实现InvocationHandler 接口:
public class InvocationHandlerImpl implements InvocationHandler{ public Object target; InvocationHandlerImpl(Object target){ this.target=target; } @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { //System.out.println(proxy); System.out.println("动态执行一些方法"); Object result=method.invoke(target, args); return result; } }
-
生成接口代理并测试
public class TestProxy { public static void main(String[] args) { StudentDao sd=new StudentImpl(); System.out.println("代理前:"+"\n"+"------------------------------------"); sd.dream(); sd.identify(5); System.out.println("------------------------------------"); //生成接口代理 InvocationHandlerImpl h=new InvocationHandlerImpl(sd); StudentDao sdProxy=(StudentDao)Proxy.newProxyInstance(sd.getClass().getClassLoader(), sd.getClass().getInterfaces(), h); System.out.println("代理后:"+"\n"+"------------------------------------"); sdProxy.dream(); sdProxy.identify(5); System.out.println("------------------------------------"); } }
测试结果:
代理前:
------------------------------------
成绩高
我是5年纪的学生
------------------------------------
代理后:
------------------------------------
动态执行一些方法
成绩高
动态执行一些方法
我是5年纪的学生
------------------------------------
四、设计模式
1.设计思想:
1.1单一职责思想设计原则:
- 每个类实现一种功能,引起改变的原因也只有一个。
1.2开闭原则
- 对类改动通过增加代码,而不是修改代码(对类的改动通过增加代码进行,而不是修改代码)多借助抽象和多态。
1.3里氏替换原则
- 任何父类出现的地方都应该可以用其子类替换。(同一个继承体系拥有共同的特征)
1.4依赖注入原则
- 要依赖于抽象类,不要依赖于具体实现类
1.5接口分离原则
- 一个接口提供一种功能(如将对某个类的增删改查分离为四个接口,每个接口实现一个功能)
1.6迪米特原则
- 一个类应尽可能少的了解其他类(降低各个类之间的耦合)
2.设计模式
2.1设计模式的几个要素:
- 名字 必须有一个简单,有意义的名字
- 问题 描述在何时使用模式
- 解决方案 描述设计的组成部分以及如何解决问题
- 效果 描述模式的效果以及优缺点
2.2设计模式的分类
- 创建型模式 对象的创建
-
简单工厂模式
例子:
//父类:Animal (eat方法) //子类:Cat Dog (都覆盖eat方法) 传统创建: Cat cat =new Cat(); cat.eat(); Dog dog=new Dog(); dog.eat(); //简单工厂模式:创建一个动物工厂(class : AnimalFactory) public static Animal createAnimal (String type){ if("dog".equals(type)){ return new Dog(); }else if("cat".equals(type)){ return new Cat(); }else{ return null; } } //利用工厂创建: Animal a=AnimalFactory.createAnimal("dog");//通过字符串方式传递给工厂进行创建,便于代码维护。 a.eat();
-
工厂方法模式
例子://在简单工厂模式上改进了,简单工厂模式每次增加一个动物都需要该原有的代码。 //父类:Animal (eat方法) //子类:Cat Dog (都覆盖eat方法) //父工厂:Factory接口(abstract createAnimal()); //子工厂:DogFactory,CatFactory(实现Factory接口,覆盖createAnimal()方法) //测试: Factory f=new DagFactory(); Animal a=f.createAnimal(); a.eat();
-
抽象工厂模式
-
建造者模式
-
原型模式
-
单例模式。
-
- 结构型模式 对象的组成(结构)
- 外观模式
- 适配器模式
- 代理模式
- 装饰模式
- 桥接模式
- 组合模式
- 享元模式
- 行为型模式 对象的行为
- 模版方法模式
- 观察者模式
- 状态模式
- 职责链模式
- 命令模式
- 访问者模式
- 策略模式
- 备忘录模式
- 迭代器模式
- 解释器模式