java反射

反射的作用与原理。 如何提高反射效率?
1.定义: 反射机制是在运行时, 对于任意一个类, 都能够知道这个类的所
有属性和方法; 对于任意一个对象, 都能够调用它的任意一个方法。 在 java 中,
只要给定类的名字, 那么就可以通过反射机制来获得类的所有信息。
2.反射机制主要提供了以下功能: 在运行时判定任意一个对象所属的类;
在运行时创建对象; 在运行时判定任意一个类所具有的成员变量和方法; 在运
行时调用任意一个对象的方法; 生成动态代理。
3.哪里用到反射机制?
jdbc 中有一行代码:
Class.forName('com.mysql.jdbc.Driver.class');//加载 MySql 的驱动类。 这就
是反射, 现在很多框架都用到反射机制, hibernate, struts 都是用反射机制实
现的。
4.反射的实现方式
在 Java 中实现反射最重要的一步, 也是第一步就是获取 Class 对象, 得到
Class 对象后可以通过该对象调用相应的方法来获取该类中的属性、方法以及调
用该类中的方法。
有 4 种方法可以得到 Class 对象:
1.Class.forName(“类的路径” );
2.类名.class。
3.对象名.getClass()。
4.如果是基本类型的包装类, 则可以通过调用包装类的 Type 属性来获得
该包装类的 Class 对象。
例如: Class<?> clazz = Integer.TYPE;


