反射概论

功能

屏幕截图 2022-04-17 180237.jpg

实例

  1. public class ReflectionTest {
  2. //反射之前,对于Person的操作
  3. @Test
  4. public void test1(){
  5. //1.创建Person类的对象
  6. Person p1 = new Person("Tom",19);
  7. //2.通过对象,调用其内部的属性、方法
  8. p1.age = 10;
  9. System.out.println(p1.toString());
  10. p1.show();
  11. //在Person类的外部,不可以通过Person类的对象调用其内部私有的结构
  12. //比如:name、showNation()以及私有构造器
  13. }
  14. //反射之后,对于Person的操作
  15. @Test
  16. public void test2() throws Exception {
  17. Class clazz = Person.class;
  18. //1.通过反射,创建Person类的对象
  19. Constructor cons = clazz.getConstructor(String.class, int.class);
  20. Object obj = cons.newInstance("Tom", 19);
  21. Person p = (Person) obj;
  22. System.out.println(p.toString());
  23. //2.通过反射,调用对象指定的属性、方法
  24. Field age = clazz.getDeclaredField("age");
  25. age.set(p,10);
  26. System.out.println(p.toString());
  27. //调用方法
  28. Method show = clazz.getDeclaredMethod("show");
  29. show.invoke(p);
  30. //通过反射,可以调用Person类的私有结构的。比如:私有的构造器、方法、属性
  31. //调用私有构造器
  32. Constructor cons1 = clazz.getDeclaredConstructor(String.class);;
  33. cons1.setAccessible(true);
  34. Person p1 = (Person) cons1.newInstance("Jerry");
  35. System.out.println(p1);
  36. //调用私有属性
  37. Field name = clazz.getDeclaredField("name");
  38. name.setAccessible(true);
  39. name.set(p1,"Lilei");
  40. System.out.println(p1);
  41. //调用私有方法
  42. Method showNation = clazz.getDeclaredMethod("showNation", String.class);
  43. showNation.setAccessible(true);
  44. showNation.invoke(p1, "中国");//相当于p1.showNation("中国")
  45. }
  46. }
  1. public class Person {
  2. private String name;
  3. public int age;
  4. public Person(String name, int age) {
  5. this.name = name;
  6. this.age = age;
  7. }
  8. private Person(String name) {
  9. this.name = name;
  10. }
  11. public Person() {
  12. }
  13. public String getName() {
  14. return name;
  15. }
  16. public void setName(String name) {
  17. this.name = name;
  18. }
  19. public int getAge() {
  20. return age;
  21. }
  22. public void setAge(int age) {
  23. this.age = age;
  24. }
  25. @Override
  26. public String toString() {
  27. return "Person{" +
  28. "name='" + name + '\'' +
  29. ", age=" + age +
  30. '}';
  31. }
  32. public void show(){
  33. System.out.println("你好,我是个人");
  34. }
  35. private String showNation(String nation){
  36. System.out.println("我的国籍是:" + nation);
  37. return nation;
  38. }
  39. }

java.lang.Class类

理解

类的加载过程

程序经过javac.exe命令后,会生成一个或多个字节码文件(.class结尾)。接着我们使用java.exe命令对某个字节码文件进行解析运行。相当于将某个字节码文件加载到内存中。此过程就称为类的加载。加载到内存中的类,我们就称为运行时类,此运行时类,就作为Class的一个实例
也就是说,Class的实例就对应着一个运行时类
屏幕截图 2022-04-18 135653.jpg

获取Class的实例的方式

