加入收藏 | 设为首页 | 会员中心 | 我要投稿 PHP编程网 - 黄冈站长网 (http://www.0713zz.com/)- 数据应用、建站、人体识别、智能机器人、语音技术!
当前位置: 首页 > 教程 > 正文

Java反射概括

发布时间:2021-12-10 19:19:12 所属栏目:教程 来源:互联网
导读:能够分析类能力的程序称为反射。对于给定的Java类名,可以通过反射获取类的信息、将类的各成分映射出相应的Java类。 一、Class类 在程序运行期间,Java运行时系统始终对所有的对象维护一个被称为运行时的类型标识。这个信息跟踪着每个对象所属的类。虚拟机利

能够分析类能力的程序称为反射。对于给定的Java类名,可以通过反射获取类的信息、将类的各成分映射出相应的Java类。
 
一、Class类
    在程序运行期间,Java运行时系统始终对所有的对象维护一个被称为运行时的类型标识。这个信息跟踪着每个对象所属的类。虚拟机利用运行时类型信息选择相应的方法执行。可以通过专门的Java类访问这些信息。保存这些信息的类被称为Class。
 
创建Class类对象的三种方法:
 
1. 通过getClass方法
 
    Object中的getClass方法将返回一个Class类型的实例。
 
 
class Person {
   //...
}
 
Person p = new Person();
Class c = p.getClass();
 
2. forName方法
 
    可以通过静态方法forName获得类名对应的Class对象。
 
 
String className = "java.util.Date";
Class c = Class.forName(className);
 
    如果需要在运行过程中需要改变类名,就可以使用这种方法。当然,字符串className必须是一种类名或接口(包括包名),否则会出现异常。
 
3. T.class
 
Class c1 = Date.class;
Class c2 = int.class;
Class c3 = Double[].class;
    T表示任意的Java类型。通过T.class获取匹配的类对象。
 
注意:一个Class对象实际表示一种类型,而这种类型未必是一种类。
 
虚拟机为每个类型管理一个Class对象。因此可以用==运算符来实现两个类对象的比较
 
if (p.getClass() == Person.class) {...}
newInstance方法
    通过newInstance方法可以创建一个类的实例。
 
Person person = p.getClass().newInstance();
    创建了一个与p具有相同类类型的实例。newInstance调用默认的构造器初始化创建的对象。如果这个类没有默认的构造器,就会抛出异常。
 
二、利用反射解析类结构
获取包名+类名(包括父类名)
package com.xiaoxiaoyihan.reflection;
 
class Person {
    //...
}
 
class Student extends Person{
 
}
 
public class ReflectionDemo1 {
    public static void main(String[] args) {
        Student s = new Student();
        Class cl = s.getClass();
        Class superCl = cl.getSuperclass();
        System.out.println("获取类名:" + cl.getName());
        System.out.println("获取父类名:" + superCl.getName());
    }
}
【运行结果】:
获取类名:com.xiaoxiaoyihan.reflection.Student
获取父类名:com.xiaoxiaoyihan.reflection.Person
 
说明:如果类在一个包中,包的名字也作为类名的一部分。
 
一点扩展:
 
首先看一个例子:
 
class Person {
    private String name = "萧萧弈寒";
    // 省略setter和getter
}
class Animal {
    private String name = "paqi";
    // 省略setter和getter
}
 
Person p;
Animal a;
Class cPerson = p.getClass();
Class cAnimal = a.getClass();
// cPerson.getName()获取的是类名、p.getName()是Person实例的name属性值
System.out.println(cPerson.getName() + "<--->" + p.getName());
System.out.println(cAnimal.getName() + "<--->" + p.getName());
【运行结果】:
com.xxyh.reflec.Person<--->萧萧弈寒
com.xxyh.reflec.Animal<--->paqi
 
由此说明,一个Person对象p表示一个特定人的属性,一个Animal对象a表示一个特定动物的属性,一个Class对象表示一个特定类(Person或Animal)的属性。从这点看,Class的实例是一种对象。
 
解析构造函数(Constructor)
Class类中的getConstructors方法将返回公共构造器数组。Class类中的getDeclaredConstructors将返回类中声明的构造器数组。
 
package com.xiaoxiaoyihan.reflection;
 
import java.lang.reflect.Constructor;
class Person {
    private String name;
    private int age;
 
    private Person() {}
 
    protected Person(String name) {
        this.name = name;
    }
 
    public Person(String name, int age) {
        this.name = name;
        this.age = age;
    }
}
public class ReflectionDemo1 {
    public static void main(String[] args) throws ClassNotFoundException {
        Class cl = Class.forName("com.xiaoxiaoyihan.reflection.Person");  // 直接抛出异常以简化代码
 
        Constructor[] constructors = cl.getDeclaredConstructors();
        //Constructor[] constructors = cl.getConstructors();
        for (Constructor c :constructors) {
            System.out.println(c);
        }
    }
}
【运行结果】:
 
private com.xiaoxiaoyihan.reflection.Person()
protected com.xiaoxiaoyihan.reflection.Person(java.lang.String)
public com.xiaoxiaoyihan.reflection.Person(java.lang.String,int)
 
// public com.xiaoxiaoyihan.reflection.Person(java.lang.String,int)// 本部分为运行getConstructors方法输出结果
 
对结果加以分析,会发现通过System.out.println(c);直接打印的构造函数是由几部分组成的,其中包括了修饰符(public/protected/private)、类名以及构造函数的参数,那么,这些部分是如何获取的呢?
 
在Modifier类中包含静态方法getModifiers方法,它返回一个整数i,用不同的数值表示public、static、final这样的修饰符。Modifier中的静态方法toString(i)返回对应的修饰符。Constructor类中包含由静态方法getParameterTypes,它返回一个描述参数类型的Class对象数组。
 
package com.xiaoxiaoyihan.reflection;
 
import java.lang.reflect.Constructor;
import java.lang.reflect.Modifier;
 
class Person {
    private String name;
    private int age;
 
    private Person() {}
 
    protected Person(String name) {
        this.name = name;
    }
 
    public Person(String name, int age) {
        this.name = name;
        this.age = age;
    }
}
public class ReflectionDemo1 {
    public static void main(String[] args) throws ClassNotFoundException {
        Class cl = Person.class;
 
        Constructor[] constructors = cl.getDeclaredConstructors();
        for (Constructor c :constructors) {
            // 获取包名和类名
            String name = c.getName();
 
            // 获取修饰符
            String modifiers = Modifier.toString(c.getModifiers());
            if (modifiers.length() > 0) {   //如果有修饰符
                System.out.print(modifiers + " ");
            }
 
            System.out.print(name + "(");
 
            // 获取构造函数的参数类型
            Class[] paramTypes = c.getParameterTypes();
 
            for (int i = 0; i < paramTypes.length; i++) {
                if (i > 0) {    // 如果不止一个参数,使用","将参数类型分割
                    System.out.print(",");
                }
                System.out.print(paramTypes[i].getName());
            }
            System.out.println(");");
        }
 
    }
}
【运行结果】:
 
private com.xiaoxiaoyihan.reflection.Person();
protected com.xiaoxiaoyihan.reflection.Person(java.lang.String);
public com.xiaoxiaoyihan.reflection.Person(java.lang.String,int);
 
解析方法(Method)
Class类中的getMethods将返回方法的数组,其中包括本类的所有方法、从接口实现的方法、父类的公共(public)方法、父类的父类的公共方法……一直延伸到Object的公共方法。getDeclaredMethods方法将返回本类声明的方法、从接口实现的方法。
 
package com.xiaoxiaoyihan.reflection;
 
import java.lang.reflect.Constructor;
import java.lang.reflect.Method;
 
 
class Person/* extends Object */ {
    private void privateMethodPerson() {
        //...
    }
 
    protected void protectedMethodPerson() {
        // ...
    }
 
    public void publicMethodPerson() {
        //...
    }
}
 
interface Smoke {
    void smoking();
}
 
class Student extends Person implements Smoke{
    @Override
    public void smoking() {
        // ...
    }
 
    private void privateMethodStudent() {
        //...
    }
 
    protected void protectedMethodStudent() {
        // ...
    }
 
    public void publicMethodStudent() {
        //...
    }
}
 
 
public class ReflectionDemo1 {
    public static void main(String[] args) {
        Student s = new Student();
        Class cl = s.getClass();
        Method[] methods = cl.getDeclaredMethods();
//        Method[] methods = cl.getMethods();
 
        for (Method m : methods) {
            System.out.println(m);
        }
    }
}
【运行结果】:
 
public void com.xiaoxiaoyihan.reflection.Student.smoking()
protected void com.xiaoxiaoyihan.reflection.Student.protectedMethodStudent()
private void com.xiaoxiaoyihan.reflection.Student.privateMethodStudent()
public void com.xiaoxiaoyihan.reflection.Student.publicMethodStudent()
 
上面的例子故意给出一种继承结构,是为了查看getMethods的结果,在此就不给出结果了。注意Person默认继承了Object类。顺便说一句,笔者(非科班自学菜鸟)曾在面试的时候被问到Object中有哪些方法,估计他是想问有哪些常用方法吧,我没答全~2333,不知道读者您能一眼看出结果吗??。
 
类似地,我们看到上面的System.out.println(m);打印出方法由修饰符、返回值、类名、方法名以及参数组成。那么这些部分是如果获取的呢? 与Construction类相似,Method类中也提供了静态方法getParamTypes,该方法返回描述参数类型的Class对象数组。此外,Method还提供了getReturnType方法,用于获取返回类型的Class对象。
 
 
复制代码
package com.xiaoxiaoyihan.reflection;
 
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
 
class Person {
 
    private String name = "萧萧弈寒";
 
    public String getName() {
        return name;
    }
 
    public void setName(String name) {
        this.name = name;
    }
 
    public static void speak() {
        // ...
    }
 
    public final void eat() {
        // ...
    }
}
 
 
public class ReflectionDemo1 {
    public static void main(String[] args) {
 
        Class cl = Person.class;
 
        Method[] methods = cl.getDeclaredMethods();
        for (Method m : methods) {
            // 返回类型的Class对象
            Class retType = m.getReturnType();
            //
            String retTypeName = retType.getName();
 
            // 获取方法名
            String name = m.getName();
 
            String modifiers = Modifier.toString(m.getModifiers());
            if (modifiers.length() > 0) // 如果有修饰符
                System.out.print(modifiers + " ");
 
            // 返回值名
            System.out.print(retType.getName() + " ");
 
            System.out.print(name + "(");
 
            Class[] paramTypes = m.getParameterTypes();
            for (int i = 0; i < paramTypes.length; i++) {
                if (i > 0) { // 如果不止一个参数,用","分割
                    System.out.print(paramTypes[i].getName());
                }
            }
            System.out.println(");");
        }
 
    }
}
【运行结果】:
public java.lang.String getName();
public void setName();
public static void speak();
public final void eat();
 
解析域(Field)
Class类中的getDeclaredFields方法返回类中声明的域数组,getFields方法返回类中的公有域、接口中的域所组成的Field对象数组。
 
package com.xiaoxiaoyihan.reflection;
 
import java.lang.reflect.Field;
import java.util.Date;
 
class Person {
    private String name;
    protected int age;
    public Date birthday;
}
 
class Student extends Person implements Smoke{
    private float score;
}
 
interface Smoke {
    String brand = "大中华";
}
 
public class ReflectionDemo1 {
    public static void main(String[] args) {
        Class cl = Student.class;
 
        Field[] fields = cl.getFields();
        for (Field f : fields) {
            System.out.println(f);
        }
    }
}
【运行结果】:
public static final java.lang.String com.xiaoxiaoyihan.reflection.Smoke.brand
public java.util.Date com.xiaoxiaoyihan.reflection.Person.birthday
 
    结果显示了字段由修饰符、类型、类名、字段名构成。这里需要引入Field类中的getType方法,它返回字段声明类型的Class对象。下面同样作出解析:
 
package com.xiaoxiaoyihan.reflection;
 
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.util.Date;
 
class Person {
    private String name;
    protected int age;
    public Date birthday;
}
 
public class ReflectionDemo1 {
    public static void main(String[] args) {
        Class cl = Person.class;
 
        Field[] fields = cl.getDeclaredFields();
        for (Field f : fields) {
            // 属性类型的Class对象
            Class type = f.getType();
 
            // 属性类型名
            String name = type.getName();
            System.out.print(" ");
 
            // 修饰符
            String modifiers = Modifier.toString(f.getModifiers());
 
            if (modifiers.length() > 0) {   // 如果有修饰符
                System.out.print(modifiers + " ");
            }
 
            System.out.println(type.getName() + " " + name + ";");
        }
    }
}

(编辑:PHP编程网 - 黄冈站长网)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    热点阅读