- 类的加载
当程序要使用某个类时,如果该类还未被加载到内存中,则系统会通过加载,连接,初始化三步来实现对这个类进行初始化。
加载:将class文件读入内存,并为之创建一个Class文件,任何类被使用时系统都会建立一个Class对象(由类加载器完成);
连接:验证,是否有正确的内部结构,并和其他类协调一致;准备,为类的静态成员分配内存,并设置默认初始化值;解析,将类的二进制数据中的符号引用替换为直接引用;
类加载器的组成:
Bootstrap ClassLoader 根类加载器:又称引导类加载器,负责java核心类的加载;
Extension ClassLoader 扩展类加载器:负责jre的扩展目录中jar包的加载;
System ClassLoader 系统类加载器:负责在jvm启动时加载来自java命令的class文件,以及classpath环境变量所制定的jar包和类路径。 - 什么是反射:Java反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法,对于任意一个对象,都能够调用它的任意一个方法和属性;这种动态获取的信息以及动态调用对象的方法的功能称为java语言的反射机制。
- 得到class文件对象,即得到Class类的对象,有三种方法:
① Object类中的getClass()方法:
Person p = new Person();
Class c=p.getClass();
②数据类型的静态属性class:
Class c = Person.class;
③Class类中的静态方法:
//public static class forName(string className)
//className为类的全路径
Class c = Class.forName("com.test.Person");
在开发中,我们一般使用第三种方式,因为这种方式的全路径为一个字符串,在开发中可以把这样的字符串配置到文件中,使用灵活。
package com.yx1213.reflect;
/**
* 获取class文件对象的三种方法
*
* @author Administrator
*
*/
public class ReflectTest1 {
public static void main(String[] args) throws ClassNotFoundException {
// 第一种方法:Object类中的getClass()方法
Person person = new Person();
Class class1 = person.getClass();
System.out.println("第一种:" + class1);
// 第二种方法:数据类型的静态属性class
Class class2 = Person.class;
System.out.println("第二种:" + class2);
// 第三种方法:Class类中的静态方法
// public static class forName(string className)
// className为类的全路径
Class class3 = Class.forName("com.yx1213.reflect.Person");
System.out.println("第三种:" + class3);
}
}
1、通过反射获取构造方法
现有一Person类:
package com.yx1213.reflect;
public class Person {
String name;
private int age;
public String addr;
public Person() {
}
private Person(String name) {
this.name = name;
}
public Person(String name, int age) {
this.name = name;
this.age = age;
}
public Person(String name, int age, String addr) {
this.name = name;
this.age = age;
this.addr = addr;
}
public void say(){
System.out.println("hello world!");
}
public void eat(String food){
System.out.println("eat"+food);
}
public String work(){
System.out.println("work");
return "success";
}
@Override
public String toString() {
return "Person [name=" + name + ", age=" + age + ", addr=" + addr + "]";
}
}
获取以及使用该类的构造方法:
package com.yx1213.reflect;
import java.lang.reflect.Constructor;
/*
* 通过反射获取构造方法
*/
public class ReflectTest2 {
public static void main(String[] args) throws Exception {
// 获取class对象
String className = "com.yx1213.reflect.Person";
Class class1 = Class.forName(className);
// public Constructor getConstructor(Class<?>... parameterTypes)
// 返回一个 Constructor 对象,它反映此 Class 对象所表示的类的指定公共构造方法。
// 获取无参构造方法
Constructor constructor = class1.getConstructor();
System.out.println(constructor);
// 根据所传形参的个数与类型,获取相应有参构造方法
Constructor constructor2 = class1.getConstructor(String.class,
int.class);
System.out.println("=================");
System.out.println(constructor2);
System.out.println("=================");
// public Constructor[] getConstructors()
// 返回一个包含某些 Constructor 对象的数组,
// 这些对象反映此 Class 对象所表示的类的所有公共构造方法。
Constructor[] constructors = class1.getConstructors();
for (Constructor cons : constructors) {
System.out.println(cons);
}
// getDeclaredConstructor与getConstructor相似,
// 返回一个 Constructor 对象,该对象反映此 Class 对象所表示的类或接口的指定构造方法
// getDeclaredConstructors与getConstructors相似
// 返回 Constructor 对象的一个数组,这些对象反映此 Class 对象表示的类声明的所有构造方法。
// Constructor类中一个方法:public T newInstance(Object... initargs)
// 使用此 Constructor 对象表示的构造方法来创建该构造方法的声明类的新实例,并用指定的初始化参数初始化该实例。
// 相当于Person person=new Person("张三",23);
Object obj = constructor2.newInstance("张三", 23);
System.out.println("**************");
System.out.println(obj);
}
}
2、 通过反射获取成员变量并使用
package com.yx1213.reflect;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
/*
* 通过反射获取成员变量
*/
public class ReflectTest3 {
public static void main(String[] args) throws Exception {
// 获取class对象
Class class1 = Class.forName("com.yx1213.reflect.Person");
// 通过反射获得无参构造方法创建对象
Constructor constructor = class1.getConstructor();
Object object = constructor.newInstance();
// public Field getField(String name)
// 返回一个 Field 对象,它反映此 Class 对象所表示的类或接口的指定公共成员字段。
// name 参数是一个 String,用于指定所需字段的简称。
Field field = class1.getField("addr");
// public void set(Object obj,Object value)
// 将指定对象变量上此 Field 对象表示的字段设置为指定的新值。
field.set(object, "深圳");
System.out.println(object);
// public Field getDeclaredField(String name)
// 返回一个 Field 对象,该对象反映此 Class 对象所表示的类或接口的指定已声明所有字段。
Field field2 = class1.getDeclaredField("name");
// 对私有变量要设置取消访问检查,否则会报java.lang.IllegalAccessException
field2.setAccessible(true);
field2.set(object, "李四");
System.out.println(object);
// public Field[] getFields()
// 返回一个包含某些 Field 对象的数组,这些对象反映此 Class 对象所表示的类或接口的所有可访问公共字段。
Field[] fields = class1.getFields();
for (Field fieldss : fields) {
System.out.println(fieldss);
}
// public Field[] getDeclaredFields()与getFields相似
// 返回 Field 对象的一个数组,这些对象反映此 Class 对象所表示的类或接口所声明的所有字段。
Field[] fields2=class1.getDeclaredFields();
System.out.println("================");
for (Field field3 : fields2) {
System.out.println(field3);
}
}
}
3、通过反射获取并使用成员方法
package com.yx1213.reflect;
import java.lang.reflect.Constructor;
import java.lang.reflect.Method;
public class ReflectTest4 {
public static void main(String[] args) throws Exception {
// 获取class对象
Class class1 = Class.forName("com.yx1213.reflect.Person");
// 通过反射获得无参构造方法创建对象
Constructor constructor = class1.getConstructor();
Object object = constructor.newInstance();
//public Method getDeclaredMethod(String name,Class<?>... parameterTypes)
//返回一个 Method 对象,该对象反映此 Class 对象所表示的类或接口的指定已声明方法。
//name 参数是一个 String,它指定所需方法的简称
//parameterTypes 参数是 Class 对象的一个数组,它按声明顺序标识该方法的形参类型。
Method method = class1.getDeclaredMethod("say");
//对私有方法要设置取消访问检查,否则会报java.lang.IllegalAccessException
method.setAccessible(true);
//public Object invoke(Object obj,Object... args)
//第一个形参对象是谁,第二个形参表示该方法所需要的实参
method.invoke(object);
//如果有参数的情况下
Method method2 = class1.getDeclaredMethod("eat",String.class);
method2.invoke(object,"苹果");
System.out.println("=============");
//有返回值的情况下
Method method3 = class1.getDeclaredMethod("work");
String st=(String) method3.invoke(object);
System.out.println("执行"+st);
}
}