学习Java之day28

1. 反射概述

Reflection(反射)是被视为动态语言的关键,反射机制允许程序在执行期借助于Reflection API取得任何类的内部信息,并能直接操作任意对象的内部属性及方法。

加载完类之后,在堆内存的方法区中就产生了一个Class类型的对象(一个类只有一个Class对象),这个对象就包含了完整的类的结构信息。我们可以通过这个对象看到类的结构。这个对象就像一面镜子,透过这个镜子看到类的结构,所以,我们形象的称之为:反射

2.反射的使用


   //反射之前,对Person的操作
   @Test
   public void test1(){
       //1.创建Person类的对象
       Person person = new Person("Tom",25);

       //2.通过对象,调用其内部的属性、方法
       person.age = 35;
       System.out.println(person.getAge());
       System.out.println(person.toString());
       person.show();

       //3.在Person类的外部,不能通过对象调用其内部的私有结构
       //比如:name、showNation()以及私有的构造器

  }

   //反射之后,对Person的操作
   @Test public void test2() throws Exception {
       Class clazz = Person.class;
       //1.通过反射,创建Person的对象
       Constructor cons = clazz.getConstructor(String.class, int.class);
       Object object= cons.newInstance("Tom",12);
       Person person = (Person)object;
       System.out.println(person.toString());

       //2.通过反射,调用对象指定的属性、方法
       Field age =  clazz.getDeclaredField("age");
       //调用属性
       age.set(person,20);
       System.out.println(person);
       //调用方法
       Method show =  clazz.getDeclaredMethod("show");
       show.invoke(person);

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

       //通过反射,可以调用Person类的私有结构,比如私有的构造器、属性、方法
       //调用私有的构造器
       Constructor cons1 = clazz.getDeclaredConstructor(String.class);
       cons1.setAccessible(true);//设置对私有的构造器是可以访问的
       Object object1 = cons1.newInstance("Jreey");
       Person person1 = (Person) object1;
       System.out.println(person1.toString());
       //调用私有的属性
       Field name = clazz.getDeclaredField("name");
       name.setAccessible(true);
       name.set(person1,"bao");
       System.out.println(person1);
       //调用私有的方法
       Method showNation = clazz.getDeclaredMethod("showNation", String.class);
       showNation.setAccessible(true);
       String nation = (String)showNation.invoke(person1,"中国");
       System.out.println(nation);

  }


   /*
   问题1:通过new的方式或反射的方式都可以调用类的公共结构,开发中到底用哪个?
       答:使用new 的方式
        什么时候使用:反射的方式 反射的特征:动态性

   问题2:反射机制和面向对象中的封装性是否矛盾的?如何看待这两种技术?
       答:不矛盾

    */

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

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

    */
   //获取Class的实例的方式(前三种需要掌握)
   @Test public void test3() throws Exception {
       //方式一:调用运行时类的属性: .class
       Class clazz1 = Person.class;
       System.out.println("方式一 " + clazz1);
       //方式二:通过运行时类的对象,调用getClass();
       Person person = new Person();
       Class clazz2 = person.getClass();
       System.out.println("方式二 "+ clazz2);
       //方式三:调用Class的静态方法:Class.forName("全类名");
       Class clazz3 = Class.forName("com.bao.java.Person");
       System.out.println("方式三 " + clazz3);
       System.out.println(clazz1 == clazz2);//true
       System.out.println(clazz1 == clazz3);//true


       //方式四:使用类的加载器
       ClassLoader classLoader = ReflectionTest.class.getClassLoader();
       Class clazz4 = classLoader.loadClass("com.bao.java.Person");
       System.out.println("方式四 "+clazz4);

       System.out.println(clazz1 == clazz4);

  }

   //万事万物皆对象?对象.xxx,File,URL,反射,前端、数据库操作


   //Class实例可以是哪些结构的说明:
   @Test
   public void test4(){
       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();
       // 只要数组的元素类型与维度一样,就是同一个Class
       System.out.println(c10 == c11);

  }

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

 @Test
   public void test1() throws IllegalAccessException, InstantiationException {

       Class<Person> clazz = Person.class;
       /*
       newInstance():调用此方法,创建对应的运行时类的对象。内部调用了运行时类的空参的构造器。

       要想此方法正常的创建运行时类的对象,要求:
       1.运行时类必须提供空参的构造器
       2.空参的构造器的访问权限得够。通常,设置为public。


       在javabean中要求提供一个public的空参构造器。原因:
       1.便于通过反射,创建运行时类的对象
       2.便于子类继承此运行时类时,默认调用super()时,保证父类有此构造器

        */
       Person obj = clazz.newInstance();
       System.out.println(obj);

  }

   //体会反射的动态性
   @Test
   public void test2(){

       for(int i = 0;i < 100;i++){
           int num = new Random().nextInt(3);//0,1,2
           String classPath = "";
           switch(num){
               case 0:
                   classPath = "java.util.Date";
                   break;
               case 1:
                   classPath = "java.lang.Object";
                   break;
               case 2:
                   classPath = "com.bao.java.Person";
                   break;
          }

           try {
               Object obj = getInstance(classPath);
               System.out.println(obj);
          } catch (Exception e) {
               e.printStackTrace();
          }
      }



  }

   /*
   创建一个指定类的对象。
   classPath:指定类的全类名
    */
   public Object getInstance(String classPath) throws Exception {
       Class clazz =  Class.forName(classPath);
       return clazz.newInstance();
  }

