概述

image.png
image.png
image.png
image.png

  1. @Test
  2. public void test1() throws Exception {
  3. //1、通过反射创建Person类的对象
  4. Class<Person> personClass = Person.class;
  5. Constructor<Person> constructor = personClass.getConstructor(String.class, int.class);
  6. Person person = constructor.newInstance("huang", 12);
  7. System.out.println(person);
  8. //2、通过反射调用对象的属性和方法
  9. //调用属性
  10. Field age = personClass.getDeclaredField("age");
  11. age.set(person, 10);
  12. System.out.println(person);
  13. //调用方法
  14. Method show = personClass.getDeclaredMethod("show");
  15. show.invoke(person);
  16. //3、通过反射可以调用Person类的私有结构(如:私有构造器、方法、属性)
  17. //调用私有构造器
  18. Constructor<Person> cons1 = personClass.getDeclaredConstructor(String.class);
  19. cons1.setAccessible(true);
  20. Person person1 = cons1.newInstance("tom");
  21. System.out.println(person1);
  22. //调用私有的属性
  23. Field name = personClass.getDeclaredField("name");
  24. name.setAccessible(true);
  25. name.set(person1, "song");
  26. System.out.println(person1);
  27. //调用私有方法
  28. Method showPrivate = personClass.getDeclaredMethod("showPrivate");
  29. showPrivate.setAccessible(true);
  30. showPrivate.invoke(person1);
  31. }
  1. 通过直接new的方式或反射的方式都可以调用公共的结构,开发中到底用那个?
  • 多数情况建议直接new的方式(编译的时候就确定了要初始化的对象)。
  • 当需要动态创建类的对象时使用反射(不确定要去new哪个对象)。
  1. 反射机制(类的所有属性和方法都可调用)与面向对象中的封装性(不能调用私有属性和方法)是不是矛盾的?
  • 这两者并不矛盾。封装性相当于是建议其他类去调用当前类的公共方法,而私有方法不建议去调用,因为公共的方法可能比私有的方法更好,公共方法里面可能添加了一些逻辑。如果非要调用私有的方法,也可以调用,那我们就通过反射的方式去调用。
  • 封装性:其主要体现是将属性和方法设置为私有的使其在其他类中调用时无法访问该类中内部的私有属性和私有方法,隐藏了内部的细节,保证了代码的安全性。如果我们要想使用其私有属性和私有方法则应该使用该类内部的public方法进行调用。
  • 反射:指的是我们在程序运行期间可以借助于反射的API获取任意对象的属性和方法,并且能够操作任意类的属性和方法。这种动态获取的信息以及动态调用对象的方法的功能称为java语言的反射机制。 反射最大的特点就是动态性。 而反射解决的是能不能调用的问题,它可以调用私有方法,但是通常我们不建议调用。

Class类

image.png
image.png

关于java.lang.CLass类的理解

  1. 类的加载过程:

程序经过javac.exe命令以后,会生成一个或多个字节码文件(.class结尾)。接着我们使用java.exe命令对某个字节码文件进行解释运行,相当于将某个字节码文件加载到内存中,此过程就称为类的加载。加载到内存中的类,我们就称为运行时类,此运行时类就作为Class的一个实例。

  1. 换句话说,Class的实例就对应着一个唯一存在的运行时类(单例)
  2. 加载到内存中的运行时类,会缓存一定的时间。在此时间之内,我们可以通过不同的方式来获取此运行时类。

🌟获取Class类的实例

image.png

@Test
public void test2() throws ClassNotFoundException {
    //方式一:通过调用运行时类的属性class
    Class<Person> personClass = Person.class;
    System.out.println(personClass);

    //方式二:通过运行时类的对象
    Person person = new Person();
    Class<? extends Person> personClass1 = person.getClass();
    System.out.println(personClass1);

    //方式三(常用):调用Class的静态方法:forName(String classPath)
    Class<?> clazz = Class.forName("reflection.Person");
    System.out.println(clazz);

    System.out.println(clazz == personClass1); //true

    //方式四(了解):使用类的加载器:ClassLoader
    ClassLoader classLoader = ReflectionTest.class.getClassLoader();
    Class<?> clazz2 = classLoader.loadClass("reflection.Person");
    System.out.println(clazz2);

    System.out.println(clazz == clazz2); //true
}

哪些类型可以有Class对象?

image.png

