☕ Java基础: (8) Java的反射
[========]
编译期是指把源码交给编译器编译成计算机可以执行的文件的过程。在 Java 中也就是把 Java 代码编成 class 文件的过程。编译期只是做了一些翻译功能,并没有把代码放在内存中运行起来,而只是把代码当成文本进行操作,比如检查错误。
运行期是把编译后的文件交给计算机执行,直到程序运行结束。所谓运行期就把在磁盘中的代码放到内存中执行起来。
Java 反射机制是在【运行状态】中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意方法和属性;这种动态获取信息以及动态调用对象方法的功能称为 Java 语言的反射机制。简单来说,反射机制指的是程序在运行时能够获取自身的信息。在 Java 中,只要给定类的名字,就可以通过反射机制来获得类的所有信息,它不需要事先(写代码的时候或编译期)知道运行对象是谁。
应用:在 ORM 中间件的实现中,运用 Java 反射机制可以读取任意一个 JavaBean 的所有属性,或者给这些属性赋值。
Java反射主要提供以下功能:
- 在运行时判断任意一个对象所属的类
- 在运行时构造任意一个类的对象
- 在运行时判断任意一个类所具有的成员变量和方法(通过反射甚至可以调用private方法)
- 在运行时调用任意一个对象的方法
反射的基本运用
反射相关的类一般都在 java.lang.relfect
包里。要想知道一个类的属性和方法,必须先获取到该类的字节码文件对象。获取类的信息时,使用的就是 Class 类中的方法。所以先要获取到每一个字节码文件(.class)对应的 Class 类型的对象.
1. 获取 Class
对象
-
(1)使用
Class
类的forName
静态方法:// 比如JDBC开发中常用此方法加载数据库驱动 Class.forName(driver);
-
直接获取某一个对象的
class
:Class<?> klass = int.class; Class<?> classInt = Integer.TYPE;
-
调用某个对象的
getClass()
方法:StringBuilder sb = new StringBuilder("123"); Class<?> klass = sb.getClass();
2. 判断是否为某个类的实例
一般用 instanceof
关键字判断是否为某个类的实例,同时也可借助反射中 Class
对象的 isInstance()
方法判断是否为某个类的实例:
public native boolean isInstance(Object obj);
3. 创建实例
-
使用Class对象的
newInstance()
方法来创建Class对象类的实例Class<?> c = String.class; Object str = c.newInstance();
-
先通过 Class 对象获取指定的 Constructor 对象,再调用 Constructor 对象的newInstance() 方法来创建实例。(该方法可以用指定的构造器构造类的实例)
// 获取String所对应的Class对象 Class<?> c = String.class; // 获取String类带一个String参数的构造器 Constructor constructor = c.getContructor(String.class); // 再根据构造器创建实例 Object obj = constructor.newInstance("2333"); sout(obj);
4. 获取方法
-
getDeclaredMethods
方法返回类或接口声明的所有方法,包括公共、保护、默认(包)访问和私有方法,但不包括继承的方法。public Method[] getDeclaredMethods() throws SecurityException
-
getMethods
方法返回某个类的所有公用(public)方法,包括其继承类的公用方法。public Method[] getMethods() throws SecurityException
-
getMethod
方法返回一个特定的方法,其中第一个参数为方法名称,后面的参数为方法的参数对应Class的对象。public Method getMethod(String name, Class<?>... parameterTypes)
Example:
public class test1 {
public static void main(String[] args) throws InstantiationException, IllegalAccessException, NoSuchMethodException {
Class<?> c = MethodClass.class;
Object obj = c.newInstance();
final Method[] methods = c.getMethods();
final Method[] declaredMethods = c.getDeclaredMethods();
// 获取MethodClass的特定方法
final Method method = c.getMethod("add", int.class, int.class);
System.out.println("getMethods()方法获取的所有方法:");
for (Method m : methods) System.out.println(m);
System.out.println("\ngetDeclaredMethods方法获取的所有方法:");
for (Method m : declaredMethods) System.out.println(m);
}
}
class MethodClass {
public final int fuck = 3;
public int add(int a, int b) {
return a + b;
}
public int sub(int a, int b) {
return a + b;
}
}
6. 获取类的成员变量(字段)信息
-
getFiled
:访问公有的成员变量c.getField("fuck");
-
getDeclaredField
:所有已声明的成员变量,但不能得到其父类的成员变量
getFileds
和 getDeclaredFields
方法用法同上(5.)
7. 调用方法
从类中获取了一个方法后,我们就可以用 invoke()
方法来调用这个方法。
public class test1 {
public static void main(String[] args) throws IllegalAccessException, InstantiationException, NoSuchMethodException, InvocationTargetException {
Class<?> kclass = MethodClass.class;
Object obj = kclass.newInstance();
Method method = kclass.getMethod("add", int.class, int.class);
Object res = method.invoke(obj, 1, 4);
sout(res); // 5
}
}
8. 利用反射创建数组
Class<?> cls = Class.forName("java.lang.String");
//通过Array.newInstance()创建数组对象
Object array = Array.newInstance(cls, 25);
Array.set(array,0,"hello");
Array.set(array,1,"Java");
Array.set(array,2,"fuck");
Array.set(array,3,"Scala");
Array.set(array,4,"Clojure");
// 获取某一项
System.out.println(Array.get(array, 3));
Java 反射机制的优缺点
优点:
- 能够运行时动态获取类的实例,大大提高系统的灵活性和扩展性。
- 与 Java 动态编译相结合,可以实现无比强大的功能。
- 对于 Java 这种先编译再运行的语言,能够让我们很方便的创建灵活的代码,这些代码可以在运行时装配,无需在组件之间进行源代码的链接,更加容易实现面向对象。
缺点:
- 反射会消耗一定的系统资源,因此,如果不需要动态地创建一个对象,那么就不需要用反射;
- 反射调用方法时可以忽略权限检查,获取这个类的私有方法和属性,因此可能会破坏类的封装性而导致安全问题。
本文来自博客园,作者:micromatrix,转载请注明原文链接:https://www.cnblogs.com/cenjw/p/java-reflection.html
posted on 2022-03-20 20:15 micromatrix 阅读(86) 评论(0) 编辑 收藏 举报