Logo

郎哥编程

Class对象

2021-07-18 268

学习目标:掌握Class对象的属性、方法和相关操作。

认识Class对象

前面我们谈到了使用new运算符实例化类时,如果类没有加载到内存,类加载器会把类的字节码文件读入内存,并创建一个java.lang.Class对象。java.lang.Class对象由JVM创建,它存储了被加载类在运行时态下的类信息,程序可以通过Class类提供的方法获取被加载类的类名、类的包名、类方法、类属性、类构造方法等类信息。

java编译器在编译Java类时,会创建Class对象数据,并存放在同名的.class文件中。类加载器加载该类时,JVM会检查该类是否已经加载到内存中,若是没有加载,则把class文件加载到内存并创建Class对象,创建的Class对象是该类所有实例化对象在内存中的代理。如下图所示:

01.png

案例3:建立ClassTest类,并在ClassTest类的main()方法分别使用三种方式创建Book类的实例化对象,然后输出Book类实例化对象的Class对象的哈希码值,观察Book类三个实例化对象的Class对象的哈希码值是否相同。

在reflex包下新建ClassTest类。代码如下:

package reflex;
 
public class ClassTest {
    public static void main(String[] args) throws InstantiationException, IllegalAccessException {
        try {
            // 使用Class.forName()
            Class<?> obj1 = Class.forName("reflex.Book");
            Book book1 = (Book) obj1.newInstance();
            // 输出book1的哈希码
            System.out.println("book1的Class对象的哈希码:---" + book1.getClass().hashCode());
 
            // 获取Book类的Class对象
            Class<?> obj2 = Book.class;
            Book book2 = (Book) obj2.newInstance();
            // 输出book2的哈希码
            System.out.println("book2的Class对象的哈希码:---" + book2.getClass().hashCode());
 
            // 使用new运算符实例化Book类
            Book book3 = new Book();
            // 输出rect2的Class对象的哈希码
            System.out.println("book3的Class对象的哈希码:---" + book3.getClass().hashCode());
 
        } catch (ClassNotFoundException e) {
 
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
 
    }
}

ClassTest程序分别使用Class类的forName方法、Book类的class静态变量、new运算符三种方式对Book类进行实例化,并分别输出实例化对象的哈希码。

程序执行结果如下图所示:

02.png

从执行结果可以看出,Book类的三个实例化对象book1、book2、book3的Class对象的哈希码值完全相同。因此可以说类的Class对象是该类所有实例化对象在内存中的代理。

类的哈希码通是过哈希算法散列得来的,在逻辑上可以确保类对象的唯一性,当多个类对象的哈希码相同时,就认为这多个类对象是同一个对象。

如何获取类的Class对象?

有三种方式获得Class对象:一种方式是使用Class类的forName方法来获取类的Class对象;一种方式是使用类实例化对象的getClass方法获取类的Class对象;一种方式是使用类的class静态变量获取Class对象,使用这种方式获取Class类对象时,JVM不会自动加载该类。

(1)使用Class类的forName方法获取类的Class对象

Class类的forName方法是一个静态方法,它使用一个包含类路径的文本串 String 作为输入参数,并返回该类Class 对象的引用。forName方法会调用类加载器从磁盘读取该类的字节码文件,并转换成 java.lang.Class 类的一个实例对象,并进行初始化操作,执行类的静态语句,包括静态变量的声明还有静态代码块。forName方法在调用类加载器加载类之前,会检查此类是否被加载到内存,如果没有,才会调用类加载器执行加载操作。如果该类已被加载到内存,forName会直接返回该类Class对象的引用。

Class类重载了forName方法,forName方法分别定义如下:

public static Class<?>  forName(String className)
public static Class<?>  forName(
String name, 
boolean initialize, 
ClassLoader loader
)

第一个forName重载方法只有一个参数,参数是包含类路径的String对象,类路径要包含类所在包的完整包路径和包名。

第二个forName重载方法有三个参数,第一个参数包含类路径的String对象,第二个参数是布尔值,设定是否初始化加载的类,第三个参数是类加载器对象,该参数用来加载由第一个参数指定的类。

(2) 使用类实例化对象的getClass方法获取类的Class对象

getClass()方法是在Object类定义的方法,方法说明如下:

●   Class<?>  getClass ()

该方法返回该实例化对象的Class对象。

例如:

    // 获取Book类的Class对象

