java反射机制概述
JAVA反射机制是在运行状态中,对于任意一个类,都能够知道这个
类的所有属性和方法;对于任意一个对象,都能够调用它的任意一个
方法和属性;这种动态获取信息以及动态调用对象的方法的功能称为
java语言的反射机制。
Class类
- 一旦class文件被加载到内存,就会为其创建一个Class对象。任何类被使用时都会创建一个Class对象。
- Class类是Java反射机制的基础,通过Class类,可以得到一个类的基本信息。
Class类的常用方法
方法名 | 用法 |
---|---|
static Class forName(String name) | 返回指定类名 name 的 Class 对象 |
Object newInstance() | 调用缺省构造函数,返回该Class对象的一个实例 |
getName() | 返回此Class对象所表示的实体(类、接口、数组类、基本类型或void)名称 |
Field[] getDeclaredFields() | 返回Field对象的一个数组 |
如何获得类的Class对象
package com.ffyc.javareflect;
public class Test1 {
public static void main(String[] args) throws ClassNotFoundException {
//以前使用类,已知类名,new创建对象,调用对象成员
//User user = new User();
//user.eat();
//使用反射机制时,只知道类的名称(包名+类名)
String classname = "com.ffyc.javareflect.User";
//如何类的信息? 可以通过Class 类来获得类中的信息
//如何获得类的class对象?
//方式1:
Class clazz1 = Class.forName(classname);
System.out.println(clazz1);
//方式2:
Class clazz2 = User.class;
System.out.println(clazz1 == clazz2);
//方式3:
User user = new User();
Car car = new Car();
Class clazz3 = user.getClass();
Class clazz4 = car.getClass();
clazz3.getFields();
clazz4.getFields();
System.out.println(clazz1==clazz3);
}
}
获得Field实例
package com.ffyc.javareflect;
import java.lang.reflect.Field;
import java.sql.SQLOutput;
import java.util.HashMap;
public class Test3 {
public static void main(String[] args) throws ClassNotFoundException, IllegalAccessException, InstantiationException, NoSuchFieldException {
/*
java中创建对象的方式:
1.new
2.反序列化
3.反射机制
4.对象克隆
*/
//使用反射机制时,只知道类的名称(包名+类名)
String classname = "com.ffyc.javareflect.User";
//String classname = "com.ffyc.javareflect.Car";
//1.通过类名 获得到类的Class对象
Class aClass = Class.forName(classname);
//2.通过类的Class对象,创建对象
Object object = aClass.newInstance();
//获得类中成员变最
//Field accountFiled = aClass.getField("account");//获得指定名称的公共的成员变最
/*Field accountFiled = aClass.getDeclaredField("account");//获得指定名称的成员变最,包含私有的
accountField.setAccessible(true):
accountFiled.set(object, "admin");
System.out.println();*/
HashMap<String,String> map = new HashMap<>();
map.put("account", "admin");
map.put("password", "1111");
Field[] declaredFields = aClass.getDeclaredFields();//获得类中所有的成员变量
for(Field field : declaredFields){
field.setAccessible(true);//允许访问操作私有属性,不建议
field.set(object,map.get(field.getName()));
}
System.out.println(object);
}
}
Field类的作用
- Field类将类的属性进行封装,可以获得属性的基本信息、属性的值,也可以对属性进行赋值.
- getName:返回属性的名字
- set:设置属性值
获得Method实例
package com.ffyc.javareflect;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
public class Test4 {
public static void main(String[] args) throws ClassNotFoundException, IllegalAccessException, InstantiationException, NoSuchMethodException, InvocationTargetException {
/*
java中创建对象的方式:
1.new
2.反序列化
3.反射机制
4.对象克隆
*/
//使用反射机制时,只知道类的名称(包名+类名)
String classname = "com.ffyc.javareflect.User";
//String classname = "com.ffyc.javareflect.Car";
//1.通过类名 获得到类的Class对象
Class aClass = Class.forName(classname);
//2.通过类的Class对象,创建对象
Object object = aClass.newInstance();
//获得类中成员方法
Method method = aClass.getMethod("eat" );
//调用访问
method.invoke(object);
}
}
Method类的作用
- Method类将类中的方法进行封装,可以动态获得方法的信息,例如:
getName:获得方法名字
getParameterTypes:获得方法参数类型 - 除了动态获得方法信息外,Method还能动态调用某一个对象的具体方法
invoke(Object obj, Object… args) :使用obj调用该方法,参数为args
反射案例
自定义java对象转json工具类
package com.ffyc.javareflect;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
public class JsonUtil {
public static String objectToJson(Object object) throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
Class clazz = object.getClass();
String json = "{";
//获取类中所有属性
Field[] declaredFields = clazz.getDeclaredFields();
for (Field field : declaredFields){
//生成属性get方法名字
json += field.getName()+":";
String getmethod = "get"+field.getName().substring(0, 1).toUpperCase()+field.getName().substring(1);
//获得方法对象
Method method = clazz.getMethod(getmethod);
//调用方法
String value = (String)method.invoke(object);
//把属性名和值拼接成键值
json += field.getName()+":"+value+",";
}
json = json.substring(0, json.length()-1);//去掉多余的逗号
json +="}";
return json;//{属性:值,属性:值}
}
public static void main(String[] args) throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
User user = new User();
user.setAccount("admin");
user.setPassword("1111");
Car car = new Car();
car.setName("宝马");
car.setColor("红色");
System.out.println(JsonUtil.objectToJson(user));
System.out.println(JsonUtil.objectToJson(car));
}
}
package com.ffyc.javareflect;
public class User {
private String account;
private String password;
public User() {
System.out.println("User无参构造");
}
private User(String account, String password) {
this.account = account;
this.password = password;
System.out.println("User有参构造方法");
}
public String getAccount() {
return account;
}
public void setAccount(String account) {
System.out.println("setaccount");
if(account!=null)
this.account = account;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
System.out.println("setpassword");
this.password = password;
}
public void eat() {
System.out.println("用户吃东西");
}
@Override
public String toString() {
return "User{" +
"account='" + account + '\'' +
", password='" + password + '\'' +
'}';
}
}
package com.ffyc.javareflect;
public class Car {
private String name;
private String color;
public Car() {
}
public Car(String name, String color) {
this.name = name;
this.color = color;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getColor() {
return color;
}
public void setColor(String color) {
this.color = color;
}
@Override
public String toString() {
return "Car{" +
"name='" + name + '\'' +
", color='" + color + '\'' +
'}';
}
}
反射的优缺点
优点:
1.增加程序的灵活性,可以在运行的过程中动态对类进行修改和操作
2.提高代码的复用率,比如动态代理
3.可以在运行时轻松获取任意一个类的方法、属性,并且还能通过反射进行动态调用
缺点:
1.反射会涉及到动态类型的解析,导致性能要比非反射调用更低
2.使用反射技术通常要在一个没有安全限制的程序运行
3.反射可以绕过一些限制访问的属性或者方法,可能会导致破坏代码本身的抽象性