01-反射
反射是Java成为动态语言的关键
什么是反射
程序中的反射是通过对象映射到类,在程序运行期间就可以获取到类的信息(结构)
类-》对象
对象-》类
在编写程序的时候,不知道要创建的对象是谁,直到程序运行的时候,才知道要创建那个对象
Class类是专门用来描述其他类的类,Class的对象就是另外一个类结构的抽象对象
bean=com.sholin.entity.Car
public class Test {
public static Properties properties = null;
static {
//new一个配置文件
properties = new Properties();
try {
//加载配置文件
properties.load(new FileInputStream(System.getProperty("user.dir")
+"/src/com/sholin/test29/bean.properties"));
} catch (IOException e) {
e.printStackTrace();
}
}
public static void main(String[] args) throws Exception {
//获取目标类名
String bean = properties.getProperty("bean");
//根据目标类名获取目标类所对应的Class对象
Class clazz = Class.forName(bean);
//获取构造器(有参构造,传null,表示无参构造)
Constructor constructor = clazz.getConstructor(String.class);
//根据构造器创建对象(上面传null,这也得传null,否则抛异常)
Object newInstance = constructor.newInstance("宝马");
System.out.println(newInstance);
}
}
如何使用反射
反射的源头是Class类,Java.lang.Class
Class类是专门用来描述其他类的类,Class的每一个实例化对象都是对目标类的具体描述
Class有三种获取方式
- 通过类名获取
- 通过类字面量获取
- 通过对象获取
Car car = new Car();
Class clazz = car.getClass();
每个类的Class对象只有一个,因为每个类在内存中只加载一次,加载到内存中的类叫做运行时类,因为只能加载一次,所以每个类的运行时类只有一个
Class就是描述运行时类的,每个Clas对象就是目标类的运行时类
获取到了反射源头之后,就可以进行操作,获取类的各种信息
类的信息包括属性、方法、构造器、父类、实现的接口、所在包的名称、访问权限等
构造器
无参构造
Constructor是专门用来描述构造器的类,Constructor的对象就是目标类的构造器
public class ConstructorTest {
public static Properties properties;
static {
properties = new Properties();
try {
properties.load(new FileInputStream(System.getProperty("user.dir")+"/src/com/sholin/test29/bean.properties"));
} catch (IOException e) {
e.printStackTrace();
}
}
public static void main(String[] args) throws Exception {
//方式一:对象名获取
String bean = properties.getProperty("bean");
Class clazz = Class.forName(bean);
Class clazz1 = Class.forName("com.sholin.test29.Car");
//方式二:字面量获取
Class clazz2 = Car.class;
//方式三:创建对象获取
Car car = new Car();
Class clazz3 = car.getClass();
//获取无参构造器getConstructor()
Constructor constructor = clazz.getConstructor(null);
//创建对象newInstance()
Object instance = constructor.newInstance(null);
System.out.println(instance);
}
}
有参构造
public class ConstructorTest {
public static Properties properties;
static {
properties = new Properties();
try {
properties.load(new FileInputStream(System.getProperty("user.dir")+"/src/com/sholin/test29/bean.properties"));
} catch (IOException e) {
e.printStackTrace();
}
}
public static void main(String[] args) throws Exception {
//方式一:对象名获取
String bean = properties.getProperty("bean");
Class clazz = Class.forName(bean);
Class clazz1 = Class.forName("com.sholin.test29.Car");
//方式二:字面量获取
Class clazz2 = Car.class;
//方式三:创建对象获取
Car car = new Car();
Class clazz3 = car.getClass();
// Constructor constructor = clazz.getConstructor(null);
// Object instance = constructor.newInstance(null);
//有参构造 传入参数类型
Constructor constructor = clazz.getConstructor(String.class);
//创建对象,传递参数值
Object instance = constructor.newInstance("宝马");
System.out.println(instance);
}
}
属性
//获取所有共有属性 getFields() 无视访问权限, getDeclaredFields()
Field[] fields = clazz.getFields();
for (Field field : fields) {
System.out.println(field);
}
//name属性私有,无法获取
Field name = clazz.getField("name");
//无视访问权限 getDeclaredField()
Field name1 = clazz.getDeclaredField("name");
System.out.println(name1);
获取属性的目的就是给对象赋值,首先通过构造器创建对象,接下来通过属性给对象赋值
方法
//获取所有共有方法 getMethods();
Method[] methods = clazz.getMethods();
for (Method method : methods) {
System.out.println(method);
}
//无参构造
Constructor constructor = clazz.getConstructor(null);
Object instance = constructor.newInstance(null);
System.out.println("*************方法设值**************");
//getMethod获取方法
Method setName = clazz.getMethod("setName",String.class);
//传递参数
setName.invoke(instance, "宝马");
System.out.println(instance);
反射应用
在程序运行过程中动态创建对象
- 在配置问价那种定义类的信息
- 动态读取配置文件,创建对象
public class Test { public static Properties properties = null; static { //new一个配置文件 properties = new Properties(); try { //加载配置文件 properties.load(new FileInputStream(System.getProperty("user.dir")+"/src/com/sholin/test29/bean.properties")); } catch (IOException e) { e.printStackTrace(); } } public static void main(String[] args) throws Exception { //获取目标类名 String bean = properties.getProperty("bean"); //根据目标类名获取目标类所对应的Class对象 Class clazz = Class.forName(bean); //获取构造器 Constructor constructor = clazz.getConstructor(null); //根据构造器创建对象 Object newInstance = constructor.newInstance(null); System.out.println(newInstance); } }
动态代理
动态代理主要通过反射完成
代理模式
代理模式是一种常用的Java设计模式,代理模式是指在处理一个业务的时候,通过代理的方式来完成
委托方和代理方,委托方委托代理帮助完成某些工作(就像外包公司一样,核心的功能自己完成,其余的交给外包公司帮忙做)
在所有的代理模式中,委托方和代理方有一个共性,双方都具备完成需求的能力
Java中将对象所具备的能力封装成接口,Java中的代理模式的原则就是委托类和代理类实现了同样的接口
动态代理
代理类和委托类之间通过依赖注入进行关联,在设计程序时,需要将委托类定义为代理类的成员变量。
代理类本身并不会取执行业务逻辑,而是通过调用委托类的方法来完成,真正的业务逻辑仍然时委托类来完成,代理类只是完成一些核心业务意外的功能,这样实现解耦合
一个完整的业务包含:核心业务模块+辅助性的业务(打印日志、消息过滤、类型转换)
委托类只需要负责核心业务,不需要参杂任何与核心业务无关的代码
辅助性的业务有代理类完成,将委托类注入到代理类中,分别完成核心业务和辅助性业务
开发者只需要调用代理对象即可完成整套业务
静态代理
静态代理是指代类提前写好的,动态代理是指代理类时动态生成的
静态代理
public class ProxyTest {
public static void main(String[] args) {
//创建对象
BaoMa baoMa = new BaoMa();
//Car代理类
ProxyCar proxyCar = new ProxyCar(baoMa);
System.out.println(proxyCar.saleCar());
//同上,代码冗余,耦合度高
Audi audi = new Audi();
ProxyCar proxyCar1 = new ProxyCar(audi);
System.out.println(proxyCar1.saleCar());
}
}
//Car代理类
public class ProxyCar implements Car {
private Car car;
public ProxyCar(Car car) {
this.car = car;
}
@Override
public String saleCar() {
System.out.println("启动代理销售汽车");
return this.car.saleCar();
}
}
//Car接口
public interface Car {
public String saleCar();
}
//实现类
public class BaoMa implements Car {
@Override
public String saleCar() {
return "销售宝马汽车";
}
}
动态代理实现
指定代理类的生成策略
通过java.lang.reflect.InvocationHandler接口,可以在程序运行期间动态生成代理类,即生成策略通过接口来完成
实现InvocationHandler接口,Porxy.newProxyInstances()三个参数
- 类加载器ClassLoader
- 委托类的接口
- 当前InvocationHandler实例对象(动态代理方法在执行时,会调用h里面的invoke方法去执行)
动态生成一个类,代理类
代理类要调用委托类的接口,必须首先获取委托类的接口,所以要传入委托类的接口
类需要类加载器将动态生成的代理类加载到Java内存中才能使用,所以要传入ClassLoader
上述过程需要一个对象完成,即当前实例对象
如下代码实现通过动态代理方式生成不同对象,执行彼此功能
public class MyInvocationHandler implements InvocationHandler {
private Object obj=null;
public Object bind(Object obj){
this.obj = obj;
return Proxy.newProxyInstance(MyInvocationHandler.class.getClassLoader(),obj.getClass().getInterfaces(),this);
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
//核心业务代码委托对象来完成,方法由委托对象调用
System.out.println("启动动态代理模式");
Object invoke = method.invoke(this.obj, args);
return invoke;
}
}
public class Test {
public static void main(String[] args) {
MyInvocationHandler myInvocationHandler = new MyInvocationHandler();
//定义委托类
Car car = new Audi();
//获取动态代理对象
Car proxy = (Car)myInvocationHandler.bind(car);
System.out.println(proxy.saleCar());
//定义委托类
Phone phone = new Huawei();
//获取动态代理对象
Phone proxy1 = (Phone) myInvocationHandler.bind(phone);
System.out.println(proxy1.salePhone());
}
}
//Car接口
public interface Car {
public String saleCar();
}
//Car接口实现(核心任务)
public class BaoMa implements Car {
@Override
public String saleCar() {
return "销售宝马汽车";
}
}
//Phone接口及接口实现
public interface Phone {
public String salePhone();
}
public class Huawei implements Phone {
@Override
public String salePhone() {
return "销售华为手机";
}
}