写过一篇Java中的反射机制,不算是写,应该是抄了,因为那是别人写的,这一篇也是别人写的,摘抄如下:

引自于Java基础--反射机制的知识点梳理,作者醉眼识朦胧。(()为我手记)

什么是反射?

正常编译执行java文件时,会生成一个.class文件,反射就是一个反编译的过程,它可以通过.class文件得到一个java对象。一个类会有很多组成部分,比如成员变量、成员方法、构造方法等,反射可以通过加载类(加载类是个什么东西?一直搞不清楚),解剖出类的各个组成部分。

为什么要用反射?

我们需要访问一个类的方法或字段的时候,直接new一个该类的对象然后调用就好了,干嘛要用反射呢?刚学的时候我也不懂,并且学了也没机会用到,或者根本用不到,后来开始接触strut2、hibernate等一些框架的时候,才慢慢懂得了一点反射的强大之处。在框架中会有很多配置文件,而配置文件中一般只有一些类的全路径的字符串,而就是通过这些个字符串,就能得到这个类的对象,以及类中所有的信息。我给你这个类,当然你可以轻松得到它的实例,但如果我给你的只是这个类的路径的字符串呢?没有反射你就傻眼了吧。学习反射一般只会在写框架的时候用到,如果你没有达到写框架的高度,能够看懂别人的框架也是极好的。

这里面还涉及到一个静态编译和动态编译(静态编译和动态编译应该是过的,但是忘记了)的概念,前者的意思就是在编译的时候已经绑定了对象,确定了对象;而动态编译就是直到运行的时候,才根据需要去绑定对象。

加载类:

加载类就是获得类的字节码。要想通过反射获取到一个类的内部信息,首先得先获取到这个类的字节码对象。

加载类有三种方式:

现在我有一个类User,我希望加载这个类,获得它的字节码对象:

package cn.ren.reflect2;

public class Demo {

    public static void main(String[] args) throws ClassNotFoundException {
//第一种方式, 通过Class的forName方法,注意使用目标类的全路径
Class clazz = Class.forName("cn.ren.reflect2.User"); //第二种方式,通过Object类的getClass()方法
Class clazz1 = new User().getClass(); //第三种方式,通过类的.class属性
Class clazz2 = User.class;
} }

一般第一种方式最常用,也最好用,因为看代码我们可以发现,后两种在编译前就必须要知道具体的类的,否则就无法通过编译,而第一种方式,没有那么大的强制性,他只是提供了一个空间,运行时你可以想把谁传给它就把谁传给它,这个类甚至可以不存在,后果只是抛出一个异常。

反射类的方法(Method):

一个类中总会有实现某些功能的方法,这些方法可能有返回值也可能没有返回值,可能有参数也可能没参数,可能是静态方法也可能是普通方法。下面通过例子分别讲解:

package cn.ren.reflect2;

import java.lang.reflect.Method;

public class Test {

    public static void main(String[] args) throws Exception {
User u = new User();
//通过Class的forName方法,注意使用目标类的全路径
Class clazz = Class.forName("cn.ren.reflect2.User"); /*
* 获取无参无返回值的方法login
* 获得一个方法名为"login"但是没有参数的Method对象
*/
Method method = clazz.getMethod("login", null); /*
* 第一个参数:要想执行这个login方法你总得告诉她是哪个User的login方法吧
* 第二个参数就是login方法的参数(实参),这里为null
*/
method.invoke(u, null); //获取有参有返回值的方法eat
Method method1 = clazz.getMethod("eat", String.class);
String agrs = (String) method1.invoke(u, "超人"); /*
* 获取带参无返回值的静态方法sleep
* 静态方法,可以不提供User对象,传一个null即可
*/
Method method2 = clazz.getMethod("sleep", String.class);
method2.invoke(null, "蝙蝠侠");
}
}

打印结果为:

无参构造函数
用户登录了
超人去吃饭了
蝙蝠侠去睡觉了

反射类的字段:

package cn.ren.reflect2;

import java.lang.reflect.Field;

public class Test1 {