加载到内存的运行时类,会缓存一定时间。在此时间之内,我们可以通过不同的方式类获取此运行类

  1. //获取Class的实例的方式
  2. @Test
  3. public void test3() throws ClassNotFoundException {
  4. //方式一:调用运行时类的属性:.class
  5. Class clazz1 = Person.class;
  6. System.out.println(clazz1);
  7. //方式二:通过运行时类的对象
  8. Person p1 = new Person();
  9. Class clazz2 = p1.getClass();
  10. System.out.println(clazz2);
  11. //方式三:调用Class的静态方法:forName(String classPath)
  12. Class clazz3 = Class.forName("Java5.Person");
  13. System.out.println(clazz3);
  14. System.out.println(clazz1 == clazz2);//true
  15. System.out.println(clazz1 == clazz3);//true
  16. //方式四:使用类的加载器:ClassLoader
  17. ClassLoader classLoader = ReflectionTest.class.getClassLoader();
  18. Class clazz4 = classLoader.loadClass("Java5.Person");
  19. System.out.println(clazz4);
  20. System.out.println(clazz1 == clazz4);//true
  21. }

Class实例对应的结构

屏幕截图 2022-04-18 135139.jpg
屏幕截图 2022-04-18 135241.jpg

ClassLoader

理解

屏幕截图 2022-04-18 140514.jpg
屏幕截图 2022-04-18 142231.jpg

  1. public void test1(){
  2. //对于自定义类,使用系统类加载器进行加载
  3. ClassLoader classLoader = ClassLoaderTest.class.getClassLoader();
  4. System.out.println(classLoader);
  5. //调用系统类加载器的getParent():获取扩展类加载器
  6. ClassLoader classLoader1 = classLoader.getParent();
  7. System.out.println(classLoader1);
  8. //调用扩展类加载器的getParent():无法获取引导类加载器
  9. //引导类加载器主要负责加载java的核心类库,无法加载自定义类
  10. ClassLoader classLoader2 = classLoader1.getParent();
  11. System.out.println(classLoader2);//null
  12. ClassLoader classLoader3 = String.class.getClassLoader();
  13. System.out.println(classLoader3);//null
  14. }

使用ClassLoader加载配置文件

  1. public void test2() throws Exception {
  2. Properties pros = new Properties();
  3. //此时的文件默认在当前的module下
  4. //读取配置文件的方式一:
  5. /*FileInputStream fis = new FileInputStream("jdbc.properties");
  6. pros.load(fis);*/
  7. //配置文件默认识别为:当前module的src下
  8. //读取配置文件的方式二:使用ClassLoader
  9. ClassLoader classLoader = ClassLoaderTest.class.getClassLoader();
  10. InputStream is = classLoader.getResourceAsStream("jdbc1.properties");
  11. pros.load(is);
  12. String user = pros.getProperty("user");
  13. String password = pros.getProperty("password");
  14. System.out.println("user = " + user + ",password = " + password);
  15. }

创建运行时类的对象

要想此方法正常的创建运行时类,要求:
1.运行时类必须提供空参的构造器
2.空参的构造器的访问权限要够 。通常设置为public
在javabean中要求提供一个public的空参构造器,原因:
1.便于通过反射,创建运行类的对象
2.便于子类继承此运行时类时,默认调用super()时,保证父亲有此构造器

  1. public void test1() throws InstantiationException, IllegalAccessException {
  2. Class clazz = Person.class;
  3. //newInstance():调用此方法,创建对应的运行时类的对象,内部调用了运行时类的空参的构造器
  4. Person obj = (Person) clazz.newInstance();
  5. System.out.println(obj);
  6. }

获取运行时类的完整结构

获取属性及其内部结构

  1. public void test1(){
  2. Class clazz = Person.class;
  3. //获取属性结构
  4. //getFields():获取当前运行时类及其父类中声明为public访问权限的属性
  5. Field[] fields = clazz.getFields();
  6. for(Field f : fields){
  7. System.out.println(f);
  8. }
  9. //getDeclaredFields():获取当前运行时类中声明的所有属性(不包含父类)
  10. Field[] declaredFields = clazz.getDeclaredFields();
  11. for(Field f : declaredFields){
  12. System.out.println(f);
  13. }
  14. }
  15. @Test
  16. public void test2(){
  17. Class clazz = Person.class;
  18. Field[] declaredFields = clazz.getDeclaredFields();
  19. for (Field f : declaredFields){
  20. //1.权限修饰符
  21. int modifier = f.getModifiers();
  22. System.out.println(Modifier.toString(modifier));
  23. //2.数据类型
  24. Class type = f.getType();
  25. System.out.println(type.getName());
  26. //3.变量名
  27. String fName = f.getName();
  28. System.out.println(fName);
  29. }
  30. }

