/*本类用于反射技术的测试类*/
/*单元测试方法:是Java中最小的测试单位,使用灵活,推荐指数:5颗星
* 语法要求:public + void + 没有参数 + @Test 四个缺一不可
* 注意:使用时需要导包:Add JUnit4 to classpath
* 导包以后的效果:import org.junit.Test;
* 执行方式:成功运行后,方法名前面会有绿色的对勾提示
* */
/*测试1:通过单元测试方法,获取目标类Student对应的字节码对象*/
@Test
public void getClazz() throws ClassNotFoundException {
System.out.println(1/1);
//练习获取字节码对象的三种方式
Class<?> clazz = Class.forName("cn.tedu.reflection.Student");
Class<?> clazz1 = Student.class;
Class<?> clazz2 = new Student().getClass();
//直接打印字节码对象,注意前面有个class,这是对象
System.out.println(clazz);//class cn.tedu.reflection.Student 对象
//通过字节码对象获得的目标类Student的全路径名
System.out.println(clazz.getName());//cn.tedu.reflection.Student
//通过字节码对象获取目标类的类名
System.out.println(clazz1.getSimpleName());//Student
//通过字节码对象获取目标类的包对象
System.out.println(clazz2.getPackage());//package cn.tedu.reflection
//先通过字节码对象获取目标类的包对象,再通过包对象获取包名
System.out.println(clazz2.getPackage().getName());//cn.tedu.reflection
}
获取成员变量
/*测试2:通过反射技术,获取目标类中的成员变量*/
@Test
public void getFie() throws ClassNotFoundException {
//获取字节码对象
Class<?> clazz = Class.forName("cn.tedu.reflection.Student");
//通过字节码对象获取目标类中成员变量们
Field[] fs = clazz.getFields();
/*注意!目前我们只能获取到用public修饰的成员变量
* 比如默认或者private修饰符修饰的成员变量是获取不到的*/
//遍历数组,获取每个字段对象,并进行进一步操作
System.out.println(Arrays.toString(fs));//这个只是测试看一看
for (Field f:fs){
//通过本轮循环到的字段对象,进一步获取字段的名字与字段的类型
System.out.println(f.getName());
System.out.println(f.getType());
}
}
回顾数组练习
/*测试三:通过单元测试方法,练习引用类型数组的定义与遍历*/
@Test
public void getStu(){
//创建Student类对象的3个对象
Student s1 = new Student("李槐", 21);
Student s2 = new Student("李宝瓶",22);
Student s3 = new Student("林守一",28);
Student[] s = {s1,s2,s3};
//直接打印查看数组中的所有元素,可以重写toString看文字
System.out.println(Arrays.toString(s));//只能看一看.
//遍历数组,拿到每一个学生对象进一步操作
for (Student st:s){
System.out.println(st);//直接打印本轮循环到的学生对象
st.play();//通过本轮循环到的学生对象调用学生的play
System.out.println(st.age);//通过本轮循环到的学生对象查看属性值
}
获取成员方法
/*测试4:通过反射技术,获取目标类中的成员方法*/
@Test
public void getFuction(){
//获取字节码对象
Class<?> clazz = Student.class;
//通过字节码对象获取目标类中的成员方法们
Method[] ms = clazz.getMethods();
//通过高效for循环遍历数组,拿到每一个方法对象,做进一步操作
for (Method mt:ms){
System.out.println(mt);//查看循环获取到的每个方法对象
System.out.println(mt.getName());//通过方法对象,获取当前的方法名
Class<?>[] pt = mt.getParameterTypes();//通过方法对象获取当前方法的参数类型
System.out.println(Arrays.toString(pt));
}
}
获取构造方法
/*测试5:通过反射技术,获取目标类中的构造方法*/
@Test
public void getCons(){
//获取字节码对象
Class<?> clazz = new Student().getClass();
//通过字节码对象,获取目标类中的构造方法们
Constructor<?>[] cs = clazz.getConstructors();
//遍历构造函数数组,获取每一个构造函数对象,做进一步操作
for(Constructor ct:cs){
System.out.println(ct);
System.out.println(ct.getName());//通过遍历到的构造函数对象,获取构造函数名
Class[] pt = ct.getParameterTypes();//通过遍历到的构造函数对象,获取构造函数的参数类型
System.out.println(Arrays.toString(pt));
}
}
创建对象
/*测试6:通过反射技术,创建目标类Student的对象*/
@Test
public void getObject() throws Exception{
//获取字节码对象
Class<?> clazz = Student.class;
//通过字节码对象,创建目标类的对象,注意抛出异常
/*反射创建对象的方案1:通过字节码对象触发目标类中的无参构造来创建对象*/
Object o = clazz.newInstance();
//这一步已经通过无参构造创建好了对象:Student{name='null', age=0}
System.out.println(o);
/*反射创建对象的方案2:通过出发目标类中其他的含参构造来创建对象
* 思路:
* 1.先获取指定的构造函数对象,注意传入对应的构造函数参数,传入的是字节码对象
* 2.通过刚刚获取到的构造函数对象来创建目标类Student的对象*/
//获取目标类中指定的全参构造
Constructor<?> c = clazz.getConstructor(String.class,int.class);
//通过刚刚获取到的构造函数对象来创建目标类的对象
Object o1 = c.newInstance("赵六",7);
System.out.println(o1);
}
public void getOBject() throws Exception {
Class<?> clazz = Student.class;
Constructor<?> c = clazz.getConstructor(String.class);
Object o3 = c.newInstance("魏桀");
System.out.println(o3);
}