    Book book = new Book();

Class<?> obj = book.getClass();

上面的例句调用book对象的getClass()方法,获取book对象的Class对象。

(3) 使用类的Class属性获取Class对象

每个类都有一个静态的Class属性,该属性指向Class对象。

例如:

// 获取Book类的Class对象

Class<?> obj = Book.class;

上面的例句获取Book类的Class对象。

访问类的基础信息

使用Class对象可以直接访问类的基础信息,这些基础信息包括类名称、类所在的包名、类的哈希码。

Class类访问类基础信息的方法说明如下:

●   String  getName()

该方法用于返回类的名称,类的名称也包含包的路径。返回类型为字符串。

●   Package  getPackage()

该方法用于返回类所在的包,返回类型为Package类型。

●   int  hashCode()

该方法返回调用对象的哈希码,hashCode()方法是父类Object的方法。

案例4:建立ClassBasicInfo测试类,实例化Book类,输出Book类的基础信息。

在PUnit13项目新建info包,在info包下新建ClassBasicInfo类。代码如下:

package info;
 
import reflex.Book;
 
public class ClassBasicInfo {
    public static void main(String[] args) {
        // 实例化Book类
        Book book = new Book();
        // 获取book的class对象
        Class  bookClass = book.getClass();
        // 输出类的名称
        System.out.printf("book对象的类名:%s\n",bookClass.getName());
        // 输出类所在包的名称
        Package pack = bookClass.getPackage();
        System.out.printf("Book类所在的包名:%s\n",pack.getName());
        // 输出Class对象的哈希码
        System.out.printf("Book类Class对象的哈希码为:%s\n",bookClass.hashCode());
        // 输出book对象的哈希码
        System.out.printf("book对象的哈希码为:%s\n",book.hashCode());
 
 
    }
}

ClassBasicInfo程序首先实例化Book类,然后调用getClass()方法获取Book类的Class对象,分别输出book对象的类名、Book类所在的包名、Book类静态变量Class对象的哈希码、book对象的哈希码。

程序执行结果如下图所示:

03.png

访问类的构造方法

使用Class对象可以获取类定义的所有构造方法,获取的构造方法以Constructor类型的对象或数组方式返回,每个Constructor对象代表一个构造方法,利用Constructor提供的方法可以调用获取的构造方法来实例化类。

Class类定义了如下方法,用于访问类的构造方法。

●   Constructor<T>  getConstructor(Class<?>... parameterTypes)

该方法返回一个构造函数对象,该对象为由该类对象表示的类的指定公共构造函数。返回类型为Constructor类型。parameterTypes参数是一个类对象数组,它按声明的顺序标识构造函数的形式参数类型。如果参数为空,返回默认的构造方法。

●   Constructor<?>[]  getConstructor()

该方法返回一个数组,该数组包含反映该类对象所表示的类的所有公共构造函数的构造方法对象。如果类没有公共构造方法,则返回长度为0的数组。

●   Constructor<T>  getDeclaredConstructor(Class<?>... parameterTypes)

该方法返回一个类的构造方法,返回类型为Constructor类型。parameterTypes参数是一个类对象数组,它按声明的顺序标识构造方法的形式参数类型。

●   Constructor<?>[]  getDeclaredConstructors()

该方法返回一个构造函数对象数组,该数组包含由该类对象表示的类声明的所有构造方法。这些是公共、受保护、默认(包)访问和私有构造方法。

案例5:建立Person类,定义成员变量name(姓名),age(年龄)、job(职业)、income(收入),定义无参和有参三个构造方法。建立ConstructorTest1测试类,获取指定参数类型的构造方法。

在PUnit13项目新建constructor包,在constructor包下新建Person类。代码如下:

package constructor;
 
public class Person {
    // 姓名
    String  name;
    // 年龄
    int  age;
    // 职业
    public String  job;
    // 收入
    public double income;
 
    // 无参构造函数(public权限)
    public Person()
    {
        name = "";
        age = 0;
        job = "";
        income = 0.0;
    }
 
    // 有参构造函数(public权限)
    public Person(String name,int age)
    {
        this.name = name;
        this.age = age;
        job = "";
        income = 0.0;
 
    }
 
    // 有参构造函数(protected权限)
    protected Person(String name,int age,String job,double income)
    {
        this.name = name;
        this.age = age;
        this.job = job;
        this.income = income;
    }
 
    /**
     * @return the name
     */
    public String getName() {
        return name;
    }
 
