今年暑期项目实训中我接到的任务是做整个项目的菜单界面。其中要利用到java中的反射机制,所以学习下这一个知识点。
实训任务要求:窗口中显示管理信息系统的功能菜单项,当用户要点击某个功能菜单项时,能够出现该功能相应的界面。
根据要求,或许有诸多解决方案,例如识别出用户点击哪个菜单项,然后再创建相应的类的对象,调用相应的方法,但是这种方案或编程复杂或代码垄杂,建议不要使用。最好的解决方案莫过于利用java的反射机制,动态的调用各个模块的类。
1、 什么是Java的反射机制?
Java反射机制是指程序在运行状态中,动态获取类中的所有信息以及动态调用对象方法的功能。
2、 java反射机制的原理是什么?
想要知道反射原理,我们就必须先来看java程序的执过程。想要java程序能够运行,java类必须被java虚拟机加载。运行程序都是在编译时就已经加载了所需要的类。我们在这先讲一下什么是编译:编译就是编辑器帮你把代码翻译成电脑可以识别的代码,编译器在编译时会做一些简单的工作,例如检查你的语法是否有误,关键字是否有错等,还有加载类。当你用eclipse(或其他高级编辑器)写好一个类时,你的程序其实已经做完了编译的功能。如果你用记事本写一个类,在Dos命令行下执行javac 类名.java时,就是在编译。编译好了后,那么程序就到运行了,运行时你的代码被装载到内存中,运行时的检查就是在你的内存中做操作与判断,下面举个例子:
int sun[] = new int[6];
sun[6] = 8;
上面的代码明显的是数组下标越界的错误,但是程序在编译时是不会出错的,在运行时却会出现错误的,报出ArrayIndexOutOfBountsException的异常,这个就是程序编译和运行时的区别。
但是java的反射机制在编译时是不能确定哪个类被加载进来了(和我上面任务要求一样,你现在编写的程序怎么能知道将来用户会点哪个菜单项,加载哪个类?),它是在程序运行的时候才加载和使用的(所以要用java的反射机制)。
3、 通过java的反射我们可以实现什么功能?
1、 在运行时判断任意一对象所属类。
2、 在运行时构造任意一个类的对象。
3、 在运行时,判断任意一个类所具有的属性和方法。
4、 在运行时调用任意一个对象的方法。
4、 java的反射常用的类
1、 Class类:java中反射的核心类,通过Class类可以获得类的属性,方法等内容。Class class = Class.forName(“类名”),加载类有多种方法,在这就用Class.forName()的方法吧!注意:类名必须是全名,也 就是 要有包名,如果你创建工程时建了包就加上,格式为:包名.类名,未加包就直接是类名称 即可。
2、 Filed类:表示类中的属性,可获得和更改类中属性的值。
Field field = class.getField(String name)//根据属性名,得到相应的属性。
Field[ ] field = class.getFields()//获得类中所有的public属性。
Field[ ] field = class.getDeclaredFields()//得到类中public和非public的属性。
Field field = class.getDeclareField(String name)//根据属性名,得到对应的public和非public的属性。
3、 Method类:表示类的方法,可以用来获取类中方法的信息和执行方法。
Method method =class.getDeclaredMethod(String name, Class[ ] params)//根据方法名和参数,得到指定的 public和非public的方法。
Method[ ] method =class.getDeclareMethods()//得到所有的public和非public的方法。
Method method =class.getMethod(String name, Class[ ] params)//根据方法名和参数,得到指定的公共方法。
Method[ ] method =class.getMetnods()//得到所有的public的方法。
4、 Constructor类:表示类的构造方法。
Constructor constructor =class. getDeclareConstructor(Class[ ] params)//根据参数,得到指定的构造方法。
Constructor[ ] constructor=class. getDeclareConstructors()//得到所有的构造方法。
Constructor constructor= class.getConstructor(Class[ ] parame)//得到指定的带参数的公共构造方法。
Constructor[ ] constructor= class.getConstructors()//得到类中所有公共构造方法。
以上方法是一些基本的方法,更多方法的使用请查阅API手册Class类。相信读者已经对java的反射有一定的了解了,那么就用代码来实现一下吧!
下面是myReflection01类:
package Reflection;
public class myReflection01
{
private int age;
private String string= "hello!";
public boolean is = true;
//构造方法
public myReflection01()
{
this.age = 10;
System.out.println("hello!");
}
//公共Out方法
public void Out()
{
System.out.println("age:" + age);
}
//公共name方法
public int name(int n)
{
n += 2;
return n;
}
//私有say方法
private void say()
{
System.out.println("这个是一个私有的方法,你可以得到吗?");
}
//私有成员的取得和设置
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public String getString() {
return string;
}
public void setString(String string) {
this.string = string;
}
}
package Reflection;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.jar.Attributes.Name;
public class MyReflection02
{
public Object getProperty(String classname ) throws NoSuchMethodException, IllegalArgumentException, InvocationTargetException
{
try
{
Class class1 = Class.forName(classname);
//创建一个classname类的对象,并调用它的无参数构造方法。
Object property = class1.newInstance();
System.out.println("property的类名是:" +property.getClass());
System.out.println(class1.getName());
System.out.println("得到构造函数");
//获得构造函数的方法 返回的是一个数组
Constructor[] constructors = class1.getConstructors();
for (int i = 0; i < constructors.length; i++)
System.out.println(constructors[i]);
System.out.println("得到方法");
//得到公共方法
Method[] methods = class1.getMethods();
for (int i = 0; i < methods.length; i++)
System.out.println(methods[i]);
System.out.println("得到公共成员的属性");
//得到类中的属性, 私有的不能获得
Field[] fields = class1.getFields();
for (int i = 0; i < fields.length; i++)
System.out.println(fields[i]);
try
{//获取私有属性的值 获取myReflection01类中age,string这个私有属性
Field f1 = class1.getDeclaredField("string");
Field f2 = class1.getDeclaredField("age");
//要先设置允许访问
f1.setAccessible(true);
f2.setAccessible(true);
//通过get方法来获得该属性的值 //参数为一个myReflection01的对象
String getString = (String) f1.get(property);
int getage = (int) f2.get(property);
System.out.println("得到该类的石油成员age的值是:" +getage);
System.out.println("得到该类的私有成员值是:"+getString);
} catch (NoSuchFieldException e)
{
e.printStackTrace();
} catch (SecurityException e)
{
e.printStackTrace();
}
//得到所有的公共构造方法
System.out.println("公共构造方法");
Constructor[] constructor = class1.getConstructors();
for (int i = 0; i < constructor.length; i++)
System.out.println(constructor[i]);
//通过反射调用方法
try
{
//在这执行了invokeMethod方法,请看该方法
//参数分别为myReflection01的实例, myReflection01中的name方法名, name中传入的参数
int res = (int) invokeMethod(property, "name", new Object[] {1});
} catch (SecurityException e)
{
e.printStackTrace();
}
} catch (ClassNotFoundException e)
{
e.printStackTrace();
} catch (InstantiationException e)
{
e.printStackTrace();
} catch (IllegalAccessException e)
{
e.printStackTrace();
}
return classname;
}
private Object invokeMethod(Object owner, String methodName, Object[] args) throws IllegalAccessException, IllegalArgumentException, InvocationTargetException
{
Class ownerClass = owner.getClass();
Class[] argsClass = new Class[args.length];
for (int i = 0; i < args.length; i++)
argsClass[i] = args[i].getClass();//获得方法中每个参数的类型
Method method = null;
try {
//得到和methodName名称相同。参数为argsClass一致的方法
method = ownerClass.getDeclaredMethod(methodName, argsClass);
} catch (NoSuchMethodException e1) {
e1.printStackTrace();
} catch (SecurityException e1) {
e1.printStackTrace();
}
//执行该方法,第一个参数为之前myReflection01类的对象, 第二个参数为实际传入的参数
Object object = method.invoke(owner, args);
return object;
}
public MyReflection02() throws IllegalArgumentException, InvocationTargetException
{
try {
//传入类名,这里是加了包的,所以是包名.类名
getProperty("Reflection.myReflection01");
} catch (NoSuchMethodException e) {
e.printStackTrace();
}
}
public static void main (String[] args) throws IllegalArgumentException, InvocationTargetException
{
new MyReflection02();
}
}