Java反射
Posted jztx123
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Java反射相关的知识,希望对你有一定的参考价值。
反射定义
什么是反射?
将类中的各个组成部分
封装
为其他对象
,这就是反射
机制。了解
Java代码
经历的三个阶段- 使用反射的好处?
- 可以在程序
运行
过程中,操作
这些对象
。 可以
解耦
,提高程序的可扩展
性。使用反射
使用反射要先获得类的
Class对象
- 三种方式获取
Class对象
// 1.对应第一阶段:编译时
Class.forName("包名.类名"):将class字节码文件加载进内存, 返回Class对象
(多用于配置文件,将类名定义在配置文件中;读取文件,加载类)
// 2.对应第二阶段:加载进内存时
类名.class:通过类名的属性class获, 如Person.class
(多用于参数的传递)
// 3.对应第三阶段:Runtime运行时
对象.getClass():getClass()方法在Object类中定义
(多用于对象的获取字节码的方式)
//1.Source源代码阶段:配置文件
Class clazz1 = Class.forName("com.it666.reflect.Person");
//2.Class类对象阶段:参数传递
Class clazz2 = Person.class;
//3.Runtime运行时阶段:通过对象获取class字节码
Person p= new Person();
Class clazz3 = p.getClass();
//判断两个对象是否是同一个字节码文件
System.out.println(clazz1==clazz2); //true
System.out.println(clazz2==clazz3); //true
结论:同一个字节码文件
(*.class)
在一次程序运行过程中,只会被加载一次
,不论通过哪一种方式获取的Class对象
都是同一个
。
- 代码示例
Person类
package com.itlike.reflect;
public class Person {
//成员变量Field
private String name;
private Integer age;
//构造方法Constructor
public Person() {
}
public Person(String name, Integer age) {
this.name = name;
this.age = age;
}
//自定义方法Method
public void show(){
System.out.println("it is reflect!");
}
public void show(String name){
System.out.println("it is "+name);
}
public void say(){
System.out.println("Hello World!");
}
//Getter、Setter、toString
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
@Override
public String toString() {
return "Person{" +
"name=‘" + name + ‘‘‘ +
", age=" + age +
‘}‘;
}
}
- 测试类
package com.itlike.reflect;
public class reflect2 {
public static void main(String[] args) throws Exception{
/**1.Class.forName("全类名")
* 运行结果:
* class com.itlike.reflect.Person
*/
Class clazz1 = Class.forName("com.itlike.reflect.Person");
System.out.println(clazz1);
/**
* 2.类名.class
* 运行结果:
* class com.itlike.reflect.Person
*/
Class clazz2 = Person.class;
System.out.println(clazz2);
/**
* 3.对象.getClass()
* 运行结果:
*class com.itlike.reflect.Person
*/
Person person = new Person();
Class clazz3 = person.getClass();
System.out.println(clazz3);
/**
* 三个对象是否是同一个呢?
* ==:比较地址
* equals():比较内容
*/
System.out.println(clazz1==clazz2); //true
System.out.println(clazz1==clazz3); //true
}
}
反射对象
成员变量
package com.itlike.reflect;
import java.lang.reflect.Field;
public class reflect2 {
public static void main(String[] args) throws Exception {
// 1.获取Class对象
Class clazz2 = Person.class;
/**
* Field[] getFields():获取所有public修饰的成员变量
* Field getField(String name):获取指定名称的public修饰的成员变量
* Field[] getDeclaredFields():获取所有的成员变量,不考虑修饰符
* Field getDeclaredField(String name):获取指定名称的成员变量
*/
// 2.取得所有成员变量(不仅仅public修饰,数组形式)
Field[] fields = clazz2.getDeclaredFields();
// 3.取得指定名称的成员变量(不存在就会跑出抛出异常)
Field name = clazz2.getDeclaredField("name");
/**
* 可以通过反射取得/修改成员变量的值
* public可以直接获取
* 非public需要忽略访问修饰符的安全检查
*/
Field age = clazz2.getDeclaredField("age");
// 非public修饰属性,需要忽略安全检查(暴力反射)
age.setAccessible(true);
// 4.获取值(需要一个使用对象的参数)
Person p = new Person();
Object value = age.get(p);
System.out.println(value); //null,说明成功获取!
// 5.设置值(age已忽略安全检查)
age.set(p, 23);
System.out.println(p);
}
}
构造方法
package com.itlike.reflect;
import java.lang.reflect.Constructor;
public class reflect2 {
public static void main(String[] args) throws Exception {
// 1.获取Class对象
Class clazz3 = Person.class;
/**
* Constructor<?>[] getConstructors()
* Constructor<T> getConstructor(类<?>... parameterTypes)
* Constructor<T> getDeclaredConstructor(类<?>... parameterTypes)
* Constructor<?>[] getDeclaredConstructors()
*/
// 2.取得单个构造方法(根据参数类型和个数判定)
Constructor constructor = clazz3.getConstructor(String.class,Integer.class);
/**
* 构造方法的用处?
* 创建对象:newInstance
*/
// 3.使用反射获取的构造方法创建对象
Person p1 = (Person)constructor.newInstance("张三",23);
System.out.println(p1);
/**
* 把上面的String.class,Integer.class去除,就是空参构造:
* Constructor constructor = clazz3.getConstructor();
* Person p = (Person)constructor.newInstance();
* System.out.println(p);
* //Person{name=‘null‘, age=null}
*
* 使用空参构造创建对象,Java提供了更简便的方法: *
*/
Person p2 = (Person)clazz3.newInstance();
System.out.println(p2);
/**
* getDeclaredConstructor:
* 使用对象是私有的构造方法,比较少见
* 如果需要,只要加上忽略安全检查即可。
*/
}
}
成员方法
package com.itlike.reflect;
import java.lang.reflect.Method;
public class reflect2 {
public static void main(String[] args) throws Exception {
// 1.获取Class对象
Class clazz3 = Person.class;
/**
* Method[] getMethods()
* Method getMethod(String name, 类<?>... parameterTypes)
* Method[] getDeclaredMethods()
* Method getDeclaredMethod(String name, 类<?>... parameterTypes)
*/
// 2.获取指定名称的成员方法
Method show = clazz3.getDeclaredMethod("show");
/**
* 如何执行获取的方法对象?
* 使用invoke(对象[,参数])
*/
Person p = new Person();
show.invoke(p);
/**
* 执行带参数的成员方法,要注意:
* 在获取Method时,需要传入参数类型
*/
// 3.使用带参数的Method,并执行
Method show2 = clazz3.getDeclaredMethod("show",String.class);
show2.invoke(p,"张三");
/**
* 其他的,诸如:
* 获取成员方法集合、单个成员方法
* 是否public修饰的成员方法
* 参照成员变量即可!
*
* 同样地,要获取非public修饰的方法,
* 也可以使用暴力反射!
* 不过要确保使用的是Declared!
*/
// 4.获取的是全部的方法,连带着Object(默认继承)的方法
Method[] methods = clazz3.getDeclaredMethods();
for (Method method : methods) {
System.out.println(method);
}
/** 暴力反射
* getDeclaredMethod在所有方法里获取say
* getMethod在public方法里获取say
*/
System.out.println("------------");
Method say = clazz3.getDeclaredMethod("say");
say.setAccessible(true); //暴力反射
say.invoke(p);
}
}
获取类名
// 获取类名
Person person = new Person();
String name = person.getClass().getName();
System.out.println(name);
小案例(反射的实际应用!)
目标:写一个"框架",在不改变该类任何代码的情况下, 能够帮助我们创建任意类的对象,并执行其中的任意方法。
- 步骤:
- 将需要创建的对象的全类名和需要执行的方法定义在配置文件当中
- 在程序中加载并读取配置文件
- 使用反射技术来加载类文件进入内存
- 创建对象
执行方法
我们使用
配置文件
来抽取全类名和方法
pro.properties
配置文件
className=com.itlike.reflect.Student
methodName=sleep
框架实现
package com.itlike.reflect;
import java.io.InputStream;
import java.lang.reflect.Method;
import java.util.Properties;
public class Test {
public static void main(String[] args) throws Exception {
// 1.创建Properties对象
Properties pro = new Properties();
// 2.获取类加载路径
ClassLoader classLoader = Test.class.getClassLoader();
// 3.加载配置文件
InputStream is = classLoader.getResourceAsStream("pro.properties");
pro.load(is);
// 4.获取配置文件中的数据(类和方法)
String className = pro.getProperty("className");
String methodName = pro.getProperty("methodName");
// 5.加载该类进内存(className是全类名)
Class cls = Class.forName(className);
// 6.创建对象
Object obj = cls.newInstance();
// 7.获取方法
Method method = cls.getDeclaredMethod(methodName);
method.setAccessible(true); //开启暴力反射
// 8.执行方法
method.invoke(obj);
}
}
测试:
在
pro.properties
配置文件中修改全类名和要执行的方法,直接运行该"框架"类即可!
以上是关于Java反射的主要内容,如果未能解决你的问题,请参考以下文章
使用反射在外部JAR / CLASS上调用包含Hibernate事务的方法(Java EE)