Java反射机制

Java语言之所以会有如此多的开源技术支撑,很大一部分是来自于Java最大的特征——反射机制。它可以说是Java中最强大的技术了。
JAVA反射机制是在运行时,对于任意的一个类,这个类的所有属性和方法都可被知晓;对于任意一个对象,都能够调用它的任意一个方法和属性;这种动态获取的信息以及动态调用对象的方法的功能称为java语言的反射机制。

一、 “正"与"反”

正:当我们要使用一个类的时候,一定要先导入程序所在的包,而后根据类进行实例化对象,并且依靠对象调用类中的方法。
在Java程序中,在没有用到反射相关的类的时候,我们都是在做正射

import java.util.Date;//导包
public class Main {
    public static void main(String[] args) {
        Date date=new Date();//创建实例化对象
    }
}

反:根据实例化对象,反推出其类型
计算机科学中的反射(reflection) 指计算机程序在运行时可以访问、检测和修改它本身状态或行为的一种能力。通俗说,反射就是程序在运行的时候能够“观察”并且修改自己的行为,是程序对自身的反思、自检、修改。

public class Main {
    public static void main(String[] args) {
        String str="abc";
        System.out.println(str.getClass());
    }
}

输出为:
在这里插入图片描述

二、获取Class类的三种方法

从JDK1.5开始Class类定义的时候可以使用泛型进行标记,主要用来避免向下转型。
1. 类.getClass: 调用Object类中的特殊的方法getClass(),获取Class的信息,其返回值为Class类型

class Person{}
public class Main {
    public static void main(String[] args) {
        Person person=new Person();
        Class<? extends Person> cls1=person.getClass();
        Class cls2=person.getClass();//也可以不写泛型
        
        System.out.println(cls1);//输出为class Person
        System.out.println(cls2.getName());//输出为Person
    }
}

2. 类.class: 但上面的方法需要创建实例化对象,而JVM支持直接采用"类.class"形式实例化

class Person{}
public class Main {
    public static void main(String[] args) {
        Class<? extends Person> cls1=Person.class;
        System.out.println(cls1.getName());//输出为Person
    }
}

3. 类.forName: 在Class类里提供有一个static方法Class.forName

public class Main {
    public static void main(String[] args) throws ClassNotFoundException {
        String name = "java.util.ArrayList";
        Class c1= Class.forName(name);
        System.out.println(c1.getName());
    }
}

这里需要抛出异常或使用trycatch,因为我们传的这个字符串可能不合法,字符串合法命名是类的命名空间和类的名称组成

三、获取类的成员

一般情况下,根据面向对象封装性的原则,Java实体类的属性都是私有的,我们不能获取类中的属性。但我们可以根据反射,获取私有变量、方法、构造器,甚至是注解。

1.获取该类的构造方法

(1)返回类的所有构造方法:getDeclaredConstructors( )
返回所有的构造函数(public,protected,default(package)access和private),由于其中的构造方法可能会有多个,所以返回的是一个数组。

(2)获取特定参数类型的构造方法:getDeclaredConstructor( )
与上面不同的是,其返回值只有一个,是一个Class对象

(3)只返回公共构造函数:getConstructors( )

package fanshe;

import java.lang.reflect.Constructor;

class Person{
    private String name;
    private int age;

