Day29

今天专注学习时间大于五个小时,加油OVO,快要把基础看完了,还剩两天的内容了,下周可以往高阶的迈进,明天早上要是起不来的话,明天就放周六假期好了,真的好累。加油OVO

Day29

反射

通过反射创建运行时类的对象

体现了为什么需要用到反射。

package com.sorrymaker.reflection;

import org.junit.Test;

import java.util.Random;

/**
* 通过反射创建对应的运行时类的对象
*/
public class NewInstanceTest {
   @Test
   public  void test1() throws IllegalAccessException, InstantiationException {
       Class<Person> clazz =Person.class;

       //这里获得的是Person类的对象
       /**
        * newInstance():调用此方法,创建对应的运行时类的对象,内部调用了运行时类空参的构造器
        * 要想此方法正常的创建运行时类的对象,要求:
        * 1.运行时类必须提供空参的构造器
        * 2.空参的构造器的访问权限得够,通常设置为public
        *
        * 在javabean中要求提供一个public的空参构造器,
        * 原因:
        * 1.便于通过反射,创建运行时类的对象
        * 2.便于子类继承此运行时类时,默认调用super()时,保证父类有此构造器。
        *
        * 造对象就得用构造器造,
        */
       Person obj =(Person) clazz.newInstance();
       System.out.println(obj);
  }

   /**
    * 下面这个代码,就说明,假如一开始确定好了,代码就不能动态的决定生成的对象。
    * 一开始不确定需要生成哪个类的对象,所以需要反射的动态决定我等等需要生成的对象。
    * 反射的动态性体会出来了,
    */
   @Test
   public void test2(){
       for (int i = 0; i < 100; i++) {
           int num = new Random().nextInt(3);
           String classPath ="";
           switch (num){
               case 0:
                   classPath ="java.util.Date";
                   break;
               case 1:
                   //java.sql.Date没有空参构造器,所以报错了
//                   classPath="java.sql.Date";
                   classPath ="java.lang.Object";
                   break;
               case 2:
                   classPath="com.sorrymaker.reflection.Person";
                   break;
          }
           Object obj = null;
           try {
               obj = getInstance(classPath);
          } catch (Exception e) {
               e.printStackTrace();
          }
           System.out.println(obj);
      }
      }
   /**
    * 创建一个指定类的对象
    * classPath:指定类的全类名
    */
   public Object getInstance(String classPath) throws Exception {
       Class clazz =Class.forName(classPath);
       return  clazz.newInstance();
  }
}

获取运行时类的属性

package com.sorrymaker.reflection;

import org.junit.Test;

import java.lang.reflect.Field;
import java.lang.reflect.Modifier;

/**
* 获取当前运行时类的属性结构
*/
public class FieldTest {
   @Test
   public void test1(){

       Class clazz =Person1.class;

       //获取内部属性
       //.getFields():获取当前运行时类及其所有父类中声明为public访问权限的属性。
       Field[] fields = clazz.getFields();
       for(Field f:fields){
           System.out.println(f);
      }

       //.getDeclaredFields():获取当前运行时类当中声明的所有属性(不包含父类中声明的属性)。
       Field[] declaredFields = clazz.getDeclaredFields();
       for(Field f1:declaredFields){
           System.out.println(f1);
      }
  }

   /**
    * 权限 + 修饰符 + 数据类型 + 变量名
    */
   @Test
   public void test2(){
       Class clazz = Person1.class;
       Field[] declaredFields = clazz.getDeclaredFields();
       for(Field f:declaredFields){
           //1.权限修饰符
           int modifier = f.getModifiers();
           String str = Modifier.toString(modifier);
           System.out.print(str+"\t");

           //2.数据类型
           Class type = f.getType();
           System.out.print(type.getTypeName()+"\t");

           //3.变量名
           String fName = f.getName();
           System.out.println(fName);
      }
  }
}

 

获取运行时类的方法结构

package com.sorrymaker.reflection;

import org.junit.Test;

import java.lang.annotation.Annotation;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;

