19.java反射入门
一、反射机制是什么
反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;
对于任意一个对象,都能够调用它的任意一个方法和属性;
这种动态获取的信息以及动态调用对象的方法的功能称为java语言的反射机制。
二、反射机制能做什么
1.在运行时判断任意一个对象所属的类;
2.在运行时构造任意一个类的对象;
3.在运行时判断任意一个类所具有的成员变量和方法;
4.在运行时调用任意一个对象的方法;
5.生成动态代理。
三、反射机制的相关API
图片来源于 http://c.biancheng.net/view/1103.html
1.通过一个对象获得完整的包名和类名:
对象名.getClass().getName();
2.实例化Class类对象:
①clazz1 = Class.forName("完整的包名和类名");
②clazz2 = new 构造方法.getClass();
= 对象名.getClass();
③clazz3 = 类名.class;
3.获取一个对象的父类与实现的接口:
获得父类:clazz.getSuperclass();
获得所有的接口:clazz.getInterfaces();
4.获取某个类中的全部构造函数,实例化一个类的对象
①第一种方法,实例化默认构造方法:clazz.newInstance();
②第二种方法,取得全部的构造函数,可先查看每个构造函数的参数类型,再使用构造函数赋值:
clazz.getConstructors()[i].getParameterTypes()[j].getName();
clazz.getConstructors()[i].newInstance(参数);
5.获取某个类的全部属性:
本类的所有属性:
clazz.getDeclaredFields();
父类或实现的接口的所有属性:
clazz.getFields();
属性名:
fields[i].getName();
属性权限修饰符:
int mo = field[i].getModifiers();
String priv = Modifier.toString(mo);
属性类型:
field[i].getType();
属性类型名:
field[i].getType().getName();
6.获取某个类的全部方法
全部方法:
clazz.getMethods();
方法的返回类型:
methods[i].getReturnType();
某个方法的所有参数类型:
methods[i].getParameterTypes();
7.调用某个类的方法
Method method = clazz.getMethod("方法名",new Class[]{参数类型1,参数类型2,...});
method.invoke(对象名,new Object[]{参数1,参数2,...});
8.操作某个类的属性
可以直接对 private 的属性赋值:
Field field = clazz.getDeclaredField("属性名");
field.setAccessible(true);
field.set(对象名,"属性值");
四、反射机制的应用实例
1.在泛型为Integer的ArrayList中存放一个String类型的对象。
2.通过反射取得并修改数组的信息
3.通过反射机制修改数组的大小
4.将反射机制应用于工厂模式
实例1:利用反射来审查一个对象的内部
Main.java
package reflecttest; import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List; public class Main { public static void main(String[] args) {
// 打开连接
// 准备语句,设置参数
// 发送语句,执行并处理结果集(ResultSet)
// 遍历结果集,把每一行封装成对象
/*
List<Student> students = new ArrayList<>();
for (row : resultSet) {
Student student = new Student(); // 要素1:要new的是哪个类
student.setId(row.getInt(1)); // 要素2:这个类中有哪些属性,并且要能调用其setter
student.setName(row.getString(2));
student.setAge(row.getInt(3));
students.add(student);
}
*/
// Java中类似镜子的机制叫做反射,可以用来审查某个对象或者某个类的内部(哪些字段,哪些方法,调用之)
// 这面镜子叫做元对象(meta object),元数据
Student student = new Student(1, "zhangan", 20);
inspect(student);
inspect(new Teacher(1, "lisi", "软件工程"));
} /**
* 审查一个对象(打印类名,打印声明的字段列表,打印定义的方法列表)
* @param o
*/
private static void inspect(Object o) {
Class clazz = o.getClass(); // 获取描述对象的元数据
System.out.println("限定类名:" + clazz.getName());
System.out.println("简单类名:" + clazz.getSimpleName()); Field[] fields = clazz.getDeclaredFields(); // 包括public、private等,但排除集成的字段
// System.out.println(Arrays.toString(fields));
// 打印字段列表
for (int i = 0; i < fields.length; i++) {
Field field = fields[i]; // field等元信息是跟类走的
Object value;
try {
// value = field.get(o); // 实际取值或者调用时得传入目标对象(与对象挂钩的)
// 默认是不能访问私有字段的,改为调用其getter
String getterName = "get" + StringUtils.cap(field.getName()); // getName, getAge
Method getter = clazz.getDeclaredMethod(getterName);
value = getter.invoke(o);
} catch (Exception e) {
e.printStackTrace();
value = "--- 取值错误 ---";
}
System.out.println("字段:" + field.getName() + ", " +
field.getType().getSimpleName() + " = " + value);
} // 打印方法列表
Method[] methods = clazz.getDeclaredMethods();
for (int i = 0; i < methods.length; i++) {
Method method = methods[i];
System.out.println("方法:" + method.getName() + ", " +
method.getReturnType().getSimpleName());
}
}
}
StringUtils.java
package reflecttest; public class StringUtils { /**
* 将首字母大写
* @param name
* @return
*/
public static String cap(String name) {
return name.substring(0, 1).toUpperCase() + name.substring(1);
}
}
Student.java
package reflecttest; public class Student { private Integer id;
private String name;
private int age;
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public Student(Integer id, String name, int age) {
this.id = id;
this.name = name;
this.age = age;
}
public Student() {
} @Override
public String toString() {
return "Student [id=" + id + ", name=" + name + ", age=" + age + "]";
} }
Teacher.java
package reflecttest; public class Teacher { private Integer id;
private String name;
private String major;
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getMajor() {
return major;
}
public void setMajor(String major) {
this.major = major;
}
public Teacher(Integer id, String name, String major) {
this.id = id;
this.name = name;
this.major = major;
}
public Teacher() {
}
}
实例2:利用反射给对象属性赋值
Mapper.java
package reflecttest; import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Map; /**
* 作为MyBatis的一个最原始的原型
* @author Administrator
*
*/
public class Mapper { /**
* 将row中的每一列set到目标类的对象上
* @param clazz
* @param row
* @return
*/
public static Object map(Class clazz, Map<String, Object> row) {
// new一个目标对象
// new Student()
try {
// 获取无参构造器
Constructor constructor = clazz.getDeclaredConstructor();
Object obj = constructor.newInstance(); // 将各列set到obj的属性上,如id列就setId(?)
for (String columnName : row.keySet()) {
// System.out.println(columnName + " -> " + row.get(columnName));
Object value = row.get(columnName);
String setterName = "set" + StringUtils.cap(columnName);
// 此处忽略一个细节:如果列名对应的setter不存在应该忽略该列
Field field = clazz.getDeclaredField(columnName);
Method setter = clazz.getDeclaredMethod(setterName, field.getType());
setter.invoke(obj, value);
}
return obj;
} catch (Exception e) {
throw new RuntimeException(e);
}
} public static void main(String[] args) {
Map<String, Object> row = new HashMap<String, Object>();
row.put("id", 3);
row.put("name", "王五");
row.put("age", 25); Object obj = map(Student.class, row);
System.out.println(obj);
}
}
实例3:利用Apache Commons工具来复制对象(属性)
BeanUtilsTest.java
package reflecttest; import java.lang.reflect.InvocationTargetException; import org.apache.commons.beanutils.PropertyUtils; public class BeanUtilsTest { public static void main(String[] args) throws Exception {
// 如何获取bean属性
// id, name, age
Student o = new Student(5, "xyz", 30);
String name = (String) PropertyUtils.getProperty(o, "name");
System.out.println("name: " + name); // 如何设置bean属性
PropertyUtils.setProperty(o, "name", "张三");
System.out.println(o.getName()); // 应该是张三 // 如何复制所有属性
Student o2 = new Student();
PropertyUtils.copyProperties(o2, o);
System.out.println(o2);
}
}
案例4:利用反射完成javabean之间的复制
package com.myreflect; import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method; import com.pojo.User; public class ReflectDemo {
//写一个类,写一个方法完成两个数求幂值 x的n次方值
//用反射来调用此方法 //写一个工具类,完成功能是javabean之间的复制 方法的原型:copyObject(Object obj1,Object obj2);
//从obj1到obj2的复制功能
//思路:Student对象 有属性:id,name,age,sex,birthday 有方法:Set和get方法
//1.创建一个学员类给其属性赋值,然后再创建一个新的学员类,将原来的学员对象的值复制到新的学员对象中
public void copy(Object obj1,Object obj2) throws Exception{
//1.拿到obj1和obj2的类型
Class c1 = obj1.getClass();
Class c2 = obj2.getClass();
//2.通过类型中的获取obj1的get方法取值。obj2的set方法来完成复制功能 Field[] fs1 = c1.getDeclaredFields();
//获取c1中以get开头属性名结尾的所有方法
for (int i = 0; i < fs1.length; i++) {
String getmethodName = "get"+cap(fs1[i].getName());
Method getMethod = c1.getDeclaredMethod(getmethodName,null); String setmethodName = "set"+cap(fs1[i].getName());
Method setMethod = c2.getDeclaredMethod(setmethodName, new Class[]{fs1[i].getType()}); Object result = getMethod.invoke(obj1, null);
setMethod.invoke(obj2, new Object[]{result});
}
}
public String cap(String name) {
return name.substring(0, 1).toUpperCase() + name.substring(1);
} public static void main(String[] args) throws Exception {
User user1 = new User();
user1.setUsername("张三");
user1.setPwd("q2w"); User user2 = new User();
ReflectDemo rd = new ReflectDemo();
rd.copy(user1, user2); System.out.println(user2.getUsername()+" "+user2.getPwd()); }
}
19.java反射入门的更多相关文章
- java反射入门
http://www.cnblogs.com/rollenholt/archive/2011/09/02/2163758.html package reflectTest; class Demo{ / ...
- Java反射01 : 概念、入门示例、用途及注意事项
1.Java反射定义 本文转载自:https://blog.csdn.net/hanchao5272/article/details/79360452 官方定义如下: Reflection enabl ...
- 【转】JAVA反射与注解
转载自:https://www.daidingkang.cc/2017/07/18/java-reflection-annotations/ 前言 现在在我们构建自己或公司的项目中,或多或少都会依赖几 ...
- java反射机制入门01
java反射机制入门是我从极客学院的视频中学习的. 1.反射机制背景概述 反射(Reflection)是java被视为动态(或准动态)语言的一个关键性质.反射机制指的是程序在运行时能够获取任何类的内部 ...
- 大白话说Java反射:入门、使用、原理
文章首发于[博客园-陈树义],点击跳转到原文<大白话说Java反射:入门.进阶.原理> 反射之中包含了一个「反」字,所以想要解释反射就必须先从「正」开始解释. 一般情况下,我们使用某个类时 ...
- Java反射-初步入门
Java反射-初步入门 学反射先了解什么是反射. 百度百科:JAVA反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法:对于任意一个对象,都能够调用它的任意一个方法和属性:这种动 ...
- 大白话说Java反射:入门、使用、原理 (转)
文章首发于[博客园-陈树义],点击跳转到原文<大白话说Java反射:入门.进阶.原理> 目录 一个简单的例子 反射常用API 获取反射中的Class对象 通过反射创建类对象 通过反射获取类 ...
- java反射快速入门(二)
上一遍博文 , 简单介绍java 反射的常用接口,本遍博文, 我会结合项目开发的实际例子讲解下 java反射的使用 现在有个需求, 要将一个对象转换成xml格式, 或者将一串xml转换一个对象, 这时 ...
- java反射快速入门(一)
本文会从以下几个方面讲起 ① 反射的简单解释 ② java反射的API接口 及 demo ③ 反射的优缺点.应用场景 一.什么是反射? java反射:在程序运行中动态获取类的信息,及动态调用对象的方法 ...
随机推荐
- SpringCloud Config客户端
SpringCloud Config服务端 1.导入依赖 <dependency> <groupId>org.springframework.cloud</groupI ...
- Google SwipeRefreshLayout(Goolge官方下拉刷新控件)尝鲜
前天Google官方终于出了Android刷新控件——SwipeRefreshLayout. 使用前先需要将android.support.v4.jar升级到19.1.升级后,可能会出现SDK版本与A ...
- 痞子衡嵌入式:ARM Cortex-M文件那些事(5)- 映射文件(.map)
大家好,我是痞子衡,是正经搞技术的痞子.今天痞子衡给大家讲的是嵌入式开发里的map文件. 第四节课里,痞子衡给大家介绍了第一种output文件-relocatable文件,本文继续给大家讲projec ...
- .Net Core 实践 - 使用log4net记录日志(3)— log4net向ElasticSearch写日志
demo地址:https://github.com/PuzzledAlien/log4net_demo/tree/master/DotNetCoreConsole_V3 Windows 10 安装部署 ...
- C# 创建EXCEL图表并保存为图片
数据表格能够清晰的呈现数据信息,但是我们对于一些繁杂多变的数据想要很直观的看到数据变化走势或者数据的占比时,数据图表会更具代表性,并且在呈现数据信息上也更形象,也能获取更多纯数字信息所不能直接展现的信 ...
- Java开发笔记(十二)布尔变量论道与或非
在编程语言的设计之初,它们除了可以进行数学计算,还常常用于逻辑推理和条件判断.为了实现逻辑判断的功能,Java引入了一种布尔类型boolean,用来表示“真”和“假”.该类型的变量只允许两个取值,即t ...
- Django学习之二:Django 项目创建 和 应用创建
Django 项目创建 和 应用创建 创建一个Django项目 都是在相应平台的命令行环境下操作: 1. 进入用于存放项目的目录下 1.1 windows下切换目录:先进入具体的分区磁盘中如E盘就输入 ...
- vue 常用语法糖
//来自 https://www.cnblogs.com/lhl66/p/8021730.html 侵删 el:element 需要获取的元素,一定是HTML中的根容器元素 data:用于数据的存储 ...
- js获取地址栏传参
地址:http://127.0.0.1:8082/prosperleedir/index.html?id=6666&name=prosper#prosper Location{ ...
- 腾讯云服务器 ubuntu 设置允许root用户登录
背景:最近购买了腾讯云服务器,使用了Ubuntu Server 14.04.1 LTS 64位操作系统,腾讯云主机ubuntu系统默认用户名为ubuntu,登录服务器时每一次都是以默认账号ubuntu ...