@Test
public void test3() {
    Class c1 = Object.class;
    Class c2 = Comparable.class;
    Class c3 = String[].class;
    Class c4 = int[][].class;
    Class c5 = ElementType.class;
    Class c6 = Override.class;
    Class c7 = int.class;
    Class c8 = void.class;
    Class c9 = Class.class;
    int[] a = new int[10];
    int[] b = new int[100];
    Class c10 = a.getClass();
    Class c11 = b.getClass();

    System.out.println(c10 == c11); //true 只要元素类型与维度一样,就是同一个Class
}

(了解)类的加载过程

image.png
image.png

🌟创建运行时类的对象

  • newInstance():调用此方法创建对应的运行时类的对象,内部调用了运行时类的空参构造器,要求:
    1. 运行时类必须提供空参构造器;
    2. 空参构造器的访问权限要够(通常设置为public)。
  • 在Javabean中要求提供一个public的空参构造器的原因:
    1. 便于通过反射创建运行时类的对象;
    2. 便于子类继承此运行时类,默认调用super()时,保证父类有此构造器。
@Test
public void test4() throws InstantiationException, IllegalAccessException {
    Class<Person> personClass = Person.class;

    Person person = personClass.newInstance();
    System.out.println(person);
}

获取运行时类的完整结构

//父类
public class Creature<T> implements Serializable {
    private char gender;
    public double weight;

    private void breath() {
        System.out.println("生物呼吸");
    }

    public void eat() {
        System.out.println("生物吃东西");
    }
}

//接口
public interface MyInterface {
    void info();
}

//注解
@Target({TYPE, FIELD, METHOD, PARAMETER, CONSTRUCTOR, LOCAL_VARIABLE})
@Retention(RetentionPolicy.RUNTIME)
public @interface MyAnnotation {
    String value() default "hello";
}

//结构丰富的person类
@MyAnnotation(value = "hi")
public class Person extends Creature<String> implements Comparable<String>, MyInterface {

    private String name;
    int age;
    public int id;

    public Person() {
    }

    @MyAnnotation(value = "abc")
    private Person(String name) {
        this.name = name;
    }

    Person(String name, int age) {
        this.name = name;
        this.age = age;
    }

    @MyAnnotation()
    private String show(String nation) {
        System.out.println("我的国籍是" + nation);
        return nation;
    }

    public String display(String interests) {
        return interests;
    }

    @Override
    public int compareTo(String o) {
        return 0;
    }

