目录
反射:
一种 加载类 并且操作类的成分(构造方法,成员变量,成员方法)的方式
可以操作一个不存在的类 是框架的灵魂
类执行的流程:
1.编写java源文件
2.编译源文件,产生.class字节码文件
3.使用类加载器 把类加载到内存当中 在内存中会有哟个Class对象用于记录当前类的所有成分
1.Class对象的获取:
三种方法:1.Class.forName(全类名) 全类名为 包名.类名
2.对象.getClass()
3.类名.class
public static void main(String[] args) throws ClassNotFoundException {
//1. Class.forName(String className): className: 包名.类名 | 全类名
Class clazz = Class.forName("com.itheima.reflect.Student");
System.out.println(clazz);
//2. 对象.getClass(): 获取对象所属的类对象
Student s1 = new Student();
Class clazz2 = s1.getClass();//getClass来自于Object
System.out.println(clazz2);
//3. 类名.class: 获取某个类的类对象
Class clazz3 = Student.class;
System.out.println(clazz3);
//3次获取到的Class对象是同一个, 一个类在一次程序运行过程中只加载一次!!,所以在方法区中只有对应的一个Class类对象
System.out.println(clazz == clazz2);
System.out.println(clazz2 == clazz3);
}
2.反射获取类中构造器:
public static void main(String[] args) throws Exception {
//1.获取字节码文件对象
Class clazz = Class.forName("com.itheima.reflect.Student");
//2.获取构造器对象 Constructor
//获取所有被public修饰的构造方法
Constructor[] cs = clazz.getConstructors();
System.out.println(Arrays.toString(cs));
//获取所有权限修饰的构造方法,无视权限修饰符
Constructor[] cs2 = clazz.getDeclaredConstructors();
System.out.println(Arrays.toString(cs2));
//获取指定参数的构造方法, 被public修饰的
Constructor c1 = clazz.getConstructor();
System.out.println(c1);
Constructor c2 = clazz.getConstructor(String.class, int.class);
System.out.println(c2);
//获取指定参数的构造方法, 无视权限修饰符
Constructor c3 = clazz.getDeclaredConstructor(String.class);
System.out.println(c3);
//Constructor: newInstance(Object... args)
Object obj = c2.newInstance("柳岩", 23);
System.out.println(obj);
Object obj2 = c1.newInstance();
System.out.println(obj2);
//设置私有可访问, 暴力反射
//如过构造器为私有不让创建对象 可用暴力反射创建 (暴力反射, 忽略权限修饰符)
c3.setAccessible(true);
Object obj3 = c3.newInstance("龚玥菲");
System.out.println(obj3);
}
3.反射获取成员变量:
public static void main(String[] args) throws Exception {
//1.加载类,获取Class对象
Class clazz = Class.forName("com.itheima.reflect.Student");
//目标对象
Object target = clazz.getConstructor().newInstance();
//2.获取成员变量对象Filed
//获取被public修饰的成员变量
Field[] fs1 = clazz.getFields();
System.out.println(Arrays.toString(fs1));
//获取所有的成员变量,无视权限修饰符
Field[] fs2 = clazz.getDeclaredFields();
System.out.println(Arrays.toString(fs2));
//根据名字获取指定的Filed对象,只能获取public修饰的
Field ageField = clazz.getField("age");
System.out.println(ageField);
//根据名字获取指定的Filed对象,无视权限修饰符
Field nameField = clazz.getDeclaredField("name");
System.out.println(nameField);
//set(Object obj, Object value) obj: 你要给哪个对象的该变量赋值, value: 赋的值
ageField.set(target,23);
//暴力反射
nameField.setAccessible(true);
nameField.set(target,"柳岩");
//Object get(Object obj) obj: 要获取哪个对象的该成员变量的值
System.out.println(ageField.get(target));
System.out.println(nameField.get(target));
}
4.反射获取成员方法:
Method方法对象为静态方法时 invoke第一个参数传null
public static void main(String[] args)throws Exception {
//1.加载类,获取Class对象
Class clazz = Class.forName("com.itheima.reflect.Student");
//目标对象
Object target = clazz.getConstructor().newInstance();
//2.获取方法对象, 获取当前类以及父类中的方法 获取被public修饰的
Method[] ms1 = clazz.getMethods();
System.out.println(Arrays.toString(ms1));
//根据方法名和参数列表获取方法
//getMethod(String name, Class<?>... parameterTypes) name:方法名, parameterTypes: 参数列表的类型
Method methodMethod = clazz.getMethod("method", String.class);
System.out.println(methodMethod);
//执行方法
//invoke(Object obj, Object... args) obj: 要执行那个对象的该方法, args: 调用方法时传递的参数
methodMethod.invoke(target,"我爱柳岩一万年????");
}
注解:
概念:是堆程序的一种特殊标识,给程序看的,程序可以通过这些标识,选择不同的执逻辑
注解本质是一个接口 枚举本质是一个类调用其静态常量
注解的定义:
元注解:
有两种元注解:
parameter方法参数
注解的使用(重点):
格式: @注解名(属性名=值,属性名=值)
注意:
1.如果给数组赋值 ,数组里只有一个元素 {}可以省略
2.如果只给变量名为value的属性赋值 那么valve=可以胜略
3.本质实现了一个接口的实现类对象
注解的解析:
核心思想:在哪个位置上使用的注解,需要找到该位置对应的反射现象(Class,Constructor,Field,Method)解析
注解的定义:
@Target(ElementType.METHOD)//只能在方法上使用RequestMapping注解
@Retention(RetentionPolicy.RUNTIME)//标识该注解会保存在运行时阶段
public @interface RequestMapping {
String value();//执行方法对应的字符串标识
}
注解的使用:
public class UserController {
@RequestMapping("/addUser")//标识将来用户输入了/addUser后,执行addUser方法
public void addUser() {
System.out.println("添加用户...");
}
@RequestMapping("/deleteUser")
public void deleteUser() {
System.out.println("删除用户...");
}
@RequestMapping("/updateUser")
public void updateUser() {
System.out.println("修改用户...");
}
@RequestMapping("/seleteUser")
public void selectUser() {
System.out.println("查询用户...");
}
public void login() {
System.out.println("登录...");
}
@RequestMapping("/show")
public void show() {
System.out.println("show......");
}
}
注解的解析:
public class SpringMvc {
public static void main(String[] args) throws Exception {
//0.创建一个Map集合,用于记录录入的字符串和对应的Method对象的对应关系
Map<String, Method> map = new HashMap<>();
//1.加载UserController类,得到Class字节码文件对象
Class clazz = UserController.class;
//2.获取空参构造器,并创建目标对象
Object target = clazz.getConstructor().newInstance();
//3.借助于Class字节码文件对象,获取到所有的方法 Method[] getMethods(), 可以获取到父类中的方法
Method[] ms = clazz.getMethods();
//4.遍历Method[] 数组,得到每一个Method(某一个方法)
//5.判断Method对应的方法上有没有@RequestMapping注解
Arrays.stream(ms).filter(m -> m.isAnnotationPresent(RequestMapping.class)).forEach(m->{
//6.如果有, 获取@RequestMapping注解中的value属性值
RequestMapping rm = m.getDeclaredAnnotation(RequestMapping.class);
String value = rm.value();// /addUser
//7.把value属性值和method对象存储到Map集合中
map.put(value,m);
});
//8.获取用户录入的字符串
Scanner sc = new Scanner(System.in);
System.out.println("请输入访问路径: ");
String path = sc.next();
//9.根据用户录入的字符串,从Map集合中获取对应的Method对象
Method method = map.get(path);
if (method!=null){
//10.执行Method, invoke
method.invoke(target);
}else{
System.out.println("404,您访问的资源不存在!");
}
}
}
此代码的作用为获取每一个有注解的方法 并且得到注解对象 读取注解对象的内容 把注解对象的内容 与 方法对象存储到map集合中 以注解对象的内容来确定每一个不同的方法
getDeclaredAnnotation 为获取注解的实例化对象因为注解本质上是一个接口 可以访问其中的抽象方法 方法名为value 返回值为String
动态代理:
概念: 创建对象的一种方式
作用:在不修改源码的情况下 增强方法 -------核心思想
//动态代理的方式创建接口的实现类对象, 会在内存中动态的生成一个该接口的实现类
public static Object newProxyInstance( ClassLoader loader, 类加载器(把字节码文件加载进内存!), 固定书写: 本类名.class.getClassLoader() Class[] interfaces, 创建的对象要实现哪些接口,把这些接口的字节码文件对象放到一个数组中传递,固定书写: new Class[]{接口名.class,接口名.class...} InvocationHandler h, 将来创建的对象调用方法时, 现需要使用InvocationHandler来处理,编写方法的行为,固定书写 new InvocationHandler(){重写方法}
InvocationHandler也为一个函数式接口可以用lambda表达式创建匿名内部类
public interface Sale {
//销售
String sale(int money);
//回收
int recycle(String something);
}
s为用动态代理的方法生成的Sale接口实现类对象
每一个对象调用方法时都会经过InvocationHandler接口的实现类对象处理
public class Test02 {
public static void main(String[] args) {
//动态代理的方式创建Sale接口的实现类对象 Proxy
//动态代理的方式创建接口的实现类对象, 会在内存中动态的生成一个该接口的实现类
public static Object newProxyInstance(
ClassLoader loader, 类加载器(把字节码文件加载进内存!), 固定书写: Test02.class.getClassLoader()
Class[] interfaces, 创建的对象要实现哪些接口,把这些接口的字节码文件对象放到一个数组中传递,固定书写: new Class[]{接口名.class,接口名.class...}
InvocationHandler h, 将来创建的对象调用方法时, 现需要使用InvocationHandler来处理,编写方法的行为,固定书写 new InvocationHandler(){重写方法}
)
Sale s = (Sale) Proxy.newProxyInstance(Test02.class.getClassLoader(), new Class[]{Sale.class}, new InvocationHandler() {
//invoke方法的作用, 将来使用创建好的实现类对象调用方法, 这个invoke会自动执行, 并且每调用一个方法, invoke会执行一次
/*
Object proxy: 不用关注!!!!
Method method: 用户正在调用的方法
Object[] args: 用户调用方法时传递的参数
*/
//返回值类型就是方法执行的结果
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
//System.out.println(method);
//System.out.println(Arrays.toString(args));
//用户现在调用的是哪个方法??
String methodName = method.getName();
if ("sale".equals(methodName)){
//sale方法的逻辑
System.out.println("收到"+args[0]+"元, 卖出晨光钢笔一支~");
return "晨光钢笔";
}
if ("recycle".equals(methodName)){
//recycle方法的逻辑
System.out.println("使用100块回收了: "+args[0]);
return 100;
}
return null;
}
});
//使用对象调用方法
String result = s.sale(999);
System.out.println(result);
int money = s.recycle("口罩");
System.out.println(money);
}
}
//ctrl+p: 查看方法参数
此为利用 动态代理 来增强 原接口实现类中方法 的效果
public static Computer makeComputer() {
//被代理对象
Computer c = new ThinkPad();
//使用动态代理造一台电脑,创建Computer接口的实现类对象
//代理对象
Computer proxy = (Computer) Proxy.newProxyInstance(
ComputerFactory.class.getClassLoader(),
new Class[]{Computer.class},
new InvocationHandler() {
//每次调用方法后,invoke会自动执行
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
//方法的实现方案
long start = System.currentTimeMillis();//开始时间
//执行method
Object result = method.invoke(c, args);
long end = System.currentTimeMillis();//结束时间
System.out.println("本次操作共耗时: " + (end - start));
return result;
}
});
return proxy;
}
public interface Computer {
void searchFile(String var1, String var2);
void copyDir(String var1, String var2);
}
public class ThinkPad implements Computer {
public ThinkPad() {
}
public void searchFile(String dir, String fileName) {
File source = new File(dir);
if (source.exists() && !source.isFile()) {
File[] files = source.listFiles();
File[] var5 = files;
int var6 = files.length;
for(int var7 = 0; var7 < var6; ++var7) {
File file = var5[var7];
if (file.isDirectory()) {
this.searchFile(file.getAbsolutePath(), fileName);
} else if (file.getName().contains(fileName)) {
System.out.println(file.getAbsolutePath());
}
}
}
}
public void copyDir(String sourceDir, String targetDir) {
try {
FileUtils.copyDirectory(new File(sourceDir), new File(targetDir));
} catch (IOException var4) {
IOException e = var4;
e.printStackTrace();
}
}
}
//用户
public static void main(String[] args) {
Computer computer = ComputerFactory.makeComputer();
//ctrl+p: 查看参数
computer.searchFile("C:\\Users\\Administrator\\Desktop\\JavaSE进阶","作业题");
computer.copyDir("C:\\Users\\Administrator\\Desktop\\JavaSE进阶\\day01","C:\\Users\\Administrator\\Desktop\\JavaSE进阶\\day01_02");
}