获取方法及其内部结构

  1. public void test1(){
  2. Class clazz = Person.class;
  3. //getMethods():获取当前运行时类及其所有父类中声明为public权限的方法
  4. Method[] methods = clazz.getMethods();
  5. for (Method m : methods){
  6. System.out.println(m);
  7. }
  8. //getDeclaredMethods():获取当前运行时类中声明的所有方法
  9. Method[] declaredMethods = clazz.getDeclaredMethods();
  10. for (Method m : declaredMethods){
  11. System.out.println(m);
  12. }
  13. }
  14. @Test
  15. public void test2(){
  16. Class clazz = Person.class;
  17. Method[] declaredMethods = clazz.getDeclaredMethods();
  18. for (Method m : declaredMethods){
  19. //1.获取方法声明的注解
  20. Annotation[] annos = m.getAnnotations();
  21. for (Annotation a : annos){
  22. System.out.println(a);
  23. }
  24. //2.权限修饰符
  25. System.out.println(Modifier.toString(m.getModifiers()) + "\t");
  26. //3.返回值类型
  27. System.out.println(m.getReturnType().getName() + "\t");
  28. //4.方法名
  29. System.out.println(m.getName() + "\t");
  30. //5.形参列表
  31. Class[] parameterTypes = m.getParameterTypes();
  32. if (! (parameterTypes == null && parameterTypes.length == 0)){
  33. for (int i = 0;i < parameterTypes.length;i++){
  34. if (i == parameterTypes.length - 1){
  35. System.out.println(parameterTypes[i].getName() + "args_" + i);
  36. break;
  37. }
  38. System.out.println(parameterTypes[i].getName() + "args_" + i + ",");
  39. }
  40. }
  41. //6.抛出的异常
  42. Class[] exceptionTypes = m.getExceptionTypes();
  43. if(exceptionTypes.length > 0){
  44. System.out.print("throws");
  45. for (int i = 0;i < exceptionTypes.length;i++){
  46. if (i == exceptionTypes.length - 1){
  47. System.out.println(exceptionTypes[i].getName());
  48. break;
  49. }
  50. System.out.print(exceptionTypes[i].getName() + ",");
  51. }
  52. }
  53. System.out.println();
  54. }
  55. }

获取构造器

  1. //获取构造器
  2. @Test
  3. public void test1(){
  4. Class clazz = Person.class;
  5. //getConstructors():获取当前运行时类中声明为public的构造器
  6. Constructor[] constructors = clazz.getConstructors();
  7. for (Constructor c : constructors){
  8. System.out.println(c);
  9. }
  10. System.out.println();
  11. //getDeclaredConstructors():获取当前运行类中声明的所有的构造器
  12. Constructor[] declaredConstructors = clazz.getDeclaredConstructors();
  13. for (Constructor c : declaredConstructors){
  14. System.out.println(c);
  15. }
  16. }

