反射概念
❶ Java程序可以在运行时加载、探知、使用编译期间完全位置的classes。也就是说Java程序可以加载一个在运行时才得知名称的class,获悉其完整构造(constructors、fields、methods),并生成其对象实体、或对其fields设值、或调用其methods。这种编程机制称为Java反射机制。
反射用途
❶ 反射通常由需要检查或修改Java虚拟机中运行的应用程序的运行时行为的程序使用。 这是一个相对高级的功能,只应由对语言基础有很深了解的开发人员使用。 考虑到这一警告,反射是一种强大的技术,可以使应用程序执行原本不可能的操作。
❷ 可以通过使用类全名创建类实例来使用外部用户定义的类
❸ 开发类浏览器和智能IDE
❹ 在测试工具中用于检测类的内部结构
❺ 在框架开发中用于实现配置信息的处理
❻ 实现Java的动态代理
反射的缺点
反射是强大的,但不应该不分青红皂白地使用。如果无需使用反射即可执行操作,则最好避免使用反射。在通过反射访问代码时,应牢记以下注意事项。
❶ 性能开销
由于反射涉及动态解决的类型,因此无法执行某些 Java 虚拟机优化。因此,反光操作的性能比非反光操作慢,在对性能敏感的应用程序中经常称为代码的部分中应避免。
❷ 安全限制
反射需要在安全管理器下运行时可能不存在的运行时权限。这是代码的一个重要考虑因素,代码必须在受限的安全环境中运行,例如在 Applet 中运行。
❸ 内部暴露
由于反射允许代码执行非反光代码中非法的操作,例如访问字段和方法,因此使用反射可能导致意外的副作用,从而可能使代码功能失调,并可能破坏便携性。反射码(Reflective code)会破坏抽象,因此可能会随着平台的升级而改变行为。
反射实践
在实战之前先补充一些知识点。如下:
java.lang.Class类是所有Reflection API的切入点,是所有反射操作的入口
在Java程序运行的过程中,对程序中的每种类型的对象,Java虚拟机都会实例化一个不可变的java.lang.Class实例,每个对象都是引用或者原始类型
简单来讲,就每个类型的对象都会有对应的Class实例。
获取Class类实例的三种方法,如下:
☞ 对象名.getClass()
☞ 类型名.class
☞ Class.forName()
接下来开始实战~~
上面是获取对象的Class实例的各种样例,接下来讲其中一种例子,因为反射的原理都是一样的。
import static java.lang.System.out;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.Scanner;
public class Main {
private static String s;
public static void Look()
{
try {
@SuppressWarnings("rawtypes")
Class c =Class.forName(s);
out.println("***************输出公共的属性Field****************");
Field[] fs=c.getFields();
for(Field f:fs)
{
System.out.println(f.toGenericString());
}
out.format("%n%n");
out.println("***************所有公共的Constructor****************");
@SuppressWarnings("rawtypes")
Constructor[] cons=c.getConstructors();
for(@SuppressWarnings("rawtypes") Constructor con:cons)
{
out.println(con.toGenericString());
}
out.format("%n%n");
out.println("***************所有本类自己定义的方法Method****************");
Method[] ms=c.getDeclaredMethods();
for(Method m:ms)
{
System.out.println(m.toGenericString());
}
} catch (ClassNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
public static void main(String[] args) {
// TODO Auto-generated method stubs
@SuppressWarnings("resource")
Scanner scanner = new Scanner(System.in);
System.out.println("请输入类名");
s=scanner.next();
Look();
}
}
具体更多的方法(例如获取这个类的所有公共方法,甚至是父类里面的东西等等)可以去其他网站查阅,这里就不细讲了。
或许都会有一个疑惑,就是我们通过获得对象的Class实例,然后知道了里面有哪些属性、方法等,但是我们怎么去用它呢?接来下我们通过代码来发掘问题。
Student 类
public class Student {
private String name; // Field(别名:属性,成员变量,数据成员,字段)
public Student(String name) { // Constructor(别名:构造方法,构造函数)
super();
this.name = name;
}
public Student() {
super();
}
public String getName() {// Method(别名:方法,成员方法,成员函数)
return name;
}
public void setName(String name) {
this.name = name;
}
public void setName() {
this.name = "zhangsan";
}
public String tString() {
return "学生的姓名是:" + name;
}
public String toString() {
return "学生的姓名是:" + name;
}
}
Main 类
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
public class Main {
public static void main(String[] args) {
// TODO Auto-generated method stub
try {
/*创建Class实例*/
Class c = Class.forName("inflect2.Student");
/*获取构造函数的方法,可以有参数,可以无参。具体可以通过IDE看看底层实现。*/
Constructor cons = c.getDeclaredConstructor();
/*这里就是通过调用 newInstance() 的方法来进行创建对象*/
Object o =cons.newInstance();
/*获取Class实例里面的一个方法,方法名叫 tString*/
Method p=c.getDeclaredMethod("tString");
/*用反射技术给属性赋值,这个是直接给属性赋值
获取属性*/
Field f=c.getDeclaredField("name");
/*setAccessible 方法下面会讲到*/
f.setAccessible(true);
/*对 o 这个对象里面的属性name 赋值为"一开始是小明"*/
f.set(o, "一开始是小明");
/*执行方法时用invoke方法,这里主要是验证是否成功赋值*/
System.out.println(p.invoke(o));
/*用反射技术调用方法给属性赋值
获取方法名为 setName,并且这个方法有一个参数,是String类型的*/
Method m=c.getDeclaredMethod("setName",String.class);
m.invoke(o, "后面变小红");
System.out.print(p.invoke(o));
} catch (ClassNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (NoSuchMethodException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (SecurityException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (InstantiationException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IllegalAccessException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IllegalArgumentException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (InvocationTargetException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (NoSuchFieldException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
还有很多很多的执行方法,其他看其他网址吧