1. 获取父类信息
在Class类中提供了一些方法来获取父类信息,以下列举出三个:
- 获取类的包名称:public Package getPackage()
- 取得父类的Class对象:public native Class<? super T> getSuperclass();
- 取得实现的父接口:public Class<?>[] getInterfaces()
举例:使用以上三个方法
public class TestReflect {
public static void main(String[] args) {
Class classz = Student.class;
//1.取得Student类的包名
Package packagez = classz.getPackage();
System.out.println(packagez.getName()); //www.csdn.classse
//2.获取Student父类的Class对象
Class superclass = classz.getSuperclass();
//类的权限定名称,包含包名 www.csdn.classse.Person
System.out.println(superclass.getName());
//只含类名称 Person
System.out.println(superclass.getSimpleName());
//3.取得Student类实现的接口
Class[] interfaces = classz.getInterfaces();
for(Class cls:interfaces){
System.out.println(cls.getSimpleName());
}
}
}
interface Message{}
interface Knowledge{}
class Person{}
class Student extends Person implements Message,Knowledge{}
2. 调用构造方法
一个类中可以有多个构造方法,如果想要取得类中的构造方法,就可以使用Class类中的两个构造方法:
- 取得指定参数类型的构造
public Constructor<T> getConstructor(Class<?>... parameterTypes)
throws NoSuchMethodException, SecurityException
- 取得类中的所有构造
public Constructor<?>[] getConstructors() throws SecurityException
举例:获取类中的构造方法
public class TestReflect {
public static void main(String[] args) {
Class personClass = Person.class;
//获取所有构造方法
Constructor[] constructors = personClass.getConstructors();
for (Constructor c:constructors){
System.out.println(c.getName()+" ("+Arrays.toString(c.getParameterTypes())+")");
}
System.out.println("------------");
//获取不同参数列表的构造方法
try {
Constructor constructor = personClass.getConstructor(String.class);
System.out.println(constructor.getName()+" ("+Arrays.toString(constructor.getParameterTypes())+")");
Constructor constructor1 = personClass.getConstructor(String.class, Integer.class);
System.out.println(constructor1.getName()+" ("+Arrays.toString(constructor1.getParameterTypes())+")");
} catch (NoSuchMethodException e) {
e.printStackTrace();
}
}
}
使用到的Person类:
public class Person {
private String name;
private Integer age;
public Person(){
}
public Person(String name) {
this.name = name;
}
public Person(String name, Integer age) {
this.name = name;
this.age = age;
}
@Override
public String toString() {
return "Person{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
}
之前通过反射实例化对象的时候,是通过Class对象调用newInstance()
方法实例化的。这其中必须保证该类是有一个无参构造的。但若此时我们在自定义Person类的时候,没有无参构造,则无法使用Class类调用。那么此时我们可以通过明确的调用构造实例化去处理。
Constructor中的newInstance方法:
public T newInstance(Object ... initargs)
throws InstantiationException, IllegalAccessException,
IllegalArgumentException, InvocationTargetException
举例:通过Constructor实例化对象
public class TestReflect {
public static void main(String[] args) {
Class personClass = Person.class;
try {
//取得指定参数列表的构造方法
Constructor constructor = personClass.getConstructor(String.class,Integer.class);
//利用构造方法实例化对象
Object object = constructor.newInstance("张三",20);
Constructor constructor1 = personClass.getConstructor(String.class);
Object object1 = constructor1.newInstance("张三");
System.out.println(object);
System.out.println(object1);
} catch (NoSuchMethodException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InstantiationException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}
}
}
public class Person {
private String name;
private Integer age;
public Person(String name) {
this.name = name;
}
public Person(String name, Integer age) {
this.name = name;
this.age = age;
}
@Override
public String toString() {
return "Person{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
}
3. 反射调用普通方法
在Class中有两种取得类中的普通方法的函数:
- 取得所有类中的普通方法
public Method[] getMethods() throws SecurityException
- 取得指定的普通方法
public Method getMethod(String name, Class<?>... parameterTypes)
throws NoSuchMethodException, SecurityException
举例:获取类中的普通方法
public class TestReflect {
public static void main(String[] args) {
Class personClass = Person.class;
//获取Person类中所有的方法
Method[] methods = personClass.getMethods();
for (Method m:methods){
System.out.println(m.getName()+"("+Arrays.toString(m.getParameterTypes())+")");
}
System.out.println("------------");
//获取Person类中指定的普通方法
try {
Method method = personClass.getMethod("setName", String.class);
System.out.println(method.getName()+"("+Arrays.toString(method.getParameterTypes()));
} catch (NoSuchMethodException e) {
e.printStackTrace();
}
}
}
在以前我们调用一个自定义类的setter和getter方法时,必须实例化该类的对象,用对象调用这些方法。现在通过反射,可以不用有明确的实例化对象,就可以调用方法。
在java.lang.reflect.Method
中提供了一个调用方法的支持:
public Object invoke(Object obj, Object... args)
throws IllegalAccessException, IllegalArgumentException,
InvocationTargetException
举例:使用反射去调用自定义类中的方法
public class TestReflect {
public static void main(String[] args) {
Class personClass = Person.class;
try {
//取得Class的实例化对象
Object object = personClass.newInstance();
//获取指定的方法,设置方法名称和参数类型
Method setMethod = personClass.getMethod("setName", String.class);
//用Method对象去调用指定方法,同时传入参数
setMethod.invoke(object,"张三"); //相当于person.setName("张三");
Method getMethod = personClass.getMethod("getName");
Object result = getMethod.invoke(object); //相当于person.getName();
System.out.println(result); //张三
System.out.println(object);
} catch (NoSuchMethodException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InstantiationException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}
}
}
4. 反射调用类中属性
在反射调用类中属性时,必须实例化对象,通过newInstance()
可以直接取得实例化对象(Object)。
在Class中提供了两组获得属性的方法:
- 取得类中(父类和子类)全部属性:public Field[] getFields()
- 取得类中(父类和子类)指定名称属性:public Field getField(String name)
- 取得类中(Class类对象的类型)全部属性:public Field[] getDeclaredFields()
- 取得指定类中(Class类对象的类型)的名称属性:public Field getDeclaredField(String name)
举例:使用两组方法
public class TestReflect {
public static void main(String[] args) {
Class<Student> studentClass = Student.class;
try {
Object object = studentClass.newInstance();
//获取所有属性,包括父类属性
Field[] fields = studentClass.getFields();
for (Field f :fields){
System.out.println(f.getName());
}
Field field = studentClass.getField("school");
System.out.println(field.getName());
System.out.println("--------------");
//获取Class对象的类的所有属性
Field[] fields1 = studentClass.getDeclaredFields();
for (Field f:fields1){
System.out.println(f.getName());
}
Field field1 = studentClass.getDeclaredField("school");
System.out.println(field1.getName());
} catch (InstantiationException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (NoSuchFieldException e) {
e.printStackTrace();
}
}
}
public class Person {
private String name;
public Integer age;
}
public class Student extends Person {
private String school;
}
在以上的过程中发现,如果想要得到父类的属性,必须属性是public
修饰的。而如果只是访问本类属性,private
修饰的也可以访问。所以常用的获取属性的方式为第二组。
另外,在java.lang.reflect.Field中有三个方法:
- 设置属性内容:
public void set(Object obj, Object value)
throws IllegalArgumentException, IllegalAccessException
- 取得属性内容:
public Object get(Object obj)
throws IllegalArgumentException, IllegalAccessException
- 取得属性类型
public Class<?> getType()
举例:使用上面的方法
class Person{
public String name;
private Integer age;
}
public class TestReflect {
public static void main(String[] args) {
Class<Person> personClass = Person.class;
try {
Object object = personClass.newInstance();
//获取指定属性
Field field = personClass.getDeclaredField("name");
//获取属性类型
System.out.println(field.getType().getName()); //java.lang.String
//设置属性内容
field.set(object,"张三"); //等价于person.name = "张三";
//取得属性内容
System.out.println(field.get(object)); //张三
} catch (InstantiationException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (NoSuchFieldException e) {
e.printStackTrace();
}
}
}
5. 总结
1. 在获取父类信息时,通过类对象调用Class类的方法,获取父类信息。在上面介绍的主要有三个:(1)获取包;(2)获取继承的父类;(3)获取实现的父类接口。
2. 对于获取构造方法,获取普通方法,获取属性,Class类都各自提供了2个方法。
3. 在通过反射实例化对象时,如果自定义类中含有无参构造,那么直接通过Class类中的newInstance()
方法去实例化对象;如果没有,则先取得指定参数列表的构造方法,在通过Constructor类
中的newInstance(Object...initargs)
去实例化对象。
4. 反射调用方法时,通过Method类
中的invoke(Object obj, Object...initargs)
,也可以同时传参。
这些方法都是很简单的,只要多用几次,就能熟练掌握!!!