在运行状态中,对于任意一个类都能够知道这个类所有的属性和方法;并且对于任意一个对象,都能够调用它的任意一个方法;这种动态获取信息以及动态调用对象方法的功能称为Java语言的反射机制
类加载机制
反射机制
获取Class实例的三种常见方式
- Class class1=类名.class;(这种情况写死类名,体现不出反射的动态性,一般不推荐)
- Class class2=对象.getClass();(联想equals()方法重写中的判断)
- Class class3=Class.forName(String classPath);(最常用,体现反射的动态性)
Class类的理解
Class的实例对应着加载到内存中的一个运行时类。 该类作为Class类的一个对象,我们可以根据Class的实例来调用运行时类的结构。
创建Class对应运行时类对象的通用方法
class.newInstance();
- 必须有空参构造器
- 权限修饰符的权限要够。通常设为public
Class类的常用方法
获取属性
getFields() -所有可访问的公共字段
getDeclaredFields() -所有字段
getField(String name) -返回一个特定的公共Field对象Field.getName()-显示为该类的属性名字,前面没有“class”修饰
获取方法
getMethods()-所有公共方法,包括从超类和超接口继承的声明
getDeclaredMethods() -所有方法,包括公共,保护,默认(包)访问和私有方法,但不包括继承的方法
getMethod(String name, Class[] parameterTypes)-返回一个方法对象Method.getName()-显示为该类的方法名字,前面没有“class”修饰
获取构造器
getConstructor(Class[] parameterTypes)-返回一个构造方法对象
调用运行时类结构
定义的Person类:
public class Person extends Creature<String>implements Comparable<String>,MyInterface{
private String name;
int age;
public int id;
@Override
public String toString() {
return "Person{" +
"name='" + name + '\'' +
", age=" + age +
", id=" + id +
'}';
}
public Person(){
}
private Person(String name){
this.name=name;
}
Person(String name,int age){
this.name=name;
this.age=age;
}
private String show(String nation){
System.out.println("我的国籍是:"+nation);
return nation;
}
public String display(String interests){
return interests;
}
@Override
public void info() {
System.out.println("为人");
}
@Override
public int compareTo(String o) {
return 0;
}
private static void showDesc(){
System.out.println("你好可爱!");
}
}
反射测试类:
//调用运行时类中指定的结构:属性、方法、构造器
public class ReflectionTest {
@Test
public void testField() throws Exception {
Class pClass = Person.class;
Person p = (Person) pClass.newInstance();
//获取指定的属性:要求运行时类中的属性声明为public,通常不采用此方法。
Field id = pClass.getField("id");
/*
设置当前属性值
set():参数1:指明哪个对象的属性 参数2:设置此属性值
*/
id.set(p, 1001);
/*
设置当前属性值
set():参数1:获取哪个对象的属性
*/
int i = (int) id.get(p);
System.out.println(i);
}
//如何操作运行时类中的指定的属性
@Test
public void testField1() throws Exception {
Class pClass = Person.class;
Person p = (Person) pClass.newInstance();
Field name = pClass.getDeclaredField("name");
//保证当前属性是可访问的;
//name.setAccessible(true);
name.set(p,"Sam");
System.out.println(name.get(p));//会报错!访问权限只能为public和上面方法一样。怎样解决这个问题?
}
//如何操作运行时类中的指定的属性
@Test
public void testField2() throws Exception {
Class pClass = Person.class;
//非静态方法必须要创建运行时类对象
Person p = (Person) pClass.newInstance();
//获取指定的方法
//getDeclaredMethod() 参数1:指明获取的方法的名称 参数2:指明获取方法的形参列表类型
//invoke():参数1:方法的调用者 参数2:给方法形参赋值的实参。invoke() 方法的返回值即为对应类中调用方法的返回值。
Method show = pClass.getDeclaredMethod("show", String.class);
//保证当前属性是可访问的;
show.setAccessible(true);
String returnValue = (String)show.invoke(p, "CHN");//同样是权限原因报错!
System.out.println(returnValue);
System.out.println("**********如何调用静态方法************");
Method showDesc = pClass.getDeclaredMethod("showDesc");
showDesc.setAccessible(true);
String showD = (String) showDesc.invoke(Person.class);
// String showD = (String) showDesc.invoke(null);
System.out.println(showD);//调用的方法无返回值,输出为null
}
//如何操作运行时类中的指定的构造器
//getDeclaredConstructor() 参数:指明获取构造器的形参列表类型。比方法少一个形参,因为构造器和类名同名。
@Test
public void testField3() throws Exception {
Class pClass = Person.class;
Constructor declaredConstructor = pClass.getDeclaredConstructor(String.class);
//保证此构造器可访问
declaredConstructor.setAccessible(true);
//调用此构造器创建运行时类的对象
Person p = (Person) declaredConstructor.newInstance("Jerry");
System.out.println(p);
}
}