「这是我参与2022首次更文挑战的第8天,活动详情查看:2022首次更文挑战」。
什么是反射
在程序运行的时候,查看一个类包含哪些信息(成员变量和方法等)。这个过程称之为反射。 可以这样理解:一切对Class对象的操作都是反射。
如果我们知道我们要使用哪个类,那么我们只需要用这个类创建对象,然后就可以调用获取这个对象里面的数据和调用里面的方法。但如果我们不知道要使用的是哪个类,只需要使用反射获取类中的信息,再使用。
获取Class对象
1. 通过对象获取
调用对象的getClass方法就可以得到它的Class对象
public static void main(String[] args) {
User user = new User(1,"用户1","12345","zhangsan");
Class c = user.getClass();
System.out.println(c);
}
如果我们调动同一个类的两个不同对象的getClass方法,得到的Class对象是一样的吗?答案是:是一样的。
public static void main(String[] args) {
User user1 = new User(1,"用户1","12345","zhangsan");
User user2 = new User(2,"用户2","12345","lisi");
Class c1 = user1.getClass();
Class c2 = user2.getClass();
boolean flag = c1 == c2;
System.out.println("c1 == c2 :" + flag);
}
2. 通过类名获取
public static void main(String[] args) {
Class c = User.class;
System.out.println(c);
}
那么,通过对象获取和通过类获取的Class对象是一样的吗?答案也是:是一样的。
public static void main(String[] args) {
Class c = User.class;
User user = new User(1,"用户1","12345","zhangsan");
Class c1 = user.getClass();
System.out.println(c == c1);
}
3. 通过Class类的静态方法forName获取
public static void main(String[] args) throws ClassNotFoundException {
Class c = Class.forName("test.User");
System.out.println(c);
}
forName中传入的类必须加上全包名,若果传入的类找不到就会抛出java.lang.ClassNotFoundException异常
利用反射构造对象
获取构造方法
public static void main(String[] args) throws ClassNotFoundException {
Class c = Class.forName("test.User");
Constructor[] constructors = c.getConstructors();
for(Constructor constructor: constructors){
System.out.println(constructor);
}
}
利用构造方法创建对象
public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {
Class c = Class.forName("test.User");
Constructor constructor = c.getConstructor();
User user = (User) constructor.newInstance();
System.out.println(user);
}
获取成员变量
public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {
Class c = Class.forName("test.User");
Field[] fields = c.getFields(); //获取所有公共成员变量
for(Field field:fields){
System.out.println("公共成员变量:" + field);
}
System.out.println("-----------------------------------");
Field[] fields2 = c.getDeclaredFields(); //获取公共成员变量(包括private)
for(Field field:fields2){
System.out.println("成员变量:" + field);
}
}
获取成员方法
| 方法 | 解释 |
|---|---|
| getMethod(参数) | 获取指定公共成员方法 |
| getMethods() | 获取所有公共成员方法 |
| getDeclaredMethod(参数) | 获取公共成员方法(含private) |
| getDeclaredMethods() | 获取所有成员方法(含private) |
public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {
Class c = Class.forName("test.User");
Method[] declaredMethods = c.getDeclaredMethods();
for(Method method: declaredMethods){
System.out.println(method);
}
}
通过invoke调用获取到的toString方法
public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, InvocationTargetException, IllegalAccessException {
User user = new User(1,"用户1","12345","zhangsan");
Class c = Class.forName("test.User");
Method method = c.getMethod("toString");
Object o = method.invoke(user);
System.out.println(o);
}
java为什么需要反射
使用反射可以赋予jvm动态编译的能力,否则类的元数据信息只能用静态编译的方式实现。
静态编译:在编译时确定类型,绑定对象即通过。
动态编译:运行时确定类型,绑定对象。动态编译最大限度地发挥了Java的灵活性,体现了多态的应用,可以减低类之间的耦合性。
反射机制允许程序在运行时取得任何一个已知名称的class的内部信息,并可于运行时改变成员变量内容或唤起成员方法。
User类
public class User {
private int id;
private String username;
private String password;
public String nickName;
public String phone;
public User(){}
public User(int id, String username, String password, String nickName) {
this.id = id;
this.username = username;
this.password = password;
this.nickName = nickName;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
@Override
public String toString() {
return "User{" +
"id=" + id +
", username='" + username + '\'' +
", password='" + password + '\'' +
'}';
}
public void show(){
System.out.println(username + ":" + password);
}
public void online(){
System.out.println(username + "is doing.");
}
}