网站首页 > java教程 正文
JAVA反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意一个方法和属性;这种动态获取的信息以及动态调用对象的方法的功能称为java语言的反射机制。—百度百科
动态:运行期间动态绑定执行规则。
静态:编译以后就已经确定的执行过程。
一、动态获取类的信息
动态获取类的方法信息
Foo类(package:demo):
//编译以后是 demo.Foo.class
//类的全名是 demo.Foo
class Foo{
public int test(){
return 5;
}
public double test1(){
return 5d;
}
}
动态获取Foo类的方法:
@Test
public void testClassForName(){
/*
* 动态的加载类信息到方法区
* 并且返回对应的Class对象!
* Class 对象可以访问类的全部信息!
*
* 将className对应的类文件,从磁盘中加载
* 内存方法区,返回这个类的信息
*/
String className = "demo.Foo";
try {
Class<?> cls = Class.forName(className);
Method[] all = cls.getDeclaredMethods();
for (Method method : all) {
System.out.println(method.getName());
}
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
//输出:
// test
// test1
动态获取类的属性信息
Eoo类:
class Eoo{
int id;
String name;
double salary;
String meno;
public Eoo(){}
public Eoo(int id, String name, double salary, String meno) {
super();
this.id = id;
this.name = name;
this.salary = salary;
this.meno = meno;
}
// get,set略
}
动态获取Eoo类的属性:
@Test
public void testField()throws Exception {
/*
* 动态获取一个类的全部属性信息
* 1 动态加载一个类到方法区
* 2 动态获取类的属性信息
*/
String className = "demo.Eoo";
// 动态加载类
Class<?> cls = Class.forName(className);
// 动态获取类声明的属性信息
Field[] all = cls.getDeclaredFields();
for (Field field : all) {
// getName 获取属性的名字
System.out.print(field.getName() + " ");
}
}
// id name salary meno
动态获取类的构造器信息
@Test
public void testCon() throws Exception{
/*
* 1 动态加载类
*/
String className = "demo.Eoo";
Class<?> cls = Class.forName(className);
Constructor[] all = cls.getDeclaredConstructors();
for (Constructor c : all) {
System.out.print(c.getName());
//获取构造器的参数类型列表
// Parameter 参数 Type类型
// Class[] 代表所有参数的类型列表
Class[] types = c.getParameterTypes();
System.out.println(Arrays.toString(types));
}
}
// demo.Eoo[]
// demo.Eoo[int, class java.lang.String, double, class java.lang.String]
二、动态创建对象
调用无参构造器创建对象
如果没有无参数构造器,将发生异常!Class 提供了方法 newInstance()。
@Test
public void testNewInstance() throws Exception{
/*
* 动态调用无参数构造器创建对象
* 1 动态加载类
* 2 利用class 的方法 newInstance 执行
* 无参数构造器常见对象
* 注意:类必须有无参数,否则出异常
*/
String className = "java.util.Date";
Class<?> cls = Class.forName(className);
// cls.newInstance()调用无参数构造器创建对象
Object obj = cls.newInstance();
System.out.println(obj);
//静态的创建对象!编译已经就固定了!
Date date = new Date();
}
// Fri Sep 16 20:04:55 CST 2020
调用有参构造器创建对象
如果没有对应有参数构造器!将发生异常!参数传递错误、将发生异常!
/**
* 调用 className 类名对应的类的有参数构造器,paramTypes 代表对应构造器的参数列表
* className + paramTypes 共同决定调用哪个构造器!执行构造器还需要具体的参数params
*/
public Object create(String className,Class[] paramTypes,Object[] params)
throws Exception{
// 动态加载类
// 动态获取指定参数类型的构造器
// 执行这个构造器,传递 params 参数。
Class<?> cls = Class.forName(className);
//getDeclaredConstructor 在类信息中查找
//给定参数类型的构造器信息
Constructor c = cls.getDeclaredConstructor(paramTypes);
//执行构造器 c.newInstance() 方法,创建对象
//返回值就是这个构造器创建的对象
Object obj = c.newInstance(params);
return obj;
}
@Test
public void testCreate() throws Exception {
String className = "java.util.Date";
//类型列表==Class类型的数组
Class[] paramTypes = {long.class};
//实际参数列表
Object[] params={-1000L * 60 * 60 * 24 * 365};
Object obj = create(className, paramTypes, params);
System.out.println(obj);
//思考:如何动态调用 new String("Hello");
className = "java.lang.String";
/*
* {} 只能拥有声明变量时候直接初始化
* 不能用于赋值语句!
* 赋值语句可以使用 new Object[]{"Hello"}
*/
paramTypes = new Class[]{String.class};
params = new Object[]{"Hello"};
obj = create(className, paramTypes, params);
System.out.println(obj);//Hello
//思考:如何动态调用 new String(byte[],"utf-8");
obj = create("java.lang.String", new Class[]{byte[].class, String.class},
new Object[]{new byte[]{65,66,67,68}, "UTF-8"});
System.out.println(obj);
}
// Wed Jan 01 08:00:00 CST 1969
// Hello
// ABCD
三、动态获取类的属性值
实现过程(如何利用反射API实现动态属性访问):
1、找到对象的类型信息(方法区)
2、在信息中找属性信息(Field)
3、在对象上获取属性的值!
类Goo:
public class Goo {
public int id;
public String name;
public Goo() {}
public Goo(int id, String name) {
super();
this.id = id;
this.name = name;
}
}
动态获取属性的值:
/**
* 获取obj对象的 fieldName 对应属性的值
* @param obj
* @param fieldName
* @return 属性值
*/
public Object get(Object obj, String fieldName)throws Exception{
//1 获取类信息
/*
* Java 中对象的getClass()方法可以获取 对象的类型信息!
* Java 中 有3种方法可以获取Class信息
* 1. 类名.class 获取类信息(静态)
* 2. Class.forName("类名") 获取类信息 动态
* 3. obj.getClass() 获取类信息。运行期间,通过当前对象获取类信息
*/
Class<?> cls = obj.getClass();
//找到属性:
/*
* getDeclaredField 按照属性名在cls中查找
* 类信息。 当属性没有找到时候,抛出异常!
*/
Field field = cls.getDeclaredField(fieldName);
//在对象上获取属性的值!
/*
* get方法:在一个对象上获取属性的值,对象上没有对应的属性,抛出异常
*/
Object value = field.get(obj);
return value;
}
@Test
public void testGetField()throws Exception {
/*
* 动态获取对象的属性
*/
Goo goo = new Goo(5, "Tom");
Object v1 = get(goo, "id");
Object v2 = get(goo, "name");
System.out.println(v1+" "+v2);
}
// 5 Tom
四、动态调用类的方法
@Test
public void testinvoke()throws Exception{
List<String> list=new ArrayList<String>();
list.add("tom");
list.add("jack");
// 动态获取类信息
Class<?> cls = list.getClass();
// 通过方法名和参数类型找到对应的方法
Method method = cls.getDeclaredMethod("remove", new Class[]{int.class});
// 调用方法,传递对象和具体参数
Object value=method.invoke(list,new Object[]{0});
System.out.println(value); //tom
}
五、反射的意义
常见的框架的底层都是使用反射实现的!如:Spring、MyBatis、Struts2、Hibernate …
现有application.xml文件:
<?xml version="1.0" encoding="UTF-8"?>
<beans>
<bean id="date" class="java.util.Date"></bean>
<bean id="list" class="java.util.ArrayList"></bean>
</beans>
模拟Spring框架的getBean()方法:
public class ApplicationContext {
private HashMap<String, Object> map= new HashMap<>();
public ApplicationContext(String xml) {
SAXReader reader = new SAXReader();
try{
//读取xml
InputStream in = this.getClass().getClassLoader().getResourceAsStream(xml);
Document doc = reader.read(in);
//解析XML内容 获取全部的<bean>
List<Element> beans = doc.getRootElement().elements();
for (Element e : beans) {
//e 是每个 <bean> 元素
String id = e.attributeValue("id");
String className = e.attributeValue("class");
//利用反射创建对象
Class cls = Class.forName(className);
Object obj = cls.newInstance();
//对象缓存到 map中
map.put(id, obj);
}
}catch(Exception e){
e.printStackTrace();
throw new RuntimeException(e);
}
}
public Object getBean(String id){
return map.get(id);
}
public static void main(String[] args) {
String conf = "application.xml";
ApplicationContext ac = new ApplicationContext(conf);
Object o = ac.getBean("date");
System.out.println(o);
}
}
// Fri Sep 16 21:30:07 CST 2020
猜你喜欢
- 2024-09-12 学习java应该如何理解反射?(怎么理解java反射)
- 2024-09-12 Java反射详解(java反射总结)
- 2024-09-12 读懂框架设计的灵魂—Java 反射机制
- 2024-09-12 Java的反射机制(java的反射机制是什么)
- 2024-09-12 java反射机制Java反射机制是什么?原理详解
- 2024-09-12 聊一聊Java当中的反射机制(java的反射机制是什么)
- 2024-09-12 Java反射机制的理解(java反射机制的理解和认识)
- 2024-09-12 聊一聊Java的反射机制?(java的反射机制是什么)
- 2024-09-12 Java学习之二——JAVA反射机制(java 反射机制原理)
- 2024-09-12 实操讲解Java的反射机制,你要是再看不懂,神仙都没救了
你 发表评论:
欢迎- 05-23Java线程池:核心参数与最佳实践
- 05-23深入理解 Java 的线程池原理
- 05-23面试突击34:如何使用线程池执行定时任务?
- 05-23Java线程池核心参数调优指南:掌控并发世界的钥匙
- 05-23Java线程池:优雅管理并发任务的艺术
- 05-23一篇文章快速搞懂Java中常用的四种线程池
- 05-23Java线程池工作原理深度解读:从创建到任务执行的全过程
- 05-23一文看懂:Java线程池任务拒绝机制解析
- 最近发表
- 标签列表
-
- java反编译工具 (77)
- java反射 (57)
- java接口 (61)
- java随机数 (63)
- java7下载 (59)
- java数据结构 (61)
- java 三目运算符 (65)
- java对象转map (63)
- Java继承 (69)
- java字符串替换 (60)
- 快速排序java (59)
- java并发编程 (58)
- java api文档 (60)
- centos安装java (57)
- java调用webservice接口 (61)
- java深拷贝 (61)
- 工厂模式java (59)
- java代理模式 (59)
- java.lang (57)
- java连接mysql数据库 (67)
- java重载 (68)
- java 循环语句 (66)
- java反序列化 (58)
- java时间函数 (60)
- java是值传递还是引用传递 (62)
本文暂时没有评论,来添加一个吧(●'◡'●)