对Java反射的个人总结

Java是一门静态语言,但反射机制使其具有了动态语言的很多特征,所以我认为Java可以看作一门准动态语言。那么,我们再看看什么是Java的反射机制?

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

首先,Java是一门面向对象语言,Java中的类也是一个对象。所有类都是java.lang.Class类的一个对象,这个关于该类的Class类的对象也被称为该类的类类型(class type)

  • 如何获取一个类的类类型?有三种方式

       package test;
       
       public class Test {
            public static void main(String [] args){
                //第一种通过类名获取类类型
                Class c1=Test.class;
                //第二种已知该类对象获取类类型
                Test t=new Test();
                Class c2=t.getClass();
                //第三种通过全限定名获取类类型
                Class c3=null;
                try {
                    c3=Class.forName("test.Test");
                } catch (ClassNotFoundException e) {
                    e.printStackTrace();
                }
            }
        }
    

那么通过这三种方式获取到Test类的类类型,是否相等?答案是肯定的,因为他们是属于同一个类的类类型。我们可以通过代码测试一下

  	    boolean b1=(c1==c2)?true:false;
        boolean b2=(c1==c3)?true:false;
        boolean b3=(c2==c3)?true:false;
        System.out.println(b1+","+b2+","+b3);

结果如下图所示:
在这里插入图片描述

其中Class.forName(“类的全限定名”)不但代表该类的类类型,还代表着动态加载类。(编译时加载类属于静态加载类,运行时加载类属于动态加载,使用new关键字创建一个类的实例对象时,属于静态加载类)相比静态加载(在编译时需要所有可能用到的类构建完毕),动态加载可以看作一种按需运行,未构建的类不影响已构建的类的使用,这样在一个庞杂的项目中,即使有些功能(类)未完成,我们依旧可以使用那些已经完成的功能(类),这并不影响整个项目的正常运行。同时,动态加载类有利于代码重用和维护,我们可以对某些相近功能的类定义一个公共的规范接口,有利于程序的扩展和维护。这就是动态加载类的好处。

  • 我们可以通过如下代码动态的获取一个类的对象

     package test;
     
     public class Test {
         public static void main(String [] args){
             Class c=null;
             try {
                 c=Class.forName("test.Test");
             } catch (ClassNotFoundException e) {
                 e.printStackTrace();
             }
             try {
                 //通过Test类的类类型c生成Test类的实例对象
                 Test t=(Test)c.newInstance();
             } catch (InstantiationException e) {
                 e.printStackTrace();
             } catch (IllegalAccessException e) {
                 e.printStackTrace();
             }
         }
     }
    
  • Class类常用api,通过这些api来获取一个类的全部信息,下面我以String类作为示例

1.首先获取String类中的相关方法信息,这些方法其实也是一个对象,是 java.lang.reflect.Method类的一个对象

package test;

import java.lang.reflect.Method;

public class Test {
    public static void main(String [] args){
        Class c1=String.class;
        //1.获取该类的全限定名
        System.out.println(c1.getName());
        //2.返回该类的简称
        System.out.println(c1.getSimpleName());
        //3.获取该类的所有public方法,包括父类继承而来的
        c1.getMethods();
        //4.获取该类声明的所有的方法,不包括父类继承的
        Method[] method=c1.getDeclaredMethods();
        for (int i=0;i<method.length;i++){
            //5.获取该方法的返回值类型
            //getReturnType()得到的是返回值类型的类类型,如返回值是String,那么得到的就是String的类类型
            Class returnType=method[i].getReturnType();
            System.out.print(returnType.getSimpleName()+" ");
            //6.获取该方法的名称
            System.out.print(method[i].getName()+" ");
            //7.获取该方法的参数类型
            Class [] paramTypes=method[i].getParameterTypes();
            for (int j=0;j<paramTypes.length;j++){
                System.out.print(paramTypes[j].getSimpleName()+",");
            }
            System.out.println();
        }

    }
}

2.获取String类中的成员变量,这些成员变量其实也是一个对象,是 java.lang.reflect.Field类的一个对象

package test;

import java.lang.reflect.Field;

public class Test {
    public static void main(String [] args){
        Class c1=String.class;
        //1.获取该类中所有public的成员变量
        Field[] fields1=c1.getFields();
        //2.获取该类中所有声明的成员变量
        Field[] fields=c1.getDeclaredFields();
        for(int i=0;i<fields.length;i++){
            //3.获取该成员变量的数据类型
            Class Type = fields[i].getType();
            System.out.print(Type.getSimpleName()+" ");
            //4.获取该成员变量的名字
            System.out.println(fields[i].getName());

        }

    }
}

3.获取String类中的构造方法,这些构造方法其实也是一个对象,是 java.lang.reflect.Constructor类的一个对象

package test;

import java.lang.reflect.Constructor;

public class Test {
    public static void main(String [] args){
        Class c1=String.class;
        //1.获取所有的构造方法
        Constructor [] constructors=c1.getDeclaredConstructors();
        for(int i=0;i<constructors.length;i++){
            //2.获取构造方法的名字
            System.out.print(constructors[i].getName());
            //3.获取构造方法的参数类型
            Class [] paramTypes=constructors[i].getParameterTypes();
            for(int j=0;j<paramTypes.length;j++){
                System.out.print(paramTypes[j].getName()+",");
            }
            System.out.println();
        }
    }
}

方法的反射操作

package test;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

public class Test {
    public static void main(String [] args){
        //1.正常方法调用过程,使用类的对象调用方法
        A a=new A();
        a.print(3,5);
        //2.通过反射调用方法
        Class c1=A.class;
        try {
            //获取声明的方法其中参数为方法名称,及参数类型的类类型
            Method method=c1.getDeclaredMethod("print", int.class, int.class);
            try {
                //通过method对象反过来操作对象a调用指定方法
                method.invoke(a,3,5);
            } catch (IllegalAccessException e) {
                e.printStackTrace();
            } catch (InvocationTargetException e) {
                e.printStackTrace();
            }
        } catch (NoSuchMethodException e) {
            e.printStackTrace();
        }
    }
}
class A{
    public void print(int a,int b){
        System.out.println(a+b);
    }
    public void print(String a,String b){
        System.out.println(a+"和"+b);
    }

}

程序结果如图,可以看到,正常的方法调用和通过反射调用方法的结果是相同的。在这里插入图片描述

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值