浅谈java的反射技术(一)

这是我参与更文挑战的第11天,活动详情查看: 更文挑战

前言

本篇是java反射技术的入门篇,通过这篇文章了解反射的基本概念。后续将会对反射进行深入讲解

一、反射概述

java不是动态 语言,但java可以被称为准动态语言,因为它的反射机制。而这个反射机制是java被视为动态语言的关键。反射机制允许程序在执行期间借助Reflection API取得任何类的内部消息,并能直接操作任意对象的内部属性及方法。加载完类之后,在堆内存的方法区中就产生了一个Class类型的对象(一个类只有一个Class对象),这个对象就包含了完整的类的结构信息。我们可以通过这个对象看到类的结构。这个对象就像一面镜子,透过这个镜子看到类的结构,所以我们形象的称为:反射。

优点:可以实现动态创建对象和编译,体现出很大的灵活性。

缺点:对性能有影响,使用反射基本上是一种解析操作,我们可以告诉jvm,我们希望做什么并且它满足我们的要求。这类操作总是慢于直接执行相同的操作。

二、获取class类型对象

2.1 java代码分析

java代码在计算机中经历有三个阶段。

第一阶段:源代码阶段。由程序员写的一个pojo类,假设为A,可以包含成员变量,构造方法,和成员方法。然后该类经过javac编译,生成了一个A.class的字节码文件。

第二阶段:class类对象阶段。这个阶段由类加载器ClassLoader加载得到一个class类的对象。该对象包含成员变量,构造方法以及成员方法。一个类只产生一个class对象。

第三阶段:运行时阶段。通过class类的这几个方法创建对象。反射的本质理解就是得到class对象后反向获取student对象的各种信息。

2.2 如何得到class类对象

方式一: Object类的getClass()方法

 Person p = new Person();
 Class c = p.getClass();
复制代码

方式二: 任何数据类型都有一个“静态”的class属性.

所有类型的class对象:

public class Test03 {
    public static void main(String[] args) {
        Class c1 = Object.class;//对象
        Class c2= Comparable.class;//接口
        Class c3=String[].class;//数组
        Class c4=int[][].class;//二维数组
        Class c5=Override.class;//注解
        Class c6=Integer.class;//基本数据类型
        Class c7= ElementType.class;//枚举类型
        Class c8=void.class;//空
        Class c9=Class.class;//class

        System.out.println(c1);
        System.out.println(c2);
        System.out.println(c3);
        System.out.println(c4);
        System.out.println(c5);
        System.out.println(c6);
        System.out.println(c7);
        System.out.println(c8);
        System.out.println(c9);

    }
}
复制代码

输出结果:

