问题:java程序在运行时,对于一个java类,能否知道属性和方法;能否去调用它的任意方法? 答案是肯定的,就是使用java的反射机制。
一、什么是反射机制
简解:Java可以加载一个运行时才得知名称的class,获得其完整结构。
二、哪里用到反射机制
三、反射机制的优点与缺点
为什么要用反射机制?直接创建对象不就可以了吗,这就涉及到了动态与静态的概念,
静态编译:在编译时确定类型,绑定对象,即通过。
动态编译:运行时确定类型,绑定对象。动态编译最大限度发挥了java的灵活性,体现了多态的应用,有以降低类之间的藕合性。
一句话,反射机制的优点就是可以实现动态创建对象和编译,体现出很大的灵活性,特别是在J2EE的开发中它的灵活性就表现的十分明显。比如,一个大型的软件,不可能一次就把把它设计的很完美,当这个程序编译后,发布了,当发现需要更新某些功能时,我们不可能要用户把以前的卸载,再重新安装新的版本,假如这样的话,这个软件肯定是没有多少人用的。采用静态的话,需要把整个程序重新编译一次才可以实现功能 的更新,而采用反射机制的话,它就可以不用卸载,只需要在运行时才动态的创建和编译,就可以实现该功能。
它的缺点是对性能有影响。使用反射基本上是一种解释操作,我们可以告诉JVM,我们希望做什么并且它
满足我们的要求。这类操作总是慢于只直接执行相同的操作。
Java反射机制提供如下功能:
1、在运行时判断任意一个对象所属的类
2、在运行时构造任意一个类的对象
3、在运行时判段任意一个类所具有的成员变量和方法
4、在运行时调用任一个对象的方法
5、在运行时创建新类对象
在使用Java的反射功能时,基本首先都要获取类的Class对象,再通过Class对象获取其他的对象。
package lxf;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
class Person {
private String name;
private int age;
public Person(String name, int age) {
this.name = name;
this.age = age;
}
public Person() {
// TODO Auto-generated constructor stub
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
}
/**
* 使用反射机制来创建对象
*
* @author lxf
* @time 2014-4-8下午05:08:41
*
*/
public class CreateObject {
/**
* Java的反射机制是指:反射就是把Java类中的各种成分映射成相应相应的Java类, 然后就可以获取这个类的所有信息
*
* @throws Exception
*/
public static void createObj1() throws Exception {
// 返回与带有给定字符串名的类或接口相关联的 Class 对象。
// Class classType = Person.class;
Class classType = Class.forName("lxf.Person");
Object obj = classType.newInstance();
System.out.println("使用反射反射机制创建出来的对象是否是Person类的对象:"
+ (obj instanceof Person));
}
/**
* 创建带有构造参数的对象的时候我们需要使用另外一种方式即: 1.先获取操作类的Class对象即字节码文件
* 2.使用Class对象的getConstructor
* (parameterTypes)方法获取该对象的构造方法的对象,注意括号中可以带不等的可变参数,
* 3.使用构造方法对象的newInstance(initargs)方法就可以实例化一个对象 4.注意,使用这些方法都不可以访问被
* private修饰的方法,需要设置某些访问权限setAccessable()方法
*
* @throws Exception
*/
public static void createObj2() throws Exception {
@SuppressWarnings("rawtypes")
Class classType = Person.class;
@SuppressWarnings("unchecked")
Constructor<Person> con = classType.getConstructor(String.class,
int.class);
Object obj = con.newInstance("lxf", 23);
System.out.println("使用constructor对象的newInstance方法创建对象的信息:"
+ ((Person) obj).getName());
}
/**
* 操作方法包括(private方法) 步骤: 1.首先获取要操作类的Class对象
* 2.然后通过Class对象的getMethod方法获取要操作的方法的Method对象(两个参数,第一个参数是方法名,第二个参数是参数类型)
* 3.调用Method的方法的invoke方法(两个参数,第一个参数是该方法属于的类对象,具体参数)
* 4.当方法被private修饰的时候,首先需要调用getDeclaredMethod()方法获取要操作的被private修饰的类。
* 在这里要注意这个getDeclaredMethod方法,它既可以用作获取普通方法的对象也可以用来操作private修饰的方法,
* 但是操作private修饰的方法的时候,必须使用这个方法,其它方法不可以。普通方法还可以使用getMethod方法,
* 且属性操作也是如此。另外,还需要设置访问权限setAccessable(true)才可以
*
* @throws Exception
*/
public static void methodDo() throws Exception {
Person p = new Person();
Class classType = Person.class;
Method method = classType.getMethod("setName", String.class);
method.invoke(p, "ckl");
System.out.println("使用反射操作SetName方法后,Person对象的name值是:" + p.getName());
Method method2 = classType.getDeclaredMethod("test");
method2.setAccessible(true);
method2.invoke(p);
}
/**
* 操作字段
*
* @throws Exception
*/
public static void FieldDo() throws Exception {
Person p = new Person();
Class classType = Person.class;
Field field = classType.getDeclaredField("name");
Field field2 = classType.getDeclaredField("age");
field.setAccessible(true);
field2.setAccessible(true);
field.set(p, "lxf");
field2.set(p, 23);
System.out.println("使用反射机制操作被private修饰的对象字段后得到的属性值是:" + p.getName());
System.out.println("使用反射机制操作被private修饰的对象字段后得到的属性值是:" + p.getAge());
}
public static void main(String[] args) throws Exception {
new CreateObject().FieldDo();
}
}