/**
* 获取运行时类的方法结构
*/
public class MethodTest {
   @Test
   public void test1() {
       Class clazz = Person1.class;

       //.getMethods()获取当前运行时类及其所有父类当中声明为public的方法。
       Method[] methods = clazz.getMethods();
       for (Method m : methods) {
           System.out.println(m);
      }
       System.out.println();

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

   /**
    * @Xxx 权限修饰符   返回值类型   方法名(参数类型1 形参名1,...)thorows XxxException{}
    */
   @Test
   public void test2() {

       //1.获取方法声明的注解
       Class clazz = Person1.class;
       Method[] declaredMethods = clazz.getDeclaredMethods();
       for (Method dm : declaredMethods) {
           //1.获取方法声明的注解
           //注解可以写很多个,所以是个数组
           Annotation[] annotations = dm.getAnnotations();
           for (Annotation a : annotations) {
               System.out.println(a);
          }
           //2.权限修饰符
           System.out.print(Modifier.toString(dm.getModifiers()) + "\t");


           //3.返回值类型
           System.out.print(dm.getReturnType().getName() + "\t");

           //4.方法名
           System.out.print(dm.getName());
           System.out.print("(");
           //5.形参列表
           Class[] parameterTypes = dm.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 = dm.getExceptionTypes();
           if (exceptionTypes.length>0) {
               System.out.print("thorows");
               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();
      }
  }
}

 

获取 构造器结构、父类、带泛型的父类、父类的泛型、接口、父类实现的接口、包、注解

package com.sorrymaker.reflection;

import org.junit.Test;

import java.lang.annotation.Annotation;
import java.lang.reflect.Constructor;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;

/**
* 获取构造器结构
*/
public class OtherTest {
   @Test
   public void test1(){
       Class clazz =Person1.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);
      }
  }

   /**
    * 获取运行时类的父类
    */
   @Test
   public void test2(){
       Class clazz = Person1.class;
       Class superclass = clazz.getSuperclass();
       System.out.println(superclass);
  }
   /**
    * 获取运行时类的带泛型的父类
    */
   @Test
   public void test3(){
       Class clazz = Person1.class;
       Type genericSuperclass = clazz.getGenericSuperclass();
       System.out.println(genericSuperclass);
  }

   /**
    * 获取运行时类父类的泛型。
    */
   @Test
   public void test4(){
       Class clazz = Person1.class;
       Type genericSuperclass = clazz.getGenericSuperclass();
       ParameterizedType parmeType = (ParameterizedType)genericSuperclass;
       //获取泛型类型。
       Type[] actualTypeArguments = parmeType.getActualTypeArguments();
       System.out.println(((Class)actualTypeArguments[0]).getName());
  }

   /**
    * 获取运行时类的实现的接口
    */
   @Test
   public void test5(){
       Class clazz =Person1.class;
       Class[] interfaces = clazz.getInterfaces();
       for(Class i:interfaces){
           System.out.println(i);
      }
       System.out.println();

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

   /**
    * 获取运行时类所在的包
    */
   @Test
   public void test6(){
       Class clazz = Person1.class;
       Package pack = clazz.getPackage();
       System.out.println(pack);
  }
   /**
    * 获取运行时类的注解
    */
   @Test
   public void test7(){
       Class clazz = Person1.class;
       Annotation[] annotations = clazz.getAnnotations();
       for(Annotation a:annotations){
           System.out.println(a);
      }
  }
}

 

如何操作运行时类中的指定的属性、方法、构造器

package com.sorrymaker.reflection;

import org.junit.Test;

import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;

/**
* 调用运行时类指定的结构:属性、方法、构造器。
* 如何操作运行时类中的指定的属性、方法、构造器
*/
public class ReflectionTest {

   @Test
   public void testField1() throws Exception {
       Class clazz = Person1.class;
       //1.创建运行时类的对象
       Person1 p = (Person1) clazz.newInstance();

       Field name = clazz.getDeclaredField("name");

       //必须加这个
       //2.保证当前属性时可访问的。
       name.setAccessible(true);

       //3.获取、设置指定对象的此属性值
       name.set(p,"tom");
       //报错。非法访问IllegalAccessException
       System.out.println(name.get(p));
  }
   /**
    * 如何操作运行时类中的指定的方法。
    */
   @Test
   public void testMethod() throws Exception {
       //非静态方法的调用情况1:

       Class clazz = Person1.class;
       //1.创建运行时类的对象
       Person1 p = (Person1) clazz.newInstance();

       /*
       2.获取指定的某个方法。
       .getDeclaredMethod():参数1:指明获取方法的名称
                            参数2:指明获取方法的形参列表。
        */
       Method show = clazz.getDeclaredMethod("show", String.class);
       //3.保证当前方法时可以访问的。
       show.setAccessible(true);
       /*
       4.调用方法。 invoke()方法 :参数1:方法的调用者。参数2:给方法形参赋值的实参
                   invoke()的返回值即为对应类中调用的方法的返回值。
        */
       //这里的作用 ===>> String nation = p.show("CHN)
       Object returnValue = show.invoke(p, "CHN");

       System.out.println(returnValue);

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

       //private static void showDesc()

       Method showDesc = clazz.getDeclaredMethod("showDesc");
       showDesc.setAccessible(true);
       //如果调用的运行时类中的方法没有返回值,则此invoke()返回null;
       //这里的p和Person1.class、null都可以
       Object returnVal = showDesc.invoke(null);
       //null
       System.out.println(returnVal);
  }