    public static void main(String[] args) throws Exception {
User u = new User();
u.setName("钢铁侠");
//通过Class的forName方法,注意使用目标类的全路径
Class clazz = Class.forName("cn.ren.reflect2.User");
Field f = clazz.getDeclaredField("name");
//设置属性为可访问的
f.setAccessible(true);
//获取实例u中name属性的值
String name = (String) f.get(u);
System.out.println(name);
} }

下面介绍一个使用反射的简单例子:

(作者例子也举的不好,不知道要表达什么意思)

package cn.ren.reflect2;

interface Person {
public void location(String location);
} class Student implements Person { @Override
public void location(String location) {
System.out.println("学生的工作地点是:"+location);
} } class Teacher implements Person { @Override
public void location(String location) {
System.out.println("老师的工作地点是:"+location);
} } class Factory {
public static Person getInstance(String str) throws
InstantiationException, IllegalAccessException, ClassNotFoundException {
Person person = (Person)Class.forName(str).newInstance();
return person;
}
}
public class TestReflect { public static void main(String[] args) throws
InstantiationException, IllegalAccessException, ClassNotFoundException {
Student s = (Student)Factory.getInstance("cn.ren.reflect2.Student");
s.location("学校");
} }

这个例子使用了简单的工厂模式,调用person的location方法,通过反射,实际应用中并不会出现这样的代码,这里只是做一个反射的运用的演示。在测试代码中,只要简单的修改ForName方法中的字符串,就可以调用相应的方法。


以下为我的手记,真是不要脸,依然是摘抄别人的。我多借鉴于传智播客李勇Jdbc视频笔记(26-33),作者:longdechuanren

以下紧接我的《JDBC第三次学习》的内容。

传递给你一个Class的对象,用它来构造一对象如果这个对象有无参的构造方法那么就clazz.newInstance(),直接newInstance就可以了,但是如果没有无参的构造方法,就要首先根据参数类型得到构造方法,然后再去构造对象。例如:

static Object create(Class clazz) throws Exception {
Constructor con = clazz.getConstructor(String.class);
/*
* 利用反射技术构造一个实例
*/
Object obj = con.newInstance("test name");
return obj;
}

Java反射的更多的细节:

static Object create(Class clazz) throws Exception {
Constructor con = clazz.getConstructor(String.class);
/*
* 利用反射技术构造一个实例
*/
Object obj = con.newInstance("test name");
return obj;
} static void invoke1(Object obj, String methodName)
throws IllegalAccessException, IllegalArgumentException,
InvocationTargetException, NoSuchMethodException, SecurityException {
/*
* 得到类中所有声明的方法,包括私有方法但不能得到从父类继承来的任何方法
*/
Method[] ms = obj.getClass().getDeclaredMethods();
/*
* 得到所有的方法包括从父类继承来的,但得不到私有方法
* 下面得到属性和得到注解都一样,主要理解两个方法getDeclaredMethods()与getMethods()的不同
*/
ms = obj.getClass().getMethods();//推荐使用
for(Method m : ms) {
//System.out.println(m.getName());
if(methodName.equals(m.getName()))
m.invoke(obj, null);
} Method m = obj.getClass().getMethod(methodName, null);
m.invoke(obj, null);
} static void field(Class clazz) throws Exception {
Field[] fs = clazz.getDeclaredFields();
//fs = clazz.getFields();//取得的属性都是public
for(Field f : fs) {
System.out.println(f.getName());
}
} static void annon(Class clazz) throws Exception {
Annotation[] as = clazz.getAnnotations();
}

利用Java反射技术将查询结果封装为对象,

在这个示例中,约定数据库的字段名要和属性的字段名一致, String methodName = "set" + 数据库的字段名。用这样的方法来构成,JavaBean中属性的set方法来实现赋值操作,那么在传递sql语句的时候就有一定的局限性了,例如:你不能写 select id , name from user。因为这样得到的set方法setid、setname这样就没法完成赋值操作,要这样写:select id as Id, name as Name fromt user,然后用ResultSetMetadata的getColumnLabel()得到它的别名,然后遍历JavaBean中所有的方法找到和我们这个名字一样的,然后执行就可以了,但是通过sql语句来操纵属性名称然后构成方法名,这样的方式不大好。