4.实现 Java 反射的类
1)Class: 它表示正在运行的 Java 应用程序中的类和接口。
2)Field: 提供有关类或接口的属性信息, 以及对它的动态访问权限。
3)Constructor: 提供关于类的单个构造方法的信息以及对它的访问权限
4)Method: 提供关于类或接口中某个方法信息。
注意:Class类是Java反射中最重要的一个功能类,所有获取对象的信息(包
括: 方法/属性/构造方法/访问权限)都需要它来实现。
5.反射机制的优缺点?
优点:
(1) 能够运行时动态获取类的实例, 大大提高程序的灵活性。
(2) 与 Java 动态编译相结合, 可以实现无比强大的功能。
缺点:
(1) 使用反射的性能较低。 java 反射是要解析字节码, 将内存中的对象进
行解析。
解决方案:
1.由于 JDK 的安全检查耗时较多, 所以通过 setAccessible(true)的方式关闭安全检查
来(取消对访问控制修饰符的检查) 提升反射速度。
2.需要多次动态创建一个类的实例的时候, 有缓存的写法会比没有缓存要快很多:
3.ReflectASM 工具类 , 通过字节码生成的方式加快反射速度。
(2) 使用反射相对来说不安全, 破坏了类的封装性, 可以通过反射获取这个
类的私有方法和属性。

 

 

 

 

 

 

  1. 反射机制(reflection)
  2. 编程语言的分类

       动态语言:在程序运行时,动态的改变变量的类型,为变量增加,删除属性及方法;

                            var a=4;

                            a="hello wold";

                            a=[4,5,76,78];

                            a=new Date();

                            a=new Object();

                            a.name="james";

       非动态语言:

                     java并不是动态语言;

  1. 反射技术;

       java不是动态语言,但通过反射技术可以实现动态语言的部分特征;

  1. 什么是反射技术?

       在程序运行时,动态分析类的能力就是反射;

       具体来说;

              1.运行时,可以根据类名(String)加载这个类;

                     Class.forName("com.mysql.jdbc.Driver");

              2.可以获得某个类的信息(元数据),例如类名,属性,方法,父类等;

              3.可以动态调用一个对象的所有方法(包括private 

  1. Class类;

       Class这个类代表加载到java虚拟机中的类实例,每个类只加载一次,因此每个只有一个唯一的实现,通过这个类实例,我们可以获得关于这个类型的所有元数据;

  1. 如何获得Class实例呢?
    1. Class c= Book.class;
    2. Class c=Class.forName("com.oracle.vo.Book");
    3. Class c=obj.getClass();  
  2. Class中提供的常用方法;

       getName():获得类的全名(包括包名)

       getSimpleName():只获得类名

       getSuperclass():获得父类

       getInterfaces():获得实现的接口;

       isXXX():是否是某种类型的实例(Array,Enum,Interface)

       getComponentType():如果类实例是数组,得到数组中元素的类型;

  1. Field:

       属性的元数据的封装;

       获得Field的方法;

              Field[] getFields():获得所有公共的属性(自定义和继承的)

              Field getField(String name):根据属性名来获得指定的公共属性;

              Field[] getDeclaredFields():获得所有自定义的属性;

              Field[] getDeclaredField();根据属性名来获得自定义的      

  1. Constructor:构造器

       Class Book{

              public Book(String name,int price){

                    

              }

       }

 

       Book b=new Book();

       1.开辟空间;

       2.调用构造方法;
       3.将对象的引用返回b;

      

  1. 如何获得构造方法?

       getConstructors();获得所有的公共的构造方法;

       getConstructor(Class...args);根据参数列表获得指定的公共的构造方法

       getDeclaredConstructors();获得所有的构造方法;

       getDeclaredConstructor(Class...args);

  1. 作业:

       定义一个单模式,并使用反射来创建多个对象;

      

  1. 关于反射中构造方法的最常用场景
    1. 调用private的构造方法;
    2. 调用默认的公共的构造方法来动态创建对象,它是使用Class.newInstance()来简化我们的代码;
  2. dao的查询;

       sql,class ,将查询出来的记录转换成对应的对象;

      

  1. Method方法

       method表示类中定义的一个方法;

              修改符

              返回值类型;

              方法名;

              参数;

       如何用method

              被调用   invoke();

  1. 如何获得method;

       getMethod(String name,Class...obj):指定公共

       getMethods();所有公共

       getDeclaredMethod(String name,class...obj);指定的方法

       getDeclaredMethods();获得全部方法

  1. mthod中常用的方法;

       getReturnType():获得返回值类型   Class

       getModifiers():获得访问修饰符的组合(int

       getParameterTypes:获得参数类型的数组   Class[]
       getName():
获得方法名

       setAccessible():设置方法是否为可访问

       invoke(Object targer,Object...params):调用这个方法,

                     target:目标对象(哪个对象的方法)

                     params: 实参列表

  1. Annotation

       注解;

       简单来说,就是给编译器看的一些注释;    

       作用:在不改变类结构的情况下,每元数据(Class,Field,Constructor,Methos等)增加一些补充信息,这些补充信息可以在程序运行时获得;

  1. Annotaion(注解)分为两种

       JDK提供的:

              @Override:重写

              @Deprecated:过期,不建议使用

              @SuppressWarnings:压制警告

       自定义的:

  1. 自定义注解

       /**

 * 定义一个注解,用来修饰属性;注解一直保留到运行阶段;

 * @author Administrator

 *

 */

@Retention(RUNTIME)

@Target(FIELD)

public @interface PrimaryKey {

 

}

 

 

@Retention(RUNTIME)

@Target(TYPE)

public @interface Table {

       String value();

}

      

  1. 通过反射操作注解信息;

       Annotation getAnnotation(Class):获得指定类型的注解,如果存在,则返回注解实例,不存在则返回null;

              //如果当前的类上有Table注解,则获得此类型的注解;

              Table t=(Table)c.getAnnotation(Table.class);

       boolean isAnnotationPresent(Class) :当前的元数据中是否使用了某种类型的注解;

             

              例如:isAnnotationPresent(PrimaryKey.class)

 

 

彻底理解jdbc为什么用反射创建驱动程序对象

2016年09月13日 00:55:00 weixin_34082177 阅读数:73

1.class.forName(mysql),这样更换数据库时,不需要更改程序代码,程序不需要重新编译就能运行。

因为反射是动态编译的,程序运行期间生成指定类的对象,

这样就可以程序运行期间生成不同的数据库驱动程序对象。省去了固定写死一个数据库驱动对象(通过new 构造函数的方法),造成每更换一个数据库,要重新编译代码的问题。

2.ioc容器中生成对象时,也是根据xml配置信息中的类型,反射生成对象的。并把这些对象存储在hashmap中,供程序调用的

3.hibernate/mybatis这种持久层框架中,进行数据持久化时,通过反射生成sql语句

 

 

JDBC为什么使用反射加载驱动

2016年08月30日 17:04:30 tenlee 阅读数:2818

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/tenlee/article/details/52371088

一直不太明白在使用JDBC的时候用Class.forName("com.mysql.jdbc.Driver")去加载驱动,就谷歌了一下,得到如下答案:


前言

JDBC源码地址 
还有 
在解释具体原因之前先简单看下Class.forName做了什么。假设一个类以前从来没有被装进内存过,Class.forName(String className)这个方法会做以下几件事情: 
1、装载。将字节码读入内存,并产生一个与之对应的java.lang.Class类对 
2、连接。这一步会验证字节码,为static变量分配内存,并赋默认值(0或null),并可选的解析符号引用(这里不理解没关系) 
3、初始化。为类的static变量赋初始值,假如有static int a = 1;这个将a赋值为1的操作就是这个时候做的。除此之外,还要调用类的static块。(这一步是要点) 
Class.forName(String className)方法会将这三步都做掉,

基本原因

首先,上面一段代码的主要作用,是在运行期以反射的方式来检查JDBC驱动的主类com.mysql.jdbc.Driver是否存在,若不存则表示运行环境中没有这个驱动,进入catch段。如果你确定一定以及肯定它会存在,可以直接写成

import com.mysql.jdbc.Driver;
  • 1

效果基本是一样的(只是在编译期及运行期要都保证此类存在classpath中) 
所以,以反射形式加载的一个好处是当驱动jar包不存在时,我们可以做更多的操作。(要知道,在很久很久以前,jdbc驱动一般都是放在运行环境的classpath中的,如tomcat/lib)

另一个原因

如果你是一个有追求的程序员,那么另外一个很重要的原因是解耦。 
首先要明白JDBC是Java的一种规范,通俗一点说就是JDK在
java.sql.*下提供了一系列的接口(interface),但没有提供任何实现(也就是类)。 所以任何人都可以在接口规范之下写自己的JDBC实现(如MySQL)。而若调用者也只调用接口上的方法(如我们),那么当未来有任何变更需要时(例如要从MySQL迁移至Oracle),则理论上不需要对代码做任何修改就能直接切换(可惜SQL语法没能统一规范) 
这意味着什么?意味着你的代码中不应该引用任何与实现相关的东西,你的代码只知道
java.sql.*,而不应该知道com.mysql.*或是com.oracle.*,以避免或减少未来切换数据源时对代码的变更。 
注意,我们使用的所有其他API包括
Connection/Statement/ResultSet等都是java.sql.*的东西,甚至com.mysql.jdbc.Driver类也是:

package com.mysql.jdbc;
public class Driver ... implements java.sql.Driver { ...}
  • 1
  • 2

因此,直接import com.mysql.jdbc.Driver; 
违反了开闭原则(OCP,对扩展开放,对修改关闭)。(有人说我用反射也必须要修改代码呀,事实上你可以将类名字符串存储至.properties文件,和数据库用户名密码放在一起,就像Hibernate做的那样)

 

 

 

一般项目里都会有数据库配置文件,其中就有一条是driverName="com.mysql.jdbc.Driver",代码会根据配置文件加载驱动。
当你想换数据库时只要修改driverName的值就可以了,代码就不需要修改
你在代码里直接new 个mysql的Driver,那换数据库时不是还要修改代码中你new 的Driver

首先你要知道com.mysql.jdbc.Driver的作用是什么,加载这个类实际是注册了对应的jdbc driver,不同的数据库厂商driver是不同的简单理解是类名不同,写死在代码里面不灵活,所以提取出来到配置文件里了。

 

因为反射好用,
为什么好用呢,因为你给个类地址它就能new 一个对象出来,动态的
最重要的是地址是字符串,是一个变量,不是一个具体对象,也就是说它脱离了代码,增加了相当大的灵活性。这里的灵性性是对对象的处理。

个人理解,当你用久了面向对象编程,对一条条规定用烦的时候,你会觉得反射这个机制相当于打破了这些规定,什么对象方法,想怎么弄就怎么弄,想怎么改就怎么改。
反正好用,不过性能上不太好,所以用的都是关键的地方

 

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值