4.了解类的加载器

 @Test
   public void test1(){
       //对于自定义类,使用系统类加载器进行加载
       ClassLoader classLoader = ClassLoaderTest.class.getClassLoader();
       System.out.println(classLoader);
       //调用系统类加载器的getParent():获取扩展类加载器
       ClassLoader classLoader1 = classLoader.getParent();
       System.out.println(classLoader1);
       //调用扩展类加载器的getParent():无法获取引导类加载器
       //引导类加载器主要负责加载java的核心类库,无法加载自定义类的。
       ClassLoader classLoader2 = classLoader1.getParent();
       System.out.println(classLoader2);

       ClassLoader classLoader3 = String.class.getClassLoader();
       System.out.println(classLoader3);

  }
   /*
   Properties:用来读取配置文件。

    */
   @Test
   public void test2() throws Exception {

       Properties pros =  new Properties();
       //此时的文件默认在当前的module下。
       //读取配置文件的方式一:
//       FileInputStream fis = new FileInputStream("jdbc.properties");
//       FileInputStream fis = new FileInputStream("src\\jdbc1.properties");
//       pros.load(fis);

       //读取配置文件的方式二:使用ClassLoader
       //配置文件默认识别为:当前module的src下
       ClassLoader classLoader = ClassLoaderTest.class.getClassLoader();
       InputStream is = classLoader.getResourceAsStream("jdbc1.properties");
       pros.load(is);


       String user = pros.getProperty("user");
       String password = pros.getProperty("password");
       System.out.println("user = " + user + ",password = " + password);



  }

5. 获取当前运行时类的属性结构

@Test
   public void test1(){

       Class clazz = Person.class;

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

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

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

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

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

           System.out.println();
      }


  }

6. 获取运行时类的方法结构

@Test
   public void test1(){

       Class clazz = Person.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 m : declaredMethods){
           System.out.println(m);
      }
  }

   /*
   @Xxxx
   权限修饰符 返回值类型 方法名(参数类型1 形参名1,...) throws XxxException{}
    */
   @Test
   public void test2(){
       Class clazz = Person.class;
       Method[] declaredMethods = clazz.getDeclaredMethods();
       for(Method m : declaredMethods){
           //1.获取方法声明的注解
           Annotation[] annos = m.getAnnotations();
           for(Annotation a : annos){
               System.out.println(a);
          }

           //2.权限修饰符
           System.out.print(Modifier.toString(m.getModifiers()) + "\t");

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

           //4.方法名
           System.out.print(m.getName());
           System.out.print("(");
           //5.形参列表
           Class[] parameterTypes = m.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 = m.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();
      }



  }

7. 反射时获取其他的结构

  /*
   获取构造器结构

    */
   @Test
   public void test1(){

       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);
      }

  }

   /*
   获取运行时类的父类

    */
   @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());
  }

   /*
   获取运行时类实现的接口
    */
   @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);
      }

  }
   /*
       获取运行时类所在的包

    */
   @Test
   public void test6(){
       Class clazz = Person.class;

       Package pack = clazz.getPackage();
       System.out.println(pack);
  }

   /*
       获取运行时类声明的注解

    */
   @Test
   public void test7(){
       Class clazz = Person.class;

       Annotation[] annotations = clazz.getAnnotations();
       for(Annotation annos : annotations){
           System.out.println(annos);
      }
  }

 

posted @ 2022-01-24 10:37  天覆者  阅读(136)  评论(0)    收藏  举报