一,获取私有的属性,方法,构造器(俗名:暴力反射)

现有一个类,属性,方法,构造器均为私有的,如何创建实例对象,更该属性值,调用方法?

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

最新文章

  1. Slyx_SerAddGet
  2. 【转】Struts1.x系列教程(3):属性(资源)文件乱码问题的解决之道
  3. XDocument 获取包括第一行的声明(版本、编码)的所有节点
  4. Android之SQLite
  5. 【转载】干货再次来袭!Linux小白最佳实践:《超容易的Linux系统管理入门书》(连载八)用命令实现批量添加用户
  6. 解决Maven不能下载“oracle、aspectjweaver、com.springsource.net.sf.cglib”jar
  7. Android开发之通过Intent启动其他App的Service
  8. nginx-rrd监控nginx访问数
  9. java部分基础总结
  10. hdu2108 Shape of HDU 极角排序判断多边形
  11. 安卓高级3 RecyclerView结合SwipeRefreshLayout并添加上拉
  12. Winfon 页签切换及窗体控件自适应
  13. 缓冲区 subprocess 黏包
  14. IDEA创建第一个项目详细过程
  15. adt安装----只为测试使用adb命令,故无需安装过于复杂
  16. js 匿名函数立即执行问题
  17. bzoj2154: Crash的数字表格 莫比乌斯反演
  18. Python开发【模块】:Urllib(一)
  19. javascript使用bind指定接收者
  20. 【深入理解JAVA虚拟机】第4部分.程序编译与代码优化.2.运行期优化。这章提到的具体的优化技术,应该对以后做性能工作会有帮助。

热门文章

  1. jQuery的each内部的break,continue
  2. E20170616-hm
  3. VBNET AUTOCAD NETAPI 让插件随autocad启动
  4. Glide和Picassio的比较
  5. Linux学习之路2 Bash的基本操作
  6. 410 Split Array Largest Sum 分割数组的最大值
  7. 有符号char转无符号short
  8. mysql-installer-web-community-5.7.18.1.msi的安装(图文详解)
  9. Python学习日记之记录
  10. MySQL与MongoDB的操作对比