class java.lang.Object
interface java.lang.Comparable
class [Ljava.lang.String;
class [[I
interface java.lang.Override
class java.lang.Integer
class java.lang.annotation.ElementType
void
class java.lang.Class
复制代码

方式三(常用): 通过Class类的静态方法:forName(String className)

Class c4 = Class.forName("com.xiaolei.Person");
复制代码

三、通过反射获取构造方法并使用

写个person类:

public class Person {
    //定义三个成员变量
    private String name;
    int age;
    public String address;

    public Person() {
    }

    private Person(String name){
        this.name=name;
    }


     Person(String name, int age) {
        this.name = name;
        this.age = age;
    }

    public Person(String name, int age, String address) {
        this.name = name;
        this.age = age;
        this.address = address;
    }

    //写个无参的方法
    public void show() {
        System.out.println("show!");
    }

    //写个带参的方法
    public void method(String s) {
        System.out.println("method:" + s);
    }

    //写个带两个参数的方法
    public String getString(String s,int i){
        return s+"---"+i;
    }

    //写个私有的方法
    private void function(){
        System.out.println("function !");
    }

    //重写toStirng()

    @Override
    public String toString() {
        return "Person[name="+name+",age="+age+",address="+address+"]";
    }
}
复制代码

测试类:

package fqy1;

import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;

/*
1).批量的方法:
   public Constructor[] getConstructors():所有public构造方法
   public Constructor[] getDeclaredConstructors():
   获取所有的构造方法(包括私有、受保护、默认、公有)

2).获取单个的方法,并调用:
public Constructor getConstructor(Class... parameterTypes):
获取指定单个的"公有的"构造方法:
public Constructor getDeclaredConstructor(Class... parameterTypes):
获取"某个构造方法"可以是私有的,或受保护、默认、公有;
调用构造方法:
      Constructor-->newInstance(Object... initargs)
创建对象:
      newInstance()
      con.newInstance(“zhangsan", 20);
 */
public class ReflectDemo2 {
    public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {
        //获取字节码文件对象
        Class c1=Class.forName("fqy1.Person");

        //第一:public Constructor[] getConstructors():所有public构造方法
        System.out.println("一、获取所有公有构造方法:");
        Constructor[] cons = c1.getConstructors();
        for(Constructor con:cons){
            System.out.println(con);
        }

        //第二:public Constructor[] getDeclaredConstructors():
        //   获取所有的构造方法
        System.out.println("二、获取所有的构造方法:");
        Constructor[] cons2 =c1.getDeclaredConstructors();
        for(Constructor con:cons2){
            System.out.println(con);
        }

        //第三:public Constructor getConstructor(Class... parameterTypes):
        //获取指定的单个“共有的”构造方法
        //步骤:
        //  A:首先创造字节码文件对象
        //  B:通过字节码文件对象去创建构造器对象
        //  C:通过构造器对象去创建一个实例对象
        System.out.println("三、无参:获取指定的单个“共有的”构造方法:");
        Constructor con3= c1.getConstructor(null);//返回的是构造方法对象
        Object obj=con3.newInstance();
        System.out.println(obj);

        /*
        第四:需求:通过反射去获取该构造方法并使用
        public person (String name,int age,String address)
         */
        System.out.println("四、通过反射去获取该构造方法并使用:");
        Constructor con4=c1.getConstructor(String.class,int.class,String.class);

        //通过带参构造方法对象创建对象
        Object obj2=con4.newInstance("徐雷",18,"武汉");
        System.out.println(obj2);

        /*
        需求:通过反射获取私有构造方法并使用
         */
        System.out.println("五、需求:通过反射获取私有构造方法并使用:");
        Constructor con5=c1.getDeclaredConstructor(String.class);
        //暴力访问
        con5.setAccessible(true);
         obj2=con5.newInstance("猫猫");//IllegalArgumentException:


        System.out.println(obj2);

    }
}
复制代码

后台输出:

一、获取所有公有构造方法:
public fqy1.Person(java.lang.String,int,java.lang.String)
public fqy1.Person()
二、获取所有的构造方法:
public fqy1.Person(java.lang.String,int,java.lang.String)
fqy1.Person(java.lang.String,int)
private fqy1.Person(java.lang.String)
public fqy1.Person()
三、无参:获取指定的单个“共有的”构造方法:
Person[name=null,age=0,address=null]
四、通过反射去获取该构造方法并使用:
Person[name=徐雷,age=18,address=武汉]
五、需求:通过反射获取私有构造方法并使用:
Person[name=猫猫,age=0,address=null]
复制代码

四、通过反射获取成员变量并使用

1.获取所有成员:
1).Field[] getFields():获取所有的”公有字段”
2).Field[] getDeclaredFields():获取所有字段,包括:私有、受保护、默认、公有;

2.获取单个成员的:
1).public Field getField(String fieldName):获取某个”公有的”字段;
2).public Field getDeclaredField(String fieldName):获取某个字段(可以是私有的)

3.修改成员的值:
Field –> public void set(Object obj,Object value):

参数说明:
1.obj:要设置的字段所在的对象;这个对象通过Constructor创建
2.value:要为字段设置的值;

测试类:

public class ReflectDemo3 {
    public static void main(String[] args) throws ClassNotFoundException, NoSuchFieldException, NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {
        //创建class类对象
        Class c2=Class.forName("fqy1.Person");

        //Field[] getFields():获取所有的"公有字段"
        System.out.println("第一:获取所有公有成员变量:");
        Field[] field=c2.getFields();
        for(Field f:field){
            System.out.println(f);
        }

        //Field[] getDeclaredFields():获取所有字段,包括:私有、受保护、默认、公有
        System.out.println("第二:获取所有字段");
        Field [] field2=c2.getDeclaredFields();
        for(Field f:field2){
            System.out.println(f);
        }


        //public Field getField(String fieldName):获取某个"公有的"字段;
        //Field --> public void set(Object obj,Object value):
        System.out.println("第三:获取某个公共字段并赋值:");
        //通过无参构造方法创建对象
        Constructor con =c2.getConstructor();
        Object obj =con.newInstance();
        Field field3=c2.getField("address");
        field3.set(obj,"武汉");//给object对象的f字段设置为”武汉“
        System.out.println(obj);

        //获取name并对其赋值
        System.out.println("第四:获取私有变量并赋值");
        Field field4=c2.getDeclaredField("name");
        field4.setAccessible(true);
        field4.set(obj,"徐雷");

        System.out.println(obj);
    }
}
复制代码