代码如下(一个简单的对象关系映射Object Relational Mapping):

/*
* 对象关系映射(ORM)
*/
public class ORMTest { public static void main(String[] args) throws IllegalAccessException, IllegalArgumentException,
InvocationTargetException, SQLException, InstantiationException {
User user = (User)getObject("select id as Id,name as Name,birthday as Birthday,money as Money"
+ " from user where id = 1", User.class);
System.out.println(user); Bean b = (Bean)getObject("select id as Id,name as Name,birthday as Birthday,money as Money"
+ " from user where id = 1", Bean.class);
System.out.println(b);
} /*
* 明确返回类型是User,写死在程序里
*/
static User getUser(String sql) throws IllegalAccessException, IllegalArgumentException,
InvocationTargetException, SQLException {
Connection conn = null;
PreparedStatement ps = null;
ResultSet rs = null;
try {
conn = JdbcUtils.getConnection();
ps = conn.prepareStatement(sql);
rs = ps.executeQuery(); ResultSetMetaData rsmd = rs.getMetaData();
int count = rsmd.getColumnCount();
String[] colNames = new String[count]; for(int i = 1; i <= count; i++) {
colNames[i-1] = rsmd.getColumnLabel(i);
} User user = null;//User类是符合JavaBean规范的
Method[] ms = user.getClass().getMethods();
if(rs.next()) {
user = new User();
for(int i = 0; i < colNames.length; i++) {
String colName = colNames[i];
String methodName = "set"+colName;
System.out.println(methodName);
for(Method m : ms) {
if(methodName.equals(m.getName())) {
m.invoke(user, rs.getObject(colName));//setXxx()方法传递参数:rs.getObject("colName")
}
}
}
}
return user;
} finally {
JdbcUtils.free(rs, ps, conn);
}
} /*
* 由于返回类型是Object,所以此方法更为通用
*/
static Object getObject(String sql, Class clazz) throws IllegalAccessException, IllegalArgumentException,
InvocationTargetException, SQLException, InstantiationException {
Connection conn = null;
PreparedStatement ps = null;
ResultSet rs = null;
try {
conn = JdbcUtils.getConnection();
ps = conn.prepareStatement(sql);
rs = ps.executeQuery(); ResultSetMetaData rsmd = rs.getMetaData();
int count = rsmd.getColumnCount();
String[] colNames = new String[count]; for(int i = 1; i <= count; i++) {
colNames[i-1] = rsmd.getColumnLabel(i);
} Object obj = null;
Method[] ms = clazz.getMethods();
if(rs.next()) {
obj = clazz.newInstance();
for(int i = 0; i < colNames.length; i++) {
String colName = colNames[i];
String methodName = "set"+colName;
for(Method m : ms) {
if(methodName.equals(m.getName())) {
m.invoke(obj, rs.getObject(colName));//setXxx()方法传递参数:rs.getObject("colName")
}
}
}
}
return obj;
} finally {
JdbcUtils.free(rs, ps, conn);
}
}
}

