package com.wuya.reflection;
//用于测试反射需要准备的物料类
public class Student {
String name;
public int age;
private String addr;
public Student() {
}
public Student(String name, int age) {
super();
this.name = name;
this.age = age;
}
public Student(String name,int age,String addr) {
super();
this.name = name;
this.age = age;
this.addr = addr;
}
public void tell() {
System.out.println("tell()......");
}
@Override
public String toString() {
return "Student{" +
"name='" + name + '\'' +
", age=" + age +
", addr='" + addr + '\'' +
'}';
}
}
package com.wuya.reflection;
import org.junit.Test;
import java.lang.annotation.Annotation;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Arrays;
//测试 反射
public class Test1Reflect {
//1.通过单元测试获取类的字节码对象(类对象)
@Test
public void getClazz() throws ClassNotFoundException {
//1.1 获取Student类的字节码对象
Class<?> vs1 = Class.forName("com.wuya.reflection.Student");
Class<Student> vs2 = Student.class;
Class<? extends Student> vs = new Student().getClass();
//1.2调用方法
System.out.println(vs);//class com.wuya.reflection.Student 反射得到类的字节码Class对象
System.out.println(vs.getName()); //com.wuya.reflection.Student 获取类的全路径名
System.out.println(vs.getTypeName());//com.wuya.reflection.Student
System.out.println(vs.getSimpleName()); //Student 获取类名
System.out.println(vs.getPackage().getName());//com.wuya.reflection 获取包名
System.out.println(Arrays.toString(vs.getAnnotations()));//[] TODO getAnnotations()的返回值是数组
System.out.println(vs.getAnnotation(Annotation.class));//null TODO 终于会这个方法的传参了
}
//2.通过单元测试来获取构造方法
@Test
public void getConstructor() throws ClassNotFoundException, NoSuchMethodException {
Class<?> clazz = Class.forName("com.wuya.reflection.Student");
System.out.println(clazz.getConstructor(String.class,int.class));
//下面这行虽然也是获取构造方法们,但是它是字符串,只是能看一下,不能进一步操作;要操作还需进行遍历/循环
System.out.println(Arrays.toString(clazz.getConstructors()));//TODO getConstructors()的返回值是数组
//获取所以公开的构造方法们
Constructor<?>[] cs = clazz.getConstructors();
for (Constructor<?> c : cs) {
System.out.println(c.getName());//获取当前构造的名字
Class[] cps = c.getParameterTypes();//获取构造函数中的参数类型们
System.out.println(Arrays.toString(cps));
}
}
//3.获取成员方法
@Test
public void getMethod() throws NoSuchMethodException {
Class<Student> clazz = Student.class;
System.out.println(clazz.getMethod("tell"));//获取某一个方法,注意传参
Method[] ms = clazz.getMethods();
for (Method m : ms) {
System.out.println(m.getName());
System.out.println(Arrays.toString(m.getParameterTypes()));
}
}
//4.获取成员变量
@Test
public void getFields() throws NoSuchFieldException {
Class<? extends Student> clazz = new Student().getClass();
System.out.println(clazz.getField("age"));//TODO 必须是public修饰的变量才能获取到
System.out.println(clazz.getDeclaredField("name"));//TODO 暴力反射就无所谓了
Field[] fs = clazz.getDeclaredFields();//暴力反射
for (Field f : fs) {
System.out.println(f.getName());
System.out.println(f.getType().getName());//获取变量的类型
}
}
//5.反射创建对象
@Test
public void createObject() throws IllegalAccessException, InstantiationException, NoSuchMethodException, InvocationTargetException {
//5.1 获取类对象
Class<Student> clazz = Student.class;
//5.2 创建对象
//5.2.1 TODO 触发无参构造
Student s = clazz.newInstance();
System.out.println(s);//Student{name='null', age=0, addr='null'}
//5.2.2 TODO 根据方法的参数获取指定的构造方法
//传入的参数不是参数的直接类型,而是对应类型的字节码对象,如下:
//getConstructor(Class<?>... parameterTypes) 可见参数是"可变参数"--传入0个,1个...都行
Constructor<Student> c = clazz.getConstructor(String.class,int.class,String.class);
Student s2 = c.newInstance("张婕",56,"北京市中关村");
System.out.println(s2);//Student{name='张婕', age=56, addr='北京市中关村'}
//5.2.3 TODO 测试子类Student中的方法,用子类对象测;
// 如果 s 或 s2 是Object对象(父类对象)时,需要强转为Student类型
System.out.println(s2.age);//56
System.out.println(s2.name);//张婕
//System.out.println(s2.addr);//编译期报错,因为addr是私有属性
s2.tell();//tell()......
}
}