浅谈Java反射

今天来学习一下Java的反射机制,如有不当请多指教!

概述

反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意一个方法和属性;这种动态获取的信息以及动态调用对象的方法的功能称为Java语言的反射机制。

Java中的反射主要和Class类有关。Class类没有公共构造方法。Class 对象是在加载类时由 Java 虚拟机以及通过调用类加载器中的defineClass方法自动构造的。也就是说不需要我们自己去处理创建,JVM已经帮我们创建好了。

反射的使用

获取Class对象

1、getClass()

getClass()是Object类中的方法,也就是说每个类都有自己的Class对象。

Student s1 = new Student();//这一new 产生一个Student对象,一个Class对象。
Class stuClass1 = s1.getClass();

2、.class

任何数据类型(包括基本数据类型)都有一个“静态”的class属性,比如String.Class

Class stuClass2 = Student.class;

3、Class.forName(String className) —— 推荐

通过Class类的静态方法forName获取Class对象(常用)

Class stuClass3 = Class.forName("czy.Student");//注意此字符串必须是真实路径→包名.类名

注意:在运行期间,一个类,只有一个Class对象产生。

获取构造方法

public class Constructors {
 
    public static void main(String[] args) throws Exception {
        //1.加载Class对象
        Class c = Class.forName("czy.Student");
        
        //2.获取所有公有构造方法
        Constructor[] conArray = c.getConstructors();
    
        //3、获取所有的构造方法(包括:私有、受保护、默认、公有)
        Constructor[] conArray = c.getDeclaredConstructors();
        
        //4、获取公有、无参的构造方法
        Constructor con = c.getConstructor();
        //因为是无参的构造方法所以类型是一个null,不写也可以:这里需要的是一个参数的类型,切记是类型
        //调用构造方法
        Object obj = con.newInstance();
        
        //5、获取私有构造方法,并调用
        con = c.getDeclaredConstructor(char.class);
        //调用构造方法
        con.setAccessible(true);//暴力访问(忽略掉访问修饰符)
        obj = con.newInstance('男');
    }    
}

获取成员变量

public class Fields {
 
        public static void main(String[] args) throws Exception {
            //1、获取Class对象
            Class stuClass = Class.forName("czy.Student");
   
            //2、获取所有公有的字段
            Field[] fieldArray = stuClass.getFields();
            
            //3、获取所有的字段(包括私有、受保护、默认的)
            Field[] fieldArray = stuClass.getDeclaredFields();
            
            //4、获取公有字段"name"并调用
            Field f = stuClass.getField("name");
             //获取一个对象
            Object obj = stuClass.getConstructor().newInstance();//产生Student对象--》Student student = new Student();
             //为字段设置值
            f.set(obj, "刘德华");//为Student对象中的name属性赋值--》student.name = "刘德华"
            
            //5、获取私有字段"phone"并调用
            f = stuClass.getDeclaredField("phone");
            f.setAccessible(true);//暴力反射,解除私有限定
            f.set(obj, "13415038974");
        }
    }

获取成员方法

public class MethodClass {
 
    public static void main(String[] args) throws Exception {
        //1.获取Class对象
        Class stuClass = Class.forName("czy.Student");
  
        //2.获取所有公有方法
        Method[] methodArray = stuClass.getMethods();
    
        //3.获取所有的方法,包括私有的
        Method[] methodArray = stuClass.getDeclaredMethods();
        
        //4.获取公有的show1()方法
        Method m = stuClass.getMethod("show1", String.class);
        //调用show1()方法
        Object obj = stuClass.getConstructor().newInstance();
        m.invoke(obj, "刘德华");
        
        //5.获取私有的show4()方法
        m = stuClass.getDeclaredMethod("show4", int.class);
        m.setAccessible(true);//解除私有限定
        Object result = m.invoke(obj, 20);//需要两个参数,一个是要调用的对象(由反射获取),一个是实参
    }
}

反射的其它用法

通过反射越过泛型检查

例如:有一个String泛型的集合,怎样能向这个集合中添加一个Integer类型的值?

public class Demo {
   public static void main(String[] args) throws Exception{
            ArrayList strList = new ArrayList<>();
            strList.add("aaa");
            strList.add("bbb");
        
            //获取ArrayList的Class对象,反向的调用add()方法,添加数据
        Class intClass = strList.getClass(); //得到 strList 对象的字节码 对象
        //获取add()方法
        Method m = intClass.getMethod("add", Object.class);
        //调用add()方法
        m.invoke(strList, 100);
    }
}

当然这样只能躲过编译器检查,去遍历的话还是会抛出异常的。

你可能感兴趣的:(反射,java)