获取父类及父类的泛型

  1. //获取运行时类的父类
  2. @Test
  3. public void test2(){
  4. Class clazz = Person.class;
  5. Class superclass = clazz.getSuperclass();
  6. System.out.println(superclass);
  7. }
  8. //获取运行时类的带泛型的父类
  9. @Test
  10. public void test3(){
  11. Class clazz = Person.class;
  12. Type genericSuperclass = clazz.getGenericSuperclass();
  13. System.out.println(genericSuperclass);
  14. }
  15. //获取运行时类的带泛型的父类的泛型
  16. @Test
  17. public void test4(){
  18. Class clazz = Person.class;
  19. Type genericSuperclass = clazz.getGenericSuperclass();
  20. ParameterizedType parameterizedType = (ParameterizedType) genericSuperclass;
  21. //获取泛型类型
  22. Type[] actualTypeArguments = parameterizedType.getActualTypeArguments();
  23. System.out.println(actualTypeArguments[0]);
  24. }

获取接口

  1. //运行时类实现的接口
  2. @Test
  3. public void test5(){
  4. Class clazz = Person.class;
  5. Class[] interfaces = clazz.getInterfaces();
  6. for (Class c : interfaces){
  7. System.out.println(c);
  8. }
  9. System.out.println();
  10. //获取运行时类的父类实现的接口
  11. Class[] interface1 = clazz.getSuperclass().getInterfaces();
  12. for (Class c : interface1){
  13. System.out.println(c);
  14. }
  15. }

获取所在的包

  1. //获取运行时类所在的包
  2. @Test
  3. public void test6(){
  4. Class clazz = Person.class;
  5. Package pack = clazz.getPackage();
  6. System.out.println(pack);
  7. }

获取注解

  1. //获取运行时类的注解
  2. @Test
  3. public void test7(){
  4. Class clazz = Person.class;
  5. Annotation[] annotations = clazz.getAnnotations();
  6. for (Annotation annotation : annotations){
  7. System.out.println(annotation);
  8. }
  9. }

调用运行时类的指定结构

调用指定属性

  1. public void test2() throws Exception {
  2. Class clazz = Person.class;
  3. //创建运行时类的对象
  4. Person p = (Person) clazz.newInstance();
  5. //1.getDeclaredField(String fieldName):获取运行时类中指定变量名的属性
  6. Field name = clazz.getDeclaredField("name");
  7. //2.保证当前对象是可访问的
  8. name.setAccessible(true);
  9. //3.获取、设置指定对象的属性值
  10. name.set(p,"Tom");
  11. System.out.println(name.get(p));
  12. }

调用指定方法

  1. public void test3() throws Exception {
  2. Class clazz = Person.class;
  3. Person p = (Person) clazz.newInstance();
  4. //1.获取指定的某个方法
  5. //getDeclaredMethod():参数1:指明获取的方法的名称 参数2:指明获取的方法的形参列表
  6. Method show = clazz.getDeclaredMethod("show", String.class);
  7. //2.保证当前方法可访问
  8. show.setAccessible(true);
  9. //3.调用invoke()
  10. //invoke():参数一:方法的调用者 参数二:给方法赋值的实参
  11. show.invoke(p,"CHN");
  12. //invoke()的返回值即为对应类中调用的方法的返回值
  13. Object returnValue = show.invoke(p, "CHN");
  14. System.out.println(returnValue);
  15. }

调用静态方法

  1. public void test4() throws Exception {
  2. Class clazz = Person.class;
  3. Person p = (Person) clazz.newInstance();
  4. Method showDesc = clazz.getDeclaredMethod("showDesc");
  5. showDesc.setAccessible(true);
  6. //如果调用的运行时类中的方法没有返回值,则此invoke()返回null
  7. Object returnVal = showDesc.invoke(Person.class);
  8. System.out.println(returnVal);//null
  9. }

调用指定构造器

  1. public void test4() throws Exception {
  2. Class clazz = Person.class;
  3. //1.获取指定的构造器
  4. Constructor Constructor = clazz.getDeclaredConstructor(String.class);
  5. //2.保证此构造器是可访问的
  6. Constructor.setAccessible(true);
  7. //3.调用此构造器创建运行时类的对象
  8. Person per = (Person) Constructor.newInstance("Tom");
  9. System.out.println(per);
  10. }

代理模式