    @Override
    public void info() {
        System.out.println("我是人");
    }
}
  1. 获取属性结构

    @Test
    public void test1() {
     Class<Person> personClass = Person.class;
    
     //getFields():获取当前运行时类及其父类中声明为public访问权限的属性
     Field[] fields = personClass.getFields();
     for (Field field : fields) {
         System.out.println(field);
     }
    
     System.out.println("**************");
    
     //getDeclaredFields():获取当前运行时类中声明的所有属性(不包含父类中的)。
     Field[] declaredFields = personClass.getDeclaredFields();
     for (Field field : declaredFields) {
         System.out.println(field);
    
         //1、权限修饰符
         int modifiers = field.getModifiers();
         System.out.println(Modifier.toString(modifiers));
    
         //2、数据类型
         Class type = field.getType();
         System.out.println(type.getName());
    
         //3、变量名
         System.out.println(field.getName());
     }
    }
    


  2. 获取方法结构 ```java @Test public void test2() { Class personClass = Person.class;

    //getMethods():获取当前运行时类及其父类中声明为public访问权限的方法 Method[] methods = personClass.getMethods(); for (Method method : methods) {

     System.out.println(method);
    

    }

    System.out.println(“*“);

    //getDeclaredMethods():获取当前运行时类中声明的所有方法(不包含父类中的)。 Method[] declaredMethods = personClass.getDeclaredMethods(); for (Method method : declaredMethods) {

     System.out.println(method);
     //1.获取方法声明的注解
     Annotation[] annos = method.getAnnotations();
     for (Annotation a : annos) {
         System.out.println(a);
     }
    
     //2.权限修饰符
     System.out.print(Modifier.toString(method.getModifiers()) + "\t");
    
     //3.返回值类型
     System.out.print(method.getReturnType().getName() + "\t");
    
     //4.方法名
     System.out.print(method.getName());
     System.out.print("(");
     //5.形参列表
     Class[] parameterTypes = method.getParameterTypes();
     if (!(parameterTypes == null && parameterTypes.length == 0)) {
         for (int i = 0; i < parameterTypes.length; i++) {
    
             if (i == parameterTypes.length - 1) {
                 System.out.print(parameterTypes[i].getName() + " args_" + i);
                 break;
             }
    
             System.out.print(parameterTypes[i].getName() + " args_" + i + ",");
         }
     }
    
     System.out.print(")");
    
     //6.抛出的异常
     Class[] exceptionTypes = method.getExceptionTypes();
     if (exceptionTypes.length > 0) {
         System.out.print("throws ");
         for (int i = 0; i < exceptionTypes.length; i++) {
             if (i == exceptionTypes.length - 1) {
                 System.out.print(exceptionTypes[i].getName());
                 break;
             }
    
             System.out.print(exceptionTypes[i].getName() + ",");
         }
     }
    
    System.out.println();
}

}

<br />

3. **获取构造器结构**
```java
@Test
public void test3() {
    Class clazz = Person.class;
    //getConstructors():获取当前运行时类中声明为public的构造器
    Constructor[] constructors = clazz.getConstructors();
    for (Constructor c : constructors) {
        System.out.println(c);
    }

    System.out.println();
    //getDeclaredConstructors():获取当前运行时类中声明的所有的构造器
    Constructor[] declaredConstructors = clazz.getDeclaredConstructors();
    for (Constructor c : declaredConstructors) {
        System.out.println(c);
    }
}
  1. 获取父类结构 ```java / 获取运行时类的父类 / @Test public void test2(){ Class clazz = Person.class;

    Class superclass = clazz.getSuperclass(); System.out.println(superclass); }

/ 获取运行时类的带泛型的父类 / @Test public void test3(){ Class clazz = Person.class;

Type genericSuperclass = clazz.getGenericSuperclass();
System.out.println(genericSuperclass);

}

/* 获取运行时类的带泛型的父类的泛型

代码:逻辑性代码  vs 功能性代码
 */

@Test public void test4(){ Class clazz = Person.class;

Type genericSuperclass = clazz.getGenericSuperclass();
ParameterizedType paramType = (ParameterizedType) genericSuperclass;
//获取泛型类型
Type[] actualTypeArguments = paramType.getActualTypeArguments();
//        System.out.println(actualTypeArguments[0].getTypeName());
System.out.println(((Class)actualTypeArguments[0]).getName());

}


5. **获取接口结构**
```java
/*
    获取运行时类实现的接口
     */
@Test
public void test5() {
    Class clazz = Person.class;

    Class[] interfaces = clazz.getInterfaces();
    for (Class c : interfaces) {
        System.out.println(c);
    }

    System.out.println();
    //获取运行时类的父类实现的接口
    Class[] interfaces1 = clazz.getSuperclass().getInterfaces();
    for (Class c : interfaces1) {
        System.out.println(c);
    }

}
  1. 获取所在的包

    /*
         获取运行时类所在的包
    
      */
    @Test
    public void test6() {
     Class clazz = Person.class;
    
     Package pack = clazz.getPackage();
     System.out.println(pack);
    }
    
  2. 获取注解结构

    /*
         获取运行时类声明的注解
    
      */
    @Test
    public void test7() {
     Class clazz = Person.class;
    
     Annotation[] annotations = clazz.getAnnotations();
     for (Annotation annos : annotations) {
         System.out.println(annos);
     }
    }
    

    🌟调用运行时类的指定结构

  3. 调用运行时类的指定属性

    @Test
    public void testField1() throws Exception {
     Class clazz = Person.class;
    
     //创建运行时类的对象
     Person p = (Person) clazz.newInstance();
    
     //1. getDeclaredField(String fieldName):获取运行时类中指定变量名的属性
     Field name = clazz.getDeclaredField("name");
    
     //2.保证当前属性是可访问的
     name.setAccessible(true);
     //3.获取、设置指定对象的此属性值
     name.set(p,"Tom");
    
     System.out.println(name.get(p));
    }
    
  4. 调用运行时类的指定方法 ```java @Test public void testMethod() throws Exception {

    Class clazz = Person.class;

    //创建运行时类的对象 Person p = (Person) clazz.newInstance();

    /*

     1.获取指定的某个方法
     getDeclaredMethod():参数1 :指明获取的方法的名称  参数2:指明获取的方法的形参列表
      */
    

    Method show = clazz.getDeclaredMethod(“show”, String.class); //2.保证当前方法是可访问的 show.setAccessible(true);

    /*

     3. 调用方法的invoke():参数1:方法的调用者  参数2:给方法形参赋值的实参
     invoke()的返回值即为对应类中调用的方法的返回值。
      */
    

    Object returnValue = show.invoke(p,”CHN”); //String nation = p.show(“CHN”); System.out.println(returnValue);

    System.out.println(“*如何调用静态方法*“);

    // private static void showDesc()

    Method showDesc = clazz.getDeclaredMethod(“showDesc”); showDesc.setAccessible(true); //如果调用的运行时类中的方法没有返回值,则此invoke()返回null // Object returnVal = showDesc.invoke(null); Object returnVal = showDesc.invoke(Person.class); System.out.println(returnVal);//null

}


3. 调用运行时类的指定构造器
```java
@Test
public void testConstructor() throws Exception {
    Class clazz = Person.class;

    //private Person(String name)
    /*
        1.获取指定的构造器
        getDeclaredConstructor():参数:指明构造器的参数列表
         */

    Constructor constructor = clazz.getDeclaredConstructor(String.class);

    //2.保证此构造器是可访问的
    constructor.setAccessible(true);

    //3.调用此构造器创建运行时类的对象
    Person per = (Person) constructor.newInstance("Tom");
    System.out.println(per);

}