    /**
     * @param name the name to set
     */
    public void setName(String name) {
        this.name = name;
    }
 
    /**
     * @return the age
     */
    public int getAge() {
        return age;
    }
 
    /**
     * @param age the age to set
     */
    public void setAge(int age) {
        this.age = age;
    }
 
    /**
     * @return the job
     */
    public String getJob() {
        return job;
    }
 
    /**
     * @param job the job to set
     */
    public void setJob(String job) {
        this.job = job;
    }
 
    /**
     * @return the income
     */
    public double getIncome() {
        return income;
    }
 
    /**
     * @param income the income to set
     */
    public void setIncome(double income) {
        this.income = income;
    }
 
    /**
     * 输出类成员变量的值
     */
    public void showPerson()
    {
        System.out.println("name:" + this.name);
        System.out.println("age:" + this.age);
        System.out.println("job:" + this.job);
        System.out.println("income:" + this.income);
    }
 
 
 
}

Person类定义了三个构造方法,其中两个构造方法是public访问权限,一个构造方法是protected访问权限,定义一个protected访问权限的构造方法,主要是区分Class类的getConstructor()和getDeclaredConstructor()方法的区别。

在constructor包下新建ConstructorTest1测试类。代码如下:

package constructor;
 
import java.lang.reflect.Constructor;
 
public class ConstructorTest1 {
    public static void main(String[] args) {
        // 获取Person类的Class对象
        Class<?>  personClass = (Class)Person.class;
        try {
            // 获取指定参数类型具有public权限的构造方法
            Constructor paramConstructor1 = personClass.getConstructor(String.class, int.class);
            System.out.println("通过class.getConstructor(args...)获取带参数的构造方法:" + paramConstructor1);
            // 获取指定参数类型且对访问权限无限制的构造方法
            Constructor paramConstructor2 = personClass.getDeclaredConstructor(String.class, int.class,String.class,double.class);
            System.out.println("通过class.getDeclaredConstructor(args...)获取带参数的构造方法:" + paramConstructor2);
        } catch (NoSuchMethodException | SecurityException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
 
    }
}

ConstructorTest1程序使用Class类的getConstructor()方法和getDeclaredConstructor()方法,来获取Person类的构造方法。这两个方法的区别是:getConstructor()方法获取该类的公共构造函数;getDeclaredConstructor可以获取类的公共、受保护、默认(包)访问和私有构造函数。两种方法传入的参数类型要和构造方法的参数类型一致,参数声明顺序也要相同。

getConstructor()和getDeclaredConstructor()方法会抛出NoSuchMethodException或SecurityException异常,因此程序需要对这两种异常进行处理。

Constructor类提供了对构造方法的操作,可以获取构造方法的相关信息,并可以通过获取的构造方法实例化类。Constructor类在java.lang.reflect包内,需要使用import语句导入Constructor类。

案例6:建立ConstructorTest2测试类,获取Person类的所有构造方法。

package constructor;
 
import java.lang.reflect.Constructor;
 
public class ConstructorTest2 {
    public static void main(String[] args) {
        // 获取Person类的Class对象
        Class<?>  personClass = (Class)Person.class;
        //通过class.getConstructors()获取所有具有public权限的构造方法
        Constructor[] constructors = personClass.getConstructors();
        for (Constructor constructor : constructors) {
            System.out.println("通过class.getConstructors()获取所有具有pubic权限的构造方法:" + constructor);
        }
        //通过class.getDeclaredConstructors获取所有构造方法
        Constructor[] constructors1 = personClass.getDeclaredConstructors();
        for (Constructor constructor : constructors1) {
            System.out.println("通过class.getConstructors()获取所有构造方法:" + constructor);
        }
 
    }
}

ConstructorTest2程序使用Class类的getConstructors()方法获取Person类具有类的公共构造方法,使用Class类的getDeclaredConstructors()方法获取Person类的所有构造方法,这两个方法返回Constructor类型的数组。

程序执行结果如下图所示:

04.png

构造方法的相关操作

Constructor类提供了对构造方法的操作方法,利用这些方法可以获取构造方法的参数、修饰符,并可以通过获取的构造方法实例化类。

获取构造方法的参数

应用Constructor类可以获取构造方法的参数个数、参数名称和参数类型。方法说明如下。

●   String  getName()

该方法用于获取构造方法的名称。

●   int  getParameterCount()

该方法用于获取构造方法参数的个数。

●   Class<?>[]   getParameterTypes()

该方法返回类对象数组,该数组按构造方法参数的声明顺序,包含了构造方法的参数类型。

案例7:建立ConstructorTest3测试类,获取Person类所有构造方法的名称、参数个数和参数名称。

在constructor包下新建ConstructorTest3测试类。代码如下:

package constructor;
 
import java.lang.reflect.Constructor;
 
public class ConstructorTest3 {
    public static void main(String[] args) {
        // 获取Person类的Class对象
        Class<?>  personClass = (Class)Person.class;
        //通过class.getDeclaredConstructors获取所有构造方法
        Constructor[] constructors1 = personClass.getDeclaredConstructors();
        for (Constructor constructor : constructors1) {
            System.out.println("-------构造方法-------");
            System.out.println("构造方法名称:" + constructor.getName());
            System.out.println("构造方法参数个数:" + constructor.getParameterCount());
            // 如果是有参构造方法,输出构造方法的参数
            if( constructor.getParameterCount() > 0 )
            {
                //通过constructor.getParameterTypes()获取参数类数组(Class)
                Class[] paramClasses = constructor.getParameterTypes();
                int nParamCount = 1;
                for (Class paramClass : paramClasses) {
                    System.out.printf("参数%d:%s\n",nParamCount,paramClass.getName());
                    nParamCount++;
                }
            }
        }
 
    }
}

ConstructorTest3程序首先应用Class类的getDeclaredConstructors()方法获取Person类的所有构造方法,然后输出每个构造方法的名称和参数个数,如果是有参构造方法,再应用Constructor类的getParameterTypes()方法获取该构造方法的所有参数,输出每个参数的名称。getParameterTypes()方法返回的是Class对象数组,数组的每个元素是参数的Class对象。

程序执行结果如下图所示:

05.png

获取构造方法的修饰符

Constructor类的getModifiers()方法返回一个整数,该整数可用于Modifier类定义方法的传入参数。

Constructor类的getModifiers()方法说明如下。

●   int  getModifiers()

该方法返回一个整数,该整数可用于Modifier获取修饰符方法的传入参数。

Modifier类定义了多个静态方法用于获取当前对象修饰符信息,Modifier类的主要方法说明如下。

●   boolean  isPublic(int mod)

该方法用于判断当前对象是否使用public访问权限修饰符,如果是返回true,否则返回false。mod值由对象的getModifiers()方法返回。

●   boolean  isProtected (int mod)

该方法用于判断当前对象是否使用protected访问权限修饰符,如果是返回true,否则返回false。mod值由对象的getModifiers()方法返回。

●   boolean  isPrivate (int mod)

该方法用于判断当前对象是否使用private访问权限修饰符,如果是返回true,否则返回false。mod值对象的getModifiers()方法返回。

●   boolean  isStatic (int mod)

该方法用于判断当前对象是否使用static修饰符,如果是返回true,否则返回false。mod值由对象的getModifiers()方法返回。

●   boolean  isFinal (int mod)

该方法用于判断当前对象是否使用static修饰符,如果是返回true,否则返回false。mod值由对象的getModifiers()方法返回。

●   boolean  isAbstract (int mod)

该方法用于判断当前对象是否使用abstract修饰符,如果是返回true,否则返回false。mod值由对象的getModifiers()方法返回。

●   boolean  isInterface (int mod)

该方法用于判断当前对象是否使用interface修饰符,如果是返回true,否则返回false。mod值由对象的getModifiers()方法返回。

●   String  toString (int mod)

该方法以字符串的方式返回当前对象的所有修饰符。mod值由对象的getModifiers()方法返回。

案例8:建立ConstructorTest4测试类,获取Person类所有构造方法的修饰符。

在constructor包下新建ConstructorTest4测试类。代码如下:

package constructor;
 
import java.lang.reflect.Constructor;
import java.lang.reflect.Modifier;
 
public class ConstructorTest4 {
    public static void main(String[] args) {
        // 获取Person类的Class对象
        Class<?> personClass = (Class) Person.class;
        // 通过class.getDeclaredConstructors获取所有构造方法
        Constructor[] constructors1 = personClass.getDeclaredConstructors();
        for (Constructor constructor : constructors1) {
            System.out.println("-------构造方法-------");
            // 获取可以解析构造方法修饰符需要的整数
            int mod = constructor.getModifiers();
            System.out.println("构造方法的修饰符:" + Modifier.toString(mod));
 
        }
 
    }
}

ConstructorTest4程序应用Constructor类getModifiers()方法,获取可以解析构造方法修饰符需要的整数,然后调用Modifier类的toString()方法以字符串方式输出构造方法的修饰符。

用构造方法实例化类

应用Constructor类可以应用构造方法来实例化类。实例化类方法说明如下:

●   T  newInstance(Object... initargs)

该方法用指定的参数创建该类的一个实例化对象,如果参数错误,会抛出IllegalArgumentException异常。

案例9:建立ConstructorTest5测试类,获取Person类的构造方法并实例化Person对象。

在constructor包下新建ConstructorTest5测试类。代码如下:

package constructor;
 
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
 
public class ConstructorTest5 {
    public static void main(String[] args) {
        // 获取Person类的Class对象
        Class<?> personClass = (Class) Person.class;
        // 获取指定参数类型具有public权限的构造方法
        try {
            Constructor paramConstructor = personClass.getConstructor(String.class, int.class);
            //通过constructor.newInstance(args...)以指定构造方法进行对象实例化
            Person person = (Person) paramConstructor.newInstance("张三", 36);
            if( null != person )
            {
                System.out.println("person对象的哈希码:" + person.hashCode());
                System.out.println("person对象的成员变量name:" + person.getName());
                System.out.println("person对象的成员变量age:" + person.getAge());
            }
        } catch (NoSuchMethodException | SecurityException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (InstantiationException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (IllegalArgumentException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (InvocationTargetException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
 
    }
}

ConstructorTest5程序应用Class类的getConstructor()方法获取指定参数的构造方法,然后调用Constructor类的newInstance()方法实例化Person对象。newInstance()方法会抛出IllegalArgumentException等异常,因此在程序中需要处理这些异常。

程序执行结果如下图所示:

06.png

访问类的成员变量

使用Class对象可以获取类定义的所有成员变量,获取的成员变量以Field类型的对象或数组方式返回,每个Field对象代表一个成员变量,利用Field对象提供的方法可以操作该类的成员变量。

Class类定义了如下方法,用于访问类的成员变量。

●   Field[]  getFields()

该方法返回一个包含类成员变量对象的数组,该数组包含该类对象表示的类或接口的所有可访问的公共成员变量。

●   Field  getField(String name)

该方法返回一个类成员变量对象,该成员变量对象必须是公共成员。name参数是一个字符串,指定所需成员变量的名称。

●   Field[]  getDeclaredFields()

该方法返回一个类成员变量对象数组,该数组包括该类的所有成员变量。这包括公共、受保护、默认(包)访问和私有成员变量,但不包括继承的成员变量。

●   Field  getDeclaredField(String name)

该方法返回一个类成员变量对象。name参数是一个字符串,指定所需字段的简单名称。

案例10:建立FieldTest1测试类,应用Class类的getFields()方法获取Person类的成员变量。

在PUnit13项目新建field包,在field包下新建FieldTest1类。代码如下:

package field;
 
import constructor.Person;
 
import java.lang.reflect.Field;
 
public class FieldTest1 {
    public static void main(String[] args) {
        // 获取Person类的Class对象
        Class<?>  personClass = (Class) Person.class;
 
        try {
            //通过class.getFields()获取所有具有public权限的成员变量
            Field[] fields = personClass.getFields();
            for (Field field : fields) {
                System.out.println("通过class.getFields()获取所有具有public权限的成员变量:" + field);
            }
            //通过class.getField(name)获取指定名称的成员变量
            //成员变量必须是public访问权限
            Field field1 = personClass.getField("job");
            System.out.println("通过class.getField(name)获取指定名称的成员变量" + field1);
 
            //通过class.getDeclaredFields获取所有的成员变量
            Field[] fields1 = personClass.getDeclaredFields();
            for (Field dfield : fields1) {
                System.out.println("通过class.getDeclaredFields获取所有的成员变量:" + dfield);
            }
 
            //通过class.getDeclaredField(name)获取指定名称的成员变量
            Field field2 = personClass.getDeclaredField("name");
            System.out.println("通过class.getDeclaredField(name)获取指定名称的成员变量" + field2);
        } catch (NoSuchFieldException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (SecurityException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
 
 
    }
}

FieldTest1程序应用Person类的静态成员变量class获取Class对象,分别调用Class类的getFields()、getField()、getDeclaredFields()、getDeclaredField()方法获取Person类的成员变量。

getField()方法和getDeclaredField()方法的区别是:getField()方法用于获取类或接口的所有可访问的公共成员变量;getDeclaredField()方法可以获取包括公共、受保护、默认(包)访问和私有成员变量,但不包括继承的成员变量。

程序执行结果如下图所示:

07.png

成员变量相关操作

Field类提供了对类成员变量的操作方法,应用这些方法可以获取成员变量的名称、类型、值,也可以设置成员变量的值。Field类在java.lang.reflect包内。

Field类定义的主要方法说明如下。

●   String  getName()

该方法用于获取成员变量的名称。

●   Class<?>  getType()

该方法用于获取成员变量的类型。

●   Object   get(Object obj)

该方法用于获取指定对象成员变量的值,返回类型是Object类型。

●   void  set(Object obj, Object value)

该方法用于设置指定对象成员变量的值,参数value为要设定的值。

●   byte  getByte(Object obj)

该方法用于获取指定对象成员变量类型为byte的值,返回类型为byte。

●   void  setByte(Object obj, byte b)

该方法用于设置指定对象成员变量类型为byte的值,参数b为要设定的值。

●   int  getInt(Object obj)

该方法用于获取指定对象成员变量类型为int的值,返回类型为int。

●   void  setInt(Object obj, int i)

该方法用于设置指定对象成员变量类型为int的值,参数i为要设定的值。

●   float  getFloat(Object obj)

该方法用于获取指定对象成员变量类型为float的值,返回类型为float。

●   void  setFloat(Object obj, float f)

该方法用于设置指定对象成员变量类型为float的值,参数f为要设定的值。

●   double  getDouble(Object obj)

该方法用于获取指定对象成员变量类型为double的值,返回类型为double。

●   void  setDouble(Object obj, double d)

该方法用于设置指定对象成员变量类型为double的值,参数d为要设定的值。

●   char  getChar(Object obj)

该方法用于获取指定对象成员变量类型为char的值,返回类型为char。

●   void  setChar(Object obj, char c)

该方法用于设置指定对象成员变量类型为char的值,参数c为要设定的值。

●   boolean  getBoolean (Object obj)

该方法用于获取指定对象成员变量类型为boolean的值,返回类型为boolean。

●   void  setBoolean (Object obj, boolean z)

该方法用于设置指定对象成员变量类型为boolean的值,参数z为要设定的值。

●   int  getModifiers()

该方法返回一个整数,该整数可用于Modifier获取修饰符方法的传入参数。

案例11:建立FieldTest2测试类,应用Class类的getFields()方法获取Person类的公共成员变量,输出每个成员变量的类型和修饰符,并设置成员变量的值。

在field包下新建FieldTest2类。代码如下:

package field;
 
import constructor.Person;
 
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
 
public class FieldTest2 {
    public static void main(String[] args) {
        // 获取Person类的Class对象
        Class<?>  personClass = (Class) Person.class;
        try {
            // 获取默认构造方法
            Constructor defaultConstructor = personClass.getConstructor();
            // 实例化Person对象
            Person person = (Person)defaultConstructor.newInstance();
            //通过class.getFields()获取所有具有public权限的成员变量
            Field[] fields = personClass.getFields();
            for (Field field : fields) {
                // 输出成员变量的名称
                System.out.printf("成员变量:%s\n",field.getName());
                // 获取和设置成员变量的值
                if( field.getName().equals("job") )
                {
                    System.out.printf("成员变量%s的值为:%s\n",field.getName(),field.get(person));
                    field.set(person,"程序员");
                }
                if( field.getName().equals("income") )
                {
                    System.out.printf("成员变量%s的值为:%.2f\n",field.getName(),field.getDouble(person));
                    field.setDouble(person, 15000);
                }
            }
            // 输出person对象成员变量job和income的值
            System.out.printf("成员变量%s的值为:%s\n","job",person.getJob());
            System.out.printf("成员变量%s的值为:%.2f\n","income",person.getIncome());
 
        } catch (NoSuchMethodException | SecurityException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (InstantiationException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (IllegalArgumentException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (InvocationTargetException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
 
    }
}

FieldTest2程序首先获取Person类默认的构造方法,并应用Constructor类的newInstance()方法实例化Person对象。然后调用Class类的getFields()方法获取Person类的公共成员变量,依据获取的变量名称获取变量成员的默认值和设置成员变量的值。Field类的get和set成员变量的方法都需要传入前面实例化的person对象。

程序执行结果如下图所示:

08.png

访问类的成员方法

使用Class对象可以获取类定义的所有成员方法,获取的成员方法以Method类型的对象或数组方式返回,每个Method对象代表一个成员方法,利用Method对象提供的方法可以操作该类的成员方法。

Class类定义了如下方法,用于访问类的成员方法。

●   Method[]  getMethods()

该方法返回包含方法对象的数组,该数组包含该类对象表示的类或接口的所有公共方法,包括由该类或接口声明的方法和从超类和超接口继承的方法。

●   Method  getMethod(String name, Class<?>... parameterTypes)

该方法返回一个方法对象,该方法对象由该类对象表示的类或接口的指定公共成员方法。name参数是方法的名称,parameterTypes参数是一个类对象数组,它按声明的顺序标识方法的形式参数类型,如果方法没有参数,该参数可以为空。

●   Method[]  getDeclaredMethods()

该方法返回一个包含方法对象的数组,该数组包含该类对象表示的类或接口的所有声明方法,包括公共、受保护、默认(包)访问和私有方法,但不包括继承的方法。

●   Method getDeclaredMethod (String name, Class<?>... parameterTypes)

该返回一个方法对象,该方法对象由该类对象表示的类或接口的指定声明方法。name参数是方法的名称,parameterTypes参数是一个类对象数组,它按声明的顺序标识方法的形式参数类型,如果方法没有参数,该参数可以为空。

案例12:建立MethodTest1测试类,应用Class类的getMethod()和getDeclaredMethods()等方法获取Person类的成员方法。

在PUnit13项目新建method包,在method包下新建MethodTest1类。代码如下:

package method;
 
import constructor.Person;
 
import java.lang.reflect.Method;
 
public class MethodTest1 {
    public static void main(String[] args) {
        // 获取Person类的Class对象
        Class<?> personClass = (Class) Person.class;
 
        try {
            // 通过class.getMethods()获取所有具有public权限的成员方法
            Method[] methods = personClass.getMethods();
            for (Method method : methods) {
                System.out.println("通过class.getMethods()获取所有具有public权限的成员方法:" + method);
            }
            // 通过class.getMethod(name)获取指定名称的成员方法
            // 成员方法必须是public访问权限
            Method method1 = personClass.getMethod("showPerson");
            System.out.println("通过class.getMethod(name,parameterTypes)获取指定名称的成员方法" + method1);
 
            // 通过class.getDeclaredMethods获取所有的成员方法
            Method[] methods1 = personClass.getDeclaredMethods();
            for (Method dmethod : methods1) {
                System.out.println("通过class.getDeclaredMethods获取所有的成员方法:" + dmethod);
            }
 
            // 通过class.getDeclaredMethod(name,parameterTypes)获取指定名称的成员方法
            Method method2 = personClass.getDeclaredMethod("setName",String.class);
            System.out.println("通过class.getDeclaredField(name,parameterTypes)获取指定名称的成员方法" + method2);
        } catch (SecurityException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (NoSuchMethodException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
 
 
    }
}

MethodTest1程序程序应用Person类的静态成员变量class获取Class对象,分别调用Class类的getMethods()、getMethod()、getDeclaredMethods()、getDeclaredMethod()方法获取Person类的成员方法。

Method类在java.lang.reflect包内,需要使用import语句导入Method类。

程序执行结果如下图所示:

09.png

成员方法的相关操作

Method类提供了对类成员方法的操作方法,应用这些方法可以获取成员方法的名称、参数个数、参数类型,也可以执行方法。Method类在java.lang.reflect包内。

Method类定义的主要方法说明如下。

●   String  getName()

该方法用于获取成员方法的名称。

●   Class<?>[]   getParameterTypes()

该方法返回一个类对象数组,该数组按声明顺序存储该方法的形式参数类型。

●   int  getParameterCount()

该方法返回方法的参数个数。

●   Class<?>  getReturnType()

该方法返回一个类对象,该类对象表示此方法的返回类型。

●   Object  invoke(Object obj, Object... args)

该方法用于执行obj对象上的方法,方法的参数由args指定。

●   Class<?>[] getExceptionTypes()

该方法返回一个类对象数组,该数组表示由该方法可能引发的异常类型。

●   int  getModifiers()

该方法返回一个整数,该整数可用于Modifier获取修饰符方法的传入参数。

案例13:建立MethodTest2测试类,应用Class类的getMethods()方法获取Person类的公共成员方法,输出每个成员方法的名称、返回类型、参数个数和参数类型。

在method包下新建MethodTest2测试类。代码如下:

package method;
 
import constructor.Person;
 
import java.lang.reflect.Method;
 
public class MethodTest2 {
    public static void main(String[] args) {
        // 获取Person类的Class对象
        Class<?> personClass = (Class) Person.class;
        // 通过class.getDeclaredMethods获取所有的成员方法
        Method[] methods = personClass.getDeclaredMethods();
        for (Method method : methods) {
            System.out.println("-------成员方法-------");
            // 输出方法名称
            System.out.println("方法名称:" + method.getName());
            // 输出方法的返回类型
            System.out.println("方法返回类型:" + method.getReturnType());
            // 输出方法的参数个数
            System.out.println("方法参数个数:" + method.getParameterCount());
            // 输出方法的参数类型
            if( method.getParameterCount() > 0 )
            {
                //通过method.getParameterTypes()获取参数类数组(Class)
                Class[] paramClasses = method.getParameterTypes();
                int nParamCount = 1;
                for (Class paramClass : paramClasses) {
                    System.out.printf("参数%d:%s\n",nParamCount,paramClass.getName());
                    nParamCount++;
                }
            }
 
        }
 
    }
}

MethodTest2程序首先获取Person类的Class对象,然后调用Class对象的getDeclaredMethods()获取Person类的所有成员方法。遍历getDeclaredMethods()方法返回的Method类型的成员方法数组,在遍历过程中,输出每个方法的名称、返回类型、参数个数和参数类型。

程序执行结果如下图所示:

10.png

案例14:建立MethodTest3测试类,获取Person类的构造方法并实例化person对象。获取Person对象成员变量的set方法,并执行set方法。获取person对象的showPerson方法,并执行该方法。

在method包下新建MethodTest3测试类。代码如下:

package method;
import constructor.Person;
import java.lang.reflect.Method;
public class MethodTest3 {
    public static void main(String[] args) {
        try {
            // 获取Person类的Class对象
            Class<?> classPerson = Class.forName("constructor.Person");
            //设置Person类的setName方法名
            String setName = "setName";
            //设置Person类的setAge方法名
            String setAge = "setAge";
            //设置Person类的setJob方法名
            String setJob = "setJob";
            //设置Person类的setIncome方法名
            String setIncome = "setIncome";
            //设置Person类的showPerson方法名
            String showPerson = "showPerson";
            // 实例化Person对象
            Person person = (Person)classPerson.newInstance();
            //使用Class对象的getMethod方法获取Person类的公开方法
            Method methodName = classPerson.getMethod(setName,String.class);
            // 使用Method的invoke方法执行methodName
            methodName.invoke(person,"张三");
            //使用Class对象的getMethod方法获取Person类的公开方法
            Method methodAge = classPerson.getMethod(setAge,int.class);
            // 使用Method的invoke方法执行methodAge
            methodAge.invoke(person,26);
            //使用Class对象的getMethod方法获取Person类的公开方法
            Method methodJob = classPerson.getMethod(setJob,String.class);
            // 使用Method的invoke方法执行methodJob
            methodJob.invoke(person,"工程师");
            //使用Class对象的getMethod方法获取Person类的公开方法
            Method methodIncome = classPerson.getMethod(setIncome,double.class);
            // 使用Method的invoke方法执行methodIncome
            methodIncome.invoke(person,150000);
            //使用Class对象的getMethod方法获取Person类的公开方法
            Method methodShowPerson = classPerson.getMethod(showPerson);
            methodShowPerson.invoke(person);
        } catch (Exception ex) {
            ex.printStackTrace();
        }
    }
}

MethodTest3程序应用Class类的静态方法forName()获取Person类的Class对象,并实例化person对象。然后应用Class对象的getMethod()方法获取person对象的成员变量的set()方法,并应用Method类的invoke()方法执行set()方法。最后执行person对象的showPerson()方法。

程序执行结果如下图所示:

11.png

代码在线纠错(通义千问 qwen-max)

支持粘贴多个代码文件,提交后由阿里云通义千问自动分析代码漏洞、语法错误、逻辑问题并给出修改建议。
您已解锁 AI 代码纠错功能,可正常使用!

评论区

登录 后发表评论
暂无评论