Java基础:反射机制

一、什么是反射:

      反射是Java的特征之一,是一种间接操作目标对象的机制,核心是JVM在运行的时候才动态加载类,并且对于任意一个类,都能够知道这个类的所有属性和方法,调用方法/访问属性,不需要提前在编译期知道运行的对象是谁,他允许运行中的Java程序获取类的信息,并且可以操作类或对象内部属性。程序中对象的类型一般都是在编译期就确定下来的,而当我们的程序在运行时,可能需要动态的加载一些类,这些类因为之前用不到,所以没有加载到jvm,这时,使用Java反射机制可以在运行期动态的创建对象并调用其属性,它是在运行时根据需要才加载。

二:反射的作用

  • 在运行时判断任意一个对象所属的类;

  • 在运行时构造任意一个类的对象;

  • 在运行时判断任意一个类所具有的成员变量和方法;

  • 在运行时调用任意一个对象的方法;

三、反射的优缺点:

1、优点:使用反射,我们就可以在运行时获得类的各种内容,进行反编译,对于Java这种先编译再运行的语言,能够让我们很方便的创建灵活的代码,这些代码可以在运行时装配,无需在组件之间进行源代码的链接,更加容易实现面向对象。

2、缺点:(1)反射会消耗一定的系统资源,因此,如果不需要动态地创建一个对象,那么就不需要用反射;

(2)反射调用方法时可以忽略权限检查,因此可能会破坏封装性而导致安全问题。

四、反射机制常用的类:

Java.lang.Class;

Java.lang.reflect.Constructor;

Java.lang.reflect.Field;

Java.lang.reflect.Method;

Java.lang.reflect.Modifier;

五:反射的实现

我们知道,要使用一个类,就要先把它加载到虚拟机中,生成一个Class对象。这个class对象就保存了这个类的一切信息。
反射机制的实现,就是获取这个Class对象,通过Class对象去访问类、对象的元数据以及运行时的数据。
有三种方法获得类的Class对象:Class.forName(String className)、className.class、实例对象.getClass();

六:反射涉及的API

反射首先获取Class对象;然后获取Method类和Field类;最后通过Method和Field类进行具体的方法调用或属性访问。
1:在运行时获取对象所属类的类名等信息

对象名.getClass().getName();

2:通过反射机制创建class对象(三种方法)

class1 = Class.forName(className);
class2 = 对象名.getClass();
class3 = 对象名.class;

3:在运行时,通过创建class对象,获取自己的父类信息

Class<?> clazz = Class.forName(当前类);
Class<?> parentClass = clazz.getSuperclass();
parentClass.getName();//获得父类名

4:通过反射机制创建一个类的对象

1:反射创建class对象(见上面)
2:Classname 对象=classname.newInstance(参数);

5:获取类的全部方法,存于一个数组中

//创建class对象
Class<?> clazz = Class.forName(ClassName);
// 返回声明的所有方法,包括公共、保护、默认(包)访问和私有方法,但不包括继承的方法。 
Method[] getDeclaredMethods();
//返回可被访问的公共方法      
Method method[] = clazz.getMethods();

6:获取类的全部字段,存于一个数组中

Class<?> clazz = Class.forName(classname);
// 取得本类已声明的所有字段,包括私有的、保护的
Field[] field = clazz.getDeclaredFields();
// 取得本类中可访问的所有公共字段
Field[] filed1 = clazz.getFields();

7:操作类/对象 的某个属性(包括私有)

Class<?> clazz = Class.forName(classname);
//返回一个 Field 对象,该对象反映此 Class 对象所表示的类或接口的指定已声明字段。 包括公共、私有、保护的字段。
Field field = clazz.getDeclaredField(字段名);
//禁用Java权限修饰符的作用,无视方法权限限制进行访问
field.setAccessible(true);
// void set(Object obj, Object value) 将指定对象变量上此 Field 对象表示的字段设置为指定的新值。           
field.set(该类的一个对象, 字段值);