静态代理

  1. //静态代理
  2. interface ClothFactory{
  3. void produceCloth();
  4. }
  5. //代理类
  6. class ProxyClothFactory implements ClothFactory{
  7. private ClothFactory factory;
  8. public ProxyClothFactory(ClothFactory factory){
  9. this.factory = factory;
  10. }
  11. @Override
  12. public void produceCloth() {
  13. System.out.println("代理工厂做一些准备工作");
  14. factory.produceCloth();
  15. System.out.println("代理工厂做一些后续的收尾工作");
  16. }
  17. }
  18. //被代理类
  19. class NikeClothFactory implements ClothFactory{
  20. @Override
  21. public void produceCloth() {
  22. System.out.println("Nike工厂生产一些运动服");
  23. }
  24. }
  25. public class StaticProxyTest {
  26. public static void main(String[] args) {
  27. //创建被代理类的对象
  28. NikeClothFactory nike = new NikeClothFactory();
  29. //创建代理类的对象
  30. ClothFactory proxyClothFactory = new ProxyClothFactory(nike);
  31. proxyClothFactory.produceCloth();
  32. }
  33. }

动态代理

解决问题

1.如何根据加载到内存的被代理类,动态的创建一个代理类及其对象
2.当通过代理类的对象调用方法时,如何动态的去调用被代理类中的同名方法

  1. //动态代理的举例
  2. import java.lang.reflect.InvocationHandler;
  3. import java.lang.reflect.Method;
  4. import java.lang.reflect.Proxy;
  5. interface Human{
  6. String getBelief();
  7. void eat(String food);
  8. }
  9. //被代理类
  10. class SuperMan implements Human{
  11. @Override
  12. public String getBelief() {
  13. return "I believe I can fly!";
  14. }
  15. @Override
  16. public void eat(String food) {
  17. System.out.println("我喜欢吃" + food);
  18. }
  19. }
  20. class ProxyFactory{
  21. //调用此方法,返回一个代理类的对象。解决问题一
  22. public static Object getProxyInstance(Object obj){//obj:被代理类的对象
  23. MyInvocationHandler handler = new MyInvocationHandler();
  24. handler.bind(obj);
  25. return Proxy.newProxyInstance(obj.getClass().getClassLoader(), obj.getClass().getInterfaces(),handler);
  26. }
  27. }
  28. class MyInvocationHandler implements InvocationHandler{
  29. private Object obj;//赋值时,需要使用被代理类的对象进行赋值
  30. public void bind(Object obj){
  31. this.obj = obj;
  32. }
  33. //当我们通过代理类的对象,调用方法a时,就会自动的调用如下方法:invoke()
  34. //将被代理类要执行的方法a的功能就声明在invoke()中
  35. @Override
  36. public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
  37. //method:即为代理类对象调用的方法,此对象也就作为了被代理类对象要调用的方法
  38. //obj:被代理类的对象
  39. Object returnValue = method.invoke(obj, args);
  40. //上述方法的返回值就作为当前类中的invoke()的返回值
  41. return returnValue;
  42. }
  43. }
  44. public class ProxyTest {
  45. public static void main(String[] args) {
  46. SuperMan superMan = new SuperMan();
  47. //proxyInstance:代理类的对象
  48. Human proxyInstance = (Human) ProxyFactory.getProxyInstance(superMan);
  49. //当通过代理类对象调用方法时,会自动的调用被代理类中同名的方法
  50. String belief = proxyInstance.getBelief();
  51. System.out.println(belief);
  52. proxyInstance.eat("香辣面");
  53. System.out.println();
  54. //体现动态创建代理类
  55. NikeClothFactory nikeClothFactory = new NikeClothFactory();
  56. ClothFactory proxyClothFactory = (ClothFactory) ProxyFactory.getProxyInstance(nikeClothFactory);
  57. proxyClothFactory.produceCloth();
  58. }
  59. }