    private Person() {
    }

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

public class Main {
    public static void main(String[] args) throws Exception {
        Class<?> cls=Person.class;

        Constructor<?>[] cls1=cls.getDeclaredConstructors( );
        for(Constructor cons:cls1){
            System.out.println(cons);
        }
        System.out.println("===========");
        Constructor<?>[] cls2=cls.getConstructors( );
        for(Constructor cons:cls2){
            System.out.println(cons);
        }
    }
}

输出结果为:

private fanshe.Person()
public fanshe.Person(java.lang.String,int)
===========
public fanshe.Person(java.lang.String,int)
2.获取方法对象

在Class类中提供有如下操作可以获取方法对象:

(1)获取全部方法:getMethods()
返回的是全部方法,包括父类,由数组存储
public Method[] getMethods() throws SecurityException

(2)获取指定方法:getMethod()
public Method getMethod(String name.class<?>…parameterTypes) throws NoSuchMethodEception,SecurityException

(3)获取本类全部方法:getDeclaredMethods()
返回的是本类方法,由数组存储
public Method[] getDeclaredMethods() throws SecurityException

(4)获取本类指定方法:getDeclaredMethod()
public Method getDeclaredMethod(String name.class<?>…parameterTypes) throws NoSuchMethodEception,SecurityException

public class Main {
    public static void main(String[] args) throws Exception {
        Class<?> cls=Person.class;//Person为自定义的类

        Method method1 []= cls.getMethods();//获取全部方法,包括父类
        for(Method m: method1){
            System.out.println(m);
        }
        System.out.println("=============");
        Method method2 []= cls.getDeclaredMethods();//获取本类方法
        for(Method m: method2){
            System.out.println(m);
        }
    }
}

输出结果为:

public java.lang.String fanshe.Person.toString()
public final void java.lang.Object.wait(long,int) throws java.lang.InterruptedException
public final void java.lang.Object.wait() 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 fanshe.Person.toString()

Process finished with exit code 0

3.获取构造方法的类型、返回值、参数

(1)获取构造方法的类型:getModifiers( )
返回值是一个整型,若要其显示类型,应使用Modifier.toString(整型值) 返回值为方法类型

(2)获取构造方法的所有参数:getParameterTypes( )
返回的是一个Class数组

(3)获取返回值类型:getReturnType()

4.反射调用类中的方法

反射调用类中的方法:invoke( )
public Object invoke(Object obj,Object…args) throws IllegalAcessException,IllegalArgumentException,InvocationTargetException

5.获取成员变量

(1)获取本类全部成员:getDeclaredFields( )
这些Field 对象反映当前 Class 对象所表示的类或接口中 所声明的所有字段。包括public 、protected 、(default)即不写、private ,但不包括继承的父类字段。

(2)获取本类指定成员:getDeclaredFileld(String name)
可以获取public 、protected 、(default)即不写、private 修饰的字段,但该字段必须在当前类或接口中存在有声明。从父类继承的字段无法获取。

(3)获取父类全部成员:getFilelds( )
返回一个包含一些Field 对象的数组,这些Field 对象反映当前 Class 对象所表示的类或接口的所有可访问的公共字段,即public所定义的。

(4)获取父类指定成员:getFileld(String name)
该方法返回一个 Feild对象,它反映了当前 Class对象所表示的类或接口的指定名称的公共成员字段。name 用于指定所需字段的名称。也就是说,他只能获取public所定义的成员,否则会抛出NoSuchFieldException的异常

import java.lang.reflect.Field;

class Person2 {
    private String funame;
    public int fuage;
}
//为方便展示省略其他部分
class Person extends Person2{
    private String ziname;
    private int ziage;
}

public class Main {
    public static void main(String[] args) throws Exception{
        Class<?> cls=Person.class;//Person为自定义的类

        Field file[]=cls.getDeclaredFields();//获取本类全部成员变量
        for(Field f:file){
            System.out.println(f);
        }

        System.out.println("===============");
        Field file2[]=cls.getFields();//获取父类全部成员变量
        for(Field f:file2){//无法输出funame,因为不是公共的
            System.out.println(f);
        }

        System.out.println("===============");
        Field file3=cls.getDeclaredField("ziage");//获取本类指定成员
            System.out.println(file3);

        System.out.println("===============");
        Field file4=cls.getField("fuage");//获取父类指定成员
        System.out.println(file4);//无法访问funame,因为不是公共的
    }
}

输出为:

private java.lang.String fanshe.Person.ziname
private int fanshe.Person.ziage
===============
public int fanshe.Person2.fuage
===============
private int fanshe.Person.ziage
===============
public int fanshe.Person2.fuage
  • 5
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值