8:调用类/对象 的某个方法(包括私有)

Class<?> clazz = Class.forName(classname);

// Method getMethod(String name, Class<?>... parameterTypes) 
//返回一个 Method 对象,它反映此 Class 对象所表示的类或接口的指定公共成员方法。
//获取一个公有函数
Method method = clazz.getMethod(方法名,参数类型);
//调用具体某个实例对象的这个公有方法
method.invoke(实例对象,参数值);

// Method getDeclaredMethod(String name, Class<?>... parameterTypes) 
//返回一个 Method 对象,该对象反映此 Class 对象所表示的类或接口的指定已声明方法。 包括私有、保护、公有方法

//获取一个私有函数
Method private_method=class.getDeclaredMethod(函数名,参数类型);

//禁用Java权限限定符的作用,使私有函数可访问
private_method.setAccessible(true);

//调用具体实例对象的这个方法
private_method.invoke(实例对象,参数);

例子:

Student类:共六个构造方法

package fanshe;

public class Student {
    //---------------构造方法-------------------
    //(默认的构造方法)
    Student(String str){
        System.out.println("(默认)的构造方法 s = " + str);
    }
    //无参构造方法
    public Student(){
        System.out.println("调用了公有、无参构造方法执行了。。。");
    }
    //有一个参数的构造方法
    public Student(char name){
        System.out.println("姓名:" + name);
    }
    //有多个参数的构造方法
    public Student(String name ,int age){
        System.out.println("姓名:"+name+"年龄:"+ age);//这的执行效率有问题,以后解决。
    }
    //受保护的构造方法
    protected Student(boolean n){
        System.out.println("受保护的构造方法 n = " + n);
    }
    //私有构造方法
    private Student(int age){
        System.out.println("私有的构造方法   年龄:"+ age);
    }
}

测试类

package fanshe;

import java.lang.reflect.Constructor;

/*
 * 通过Class对象可以获取某个类中的:构造方法、成员变量、成员方法;并访问成员;
 *
 * 1.获取构造方法:
 * 		1).批量的方法:
 * 			public Constructor[] getConstructors():所有"公有的"构造方法
            public Constructor[] getDeclaredConstructors():获取所有的构造方法(包括私有、受保护、默认、公有)
 * 		2).获取单个的方法,并调用:
 * 			public Constructor getConstructor(Class... parameterTypes):获取单个的"公有的"构造方法:
 * 			public Constructor getDeclaredConstructor(Class... parameterTypes):获取"某个构造方法"可以是私有的,或受保护、默认、公有;
 * 		3).调用构造方法:
 * 			Constructor-->newInstance(Object... initargs)
 */
public class Constructors {

    public static void main(String[] args) throws Exception {
        //1.加载Class对象
        Class clazz = Class.forName("fanshe.Student");

        //2.获取所有公有构造方法
        System.out.println("**********************所有公有构造方法*********************************");
        Constructor[] conArray = clazz.getConstructors();
        for(Constructor c : conArray){
            System.out.println(c);
        }

        System.out.println("************所有的构造方法(包括:私有、受保护、默认、公有)***************");
        conArray = clazz.getDeclaredConstructors();
        for(Constructor c : conArray){
            System.out.println(c);
        }

        System.out.println("*****************获取公有、无参的构造方法*******************************");
        Constructor con = clazz.getConstructor(null);
        //1>、因为是无参的构造方法所以类型是一个null,不写也可以:这里需要的是一个参数的类型,切记是类型
        //2>、返回的是描述这个无参构造函数的类对象。
        System.out.println("con = " + con);

        //调用构造方法
        Object obj = con.newInstance();
        //	System.out.println("obj = " + obj);
        //	Student stu = (Student)obj;

        System.out.println("******************获取私有构造方法,并调用*******************************");
        con = clazz.getDeclaredConstructor(char.class);
        System.out.println(con);
        //调用构造方法
        con.setAccessible(true);//暴力访问(忽略掉访问修饰符)
        obj = con.newInstance('男');
    }
}

