zoukankan      html  css  js  c++  java
  • Java学习--反射

    1.反射的定义

    反射:(reflection):在运行时期,动态地去获取类中的信息(类的信息,方法信息,构造器信息,字段等信息进行操作)。

    2.获取类的Class实例的三种方式

    1. 类名.class 

    2. 类的对象.getClass()

    3. Class.forName(“类的全限定名”)      全限定名 = 包名 + 类名

    注意 :同一个类在JVM的字节码实例只有一份。

    public class User {
        @Test
        public void testName() throws Exception {
            //1.使用类名.class 获取类的字节码实例
            Class<User>  clz1 = User.class;
            System.out.println(clz1.toString());
            
            //2.对象.getClass()
            User user = new User();
            Class<?> clz2 =  user.getClass();
            System.out.println(clz2);
            
            //3.Class.forName("全限定名"):用的最多
            Class<?> clz3 = Class.forName("cn.sxt.reflect.User");
            System.out.println(clz3);
        }    
    }

    3.获取九大内置类的字节码实例

    对于对象来说,可以直接使用对象.getClass()或者Class.forName(className); 类名.class都可以获取Class实例.

    但是我们的基本数据类型,就没有类的权限定名,也没有getClass方法.

    问题: 那么如何使用Class类来表示基本数据类型的Class实例?

    八大基本数据类型和 void关键字都是有 字节码实例的

    byte,short,int,long,char,float,double,boolean ,void关键字

    答 : 数据类型/void.class 即可

    每个基本数据类型都是包装类型 如 :int ----Integer包装类型

    注意: 基本数据类型和包装数据类型底层的字节码实例是不相同

    //获取8大基本数据类型和void的字节码实例
    //byte,short,int,long,char,float,double,boolean ,void关键字
    public class BaiscDataTypeClassTest {
        @Test
        public void testName() throws Exception {
            //1.获取byte的字节码实例
            Class<?> byteClz = byte.class;
            System.out.println(byteClz);
            //....
            //获取void关键字的字节码实例
            Class<?> voidClz =void.class;
            System.out.println(voidClz);
            
            
            //所有的基本数据类型都有包装类型
            //int---Integer 
            //int 和Integer 的字节码是绝对不相等的
            Class<?> intClz1 = int.class;
            Class<?> intClz2 = Integer.class;
            System.out.println(intClz1);
            System.out.println(intClz2);
            System.out.println(intClz1 == intClz2);    
        }
    }

    4.获取数组类型的字节码实例

    表示数组的Class实例:

       String[] sArr1 = {"A","C"};

       Class clz = String[].class;//此时clz表示就是一个String类型的一位数组类型

    所有具有相同元素类型和维数的数组才共享同一份字节码(Class对象);

       注意:和数组中的元素没有一点关系.

    package cn.sxt.reflect._01.getclass;
    
    import static org.junit.Assert.*;
    
    import org.junit.Test;
    
    //获取数组类型的字节码实例
    public class ArrayClassTest {
        @Test
        public void testName() throws Exception {
            //定义数组
            int[] arr = {1,2,3};
            Class<int[]> clz1 = (Class<int[]>) arr.getClass();
            System.out.println(clz1);
            Class<int[]>  clz2= int[].class;
            System.out.println(clz2);
            
            
            int[] arr2 = {2,3,4};
            Class<int[]> clz3 = (Class<int[]>) arr2.getClass();
            System.out.println(clz3);
            
            
            System.out.println(clz1 == clz2);//true
            System.out.println(clz1 == clz3);//true
        }
    }

    5.构造函数-Construstor

    5.1获取构造函数

    类的构函数有 有参数构造函数,无参构造函数,公共构造函数,非公共构造函数,根据不同的构造函数 Class提供了几种获取不同构造函数的方法。

    //通过字节码实例获取构造器
    public class ConstructorTest {
        @Test
        public void testName() throws Exception {
            
            //1.获取Student的字节码实例
            Class<?>  stuClz = Student.class;
            
            //2.获取所有的公共构造函数
            Constructor<?>[] cts1 = stuClz.getConstructors();
            for (Constructor<?> ct : cts1) {
                System.out.println(ct);
            }
            System.out.println("----------------------");
            //3.获取所有的构造函数包括私有的
            Constructor<?>[] cts2 = stuClz.getDeclaredConstructors();
            for (Constructor<?> ct : cts2) {
                System.out.println(ct);
            }
            System.out.println("----------------------");
            
            //4.获取指定的构造函数(clz.getConstructor(...))只能获取公共的构造函数
            Constructor<?> ct1 = stuClz.getConstructor();
            System.out.println(ct1);
            
            Constructor<?> ct2 =stuClz.getConstructor(String.class);
            System.out.println(ct2);
            //4.获取指定的构造函数(clz.getDeclaredConstructor(...))获取的构造函数和权限没有关系
            Constructor<?> ct3=stuClz.getDeclaredConstructor(String.class,int.class);
            System.out.println(ct3);
        }
    }

     5.2调用构造函数创建对象

    Constructor<T>类:表示类中构造器的类型,Constructor的实例就是某一个类中的某一个构造器

    常用方法:

    public T newInstance(Object... initargs):如调用带参数的构造器,只能使用该方式.  参数:initargs:表示调用构造器的实际参数

      返回:返回创建的实例,T表示Class所表示类的类型

    如果:一个类中的构造器可以直接访问,同时没有参数.,那么可以直接使用Class类中的newInstance方法创建对象.

     public Object newInstance():相当于new 类名();

    调用私有的构造器:

    //使用构造器创建对象
    public class NewInstanceTest {
        @Test
        public void testName() throws Exception {
            
            //1.获取Student的字节码实例
            Class<?> clz = Class.forName("cn.sxt.reflect.Student");
            
            //1.1如果类有无参数公共构造函数,直接可以使用类的字节码实例就创建对象
            Student stu0 = (Student) clz.newInstance();
            
            
            //2.获取一个参数的构造函数
            Constructor<Student> ct1 = (Constructor<Student>) clz.getConstructor(String.class);
            //2.1.创建对象
            Student stu1 = ct1.newInstance("东方不败");
            
            //3.获取私有构造函数并创建对象
            Constructor<Student> ct2 =  (Constructor<Student>) clz.getDeclaredConstructor(String.class,int.class);
            //3.1设置权限可以创建对象
            ct2.setAccessible(true);
            //3.2创建对象
            Student stu2 = ct2.newInstance("西门吹雪",50);
        }
    }

    6.操作方法-Method

    一个类创建对象以后,一般就要执行对象的方法等等,使用反射操作对象

    首先要获取方法,再去执行.。

    package cn.sxt.reflect._03method;
    
    import java.util.Arrays;
    
    public class Person {
        
        public void hell1() {
            System.out.println("我是无参数无返回值方法");
        }
        
        public String hello2(String name) {
    
            return "你好 :"+name;
        }
        
        private String hello3(String name,int age) {
            return "我是 :"+name+",今年 :"+age;
        }
        
        
        
        public static void  staticMethod(String name) {
            System.out.println("我是静态方法 :"+name);
        }
        
        
        
        public static void method1(int[] intArr) {
            System.out.println(Arrays.toString(intArr));
        }
        
        public static void method2(String[] strArr) {
            System.out.println(Arrays.toString(strArr));
        }
        
    }
    package cn.sxt.reflect._03method;
    
    import static org.junit.Assert.*;
    
    import java.lang.reflect.Method;
    
    import org.junit.Test;
    
    //获取Person类的方法
    public class GetMethodTest {
    
        @Test
        public void testName() throws Exception {
            // 1.获取Person字节码实例
            Class<Person> clz = Person.class;
            // 2.创建对象
            Person p = clz.newInstance();
    
            // 3.获取方法(使用反射),获取所有公共方法,包含父类的公共方法
            Method[] methods1 = clz.getMethods();
            for (Method method : methods1) {
                System.out.println(method);
            }
            System.out.println("------------------------------");
            // 4.获取自己类中的所有方法(包括私有)
            Method[] methods2 = clz.getDeclaredMethods();
            for (Method method : methods2) {
                System.out.println(method);
            }
            System.out.println("------------------------------");
            // 4.获取单个指定名称的方法
            Method method = clz.getMethod("hello2", String.class);
            System.out.println(method);
    
            // 4.1执行方法
            Object res = method.invoke(p, "陆小凤");
            System.out.println(res);
    
            // 5.获取私有的方法
            Method hello3 = clz.getDeclaredMethod("hello3", String.class, int.class);
            System.out.println(hello3);
    
            // 5.1设置忽略访问权限
            hello3.setAccessible(true);
    
            Object res1 = hello3.invoke(p, "叶孤城", 30);
            System.out.println(res1);
    
            // 6.获取静态方法
            Method staticMethod = clz.getMethod("staticMethod", String.class);
    
            // 6.1执行静态方法
            staticMethod.invoke(null, "花满楼");
    
            // 7.获取有整数数组参数的方法
            Method method1 = clz.getMethod("method1", int[].class);
            method1.invoke(null, new Object[] {new int[] { 1, 2, 3, 4 }});
    
            // 8.获取有整数数组参数的方法
            /*
             * 如果反射传递的参数是引用类型,底层有一个拆箱的功能,会将数组的元素拆成一个个参数传递过来
             * 解决方案: 将数组外面在包装一层数组,如果拆箱一次,得到还是一个数组
             */
            Method method2 = clz.getMethod("method2", String[].class);
            method2.invoke(null,new Object[] {new String[] {"AA","BB","CC"}});
        }
    }
    package cn.sxt.reflect._03method;
    
    import java.util.Arrays;
    
    public class Person {
        
        public static void method1(int... intArr) {
            System.out.println(Arrays.toString(intArr));
        }
        
        public static void method2(String...strArr) {
            System.out.println(Arrays.toString(strArr));
        }
    }
    
            // 7.获取有整数数组参数的方法
            Method method1 = clz.getMethod("method1", int[].class);
            method1.invoke(null, new Object[] {new int[] { 1, 2, 3, 4 }});
    
            // 8.获取有整数数组参数的方法
            /*
             * 如果反射传递的参数是引用类型,底层有一个拆箱的功能,会将数组的元素拆成一个个参数传递过来
             * 解决方案: 将数组外面在包装一层数组,如果拆箱一次,得到还是一个数组
             */
            Method method2 = clz.getMethod("method2", String[].class);
            method2.invoke(null,new Object[] {new String[] {"AA","BB","CC"}});

    7.操作字段(成员变量)--Field

    类中的字段有各种数据类型和各种访问权限,针对这些情况,反射操作有对应的方法来获取和处理

    package cn.sxt.reflect._04Field;
    
    import static org.junit.Assert.*;
    
    import java.lang.reflect.Field;
    
    import org.junit.Test;
    
    public class FieldTest {
        
        @Test
        public void testName() throws Exception {
            //1.获取People字节码
            Class<People> clz = People.class;
            
            People p = clz.newInstance();
            
            //2.获取所有公共字段
            Field[] fields1 = clz.getFields();
            for (Field field : fields1) {
                System.out.println(field);
            }
            System.out.println("---------------------");
            //3.获取所有字段,和访问权限无关
            Field[] fields2 = clz.getDeclaredFields();
            for (Field field : fields2) {
                System.out.println(field);
            }
            System.out.println("---------------------");
            //3.获取指定的公共字段
            Field emialField = clz.getField("emial");
            System.out.println(emialField);
            
            //为字段设置值
            emialField.set(p, "zhagnsan@qq.com");
            System.out.println(p);
            //4.获取指定所有的字段,和访问权限无关
            Field nameFiled = clz.getDeclaredField("name");
            System.out.println(nameFiled);
            //设置忽略访问权限
            nameFiled.setAccessible(true);
            nameFiled.set(p, "张三");
            System.out.println(p);
            
            
            //5 获取age字段
            Field ageFile = clz.getDeclaredField("age");
            ageFile.setAccessible(true);
            //设置忽略访问权限
            ageFile.setInt(p, 18);
            System.out.println(p);
            
        }
    }

    8.Class的其他常用API方法

    //Class字节码的其他api
        @Test
        public void testName() throws Exception {
            
            //1.获取UserDaoImpl的字节码实例
            Class<?> clz = Class.forName("cn.sxt.reflect._05otherapi.UserDaoImpl");
            
            //2.获取所有的接口
            Class<?>[] interfaces = clz.getInterfaces();
            for (Class<?> intface : interfaces) {
                System.out.println(intface);
            }
            
            //3.获取全限定名
            System.out.println(clz.getName());
            
            //4.获取简单类名
            System.out.println(clz.getSimpleName());
            //5.获取包
            System.out.println(clz.getPackage().getName());
        }
  • 相关阅读:
    python signal模块
    linux 下修改时间
    CentOS7关闭防火墙和SELinux
    centOS安装配置NFS
    python 调 java(胶水就是胶水)
    uuid
    python 最麻烦的时间有药了
    linux crontab
    Linux awk+uniq+sort 统计文件中某字符串出现次数并排序
    trove taskmanger api
  • 原文地址:https://www.cnblogs.com/WhiperHong/p/10896828.html
Copyright © 2011-2022 走看看