老王:小王呀,听说你酒量不错
小王:酒量还行
老王:能喝多少
小王:白的可以喝一斤吧
老王:这酒量不错哦,看你酒量不错,那你就给我来讲一讲java的反射机制吧
小王:(懵逼中,我酒量不错和java的反射机制有什么关系)这个...........
老王:怎么了,酒量这么好java的反射机制都不知道?
小王:好吧
老王:你怎么理解反射的?反射有什么作用?
小王:我们不使用方式这种方式想获取某一个类的对象,我们只有通过new(new 类名())的方法得到该类的对象,使用反射我们可以不使用new(new 类名())的这种方式,从而创建类的对象,还可以调用该类的方法(包括私有方法)也可以获取或者设置该类的成员变量值(包括私有成员变量)
老王:反射第一步是干什么?
小王:先获取类的class对象
老王:如何获取呢?获取类的class对象有几种方式呢?
小王:三种方式, 方式1:Class clazz = 对象名.getClass(); 方式2:Class clazz = 类名.class; 方式3:Class clazz = Class.forName(“类全名”);
老王:那你觉得哪一个方式比较好,比较常用呢?
小王:我本人觉得第三种方式比较好,也比较常用, 评价:
方式一:既然我已经有该类的对象了,那我为什么还要通过发送来调用他的方法呢,为什么不直接调用呢?这种方式只有可以调用private修饰的方法。
方式二:如果你一个类的构造方法被private修饰的,那么方式一肯定是使用不了了,因为你不能直接创建该类的对象,只有通过暴力反射(暴力反射就是指调用该类私有的方法和属性)的方式去创建该类的对象, 所以可以使用第二种方式。
方式三:我觉得方式三功能最强大,我可以不知道该类的类名是什么就可以调用该类的方法和属性,很多框架中也是使用第三种方式,并且方式三比较灵活,我可以把全类名写在配置文件中,读取配置文件,获取全类名创建对象,这个是方式二和方式一都做不到的。
老王: 那你能不能跟我讲一下框架中是如何使用这种反射呢?框架中的代码是别人已经写好的哦,他怎么知道你配置的那个类中有什么方法呢?也不知道你那个方法中有什么参数,方式调用方法是要传入方法名和参数类型的Class对象的哦。
小王:这个简单,框架中一般都需要你实现指定的接口,实现接口中的抽象方法,而接口是框架的开发者写的,他肯定知道方法名和参数类型是什么呀。
老王:你理论掌握还不错,那你可以用代码写一下吗?把常用的操作写出来。
小王:我可以明天写吗?现在已经下班了。
老王:年轻人别种急着下班,现在你还年轻,要努力学习,为以后技术做铺垫。
小王:沉默中..........
老王:那你现在就去写吧,写完给我看一下。
小王:努力敲码中.................................................
反射中常用的方法
// 获得Class对象
Class<Student> c = Student.class;
// 获得类名字符串
System.out.println(c.getSimpleName());
// 获得类全名字符串
System.out.println(c.getName());
通过去反射调用构造方法创建对象
/*
反射操作public修饰的构造方法
*/
@Test
public void test01()throws Exception{
// 获得Class对象
Class c = Student.class;
// 获得两个参数构造方法对象 里面的参数为,你调用的构造方法里面需要参数类型的Class对象
Constructor conn = c.getConstructor(String.class, int.class);
// 根据参数创建学生对象
Object stu02 = conn.newInstance("老王",20);
System.out.println(stu02);
}
/*
反射操作private修饰的构造方法
*/
@Test
public void test02()throws Exception{
// 获得Class对象
Class c = Student.class;
// 获得一个参数构造方法对象
Constructor con = c.getDeclaredConstructor(String.class);
// 暴力反射(设置取消权限检查)
con.setAccessible(true);
// 创建对象
Object stu = con.newInstance("老王");
System.out.println(stu);
}
/*
反射之获得所有构造方法对象
*/
@Test
public void test03()throws Exception{
// 获得Class对象
Class c = Student.class;
// 获得所有构造方法对象:只能获得public修饰的
// Constructor[] cons = c.getConstructors();
// 获得所有构造方法对象:包括private修饰的
Constructor[] cons = c.getDeclaredConstructors();
for (Constructor con : cons) {
System.out.println(con);
}
}
小王:王哥写好了,给您
老王:(认真的看了看)你这个好像没有写完呀,还有通过反射调用方法和通过反射给变量赋值和获取变量的值。
小王:我觉得他们和使用方式调用构造方法都差不多我就没有写了,方式调用构造方法使用 Constructor 类,反射调用方法使用 Method 类,方式操作变量使用 Field 对象,其余的都没有什么改变。
老王:照你这样说月薪3k和月薪2K也差不多咯?(露出了猥琐的笑容)
小王:(马上跑到电脑面前开始敲码中.............................)
反射调用方法
/*
反射操作public修饰的成员方法
*/
@Test
public void test01()throws Exception{
// 获得Class对象
Class c = Student.class;
// 创建学生对象
Object stu = c.newInstance();
// 获得有参数的study方法对应Method对象
Method studyMethod02 = c.getMethod("study",int.class);
// 传递参数调用方法
studyMethod02.invoke(stu,10);
}
/*
反射操作private修饰的成员方法
*/
@Test
public void test02()throws Exception{
// 获得Class对象
Class c = Student.class;
// 创建学生对象
Object stu = c.newInstance();
// 获得sleep方法对应Method对象
Method sleepMethod = c.getDeclaredMethod("sleep",String.class,int.class);
// 暴力反射
sleepMethod.setAccessible(true);
// 调用方法
sleepMethod.invoke(stu,"老王",8);
}
/*
反射操作static修饰的成员方法
*/
@Test
public void test03()throws Exception{
// 获得Class对象
Class c = Student.class;
// 获得静态方法对应的Method对象
Method drinkMethod = c.getDeclaredMethod("drink");
// 暴力方式
drinkMethod.setAccessible(true);
// 调用方法
drinkMethod.invoke(c);
}
/*
反射之获得所有成员方法对象
*/
@Test
public void test04()throws Exception{
// 获得Class对象
Class c = Student.class;
// 获得类所有的成员方法对象,返回数组,只能获取public修饰的, 包括父类的
// Method[] methods = c.getMethods();
// 获得类所有的成员方法对象,返回数组,包括private修饰的,只包括本类的
Method[] methods = c.getDeclaredMethods();
for (Method method : methods) {
System.out.println(method);
}
}
反射操作变量
/*
反射操作public修饰的成员变量
*/
@Test
public void test01()throws Exception{
// 获得Class对象
Class c = Student.class;
// 创建学生对象
Object obj = c.newInstance();
System.out.println(obj);
// 根据成员变量名获得field对象
Field field01 = c.getField("gender");
// 给obj对象的gender成员变量赋值
field01.set(obj, "男");
System.out.println(obj);
// 获得对象obj的gender成员变量值
Object result = field01.get(obj);
System.out.println(result);
}
/*
反射操作private修饰的成员变量
*/
@Test
public void test02()throws Exception{
// 获得Class对象
Class c = Student.class;
// 创建学生对象
Object obj = c.newInstance();
System.out.println(obj);
// 根据成员变量名获得field对象
Field ageField = c.getDeclaredField("age");
// 暴力反射
ageField.setAccessible(true);
// 给obj对象的age成员变量赋值
ageField.setInt(obj, 20);
System.out.println(obj);
// 获得对象obj的age成员变量值
int result = ageField.getInt(obj);
System.out.println(result);
}
/*
反射之获得所有成员变量对象
*/
@Test
public void test03()throws Exception{
// 获得Class对象
Class c = Student.class;
// 获得类所有的成员变量对象,只包括public修饰的
// Field[] fields = c.getFields();
// 获得类所有的成员变量对象,包括private修饰的
Field[] fields = c.getDeclaredFields();
for (Field field : fields) {
System.out.println(field);
}
}
小王:(高高兴兴的跑过去,感叹到终于可以下班了................)写好了,给我您
老王:(认真的查看中..................)小王不错哦,继续努力,不要总想着下班,年轻人就该好好努力,下次我把我女儿介绍给你。
小王:(猥琐的笑了一笑)我怕配不上你女儿。
晚上12点.....................................
老王:小王还不下班呀!
小王:我又没有女朋友,这么早下班也没事干,所以还是好好努力工作比较好。
老王:哈哈哈哈哈哈哈哈哈哈