何为反射
反射之所以被称为框架的灵魂,主要是因为它赋予了我们在运行时分析类以及执行类中方法的能力。通过反射你可以获取任意一个类的所有属性和方法,你还可以调用这些方法和属性。
反射机制的优缺点
优点 : 可以让咱们的代码更加灵活、为各种框架提供开箱即用的功能提供了便利
缺点 :让我们在运行时有了分析操作类的能力,这同样也增加了安全问题。比如可以无视泛型参数的安全检查(泛型参数的安全检查发生在编译时)。另外,反射的性能也要稍差点,不过,对于框架来说实际是影响不大的。
反射机制有什么用?
反射机制允许程序在执行时获取某个类自身的定义信息,例如熟悉和方法等也可以实现动态创建 类的对象、变更属性的内容或执行特定的方法的功能。从而使Java具有动态语言的特性,增强了程序的灵活性和可移植性。
通过java语言中的反射机制可以操作字节码文件。 优点类似于黑客。(可以读和修改字节码文件。) 通过反射机制可以操作代码片段。(class文件。)
-
(1)在运行时判断任意一个对象所属的类型。
-
(2)在运行时构造任意一个类的对象。
-
(3)在运行时判断任意一个类所具有的成员变量和方法。
-
(4)在运行时调用任意一个对象的方法,甚至可以调用private方法。
注意:上述功能都是在运行时环境中,而不是在编译时环境中。
反射机制相关的重要的类
java.lang.Class:代表整个字节码,代表一个类型,代表整个类。
java.lang.reflect.Method:代表字节码中的方法字节码。代表类中的方法。
java.lang.reflect.Constructor:代表字节码中的构造方法字节码。代表类中的构造方法
java.lang.reflect.Field:代表字节码中的属性字节码。代表类中的成员变量(静态变量+实例变量)
(1)Class类:代表一个类。
(2)Filed类:代表类的成员变量。
(3)Method类:代表类的方法。
(4)Constructor类:代表类的构造方法。
(5)Array类:提供了动态创建数组及访问数组元素的静态方法。该类中的所有方法都是静态的。
反射机制的相关类在 java.lang.reflect.*;
★反射机制调用对象方法
获取成员方法: public Method getMethod(String name ,Class<?>… parameterTypes):获取"公有方法";(包含了父类的方法也包含Object类) public Method getDeclaredMethods(String name ,Class<?>… parameterTypes) :获取成员方法,包括私有的(不包括继承的) 参数解释: name : 方法名; Class … : 形参的Class类型对象
调用方法 Method --> public Object invoke(Object obj,Object… args): 参数说明: obj : 要调用方法的对象; args:调用方式时所传递的实参;
public static void main(String[] args) throws Exception{
// 不使用反射机制,怎么调用方法
// 创建对象
UserService userService = new UserService();
// 调用方法
/*
要素分析:
要素1:对象userService
要素2:login方法名
要素3:实参列表
要素4:返回值
*/
boolean loginSuccess = userService.login("admin","123");
//System.out.println(loginSuccess);
System.out.println(loginSuccess ? "登录成功" : "登录失败");
// 使用反射机制来调用一个对象的方法该怎么做?
Class userServiceClass = Class.forName("com.bjpowernode.java.service.UserService");
// 创建对象
Object obj = userServiceClass.newInstance();
// 获取Method
Method loginMethod = userServiceClass.getDeclaredMethod("login", String.class, String.class);
//Method loginMethod = userServiceClass.getDeclaredMethod("login", int.class);
// 调用方法
// 调用方法有几个要素? 也需要4要素。
// 反射机制中最最最最最重要的一个方法,必须记住。
/*
四要素:
loginMethod方法
obj对象
"admin","123" 实参
retValue 返回值
*/
Object retValue = loginMethod.invoke(obj, "admin","123123");
System.out.println(retValue);
}
class UserService {
/**
* 登录方法
* @param name 用户名
* @param password 密码
* @return true表示登录成功,false表示登录失败!
*/
public boolean login(String name,String password){
if("admin".equals(name) && "123".equals(password)){
return true;
}
return false;
}
// 可能还有一个同名login方法
// java中怎么区分一个方法,依靠方法名和参数列表。
public void login(int i){
}
/**
* 退出系统的方法
*/
public void logout(){
System.out.println("系统已经安全退出!");
}
}
获取 Class 对象的四种方式
1. 知道具体类的情况下可以使用:
Class alunbarClass = TargetObject.class;
但是我们一般是不知道具体类的,基本都是通过遍历包下面的类来获取 Class 对象,通过此方式获取 Class 对象不会进行初始化
2. 通过 Class.forName()
传入类的全路径获取:
Class alunbarClass1 = Class.forName("cn.javaguide.TargetObject");
3. 通过对象实例instance.getClass()
获取:
TargetObject o = new TargetObject();
Class alunbarClass2 = o.getClass();
4. 通过类加载器xxxClassLoader.loadClass()
传入类路径获取:
ClassLoader.getSystemClassLoader().loadClass("cn.javaguide.TargetObject");
通过类加载器获取 Class 对象不会进行初始化,意味着不进行包括初始化等一系列步骤,静态代码块和静态对象不会得到执行