动态代理

image.png

静态代理:代理类和被代理类在编译期间就确定下来了。

interface ClothFactory {
    void produceCloth();
}

//代理类
class ProxyClothFactory implements ClothFactory {
    private ClothFactory factory; //用被代理类对象进行实例化

    public ProxyClothFactory(ClothFactory factory) {
        this.factory = factory;
    }

    @Override
    public void produceCloth() {
        System.out.println("代理工厂做一些准备工作");
        factory.produceCloth();
        System.out.println("代理工厂做一些收尾工作");
    }
}

//被代理类
class NikeClothFactory implements ClothFactory {


    @Override
    public void produceCloth() {
        System.out.println("Nike工厂生产衣服");
    }
}

public class StaticProxyTest {
    public static void main(String[] args) {
        //创建被代理类的对象
        NikeClothFactory nikeClothFactory = new NikeClothFactory();

        //创建代理类的对象
        ProxyClothFactory proxyClothFactory = new ProxyClothFactory(nikeClothFactory);

        proxyClothFactory.produceCloth();
    }
}

动态代理

interface Human {
    String getBelief();

    void eat(String food);
}

//被代理类
class SuperMan implements Human {

    @Override
    public String getBelief() {
        return "I believe I can fly!";
    }

    @Override
    public void eat(String food) {
        System.out.println("我喜欢吃" + food);
    }
}

/*
实现动态代理的问题:
    1、如何根据加载到内存中的被代理类,动态创建一个代理类及其对象;
    2、当通过代理类的对象调用方法时,如何动态的去调用被代理类中的同名方法。
 */
class ProxyFactory {
    //问题1:调用此方法返回一个代理类的对象
    public static Object getProxyInstance(Object obj) {  //obj:被代理类的对象
        MyInvocationHandler myInvocationHandler = new MyInvocationHandler();

        myInvocationHandler.bind(obj);

        return Proxy.newProxyInstance(obj.getClass().getClassLoader(), obj.getClass().getInterfaces(), myInvocationHandler);
    }
}

class MyInvocationHandler implements InvocationHandler {
    private Object object;//需要使用被代理类的对象进行赋值

    public void bind(Object obj) {
        this.object = obj;
    }

    //当我们通过代理类的对象调用方法a时,就会自动的调用如下的方法 invoke()
    //问题2:将被代理类要执行的方法a的功能就声明在invoke()中
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {

        //method():即为代理类对象调用的方法,此方法也就作为了被代理类对象要调用的方法
        //obj:被代理类的对象
        Object invoke = method.invoke(object, args);

        //上述方法的返回值就作为当前类中的invoke()的返回值
        return invoke;
    }
}

public class ProxyTest {
    public static void main(String[] args) {
        SuperMan superMan = new SuperMan();

        //proxyInstance:代理类的对象
        Human proxyInstance = (Human) ProxyFactory.getProxyInstance(superMan);

        //当通过代理类对象调用方法时,会自动的调用被代理类中同名的方法
        String belief = proxyInstance.getBelief();
        System.out.println(belief);
        proxyInstance.eat("火锅");

        System.out.println("*****************************");

        NikeClothFactory nikeClothFactory = new NikeClothFactory();
        ClothFactory proxyClothFactory = (ClothFactory) ProxyFactory.getProxyInstance(nikeClothFactory);
        proxyClothFactory.produceCloth();
    }
}

AOP:Aspect Orient Programming

image.png
image.png
image.png