概述
个人博客:www.letus179.com
概念
Reflection enables Java code to discover information about the fields, methods and constructors of loaded classes, and to use reflected fields, methods, and constructors to operate on their underlying counterparts, within security restrictions.
通俗来讲:反射就是把Class对象的各种成分映射成对应的Java类。
作用
java反射机制其实就是将.class
转化为.java
,也即反编译。具体主要提供了以下功能:
- 在运行时判断任意一个对象所属的
类
; - 在运行时
构造
任意一个类的对象; - 在运行时判断任意一个类所具有的
成员变量
和方法
; - 在运行时
调用
任意一个对象的方法。
后面会围绕这几点具体展开。
重要API
在java.lang.reflect
包下提供类和接口,以获得关于类和对象的反射信息。这里简单罗列了与反射相关的几个重要的API,真正想学习反射机制,除了在项目中历练,API也是非常重要的手段。英语不好理解的话,就搜搜汉化后的API文档。
变量相关 | 含义 |
---|---|
getField(String name) | 返回一个 Field 对象,它反映此 Class 对象所表示的类或接口的指定公共成员字段。 |
getFields() | 返回一个包含某些 Field 对象的数组,这些对象反映此 Class 对象所表示的类或接口的所有可访问公共字段。 |
getDeclaredField(String name) | 返回一个 Field 对象,该对象反映此 Class 对象所表示的类或接口的指定已声明字段。 |
getDeclaredFields() | 返回 Field 对象的一个数组,这些对象反映此 Class 对象所表示的类或接口所声明的所有字段。 |
方法相关 | 含义 |
getMethod(String name, Class… parameterTypes) | 返回一个 Method 对象,它反映此 Class 对象所表示的类或接口的指定公共成员方法。 |
getMethods() | 返回一个包含某些 Method 对象的数组,这些对象反映此 Class 对象所表示的类或接口(包括那些由该类或接口声明的以及从超类和超接口继承的那些的类或接口)的公共 member 方法。 |
getDeclaredMethod(String name, Class… parameterTypes) | 返回一个 Method 对象,该对象反映此 Class 对象所表示的类或接口的指定已声明方法。 |
getDeclaredMethods() | 返回 Method 对象的一个数组,这些对象反映此 Class 对象表示的类或接口声明的所有方法,包括公共、保护、默认(包)访问和私有方法,但不包括继承的方法。 |
构造方法相关 | 含义 |
getConstructor(Class… parameterTypes) | 返回一个 Constructor 对象,它反映此 Class 对象所表示的类的指定公共构造方法 |
getConstructors() | 返回一个包含某些 Constructor 对象的数组,这些对象反映此 Class 对象所表示的类的所有公共构造方法 |
getDeclaredConstructor(Class… parameterTypes) | 返回一个 Constructor 对象,该对象反映此 Class 对象所表示的类或接口的指定构造方法。 |
getDeclaredConstructors() | 返回 Constructor 对象的一个数组,这些对象反映此 Class 对象表示的类声明的所有构造方法 |
父类、父接口相关 | 含义 |
getInterfaces() | 确定此对象所表示的类或接口实现的接口。 |
getSuperclass() | 返回表示此 Class 所表示的实体(类、接口、基本类型或 void)的超类的 Class。 |
其他重要相关 | 含义 |
getModifiers() | 以整数形式返回此 Method 对象所表示方法的 Java 语言修饰符。 |
getName() | 以 String 形式返回此 Method 对象表示的方法名称。 |
getReturnType() | 返回一个 Class 对象,该对象描述了此 Method 对象所表示的方法的正式返回类型。 |
newInstance() | 创建此 Class 对象所表示的类的一个新实例。 |
isInstance(Object obj) | 判定指定的 Object 是否与此 Class 所表示的对象赋值兼容。 |
具体功能实现
下面通过例子分别讲述获取Class对象的3种方式
,如何创建实例
,如何获取构造器
,如何获取方法
, 如何获取属性
以及通过反射调用方法
。
获取Class对象的3种方式
例如新建一个类MyReflectTest
,代码如下:
public class MyReflectTest {
}
方式1:使用Class
类的中静态forName()
方法获得与字符串对应的Class对象
public static void main(String[] args) {
try {
Class<?> clz = Class.forName("test.MyReflectTest");
}
catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
在数据库有关开发中,我们经常会用到这个方法,例如:
Class.forName("com.mysql.jdbc.Driver")
方式2: 利用对象的class
属性
public static void main(String[] args) {
Class clz = MyReflectTest.class;
}
注意,在基本类型和包装类型中有,例如:
Integer.TYPE
等价于
int.class
是int
的Class
对象,不等价于
Integer.class
这是Integer
的Class
对象表示,看看源码就知道了。
方式3:调用对象的getClass()
方法
public static void main(String[] args) {
MyReflectTest myReflectTest = new MyReflectTest();
Class clz = myReflectTest.getClass();
}
创建实例
获取到class对象后,调用newInstance()
方法来创建Class对象对应的类实例,
测试代码:
public static void main(String[] args) throws InstantiationException, IllegalAccessException {
Class clz = MyReflectTest.class;
MyReflectTest newInstance = (MyReflectTest) clz.newInstance();
}
获取构造器
获取类的所有构造器,测试代码:
public static void main(String[] args) {
// 获取类对象
Class clz = MyReflectTest.class;
// 获取public构造器数组
Constructor[] cons = clz.getConstructors();
// 获取public,默认,protected,private构造器数组
Constructor[] declaredCons = clz.getDeclaredConstructors();
}
获取类中指定的某个构造器,测试代码:
public MyReflectTest(String name) {
super();
this.name = name;
}
MyReflectTest(String name, int age) {
super();
this.name = name;
this.age = age;
}
public static void main(String[] args) throws NoSuchMethodException, SecurityException {
// 获取类对象
Class clz = MyReflectTest.class;
// 获取public构造器,构造器参数类型为String
Constructor con = clz.getConstructor(String.class);
// 获取public,默认,protected,private构造器,构造器参数类型为String,int
Constructor declaredCon = clz.getDeclaredConstructor(String.class, int.class);
}
获取方法
新增两个方法:add()
和get()
。
private void add(String name) {
System.out.println(name);
}
public int get() {
System.out.println(age);
return age;
}
getDeclaredMethods()
方法相关测试代码:
public static void main(String[] args) throws NoSuchMethodException, SecurityException {
// 获取类对象
Class clz = MyReflectTest.class;
Method[] declaredMethods = clz.getDeclaredMethods();
for (Method method : declaredMethods) {
System.out.println("===============================");
// 访问修饰符
System.out.println(Modifier.toString(method.getModifiers()));
// 返回类型
System.out.println(method.getReturnType());
// 方法名称
System.out.println(method.getName());
Class<?>[] parameterTypes = method.getParameterTypes();
for (Class<?> param : parameterTypes) {
// 方法参数类型
System.out.println(param.getName());
}
}
}
执行结果:
===============================
public static
void
main
[Ljava.lang.String; //"["表示数组对象
===============================
private
void
add
java.lang.String
===============================
public
int
get
能获取私有的方法add()
。
看看另一个反射方法:getMethods()
,代码和上面一个,基本没变化。
测试代码:
public static void main(String[] args) throws NoSuchMethodException, SecurityException {
// 获取类对象
Class clz = MyReflectTest.class;
Method[] methods = clz.getMethods();
for (Method method : methods) {
System.out.println("+++++++++++++++++++++++++++++++++");
System.out.println(Modifier.toString(method.getModifiers()));
System.out.println(method.getReturnType());
System.out.println(method.getName());
Class<?>[] parameterTypes = method.getParameterTypes();
for (Class<?> param : parameterTypes) {
System.out.println(param.getName());
}
}
}
执行结果:
+++++++++++++++++++++++++++++++++
public static
void
main
[Ljava.lang.String;
+++++++++++++++++++++++++++++++++
public
int
get
+++++++++++++++++++++++++++++++++
public final
void
wait
long
int
+++++++++++++++++++++++++++++++++
public final native
void
wait
long
+++++++++++++++++++++++++++++++++
public final
void
wait
+++++++++++++++++++++++++++++++++
public
boolean
equals
java.lang.Object
+++++++++++++++++++++++++++++++++
public
class java.lang.String
toString
+++++++++++++++++++++++++++++++++
public native
int
hashCode
+++++++++++++++++++++++++++++++++
public final native
class java.lang.Class
getClass
+++++++++++++++++++++++++++++++++
public final native
void
notify
+++++++++++++++++++++++++++++++++
public final native
void
notifyAll
对比上面的getDeclaredMethods()
,少了一个私有的方法add()
,但是多了好多不在本类的方法。由于每个类的超类都是Object
类,很明显,这些方法都是来自超类,看看源码也能发现这个。也就是说:
getDeclaredMethods()
获取的是本类的方法,public、默认、protected、private;getMethods()
获取的是本类和父类的所有的public的方法。
另外有获取指定某一个方法的反射方法。
测试代码:
public String save(String name, int age) {
return "name: " + name + ", age: " + age;
}
public static void main(String[] args) throws NoSuchMethodException, SecurityException {
// 获取类对象
Class clz = MyReflectTest.class;
// 第一个参数是“方法名”,后面的是方法的可变参数列表
Method method = clz.getMethod("save", String.class, int.class);
System.out.println(Modifier.toString(method.getModifiers()));
}
执行结果:
public
其他的类似。
获取属性
创建两个成员变量name
,age
,如下:
public String name;
private int age;
测试代码:
public static void main(String[] args) throws NoSuchMethodException, SecurityException {
// 获取类对象
Class clz = MyReflectTest.class;
Field[] fields = clz.getFields();
for (Field field : fields) {
System.out.println("+++++++++++++++++++++++++");
System.out.println(Modifier.toString(field.getModifiers()));
System.out.println(field.getType());
System.out.println(field.getName());
}
Field[] declaredFields = clz.getDeclaredFields();
for (Field field : declaredFields) {
System.out.println("=========================");
System.out.println(Modifier.toString(field.getModifiers()));
System.out.println(field.getType());
System.out.println(field.getName());
}
}
执行结果:
+++++++++++++++++++++++++
public
class java.lang.String
name
=========================
public
class java.lang.String
name
=========================
private
int
age
另外getField(String)
,getDeclaredField(String)
参数为方法名,和Method
类似。
调用方法
通过上面的一系列操作获取到某一方法后,我们可以利用invoke()
方法来调用这个方法。
测试代码:
public String save(String name, int age) {
return "name: " + name + ", age: " + age;
}
public static void main(String[] args) throws Exception {
// 获取类对象
Class<MyReflectTest> clz = MyReflectTest.class;
// 获取对象实例
MyReflectTest reflect = (MyReflectTest) clz.newInstance();
// 获取save方法
Method method = clz.getMethod("save", String.class, int.class);
// 第一个参数为对象实例,后面的为方法的参数
Object result = method.invoke(reflect, "jack", 27);
System.out.println(result);
}
执行结果:
name: jack, age: 27
最后:反射在工作中其实用到的时候并不多,主要用来构建框架。譬如Spring中的IOC
也即控制反转
,其底层就是利用了反射。以后有时间再整理下这块。反射机制基础到这结束。
最后
以上就是要减肥电源为你收集整理的反射机制基础解析的全部内容,希望文章能够帮你解决反射机制基础解析所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复