java 反射运用
一,获取私有的属性,方法,构造器(俗名:暴力反射)
现有一个类,属性,方法,构造器均为私有的,如何创建实例对象,更该属性值,调用方法?
public class student { private string name; private int age; private student() { system.out.println("调用了student()无参私有构造器"); } private string info() { system.out.println("调用了info()无参私有方法"); return "student [name=" + name + ", age=" + age + "]"; } private void look(string str) { system.out.println("调用了look(string str)参数为string类型的私有方法,参数为:"+str); } }
main方法:
首先要创建student类的实例对象,即调用该类私有的构造方法
public static void main(string[] args) { try { //1.首先要创建student类的实例对象 //1.1创建student类的反射对象 class<student> clazz = student.class; //1.2获取私有构造器 constructor<student> c0 = clazz.getdeclaredconstructor(); //1.3设置访问权限 c0.setaccessible(true); //1.4创建实例对象 student student = c0.newinstance(); } catch (exception e) { e.printstacktrace(); } }
运行,控制台输出结果:
调用了student()无参私有构造器
证明调用了student类的构造器,并创建了该类的一个实例对象
更改,获取该类的私有属性
public static void main(string[] args) { try { //1.首先要创建student类的实例对象 //1.1创建student类的反射对象 class<student> clazz = student.class; //1.2获取私有构造器 constructor<student> c0 = clazz.getdeclaredconstructor(); //1.3设置访问权限 c0.setaccessible(true); //1.4创建实例对象 student student = c0.newinstance(); //获取私有属性 name field name = clazz.getdeclaredfield("name"); //设置访问权限 name.setaccessible(true); //为该对象的该属性赋值 name.set(student, "张三"); field age = clazz.getdeclaredfield("age"); age.setaccessible(true); age.set(student, 18); //获取该属性的值:get(实例对象) object nameval = name.get(student); system.out.println("name:"+nameval); object ageval = age.get(student); system.out.println("age:"+ageval); } catch (exception e) { e.printstacktrace(); } }
运行结果:
调用了student()无参私有构造器 name:张三 age:18
调用私有方法
public static void main(string[] args) { try { //1.首先要创建student类的实例对象 //1.1创建student类的反射对象 class<student> clazz = student.class; //1.2获取私有构造器 constructor<student> c0 = clazz.getdeclaredconstructor(); //1.3设置访问权限 c0.setaccessible(true); //1.4创建实例对象 student student = c0.newinstance(); //获取私有属性 name field name = clazz.getdeclaredfield("name"); //设置访问权限 name.setaccessible(true); //为该对象的该属性赋值 name.set(student, "张三"); field age = clazz.getdeclaredfield("age"); age.setaccessible(true); age.set(student, 18); //获取该属性的值:get(实例对象) object nameval = name.get(student); system.out.println("name:"+nameval); object ageval = age.get(student); system.out.println("age:"+ageval); //获取info方法 method infomethod = clazz.getdeclaredmethod("info"); //设置访问权限 infomethod.setaccessible(true); //执行该方法,获取返回值 object inforet = infomethod.invoke(student); //打印返回值 system.out.println(inforet); //获取look方法 method lookmethod = clazz.getdeclaredmethod("look", string.class); //设置访问权限 lookmethod.setaccessible(true); //执行该方法,传参 lookmethod.invoke(student, "hello world"); } catch (exception e) { e.printstacktrace(); } }
运行结果:
调用了student()无参私有构造器 name:张三 age:18 调用了info()无参私有方法 student [name=张三, age=18] 调用了look(string str)参数为string类型的私有方法,参数为:hello world
小结:通过java反射机制,可以调用任意类中的任意修饰符的属性,方法,构造器
java的反射机制跟封装冲突吗?
一个房子,没有门,没有窗户,但我为了进去,只能穿墙了...
二,通过反射机制灵活调用(多态)
先上一组简单代码
public interface father { void look(); string see(string str); } public class aaa implements father{ @override public void look() { system.out.println("this is aaa look()"); } @override public string see(string str) { system.out.println("this is aaa see()"); system.out.println("str is " + str); return str; } } public class bbb implements father{ @override public void look() { system.out.println("this is bbb look()"); } @override public string see(string str) { system.out.println("this is bbb see()"); system.out.println("str is " + str); return str; } } public class test01 { public static void main(string[] args) { father a = new aaa(); a.look(); string seea = a.see("hello"); system.out.println(seea); system.out.println("=================="); father b = new bbb(); b.look(); string seeb = b.see("hello"); system.out.println(seeb); } }
打印结果:
this is aaa look() this is aaa see() str is hello hello ================== this is bbb look() this is bbb see() str is hello
当我们需要在程序运行时,有选择性的调用aaa类或bbb类
即:运行时编译,我们增加一个工厂类
public class factory { public static father getinstance(string classname) { if("aaa".equals(classname)) { return new aaa(); }else if("bbb".equals(classname)) { return new bbb(); }else { return null; } } }
在main方法中调用:
public static void main(string[] args) { //可从外部获取(properties文件,数据库,或其他方法返回值) string classname = "bbb"; father a = factory.getinstance(classname); a.look(); string seea = a.see("hello"); system.out.println(seea); }
这样,我们就可以在运行时选择性的创建对象了
这和反射有什么关系呢?
假设,需求变更,要增加一个ccc类,同样实现了father接口,并也动态调用
需要修改的代码:
//增加一个ccc类,实现father接口 public class ccc implements father{ @override public void look() { system.out.println("this is ccc look()"); } @override public string see(string str) { system.out.println("this is ccc see()"); system.out.println("str is " + str); return str; } } //修改factory工厂类,增加ccc类的创建方法 public class factory { public static father getinstance(string classname) { if("aaa".equals(classname)) { return new aaa(); }else if("bbb".equals(classname)) { return new bbb(); }else if("ccc".equals(classname)){ return new ccc(); }else { return null; } } }
注意:在实际项目中,修改一个已经运行成功没问题的方法,是存在风险的,改完万一出错了呢...(程序员都懂...)
所以,在这里如果使用反射机制,就更加灵活,以下代码举例说明
public class factory { public static father getinstance(string classname) { father f = null; // if("aaa".equals(classname)) { // return new aaa(); // }else if("bbb".equals(classname)) { // return new bbb(); // }else if("ccc".equals(classname)){ // return new ccc(); // }else { // return null; // } try { f = (father)class.forname(classname).newinstance(); } catch (exception e) { e.printstacktrace(); } return f; } }
public class test01 { public static void main(string[] args) { //可从外部获取(properties文件,数据库,或其他方法返回值) string classname = "com.dream.springboot.test.clazztest.bbb"; father f = factory.getinstance(classname); f.look(); string see = f.see("hello"); system.out.println(see); } }
在factory工厂类中,使用全类名获取实例,这样避免了增加类时就修改factory类中的方法,可减少错误,也减少工作量
总结:反射就是当詹姆斯·高斯林给你关了一扇门,又给你打开的一扇窗
代码上传地址:https://download.csdn.net/download/lijian0420/10803158
上一篇: 一场雪过后
下一篇: 发发牢骚,做需求真是太难了
推荐阅读