- 一、前言
- 二、案例
- 三、详解
一、前言:
在说明Class类的静态方法forName()之前,先清楚有关Class类的几个概念:
1、 Class类封装了类或接口的运行时状态
Java程序在运行时,Java运行时系统一直对所有的对象进行所谓的运行时类型标识,这些标示纪录了每个对象所属的类。
虚拟机通常使用运行时类型信息选择正确方法去执行,用来保存这些类型信息的类是Class类。
2、Class类型的对象,是加载类时自动创建的
Class 没有公共构造方法。Class 对象是在加载类时,由Java 虚拟机以及通过调用类加载器中的 defineClass 方法自动构造的,因此不能显式地声明一个Class对象。
3、虚拟机为每种类型管理一个独一无二的Class对象
每个类(型)都有一个Class对象。
运行程序时,Java虚拟机(JVM)首先检查所要加载的类对应的Class对象是否已经加载。如果没有加载,JVM就会根据类名查找.class文件,并将其Class对象载入。
1.基本的 Java 类型(boolean、byte、char、short、int、long、float 和 double)和关键字 void 也都对应一个 Class 对象。
2.每个数组属于被映射为 Class 对象的一个类,所有具有相同元素类型和维数的数组都共享该 Class 对象。
3.一般某个类的Class对象被载入内存,它就用来创建这个类的所有对象。
以上说法查看Class源码会发现,
Book.class.getName()
最终调用的:
private transient String name;
public String getName() {
String name = this.name;
if (name == null)
this.name = name = getName0();
return name;
}
此时Book也是一个独一无二的Class对象,即对象中的对象。
二、案例:
Book.java类
package com.junit.demo;
public class Book {
private static final String defName = "《程序猿植发》";
static {
System.out.println("我是静态代码块,输出: " + defName);
}
//打印生产日期:
public static String printProduceDate(String name) {
return "我是静态方法printProduceDate,输出: " + name + ", produce is:" + System.currentTimeMillis();
}
private String name;
public Book() {
System.out.println("我是Book声明的构造方法!");
name = defName;
}
public String toString(String msg) {
return name + msg;
}
}
执行方法:
public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, InvocationTargetException, IllegalAccessException, InstantiationException {
//1-将指定类加载到JVM中(ClassNotFoundException)
Class aClass = Class.forName("com.junit.demo.Book");
System.out.println(aClass);
//2.1-访问静态方法:NoSuchMethodException,InvocationTargetException
Method method = aClass.getMethod("printProduceDate", String.class);
String result = (String) method.invoke(aClass, "《程序猿的颈椎自传》");
System.out.println(result);
System.out.println("---------------------------\n");
//2.2-初始化对象:
Book obj = (Book) aClass.newInstance();
System.out.println("得到对象后访问get方法:" + obj.toString(""));
System.out.println("---------------------------\n");
//2.3-初始化对象后访问方法:
Method method3 = aClass.getMethod("toString", String.class);
String result3 = (String) method3.invoke(aClass.newInstance()/*obj*/, "这本书是我的伙伴!");
System.out.println(result3);
System.out.println("---------------------------\n");
System.out.println(Book.class.getName());
}
输出:
我是静态代码块,输出: 《程序猿植发》
class com.junit.demo.Book
我是静态方法printProduceDate,输出: 《程序猿的颈椎自传》, produce is:1626682894095
---------------------------
我是Book声明的构造方法!
得到对象后访问get方法:《程序猿植发》
---------------------------
我是Book声明的构造方法!
《程序猿植发》这本书是我的伙伴!
---------------------------
com.junit.demo.Book
三、详解:
1、访问静态方法:
// 由Class获取方法:第一个参数为方法名,第二个参数为方法的参数类型。
// 如add(int a,int b)则getMethod("add",int.class,int.class)。当然,也可以是Java对象。
Method method = aClass.getMethod("printProduceDate", String.class);
// 引用方法:(引用实例/调用静态方法可为null,参数值/有多个用逗号隔开),参数值要和参数类型的数量匹配!
String result = (String) method.invoke(aClass, "《程序猿的颈椎自传》");
简写:
2、访问实例方法:
- 重要:
aClass.newInstance();
,实例化指定对象。
和 new Book() 效果一样。
//方法一:直接转化实例化后的对象,直接调用方法
Book book= (Book) aClass.newInstance();
// book.setName('xxx'); or book.getName(); or more...
//方法二:使用invoke调用指定实例a的指定方法b
Method method3 = aClass.getMethod("toString", String.class);
//这里的book可以是已实例化的对象,或者使用 aClass.newInstance() 传入,详见简写:
String result3 = (String) method3.invoke(book, "这本书是我的伙伴!");
简写:
值得注意的是,如果是类似于工具类可用于全部类访问的,可以使用一个实例化对象,而不需要每次都newInstance。
另外,方法一适用于需要映射的类是已知或少数时,反之需要统一按指定字符串反射调用方法的话,需使用方法二。
end.