输出

**********************所有公有构造方法*********************************
public fanshe.Student(java.lang.String,int)
public fanshe.Student(char)
public fanshe.Student()
************所有的构造方法(包括:私有、受保护、默认、公有)***************
private fanshe.Student(int)
protected fanshe.Student(boolean)
public fanshe.Student(java.lang.String,int)
public fanshe.Student(char)
public fanshe.Student()
fanshe.Student(java.lang.String)
*****************获取公有、无参的构造方法*******************************
con = public fanshe.Student()
调用了公有、无参构造方法执行了。。。
******************获取私有构造方法,并调用*******************************
public fanshe.Student(char)
姓名:男

Process finished with exit code 0

StudentNew类 获取成员变量并调用

package fanshe;

public class StudentNew {
    public StudentNew(){

    }
    //**********字段*************//
    public String name;
    protected int age;
    char sex;
    private String phoneNum;

    @Override
    public String toString() {
        return "Student [name=" + name + ", age=" + age + ", sex=" + sex
                + ", phoneNum=" + phoneNum + "]";
    }

}

测试类

package fanshe;


import java.lang.reflect.Field;

/*
 * 获取成员变量并调用:
 *
 * 1.批量的
 * 		1).Field[] getFields():获取所有的"公有字段"
 * 		2).Field[] getDeclaredFields():获取所有字段,包括:私有、受保护、默认、公有;
 * 2.获取单个的:
 * 		1).public Field getField(String fieldName):获取某个"公有的"字段;
 * 		2).public Field getDeclaredField(String fieldName):获取某个字段(可以是私有的)
 *
 * 	 设置字段的值:
 * 		Field --> public void set(Object obj,Object value):
 * 					参数说明:
 * 					1.obj:要设置的字段所在的对象;
 * 					2.value:要为字段设置的值;
 */
public class Fields {

    public static void main(String[] args) throws Exception {
        //1.获取Class对象
        Class stuClass = Class.forName("fanshe.StudentNew");
        //2.获取字段
        System.out.println("************获取所有公有的字段********************");
        Field[] fieldArray = stuClass.getFields();
        for(Field f : fieldArray){
            System.out.println(f);
        }
        System.out.println("************获取所有的字段(包括私有、受保护、默认的)********************");
        fieldArray = stuClass.getDeclaredFields();
        for(Field f : fieldArray){
            System.out.println(f);
        }
        System.out.println("*************获取公有字段**并调用***********************************");
        Field f = stuClass.getField("name");
        System.out.println(f);
        //获取一个对象
        Object obj = stuClass.getConstructor().newInstance();//产生Student对象--》Student stu = new Student();
        //为字段设置值
        f.set(obj, "刘德华");//为Student对象中的name属性赋值--》stu.name = "刘德华"
        //验证
        StudentNew stu = (StudentNew)obj;
        System.out.println("验证姓名:" + stu.name);


        System.out.println("**************获取私有字段****并调用********************************");
        f = stuClass.getDeclaredField("phoneNum");
        System.out.println(f);
        f.setAccessible(true);//暴力反射,解除私有限定
        f.set(obj, "18888889999");
        System.out.println("验证电话:" + stu);

    }
}

输出

************获取所有公有的字段********************
public java.lang.String fanshe.StudentNew.name
************获取所有的字段(包括私有、受保护、默认的)********************
public java.lang.String fanshe.StudentNew.name
protected int fanshe.StudentNew.age
char fanshe.StudentNew.sex
private java.lang.String fanshe.StudentNew.phoneNum
*************获取公有字段**并调用***********************************
public java.lang.String fanshe.StudentNew.name
验证姓名:刘德华
**************获取私有字段****并调用********************************
private java.lang.String fanshe.StudentNew.phoneNum
验证电话:Student [name=刘德华, age=0, sex= , phoneNum=18888889999]

