Java基础之——反射

一、反射概述

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

要想解剖一个类,必须先要获取到该类的字节码文件对象。而解剖使用的就是Class类中的方法.所以先要获取到每一个字节码文件对应的Class类型的对象

反射的使用步骤:

          1、获取想要操作的类的Class对象,它是反射的核心,通过Class对象我们可以任意调用类的方法

          2、调用Class类中的方法,即就是反射的使用阶段

          3、通过反射API来操作这些信息

二、获取Class对象的3种方法

1、第一种:调用某个对象的getClass()方法

2、第二种:调用某个类的class属性来获取该类对应的Class对象

3、第三种:使用Class类中的forName()静态方法

代码如下图:

public class Demo01 {

    public static void main(String[] args) {
        //第一种:调用某个对象的getClass()方法
        Person p = new Person();
        Class clazz1 = p.getClass();

        //第二种:调用某个类的class属性来获取该类对应的Class对象
        Class clazz2 = Person.class;

        //第三种:使用Class类中的forName()静态方法
        Class clazz3 = null;
        try {
            clazz3 = Class.forName("Java基础.Java反射.Person");
        } catch (ClassNotFoundException e){
            e.printStackTrace();
        }

    }
}

第一种方法的getClass()方法来源Object

第二种方法是因为任何数据类型(包括基本数据类型)都有一个“静态”的class属性,可以参见JDK对Class类的描述,这里读者感兴趣的话可以在自己的编辑器中打开JDK源码,列如Integer,Long等基本数据类型包装类,它们都有一个static final的class属性。

第三种方法是Class类的静态方法;这三种方法常用的是第三种,第一种对象都有了,反射显得很多于,第二种需要导入类的包,很麻烦容易出错。

三、获取类中的信息(构造方法、成员变量、成员函数)

  1. 通过反射获取构造方法并使用:

Person1类:

package Java基础.Java反射;

public class Person1 {
    //---------------构造方法---------------
    //默认构造方法
    Person1(String str) {
        System.out.println("默认的构造方法:" + str);
    }

    //无参构造方法
    public Person1() {
        System.out.println("无参构造方法");
    }

    //有一个参数的构造方法
    public Person1(int age) {
        System.out.println("有一个参数的构造方法");
    }

    //有多个参数的构造方法
    public Person1(String name, int age) {
        System.out.println("姓名:" + name+ "年龄:" + age);
    }

    //受保护的构造方法
    protected Person1(char c){
        System.out.println("受保护的构造方法,参数为char型" );
    }

    //私有的构造方法
    private Person1(Long L){
        System.out.println("私有的构造方法,参数为Long型");
    }
}

测试类:

package Java基础.Java反射;

import java.lang.reflect.Constructor;

public class Demo03 {

    public static void main(String[] args) throws Exception{
        //加载Class对象
        Class clazz = Class.forName("Java基础.Java反射.Person1");

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

        System.out.println("----------获取指定的公共构造方法-----------");
        Constructor con = clazz.getConstructor();
        System.out.println("无参的con = " + con);
        Object obj = con.newInstance();

        con = clazz.getConstructor(int.class);
        System.out.println("有一个参数的con = " + con);
        obj = con.newInstance(1);  //调用构造方法

        System.out.println("----------获取所有的构造方法-----------");
        array = clazz.getDeclaredConstructors();
        for(Constructor c : array){
            System.out.println(c);
        }

        System.out.println("----------获取私有构造方法-----------");
        con = clazz.getDeclaredConstructor(Long.class);
        System.out.println(con);
        con.setAccessible(true); //暴力访问(忽略掉访问修饰符)
        obj = con.newInstance(1l); //调用构造方法

        con = clazz.getDeclaredConstructor(char.class);
        System.out.println(con);
        con.setAccessible(true); //暴力访问(忽略掉访问修饰符)
        obj = con.newInstance('b'); //调用构造方法
    }
}

运行结果:

----------获取所有公共构造方法-----------
public Java基础.Java反射.Person1(java.lang.String,int)
public Java基础.Java反射.Person1(int)
public Java基础.Java反射.Person1()
----------获取指定的公共构造方法-----------
无参的con = public Java基础.Java反射.Person1()
无参构造方法
有一个参数的con = public Java基础.Java反射.Person1(int)
有一个参数的构造方法
----------获取所有的构造方法-----------
private Java基础.Java反射.Person1(java.lang.Long)
protected Java基础.Java反射.Person1(char)
public Java基础.Java反射.Person1(java.lang.String,int)
public Java基础.Java反射.Person1(int)
public Java基础.Java反射.Person1()
Java基础.Java反射.Person1(java.lang.String)
----------获取私有构造方法-----------
private Java基础.Java反射.Person1(java.lang.Long)
私有的构造方法,参数为Long型
protected Java基础.Java反射.Person1(char)
受保护的构造方法,参数为char型

 1.1:getConstructors():是获得所有的公共构造方法

 1.2:getConstructor(Class<?>...   parameterTypes):是获得指定的公共构造方法,无参就不传入参数,如果有,就一次传入参数,如int.class,long.class等等

 1.3:getDeclaredConstructors(Class<?>...   parameterTypes):是获取所有的构造方法,Declared意为声明过的

 1.4:getDeclaredConstructor():获取私有构造方法,准确说,获取指定的所有构造方法,私有的能获取,公有的当然也能获取,上面没做这个测试,感兴趣的朋友可以自己试试

     2.通过反射获取成员变量