浅说Java中的反射机制(二)的更多相关文章

  1. 浅说Java中的反射机制(一)

    在学习传智播客李勇老师的JDBC系列时,会出现反射的概念,由于又是第一次见,不免感到陌生.所以再次在博客园找到一篇文章,先记录如下: 引用自java中的反射机制,作者bingoideas.(()为我手 ...

  2. 【Java基础】java中的反射机制与动态代理

    一.java中的反射机制 java反射的官方定义:在运行状态下,可以获取任意一个类的所有属性和方法,并且可通过某类任意一对象实例调用该类的所有方法.这种动态获取类的信息及动态调用类中方法的功能称为ja ...

  3. java中的反射机制在Android开发中的用处

    JAVA反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法:对于任意一个对象,都能够调用它的任意一个方法和属性:这种动态获取的信息以及动态调用对象的方法的功能称为java语言的反 ...

  4. java 中利用反射机制获取和设置实体类的属性值

    摘要: 在java编程中,我们经常不知道传入自己方法中的实体类中到底有哪些方法,或者,我们需要根据用户传入的不同的属性来给对象设置不同的属性值,那么,java自带的反射机制可以很方便的达到这种目的,同 ...

  5. 深入理解Java中的反射机制

    JAVA反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法:对于任意一个对象,都能够调用它的任意方法和属性:这种动态获取信息以及动态调用对象方法的功能称为java语言的反射机制. ...

  6. Java中的反射机制和动态代理

    一.反射概述 反射机制指的是Java在运行时候有一种自观的能力,能够了解自身的情况为下一步做准备,其想表达的意思就是:在运行状态中,对于任意一个类,都能够获取到这个类的所有属性和方法:对于任意一个对象 ...

  7. java中的反射(二)

    java中的反射(一):https://www.cnblogs.com/KeleLLXin/p/14060555.html 目录 一.反射 1.class类 2.访问字段 3.调用方法 4.调用构造方 ...

  8. Java中的反射机制Reflection

    目录 什么是反射? 获取.class字节码文件对象 获取该.class字节码文件对象的详细信息 通过反射机制执行函数 反射链 反射机制是java的一个非常重要的机制,一些著名的应用框架都使用了此机制, ...

  9. Java 中的反射机制

    JAVA反射机制 JAVA反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法:对于任意一个对象,都能够调用它的任意一个方法:这种动态获取的信息以及动态调用对象的方法的功能称为ja ...

随机推荐

  1. 关于Filezilla是否支持sftp

    我们知道filezilla是一个开源的ftp的解决方案,它提供了客户端和服务器端,支持的fpt, sftp, ftps,这是你可以从wiki中看到的关于filezilla的介绍,但是这里需要澄清一点就 ...

  2. 2.Knockout.Js(监控属性Observables)

    前言 1.创建一个ViewModel <script type="text/javascript"> //1.创建一个ViewModel var myViewModel ...

  3. PB建数据窗口的时候会报内存错误

     同事碰到了这个问题,百度了一下,按照下边的方法解决了 ------解决方案--------------------我遇到过,是powerbuilder的注册表出问题了,找到注册表中HKEY_USER ...

  4. Midway-ModelProxy — 轻量级的接口配置建模框架

    Midway-ModelProxy - 轻量级的接口配置建模框架 前言 使用Node做前后端分离的开发模式带来了一些性能及开发流程上的优势(见<前后端分离的思考与实践 一>), 但同时也面 ...

  5. WEB 容器、WEB服务和应用服务器的区别与联系

    Web容器:    何为容器?    容器是一种服务调用规范框架,j2ee大量运用了容器和组件技术来构建分层的企业级应用,在J2EE规范中,相应的有Web Container和EJB Containe ...

  6. 如何维护SSH安全

    遇到两次,一次是公司服务器搭建好后,有人尝试ssh暴力破解,auth.log不停出现错误提示 还有买的米国vps,很荣幸地遭到来自波兰的ssh破解尝试 不得不重视ssh的安全 方法: 修改sshd_c ...

  7. Asp.net开启分布式事务管理

    1.确保服务器分布式管理服务 Distributed Transcation Coordinator 有开启 2.使用分布式事务代码的项目中添加System.Transactions程序集的引用 3. ...

  8. navicat for mysql 注册码

    PremiumSoft Navicat for MySQL Enterprise Edition v8.0.27 姓名(Name):3ddown.com 组织(Organization):3ddown ...

  9. Hibernate映射类型对照表

    Hibernate映射类型对照表 java类型  Hibernate映射类型  SQL类型 java.math.BigDecimal big_decimal numeric byte[] binary ...

  10. JS判断用户是否在线的方法

    在以前坐项目的时候,经常碰见通过sessionLisnter来判断用户是否在线的方法,但是由于用户关闭浏览器时不会立刻是否session,因此大部分时候都考虑在页面中通过JS来监控页面是否关闭. 网络 ...