java反射机制原理和使用

反射的机制原理和使用

反射概况:

反射是什么我们首先不谈,直接先讲一讲反射能干什么。比如一个类,里面有私有方法,私有属性,还有私有的构造函数,这三样东西,哪怕我们已经取到了这个类的一个实例对象,但是还是无法根据这个对象去调用和取值的(类中没有get,set方法)。那么反射就可以做到,只要我们有一个实例,我们就可以调用里面的所有私有方法,和私有属性,当然也包括公有级别的。

实例:

1.根据对象获取类名

创建一个String对象,用getClass()获取类, getName()获取类名,getSuperclass()获取父类

String str = "hello";
Class aClass = str.getClass();//class java.lang.String
System.out.println(aClass.getName());//java.lang.String
System.out.println(aClass.getSuperclass());//class java.lang.Object

2.基本属性的TYPE

/**
 * 基本属性的Type 和class
 */
Class cx1 = int.class;//这种就只有class
Class cx2 = Double.TYPE;//包装器就有TYPE
System.out.println(cx1);//int
System.out.println(cx2);//double

3.Class.forName()方法

其实就是根据类名来初始化,动态加载和创建Class 对象 返回的是一个class对象,那么这个有什么用呢?其实就是后面我们可以根据得到的这个class对象来实例化!实例化用的方法是newInstance(),这个后面也会讲到

总的来说就是根据类名,得到一个class对象,我们再根据这个class对象来实例化

String str3 = "java.lang.String";//必须是类名
Class c2 = null;
try{
	Class c2 = Class.forName(str3);//返回的就是一个class了
 	Object o = c2.newInstance();//实例化
	System.out.println(c2.getName());
    System.out.println(c2.getSuperclass());//获取父类
}catch (Exception e){
    System.out.println(e);
}

4.获取类的构造函数

1)获取所有的构造函数

这里我们定义个实体类,里面有五个不同的构造函数:四个公有,一个私有

public class Test {
    private int age;
    private String name;
    private int testint;

    public Test(int age, String name, int testint){
        this.age = age;
        this.name = name;
        this.testint = testint;
        System.out.println("name: "+name+" age: "+age+" testint: "+testint);
    }

    public Test(int age) {
        this.age = age;
        System.out.println("age: "+age);
    }

    public Test(int age, String name) {
        this.age = age;
        this.name = name;
        System.out.println("name: "+name+" age: "+age);
    }

    private Test(String name) {
        this.name = name;
        System.out.println("name: "+name);
    }

    public Test() {
    }
}

这里我们来获取这个类所有的构造方法:

  • 这里是首先我们实例化一个对象test,然后用getClass()获取它的类名。
  • 定义一个构造器数组来接收该类所有的构造函数。之后进行遍历,
  • getDeclaredConstructors()用来获取类所有的构造函数
  • getModifiers()方法其实返回的是一个整形数字,这个整形数字代表了这个方法是什么级别的(公有,私有等),之后用Modifier.toString()方法来根据这个整形数值来输出public,private等信息。
  • getParameterTypes()方法获取方法的参数列表,返回值是一个class数组,最后进行输出
    我们可以看到结果,的确是将所有的构造方法都获取到了!
  /**
    * 获取类的所有构造方法
    */
    Test test = new Test();
    Class cn1 = test.getClass();
    Constructor[] constructor;//用来接收构造方法的构造器数组
    constructor = cn1.getDeclaredConstructors();//返回类的所有构造方法
    for(int i = 0; i<constructor.length; i++){
    //System.out.println(constructor[i].getModifiers());//这里返回的是一个int
    //Modifier中的toString方法根据传回来的int来判断方法是什么类型     
        System.out.print("构造函数类型:"+
                         Modifier.toString(constructor[i].getModifiers())
                         +" 参数类型:   ");
    	Class[] parameterTypes = constructor[i].getParameterTypes();//获取方法参数列表
        for(int j = 0; j < parameterTypes.length; j++){
             System.out.print(parameterTypes[j].getName());
         }
          System.out.println();
     }
    //输出如下
    构造函数类型:public 参数类型:   
    构造函数类型:private 参数类型:   java.lang.String   
    构造函数类型:public 参数类型:   int   java.lang.String   
    构造函数类型:public 参数类型:   int   
    构造函数类型:public 参数类型:   int   java.lang.String   int 
2)获取指定级别的构造函数(这里只获取public的)

其实getConstructors()方法就是只获取public的构造函数,所以跟上面没什么区别

/**
* 根据指定的构造方法类型来获取(这里获取的是public级别的)
*/
Test test1 = new Test();
Class cn2 = test1.getClass();
Constructor[] constructors1;
constructors1 = cn2.getConstructors();
for(int i = 0; i<constructors1.length; i++){


//Modifier中的toString方法根据传回来的int来判断方法是什么类型
System.out.print("构造函数类型:"+
                  Modifier.toString(constructors1[i].getModifiers())
                 +" 参数类型:   ");
Class[] parameterTypes1 = constructors1[i].getParameterTypes();
for(int j = 0; j < parameterTypes1.length; j++){
       System.out.print(parameterTypes1[j].getName()+"   ");
 }
     System.out.println();
        }
