Java程序在运行时,Java运行时系统一直对所有的对象进行所谓的运行时类型标识。这项信息纪录了每个对象所属的类。虚拟机通常使用运行时类型信息选准正确方法去执行,用来保存这些类型信息的类是Class类。Class类封装一个对象和接口运行时的状态,当装载类时,Class类型的对象自动创建。 Class 没有公共构造方法。Class 对象是在加载类时由 Java 虚拟机以及通过调用类加载器中的 defineClass 方法自动构造的,因此不能显式地声明一个Class对象。 虚拟机为每种类型管理一个独一无二的Class对象。也就是说,每个类(型)都有一个Class对象。运行程序时,Java虚拟机(JVM)首先检查是否所要加载的类对应的Class对象是否已经加载。如果没有加载,JVM就会根据类名查找.class文件,并将其Class对象载入。 基本的 Java 类型(boolean、byte、char、short、int、long、float 和 double)和关键字 void 也都对应一个 Class 对象。 每个数组属于被映射为 Class 对象的一个类,所有具有相同元素类型和维数的数组都共享该 Class 对象。 一般某个类的Class对象被载入内存,它就用来创建这个类的所有对象。
注意:
Class类对象不同于普通的一个类的实例对象,Class类对象只是用来获取该类的内容的,具体的操作还是由一个类的实例来完成
获取Class类对象的方式
public class Demo1 {
Person p ;
public static void main(String[] args) throws Exception {
//方式1:通过Class.forName获取Class对象.
Class clazz1 = Class.forName("cn.itcast.reflect.Person");
System.out.println("clazz1:"+clazz1.getSimpleName());
//方式2:可以通过类名获取Class对象。
Class clazz2 = Person.class;
System.out.println("是同一个对象吗?"+(clazz1==clazz2));
//方式3: 可以通过对象获取Class对象
Class clazz3 = new Person().getClass();
System.out.println("是同一个对象吗:"+ (clazz2 == clazz3));
}
}
通过Class对象获取构造方法------Constructor 类
public class Demo2 {
public static void main(String[] args) throws Exception {
Class clazz = Class.forName("cn.itcast.reflect.Person");
//通过class对象找到所有的构造方法。
//获取所有构造方法
Constructor[] constructors = clazz1.getConstructors(); //只获取了公共的构造方法。
Constructor[] constructors = clazz1.getDeclaredConstructors(); //获取一个类的所有构造方法,包括私有的。
for(Constructor constructor : constructors){
System.out.println(constructor);
}
//获取单个构造方法
Constructor constructor = clazz.getConstructor(String.class,int.class);
//通过Constructor对象创建对象。
Person p = (Person) constructor.newInstance("狗娃",12);
System.out.println(p);
//获取私有构造方法
Constructor constructor = clazz.getDeclaredConstructor(null);
//通过获取私有构造方法权限来创建对象(暴力反射)
constructor.setAccessible(true);
Person p = (Person) constructor.newInstance(null);
System.out.println(p);
}
}
通过Class对象获取成员函数------Method类
public class Demo3 {
public static void main(String[] args) throws Exception {
Class clazz = Class.forName("cn.itcast.reflect.Person");
//获取所有的方法
Method[] methods = clazz.getMethods(); // 获取所有公共 的方法,包括继承下来的方法。
Method[] methods = clazz.getDeclaredMethods(); //获取所有的方法,包括私有的,但是不包括继承下来的方法。
for(Method m : methods){
System.out.println(m);
}
//获取单个方法
Method m = clazz.getMethod("eat", int.class,String[].class) ; //第一个参数是方法名, 第二参数是形参列表的数据类型。
//执行一个方法
Person p = new Person("狗娃",12);
m.invoke(p, 3,new String[]{"aa","bb"}); //第一个参数:方法的调用者对象, 第二参数: 方法执行所需要的参数。
//获取一个静态方法
Method m = clazz.getMethod("sleep", int.class);
//执行静态方法
m.invoke(null, 23);
//获取私有的方法
Method m = clazz.getDeclaredMethod("study", null);
//设置方法的访问权限是可以访问
m.setAccessible(true);
m.invoke(p, null);
}
}
通过Class对象获取一个类的成员变量------Field类
public class Demo4 {
public static void main(String[] args) throws Exception {
Class clazz = Class.forName("cn.itcast.reflect.Person");
//获取该类的所有成员变量
Field[] fields = clazz.getDeclaredFields();
for(Field field : fields){
System.out.println(field);
}
Person p = new Person("狗剩",12);
//获取私有成员变量
Field nameField = clazz.getDeclaredField("name");
nameField.set(p, "铁蛋"); // 第一个参数: 对象, 第二参数:成员变量的值。
System.out.println(p);
}
}
练习:
用反射的知识点从一个配置文件中读取一个类的数据然后实现工厂设计模式
import java.lang.reflect.*;
import java.lang.reflect.InvocationTargetException;
import java.security.KeyStore.Entry;
import java.util.*;
import com.wxhl.jq0804.Person;
public class Demo07 {
public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, SecurityException, InstantiationException, IllegalAccessException, IllegalArgumentException, InvocationTargetException, NoSuchFieldException, IOException {
Person p = (Person)getInstance("D:/Person.properties");
System.out.println(p);
}
public static Object getInstance(String path) throws IOException, ClassNotFoundException, NoSuchMethodException, SecurityException, InstantiationException, IllegalAccessException, IllegalArgumentException, InvocationTargetException, NoSuchFieldException{
//创建配置文件
Properties properties = new Properties ();
//创建管道
FileReader fileReader = new FileReader(path);
//加载配置文件
properties.load(fileReader);
//从配置文件中创建Class类
String className = properties.getProperty("class");
Class clazz = Class.forName(className);
Constructor constructor = clazz.getConstructor();
Object obj = constructor.newInstance();
//遍历配置文件
Set<java.util.Map.Entry<Object, Object>> entrySet = properties.entrySet();
for(java.util.Map.Entry entry : entrySet){
String tmp = (String)entry.getKey();
if ("class".equals(entry.getKey())){//之前使用了这个key,所以这里得跳过
continue;
}
//获取所有属性(包括私有)
Field field = clazz.getDeclaredField((String) entry.getKey());
field.setAccessible(true);
//为属性赋值
if (field.getType()==int.class){
field.set(obj, Integer.parseInt((String) entry.getValue()));
}else if (field.getType()==float.class){
field.set(obj, Float.parseFloat((String) entry.getValue()));
}else if (field.getType()==double.class){
field.set(obj, Double.parseDouble((String) entry.getValue()));
}else if (field.getType()==boolean.class){
field.set(obj, Boolean.parseBoolean((String) entry.getValue()));
}else{
field.set(obj, (String) entry.getValue());
}
}
return obj;
}
}