StudentTwo 获取成员方法并调用

package fanshe;

public class StudentTwo {
    //**************成员方法***************//
    public void show1(String s){
        System.out.println("调用了:公有的,String参数的show1(): s = " + s);
    }
    protected void show2(){
        System.out.println("调用了:受保护的,无参的show2()");
    }
    void show3(){
        System.out.println("调用了:默认的,无参的show3()");
    }
    private String show4(int age){
        System.out.println("调用了,私有的,并且有返回值的,int参数的show4(): age = " + age);
        return "abcd";
    }
}

测试类

package fanshe;

import java.lang.reflect.Method;

/*
 * 获取成员方法并调用:
 *
 * 1.批量的:
 * 		public Method[] getMethods():获取所有"公有方法";(包含了父类的方法也包含Object类)
 * 		public Method[] getDeclaredMethods():获取所有的成员方法,包括私有的(不包括继承的)
 * 2.获取单个的:
 * 		public Method getMethod(String name,Class<?>... parameterTypes):
 * 					参数:
 * 						name : 方法名;
 * 						Class ... : 形参的Class类型对象
 * 		public Method getDeclaredMethod(String name,Class<?>... parameterTypes)
 *
 * 	 调用方法:
 * 		Method --> public Object invoke(Object obj,Object... args):
 * 					参数说明:
 * 					obj : 要调用方法的对象;
 * 					args:调用方式时所传递的实参;
):
 */
public class MethodClass {

    public static void main(String[] args) throws Exception {
        //1.获取Class对象
        Class stuClass = Class.forName("fanshe.StudentTwo");
        //2.获取所有公有方法
        System.out.println("***************获取所有的”公有“方法*******************");
        stuClass.getMethods();
        Method[] methodArray = stuClass.getMethods();
        for(Method m : methodArray){
            System.out.println(m);
        }
        System.out.println("***************获取所有的方法,包括私有的*******************");
        methodArray = stuClass.getDeclaredMethods();
        for(Method m : methodArray){
            System.out.println(m);
        }
        System.out.println("***************获取公有的show1()方法*******************");
        Method m = stuClass.getMethod("show1", String.class);
        System.out.println(m);
        //实例化一个Student对象
        Object obj = stuClass.getConstructor().newInstance();
        m.invoke(obj, "刘德华");

        System.out.println("***************获取私有的show4()方法******************");
        m = stuClass.getDeclaredMethod("show4", int.class);
        System.out.println(m);
        m.setAccessible(true);//解除私有限定
        Object result = m.invoke(obj, 20);//需要两个参数,一个是要调用的对象(获取有反射),一个是实参
        System.out.println("返回值:" + result);
    }
}

输出

***************获取所有的”公有“方法*******************
public void fanshe.StudentTwo.show1(java.lang.String)
public final void java.lang.Object.wait() throws java.lang.InterruptedException
public final void java.lang.Object.wait(long,int) throws java.lang.InterruptedException
public final native void java.lang.Object.wait(long) throws java.lang.InterruptedException
public boolean java.lang.Object.equals(java.lang.Object)
public java.lang.String java.lang.Object.toString()
public native int java.lang.Object.hashCode()
public final native java.lang.Class java.lang.Object.getClass()
public final native void java.lang.Object.notify()
public final native void java.lang.Object.notifyAll()
***************获取所有的方法,包括私有的*******************
public void fanshe.StudentTwo.show1(java.lang.String)
void fanshe.StudentTwo.show3()
private java.lang.String fanshe.StudentTwo.show4(int)
protected void fanshe.StudentTwo.show2()
***************获取公有的show1()方法*******************
public void fanshe.StudentTwo.show1(java.lang.String)
调用了:公有的,String参数的show1(): s = 刘德华
***************获取私有的show4()方法******************
private java.lang.String fanshe.StudentTwo.show4(int)
调用了,私有的,并且有返回值的,int参数的show4(): age = 20
返回值:abcd

Process finished with exit code 0

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值