//结果:没有私有的
构造函数类型:public 参数类型:   
构造函数类型:public 参数类型:   int   java.lang.String   
构造函数类型:public 参数类型:   int   
构造函数类型:public 参数类型:   int   java.lang.String   int 
3)获取指定参数列表的构造方法

我们可以通过getDeclaredConstructor()方法传参获取特定参数类型的构造方法,这里注意是getDeclaredConstructor()不是 getDeclaredConstructors() ,所以返回的是一个Class对象而不是一个Class数组。

注意传参即可~!获取无参构造方法直接不传参数

/**
 * 获取指定参数的构造方法
 */
Test test2 = new Test();
Class cn3 = test2.getClass();
try{
    Constructor constructor1 =cn3.getDeclaredConstructor(int.class,String.class);
    System.out.print("构造函数类型:"+
                     Modifier.toString(constructor1.getModifiers())
                     +" 参数类型:   ");
    Class[] parameterTypes = constructor1.getParameterTypes();
    for(int j = 0; j < parameterTypes.length; j++){
        System.out.print(parameterTypes[j].getName()+" ");
    }

}catch (Exception e){
    System.out.println(e);
}
4)调用构造方法

为了方便查看是否调用了,我们将构造方法中进行输出!

//公有构造方法
public Test(int age, String name, int testint){
    this.age = age;
    this.name = name;
    this.testint = testint;
    System.out.println("name: "+name+" age: "+age+" testint: "+testint);
}
//私有构造方法
private Test(String name) {
        this.name = name;
        System.out.println("name: "+name);
    }

调用公有构造方法:

我们可以看到,首先获取相应的构造函数,然后用newInstance()方法实例化,只要参数列表对了,就直接调用了类的公有构造方法。

/**
 * 调用指定的public构造方法
 * newInstance实例化
 */
Test test3 = new Test();
Class cn4 = test3.getClass();
try{
//只要在这修改参数就可以知道是得到的是哪个构造函数
 Constructor cons = cn4.getDeclaredConstructor(int.class,String.class,int.class);
 Object o = cons.newInstance(24, "fanglei",30);//用newInstance方法,得到的是一个对象
 System.out.println(o.toString());
}catch (Exception e){
    System.out.println(e);
}
//输出
name: fanglei age: 24 testint: 30
Test{age=24, name='fanglei', testint=30}

调用私有构造方法:

这里和上面是一样的,只不过要多一项cons.setAccessible(true);

/**
 * 调用私有的构造方法 要设置constructors.setAccessible(true)
 */
Test test4 = new Test();
Class cn5 = test4.getClass();
try{
    Constructor cons = cn5.getDeclaredConstructor(String.class);
    cons.setAccessible(true);
    Object o = cons.newInstance("刘军");
    System.out.println(o.toString());

}catch (Exception e){
    System.out.println(e);
}
//输出
name: 刘军
Test{age=0, name='刘军', testint=0}

5.获取和调用类的私有成员方法

/**
 * 私有的成员函数
 * @return
 */
private void welcome(String msg){
    System.out.println("传入的msg是: "+msg);
}

这里和上面就有不同了,这里用的是getDeclaredMethod()函数,第一个参数是方法名,第二个函数参数列表,这时候我们用的就是Method来接收一个方法。然后通过setAccessible(true)来设置,用invoke()方法调用私有方法,第一个参数是对象(也就是调用哪个实例对象的方法),第二个参数就是私有方法的参数列表。

/**
 * 调用私有的成员函数
 */
Class[] p ={String.class};
Test test5 = new Test();
Class cn6 = test5.getClass();
try{
    //得到私有方法 前面是方法名,后面参数类型
    Method method = cn6.getDeclaredMethod("welcome", String.class);
    method.setAccessible(true);//设置
    Object msg[] = {"hello world"};//参数
    method.invoke(test5,msg);//用invoke调用方法


}catch (Exception e){
    System.out.println(e);
}
//输出
传入的msg是: hello world

6.获取私有字段并修改值

这里要清楚,如果没有set,get方法,我们不可能通过一个类的实例去获取和修改类的私有属性的!

这里我们用getDeclaredField方法来获取属性字段,参数是属性名,然后setAccessible(true)设置,之后用set方法来修改属性名,第一个参数是对象名,第二个是参数

/**
 * 获取类私有字段并修改值
 */
Test test6 = new Test();
Class cn7 = test6.getClass();
try{
    Field field = cn7.getDeclaredField("name");
    field.setAccessible(true);
    field.set(test6,"fanglei");
    System.out.println(test6.toString());
}catch (Exception e){
    System.out.println(e);
}
//输出
Test{age=0, name='fanglei', testint=0}

总结:

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

至于反射里面的其他方法,可以参考这篇文章:

https://www.jianshu.com/p/9be58ee20dee

本篇文章的内容是根据这篇博客打出来的,并不是复制,虽然基本相同,但是都是我手动实现的,为了自己学习的更加深刻:

https://blog.csdn.net/huangliniqng/article/details/88554510

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值