刚学反射的时候,因为没什么应用场景,领悟不深,现在过后来再看,后面不少东西的依托都是源于反射的实现,可以说是相当重要的一个概念,但是我猜,这个应该在初学的时候大概率都会如笔者一般,懵懵懂懂吧,继续学习咯,随着学习的推进,经验的增加,会对程序的设计解读有着不同阶段的理解吧,现在想来还是基础得好啊。
1、反射
在程序运行时,可以根据给定的类动态的获取类的信息;通过反射方式使用此类 SUN设计的反射相关组件放在:java.lang.reflect包
探测器对象(Class类型的对象):首先得要得到(常见以下几种方式)
方法一
User user = new User();
Class<?> c = user.getClass();
方法二
Class<?> clz2 = User.class;
方法三
Class<?> clz3 = Class.forName(className); className:类的全路径
对基本数据类型的包装类
Class<?> clz4 = Integer.TYPE;
2、类加载器(ClassLoader)
1、系统类加载器
ClassLoader loader1 = ClassLoader.getSystemClassLoader();
2、扩展类加载器
ClassLoader loader2 = loader1.getParent();
3、引导类加载器
ClassLoader loader3 = loader1.getParent(); //null
类加载器应用:通过类加载器获取项目资源【重要的】
ClassLoader loader1 = ClassLoader.getSystemClassLoader();
InputStream in = loader1.getResourceAsStream("db.properties");
//对properties文件,SUN设计了一个类:Properties类,直接解析此文件;
Properties prop = new Properties();
prop.load(in);
//获取文件信息
String user = prop.getProperty("user");
String password = prop.getProperty("password");
System.out.println("user ->" + user);
System.out.println("password -> " + password);
URL url = loader1.getResource("db.properties"); 得到文件全路径
InputStream in = loader1.getResourceAsStream("db.properties"); 直接返回一个流
3、获取类信息
Field类型对象 | Constructor类型对象 | Method类型对象
Field[] fields = clz.getDeclaredFields();
for(Field f : fields) {
System.out.println(Modifier.toString(f.getModifiers()) +" " + f.getType().getSimpleName() + " " + f.getName());
}
// Constructor[] cons = clz.getDeclaredConstructors();
// for(Constructor c : cons) {
// System.out.println(c);
// }
// Method[] methods = clz.getDeclaredMethods();
// for(Method m : methods) {
// System.out.println(m);
// }
4、反射应用
通过反射 :创建对象 | 设置属性 | 调用方法
//得到一个Class对象
String className ="cn.lanqiao.reflect.User";
Class<?> clz = Class.forName(className);
//应用1:通过反射 创建对象;(无参构造方法)
//User obj = (User) clz.newInstance(); //默认调用本类的无参构造方法创建对象 -- 类必须有无参构造方法;
//java.lang.NoSuchMethodException: cn.lanqiao.reflect.User.<init>()
// System.out.println(obj);
// User obj2 = (User) clz.newInstance();
// System.out.println(obj==obj2);
//应用2:带参构造方法;
Constructor<?> con = clz.getDeclaredConstructor(String.class,String.class,int.class);
User user = (User) con.newInstance("张一","java程序员",20);
System.out.println(user);
//应用2:设置属性;
Class<?> clz= Class.forName("cn.lanqiao.User");
Object obj = clz.newInstance(); //得到一个User对象(向上转型)
//获取某一属性;
Field nameField = clz.getDeclaredField("name");
//给属性赋值;
//设置属性可访问
nameField.setAccessible(true);
//第1个参数为对象,第2个参数为属性值;
nameField.set(obj, "张一");
System.out.println(obj);
//应用3:通过反射调用方法;
Class clz = User.class;
//创建对象
Constructor<?> con = clz.getDeclaredConstructor(String.class,String.class,int.class);
Object obj = con.newInstance("张一","java程序员",20);
//获取方法;
//Method method = clz.getDeclaredMethod("toString");
//调用方法;
//Object val = method.invoke(obj);
//System.out.println(val);
//Method method = clz.getDeclaredMethod("getName");
//Object val = method.invoke(obj);
//System.out.println(val);
Method method = clz.getDeclaredMethod("show", String.class);
Object val = method.invoke(obj, "反射"); //动态代理模式(静态代理模式)
System.out.println(val);
5、IOC原理
IOC:Inverstion Of Control --- 控制反转 (将程序中对象创建的控制权由用户转交给Spring IOC容器) ---- 程序中需要用到哪此对象,直接从容器中取(Spring IOC容器)
容器中的对象:会在项目启动时,完成初使化(完成对象的创建)
**问题来了:**Spring IOC容器如何创建对象 --- 反射
任何一个框架,都有配制文件,框架在运行会读取配制(自动),根据配制文件完成项目必须设制及初使化;
所以IOC容器就是根据配制中要初使化的对象,在项目启动时,完成对象的创建 (程序运行中需要的对象依赖IOC容器注入进来)
6、代理模式
AOP (Aspect Oriented Programming) 的缩写:面向切面编程 ; 实现的是对功能的扩展不需要通过修改源码实现,而是在程序运行中动态注入进来;
AOP思想:将方法的内的核心业务与非核心业务分离(非核心业务切出去),非核心业务在程序运行时可以动态的植入进来 --- 如何将非核心业务(对核心业务的增强)植入进来? ---- 解决方法:代理模式(动态代理实现的)
代理模式:对方法功能的扩展不通过修改源码,而是通过代理对象实现增强(保留原核心业务,再增强新业务功能)
实现代理模式2种方式:静态代理模式 | 动态代理模式
代理模式 要求核心业务的实业类(GovTicketServiceImpl)与代理类 实现同一个接口(TicketService)
**静态代理模式:**需要手动创建一个代理类
动态代理模式 :相对静态代理模式,代理不需要手动创建,会自动生成一个代理类对象 ; 在 JDK中SUN设计了一个类,能够动态的生成代理对象
java.lang.reflect.Proxy类 --- 动态生成代理对象的类
java.lang.reflect.InvocationHandler :接口
public class Proxy{
public static Object newProxyInstance(ClassLoader loader,
Class<?>[] interfaces,
InvocationHandler h)
}
三个参数:
第1个参数为核心业务实现类的类加载器,
第2个参数为核心业务实现类的接口
第3个参数为实现InvocationHandler接口的一个对象(内部用反射实现对方法的调用)
public interface TicketService {
public String saleTicket();
}
public class GovTicketServiceImpl implements TicketService {
@Override
public String saleTicket() {
System.out.println("您成功在12306网站购买一张车票");
return "一张车票";
}
}
public static void main(String[] args){
TicketService proxyService
= (TicketService)Proxy.newProxyInstance(
GovTicketServiceImpl.class.getClassLoader(),
GovTicketServiceImpl.class.getInterfaces(), new InvocationHandler() { //匿名内部类
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("携程提供一张100元优惠卷..........");
//通过反射调用方法
Object val = method.invoke(ticketService, args); //售票的方法;
System.out.println("携程提供售后服务.........");
return val;
}
});
String val = proxyService.saleTicket();
}