后台输出:

第一:获取所有公有成员变量:
public java.lang.String fqy1.Person.address
第二:获取所有字段
private java.lang.String fqy1.Person.name
int fqy1.Person.age
public java.lang.String fqy1.Person.address
第三:获取某个公共字段并赋值:
Person[name=null,age=0,address=武汉]
第四:获取私有变量并赋值
Person[name=徐雷,age=0,address=武汉]
复制代码

五、通过反射获取成员方法并使用

5.1 批量的:

	public Method[] getMethods():获取所有"公有方法";(包含了父类的方法也包含Object类)
	public Method[] getDeclaredMethods():获取所有的成员方法,包括私有的(不包括继承的)
复制代码

5.2 获取单个的:

	public Method getMethod(String name,Class<?>... parameterTypes):
				参数:
					name : 方法名;
					Class ... : 形参的Class类型对象
	public Method getDeclaredMethod(String name,Class<?>... parameterTypes)
复制代码

【注】:第一个参数表示的是方法名,第二个参数表示的是方法的参数的class类型,这个方法返回值是Object接收,第一个参数表示对象是谁,第二参数表示调用该方法的实际参数。

5.3 调用方法:

	Method --> public Object invoke(Object obj,Object... args):
		参数说明:
		obj : 要调用方法的对象;
		args:调用方式时所传递的实参;
		
复制代码

测试成员方法:

/*
测试成员方法:
 */
public class ReflectDemo4 {
    public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {
        //创建class类对象
        Class c=Class.forName("fqy1.Person");

        //public Method[] getMethods():获取所有"公有方法";
        System.out.println("------第一:获取所有公有方法-------");
        Method []m=c.getMethods();
        for(Method method:m){
            System.out.println(method);
        }
        //public Method[] getDeclaredMethods():
        System.out.println("---------第二:获取所有方法--------");
        Method[] m2=c.getDeclaredMethods();
        for(Method method:m2){
            System.out.println(method);
        }

        Constructor con=c.getConstructor();
        Object obj=con.newInstance();

        System.out.println("--------第三获取单个无参方法并使用----------");
        //调用show方法
        Method m1=c.getMethod("show");
        //obj.m1();错误
        //
        m1.invoke(obj);//调用obj对象的m1方法

        System.out.println("-----第四,获取单个有参参数并使用-----------");
        Method m3=c.getMethod("method", String.class);
        m3.invoke(obj,"hello");

        System.out.println("-----第五,获取带多个参数的方法并使用-----");
        Method m4=c.getMethod("getString", String.class, int.class);
        Object objectString=m4.invoke(obj,"徐雷",18);//返回object类型,记住!
        System.out.println(objectString);

        System.out.println("-----第六。获取私有的方法并使用----");
        Method m5=c.getDeclaredMethod("function");
        m5.setAccessible(true);
        m5.invoke(obj);
    }
}
复制代码
------第一:获取所有公有方法-------
public java.lang.String fqy1.Person.toString()
public void fqy1.Person.method(java.lang.String)
public java.lang.String fqy1.Person.getString(java.lang.String,int)
public void fqy1.Person.show()
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 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 java.lang.String fqy1.Person.toString()
private void fqy1.Person.function()
public void fqy1.Person.method(java.lang.String)
public java.lang.String fqy1.Person.getString(java.lang.String,int)
public void fqy1.Person.show()
--------第三获取单个无参方法并使用----------
show!
-----第四,获取单个有参参数并使用-----------
method:hello
-----第五,获取带多个参数的方法并使用-----
徐雷---18
-----第六。获取私有的方法并使用----
复制代码
© 版权声明
THE END
喜欢就支持一下吧
点赞0 分享