Person2类:

package Java基础.Java反射;

public class Person2 {
    //成员变量
    public String name;
    protected int age;
    private char sex;
    String height;

    @Override
    public String toString() {
        return "Person2{" +
                "name='" + name + '\'' +
                ", age=" + age +
                ", sex=" + sex +
                ", height='" + height + '\'' +
                '}';
    }
}

测试类:

package Java基础.Java反射;

import java.lang.reflect.Field;

public class Demo04 {

    public static void main(String[] args) throws Exception{
        //加载Class对象
        Class clazz = Class.forName("Java基础.Java反射.Person2");

        System.out.println("----------获取所有公有的字段-----------");
        Field[] array = clazz.getFields();
        for(Field c : array){
            System.out.println(c);
        }
        System.out.println("----------获取指定的公共字段----------");
        Field name = clazz.getField("name");
        System.out.println(name);
        //获取一个对象
        Object obj = clazz.getConstructor().newInstance();
        name.set(obj,"反射");
        Person2 p = (Person2)obj;
        System.out.println("验证姓名:" + p.name);

        System.out.println("----------获取所有的字段----------");
        array = clazz.getDeclaredFields();
        for(Field c : array){
            System.out.println(c);
        }
        System.out.println("----------获取私有字段并调用-----------");
        name = clazz.getDeclaredField("sex");
        System.out.println(name);
        name.setAccessible(true);
        name.set(obj,'男');
        System.out.println("验证性别:" + p);
    }
}

运行结果:

----------获取所有公有的字段-----------
public java.lang.String Java基础.Java反射.Person2.name
----------获取指定的公共字段-----------
public java.lang.String Java基础.Java反射.Person2.name
验证姓名:反射
----------获取所有的字段---------------
public java.lang.String Java基础.Java反射.Person2.name
protected int Java基础.Java反射.Person2.age
private char Java基础.Java反射.Person2.sex
java.lang.String Java基础.Java反射.Person2.height
----------获取私有字段并调用-----------
private char Java基础.Java反射.Person2.sex
验证性别:Person2{name='反射', age=0, sex=男, height='null'}

2.1  这几个方法的使用与上面的构造方法的演示差不多,这里不重复说了

2.2  要调用字段时,先通过clazz.getConstructor().newInstance()构造一个实例对象 =>等同于Person2 p = new Person2();

2.3  为字段设置值 name.set(obj, "反射") =>等同于p.name = "反射";第一参数是设置的对象,第二个参数是实参;

     3.   通过反射获取成员方法

Person3类:

package Java基础.Java反射;

public class Person3 {
    //----------成员方法-----------
    public void method1(String str){
        System.out.println("调用了公有方法,参数为String:" + str);
    }
    protected void method2(){
        System.out.println("调用了受保护方法,无参数");
    }
    private String method3(int age){
        System.out.println("调用了私有方法,参数为Int:" + age);
        return "我是method3的返回值";
    }
    void method4(){
        System.out.println("调用了默认方法,无参数");
    }
}

测试类:

package Java基础.Java反射;
import java.lang.reflect.Method;
public class Demo05 {
    public static void main(String[] args) throws Exception{
        //加载Class对象
        Class clazz = Class.forName("Java基础.Java反射.Person3");

        System.out.println("----------获取所有公有的方法-----------");
        Method[] array = clazz.getMethods();
        for(Method m : array){
            System.out.println(m);
        }
        System.out.println("----------获取指定的method1公有方法-----------");
        Method m = clazz.getMethod("method1", String.class);
        System.out.println(m);
        //获取一个对象
        Object obj = clazz.getConstructor().newInstance();
        m.invoke(obj, "method1");

        System.out.println("----------获取所有声明的方法---------------");
        array = clazz.getDeclaredMethods();
        for(Method a : array){
            System.out.println(a);
        }
        System.out.println("----------获取私有的method3方法并调用-----------");
        m = clazz.getDeclaredMethod("method3", int.class);
        System.out.println(m);
        m.setAccessible(true);  //解除私有限定
        Object ret = m.invoke(obj, 20);
        System.out.println("返回值:" + ret);
    }
}

运行结果:

----------获取所有公有的方法-----------
public void Java基础.Java反射.Person3.method1(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()
----------获取指定的method1公有方法-----------
public void Java基础.Java反射.Person3.method1(java.lang.String)
调用了公有方法,参数为String:method1
----------获取所有声明的方法---------------
void Java基础.Java反射.Person3.method4()
protected void Java基础.Java反射.Person3.method2()
public void Java基础.Java反射.Person3.method1(java.lang.String)
private java.lang.String Java基础.Java反射.Person3.method3(int)
----------获取私有的method4方法并调用-----------
private java.lang.String Java基础.Java反射.Person3.method3(int)
调用了私有方法,参数为Int:20
返回值:我是method3的返回值

3.1  调用成员方法与上面不同的是clazz.getMethod("method1", String.class)和clazz.getDeclaredMethod("method3", int.class)必须传入两个参数,第一个是要找的指定方法名,第二个是参数的类型

3.2  m.setAccessible(true) //解除私有限定,没有这行代码就会报如下错误提示

 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值