   /**
    * 如何调用运行时类中的指定的构造器
    * 一般都使用.newInstance()。99%的情况都用这个.
    */
   @Test
   public void testConstructir() throws Exception {
       Class clazz =Person1.class;

       //private Person1(String name)

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

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

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

       //3.调用此构造器创建运行时类的对象
       Person1 per =(Person1) declaredConstructor.newInstance("tom");

       System.out.println(per);
  }

   //下面方法不常用。不建议
   @Test
   public void testField() throws Exception {
       Class clazz = Person1.class;
       //创建运行时类的对象
       Person1 p = (Person1) clazz.newInstance();
       //获取指定的属性:要求运行时类中属性声明为public
       //通常不使用这些方法来获取,学了个寂寞
//       Field id = clazz.getField("age");//这里改成age,没办法拿到

       Field id = clazz.getField("id");
       /*
       设置当前属性的值
       set():参数1:指明设置哪个对象的属性
             参数2:将此属性设置为多少
        */
       id.set(p, 1001);

       /*
       获取当前属性的值
       get():参数1:获取哪个对象的当前属性值
        */
       int pId = (int) id.get(p);
       System.out.println(pId);
  }
}

 

 

总结

  1. 写出获取Class实例的三种常见方式

Class clazz1 = String.class;//基本不用这个方法,把类写死了,本来用运行实例,反射需要动态性,而不是写死了。
Class clazz2 = Person.getClass();//用的蛮多的,可以看的出来是那个类造出来的。

//编译的时候,就检查是否放入String类的classPath,运行时才知道创建的是什么对象。
Class clazz3 = Class.forName(Sring classPath);//体现了反射的动态性。经常用
  1. Class类的理解

    Class实例对应着加载到内存中的一个运行时类。

  1. 创建Class对应运行时类的对象的通用方法。代码实现,以及这样子操作,需要对应的运行时类构造器方面满足的要求。

    Object obj = clazz。newInstance();//创建了对应的运行时类的对象

    要求:1.必须要有空参的构造器

    2.权限修饰符的权限要够,通常设置为public

  2. 如何调用方法show()

    User user = (User)clazz.newInstance();
    Method show = clazz.getDeclareMethod("show");
    show.setAccessiable(true);
    show.invoke(user);

     

反射的应用之一:动态代理

运行期间动态创建一个代理类,为一个接口服务。

动态代理可以搞定所有代理的通用功能,所以用到反射。

package com.sorrymaker.reflection;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

/**
* 动态代理的举例
*/
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);
  }
}
//这里不单独写个代理类。写了就成静态代理类了。
/**
* 要想实现动态代理,需要解决的问题
* 问题一-->如何根据加载到内存中的被代理类,动态的创建一个代理类及其对象。
* 问题二-->当通过代理类的对象调用方法时,如何动态的去调用被代理类中的同名方法。
*/

/**
*
*/
class ProxyFactory{
   //调用此方法,返回一个代理类的对象,解决问题一
   public static Object getProxyInstance(Object obj){
       //obj:被代理的对象。
       MyInvocationHandler handler = new MyInvocationHandler();

       handler.bind(obj);

       return Proxy.newProxyInstance(obj.getClass().getClassLoader(), obj.getClass().getInterfaces(),handler);
  }
}
class MyInvocationHandler implements InvocationHandler{
   //需要使用被代理类的对象进行赋值
   private Object obj;

   public void bind(Object obj){
       //这里给obj实例化了
       this.obj = obj;

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

       //method:即为代理类对象调用的方法,此方法也就作为被代理类对象要调用的方法。
       //obj:被代理类的对象
       Object returnValue = method.invoke(obj, args);
       //上述方法的返回值就作为当前类中的invoke()的返回值。
       return returnValue;
  }
}
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 proxyInstance1 =(ClothFactory) ProxyFactory.getProxyInstance(nikeClothFactory);

       proxyInstance1.produceCloth();
  }
}

 

posted @ 2021-04-09 21:36  独眼龙  阅读(54)  评论(0)    收藏  举报