1. 先说第一句话,这个话非常非常重要!
在java里,无论生成某个类的多少对象,这些对象都会对应于同一个Class对象。
2. 再说第二句话,java反射有什么用?
这么说吧,其实java类的成员变量、方法是不是private没有关系,运用反射就完全可以玩转类的私有变量和私有方法。正是因为反射的这两部分使用才有了hibernate、spring等那些框架,换言之,没有反射就没有框架!
3. 到底java反射有什么具体的作用?
总说:Java的反射机制允许程序在运行时透过Reflection APIs取得任何一个已知名称的class的内部信息(所有信息)。
分说:
(1) 运行时判断任意一个对象所属的类
(2) 运行时构造任意一个类的对象
(3) 运行时判断任意一个类所具有成员变量和方法
(4) 运行时调用任意一个对象的方法
注意:全是运行时,java反射是运行时的行为。
写代码诠释java反射最直观了,没有之一。下面是我写的例子,代码写了很多注释来增加理解。
package com.lzg.reflection;
public class User {
private int id;
private String name;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Override
public String toString() {
return "User [id=" + id + ", name=" + name + "]";
}
public static void main(String[] args) {
User user = new User();
user.setId(1);
user.setName("hello");
System.out.println(user);
}
}
package com.lzg.reflection;
public class UserDaoImpl {
public int id;
private String name;
private String waihao = "胖子";// 外号
public UserDaoImpl() {
super();
}
public UserDaoImpl(int id, String name) {
super();
this.id = id;
this.name = name;
}
@Override
public String toString() {
return "UserDaoImpl [id=" + id + ", name=" + name + "]";
}
public User getUserById(int userId) {
//获取User的数据用新建模拟了
User user = new User();
user.setId(100);
user.setName("lzg");
return user;
}
public int add(int a, int b) {
return a + b;
}
private String sayHello(String name) {
return "hello:" + name;
}
public String sayWaihao() {
return waihao;
}
}
package com.lzg.reflection;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
public class ReflectionClient {
public static void main(String[] args) throws Exception {
//要想使用反射,首先需要获得待处理类或对象所对应的Class对象
/**
* 获取某个类或对象所对应的Class对象的3种方式
* 1. Class classType = UserDaoImpl.class;
* 2. Class classType = Class.forName("com.lzg.reflection.UserDaoImpl");
* 3.
* UserDaoImpl userDaoImpl = new UserDaoImpl();
* Class classType2 = userDaoImpl.getClass();
*/
Class classType = Class.forName("com.lzg.reflection.UserDaoImpl");
//反射获取类的构建方法并使用,分带参数的和不带参数的。
//不带参数的
Object userDaoImplObject = classType.newInstance();
//带参数的
Constructor userDaoImplConstructor = classType.getConstructor(new Class[]{int.class, String.class});
UserDaoImpl userDaoImplOjbect2 = (UserDaoImpl) userDaoImplConstructor.newInstance(new Object[]{1001, "UserDaoImplName"});
System.out.println(userDaoImplOjbect2);
System.out.println("----------");
//反射获取UserDaoImpl.java所有声明的方法
Method[] userDaoImplMethods = classType.getDeclaredMethods();
for(Method method: userDaoImplMethods) {
System.out.println(method);
}
System.out.println("----------");
//反射获取具体方法并使用
Method addMethod = classType.getMethod("add", new Class[]{int.class, int.class});
int addResult = (int) addMethod.invoke(userDaoImplObject, new Object[]{1, 3});
System.out.println(addResult);
System.out.println("----------");
//反射获取对象的成员变量
//getField()要求该成员变量属性是公有的
Field idField = classType.getField("id");
System.out.println(idField.getName());
System.out.println("");
//getFields()只能获取所有公有属性的成员变量
Field[] fields = classType.getFields();
for(Field field : fields) {
System.out.println(field.getName());
}
System.out.println("");
//不在于成员变量的属性是否公有
Field nameField = classType.getDeclaredField("name");
System.out.println(nameField.getName());
System.out.println("");
//获取所有成员变量
Field[] fields2 = classType.getDeclaredFields();
for(Field field : fields2) {
System.out.println(field.getName());
}
System.out.println("----------");
/**
* 其实java类的成员变量、方法是不是private没有关系,运用反射就完全可以玩转类的私有变量和私有方法。
* 实用部分,反射调用对象的私有方法、反射访问对象的私有成员变量。
* 实用在哪?这么说吧,正是因为反射的这两部分使用才有了hibernate、spring等那些框架,换言之,没有反射就没有框架!
*/
//反射调用对象的私有方法
Method sayHelloMethod = classType.getDeclaredMethod("sayHello", new Class[]{String.class});
sayHelloMethod.setAccessible(true); //放开压制Java的访问控制检查
String sayHelloResult = (String) sayHelloMethod.invoke(userDaoImplObject, new Object[]{"lzg"});
System.out.println(sayHelloResult);
//反射访问对象的私有成员变量
Field waihaoField = classType.getDeclaredField("waihao");
waihaoField.setAccessible(true); //放开Java对访问修饰符访问控制检查
waihaoField.set(userDaoImplObject, "瘦子");
//调用方法测试一下是否更改了private成员变量,只是测试,就不用反射了。
System.out.println(((UserDaoImpl)userDaoImplObject).sayWaihao());
}
}
RelectionClient运行结果:
UserDaoImpl [id=1001, name=UserDaoImplName]
----------
public int com.lzg.reflection.UserDaoImpl.add(int,int)
public java.lang.String com.lzg.reflection.UserDaoImpl.toString()
private java.lang.String com.lzg.reflection.UserDaoImpl.sayHello(java.lang.String)
public com.lzg.reflection.User com.lzg.reflection.UserDaoImpl.getUserById(int)
public java.lang.String com.lzg.reflection.UserDaoImpl.sayWaihao()
----------
4
----------
id
**********
id
**********
name
**********
id
name
waihao
----------
hello:lzg
瘦子