一、理解反射

1.1、基础概念

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

“运行状态”,如何理解?

"运行状态"体现了反射的应用场景,当一些类,不需要提前加载进JVM内存,而是在运行时根据需要进行加载的时候,就可以通过反射进行动态加载

1.2、如何理解反射?

学习过java的童鞋,肯定对spring、hibernate一点也不会陌生。在进行底层配置的时候,会涉及到不同类型的数据库问题。例如sqlserver,可能会这样配置方言“org.hibernate.dialect.SQLServer2008Dialect”,而oracle,可以能会这样配置“org.hibernate.dialect.OracleDialect”。不同的数据库,只需要修改配置文件中的方言即可,这就是利用了反射的功能。程序在编译时,并不知道会使用哪种类型的数据库,只有在运行时,动态读取方言的配置,加载相应的类,运行类中定义的方法和属性,从而实现相应的功能。

其实说简单点,反射就是一种机制,可以让你仅知道类的名字的情况下,了解整个类的内部的结构,并且访问内部的成员和方法等

spring中的依赖注入、反转控制使用的都是这种机制

二、反射API及使用

反射机制的实现需要四个类:Class、Constructor、Field、Method

Class类:在程序运行期间,系统始终为所有的对象维护一个被称为运行时的类型标识。这个信息跟踪着每个对象所属的类。虚拟机利用运行时类型信息选择相应的方法执行,保存这些信息的类被称为Class

Constructor、Field、Method:分别用于描述类的构造器、域、方法

下面我们用一个简单的例子来演示反射的使用:

package com.my.po;

/**
* description:{description}
* author:jyy
* date:2018-02-06 16:28
* modify:{modify}
*/
public interface InterFace {
void read();
}
package com.my.po;

/**
* description:{description}
* author:jyy
* date:2018-02-03 13:20
* modify:{modify}
*/
public class Person implements InterFace { private String id; private String name; public String age; //构造函数1
public Person() { } //构造函数2
public Person(String id) {
this.id = id;
} //构造函数3
public Person(String id, String name) {
this.id = id;
this.name = name;
} public String getId() {
return id;
} public void setId(String id) {
this.id = id;
} public String getName() {
return name;
} public void setName(String name) {
this.name = name;
} public String getAge() {
return age;
} public void setAge(String age) {
this.age = age;
} /**
* 静态方法
*/
public static void update() { } @Override
public void read() { }
}

1)三种方式获取Class类对象

        //第一种方法:forName
try {
Class<?> class1 = Class.forName("com.my.po.Person");
System.out.println( class1 );
} catch (ClassNotFoundException e) {
e.printStackTrace();
} //第二张方法:class
Class<?> class2 = Person.class;
System.out.println( class2 ); //第三种方法:getClass
Person person = new Person();
Class<?> class3 = person.getClass(); System.out.println( class3 );

执行结果:

class com.my.po.Person
class com.my.po.Person
class com.my.po.Person

2)获取类中方法

        try {
//创建类
Class<?> class1 = Class.forName("com.my.po.Person"); //getMethods()获取当前类及其父类所有的public方法
Method[] methods1 = class1.getMethods();
for (Method method : methods1) {
System.out.println(method);
}
System.out.println("=================="); //getDeclaredMethods()获取当前类所有的方法,包括private、protected修饰的方法,但不可以获取父类的方法
Method[] methods2 = class1.getDeclaredMethods();
for (Method method : methods2) {
System.out.println(method);
} } catch (ClassNotFoundException e) {
e.printStackTrace();
}

执行结果:

public static void com.my.po.Person.update()
public java.lang.String com.my.po.Person.getName()
public void com.my.po.Person.read()
public java.lang.String com.my.po.Person.getId()
public void com.my.po.Person.setName(java.lang.String)
public java.lang.String com.my.po.Person.getAge()
public void com.my.po.Person.setId(java.lang.String)
public void com.my.po.Person.setAge(java.lang.String)
public final void java.lang.Object.wait() throws java.lang.InterruptedException
public final void java.lang.Object.wait(long,int) throws java.lang.InterruptedException
public final native void java.lang.Object.wait(long) throws java.lang.InterruptedException
public boolean java.lang.Object.equals(java.lang.Object)
public java.lang.String java.lang.Object.toString()
public native int java.lang.Object.hashCode()
public final native java.lang.Class java.lang.Object.getClass()
public final native void java.lang.Object.notify()
public final native void java.lang.Object.notifyAll()
==================
public static void com.my.po.Person.update()
public java.lang.String com.my.po.Person.getName()
public void com.my.po.Person.read()
public java.lang.String com.my.po.Person.getId()
public void com.my.po.Person.setName(java.lang.String)
public java.lang.String com.my.po.Person.getAge()
public void com.my.po.Person.setId(java.lang.String)
public void com.my.po.Person.setAge(java.lang.String)

3)获取实现的接口

        try {
//创建类
Class<?> class1 = Class.forName("com.my.po.Person"); //获取所有的接口
Class<?>[] interfaces = class1.getInterfaces(); for (Class<?> class2 : interfaces) {
System.out.println(class2);
} } catch (ClassNotFoundException e) {
e.printStackTrace();
}

运行结果:

interface com.my.po.InterFace

4)获取父类

        try {
//创建类
Class<?> class1 = Class.forName("com.my.po.Person"); //获取父类
Class<?> superClass = class1.getSuperclass(); System.out.println(superClass); } catch (ClassNotFoundException e) {
e.printStackTrace();
}

运行结果:

class java.lang.Object

5)获取构造函数

        try {
//创建类
Class<?> class1 = Class.forName("com.my.po.Person"); //getConstructors()获取当前类所有的公有构造器
Constructor<?>[] constructors1 = class1.getConstructors() ; for (Constructor<?> constructor : constructors1) {
System.out.println( constructor );
}
System.out.println("================");
//getDeclaredConstructors获取当前类所有的构造器,不包括父类构造器
Constructor<?>[] constructors2 = class1.getDeclaredConstructors() ;
for (Constructor<?> constructor : constructors2) {
System.out.println( constructor );
} } catch (ClassNotFoundException e) {
e.printStackTrace();
}

public com.my.po.Person(java.lang.String,java.lang.String)
public com.my.po.Person(java.lang.String)
public com.my.po.Person()
================
public com.my.po.Person(java.lang.String,java.lang.String)
public com.my.po.Person(java.lang.String)
public com.my.po.Person()

6)获取属性

        try {
//创建类
Class<?> class1 = Class.forName("com.my.po.Person"); //getDeclaredFields()取得当前类的全部属性,包括private、protected修饰的属性
Field[] field1 = class1.getDeclaredFields(); for (Field field : field1) {
System.out.println( field );
} System.out.println("=================="); //getFields()取得当前类和父类所有public修饰的属性
Field[] field2 = class1.getFields(); for (Field field : field2) {
System.out.println( field );
} } catch (ClassNotFoundException e) {
e.printStackTrace();
}

运行结果:

private java.lang.String com.my.po.Person.id
private java.lang.String com.my.po.Person.name
public java.lang.String com.my.po.Person.age
==================
public java.lang.String com.my.po.Person.age

7)使用获取到的Class对象,创建实例

        try {
//创建类
Class<?> class1 = Class.forName("com.my.po.Person"); //创建实例化:相当于 new 了一个对象
Object object = class1.newInstance(); //向下转型
Person person;
if (object instanceof Person) {
person = (Person) object;
person.setAge("20");
System.out.println(person.getAge());
} } catch (Exception e) {
e.printStackTrace();
}

运行结果:20

三、实战项目

一个简单的例子,使用上面所列的api

        try {
//创建类
Class<?> class1 = Class.forName("com.my.po.Person"); //创建实例
Object obj = class1.newInstance();
Person person;
if (obj instanceof Person) {
person = (Person) obj;
} else {
person = null;
} //给id,name,age赋值
Field idField = class1.getDeclaredField("id");
idField.setAccessible(true);//打破私有属性封装
idField.set(person, "1001");
Field nameField = class1.getDeclaredField("name");
nameField.setAccessible(true);//打破私有属性封装
nameField.set(person, "李明");
Field ageField = class1.getDeclaredField("age");
ageField.setAccessible(true);//打破私有属性封装
ageField.set(person, "30"); //通过执行方法给id,name,age赋值
Method setNameMethod = class1.getDeclaredMethod("setName", String.class);
setNameMethod.invoke(person, "王立"); //查询属性值
String id = (String) idField.get(person);
System.out.println(id);
String name = (String) nameField.get(person);
System.out.println(name); } catch (Exception e) {
e.printStackTrace();
}

下面是一个模拟配置文件的例子

新建两个类Bird、Dragonfly

public class Bird {

    public void fly() {
System.out.println("小鸟正在飞");
}
}
public class Dragonfly { public void fly() {
System.out.println("蜻蜓正在飞");
}
}

新建配置文件configure.properties

animal.forclass=com.my.po.Dragonfly
animal.method=fly
        try {
//读取配置文件
ResourceBundle resource = ResourceBundle.getBundle("configure");
String className = resource.getString("animal.forclass");
String methodName = resource.getString("animal.method"); //获取类
Class<?> class1 = Class.forName(className);
//根据方法名称,获取方法对象
Method m = class1.getMethod(methodName);
//获取构造器
Constructor<?> constructor = class1.getDeclaredConstructor();
//根据构造器,实例化出对象
Object obj = constructor.newInstance();
//调用对象的指定方法
m.invoke(obj); } catch (Exception e) {
e.printStackTrace();
}

执行结果:

蜻蜓正在飞

修改configure.properties文件中的animal.forclass=com.my.po.Bird

执行结果:

小鸟正在飞

分享结束,如果还想对反射有更深入的理解,可以搜索ObjectAnalyzer或ReflectionToStringBuilder,试着重写toString方法

JAVA基础知识|反射的更多相关文章

  1. 学习Spring必学的Java基础知识(1)----反射(转)

    引述要学习Spring框架的技术内幕,必须事先掌握一些基本的Java知识,正所谓"登高必自卑,涉远必自迩".以下几项Java知识和Spring框架息息相关,不可不学(我将通过一个系 ...

  2. 学习Spring必学的Java基础知识(1)----反射

    引述要学习Spring框架的技术内幕,必须事先掌握一些基本的Java知识,正所谓"登高必自卑,涉远必自迩".以下几项Java知识和Spring框架息息相关,不可不学(我将通过一个系 ...

  3. 学习Spring必学的Java基础知识(2)----动态代理

    Spring AOP使用动态代理技术在运行期织入增强的代码,为了揭示Spring AOP底层的工作机理,有必要对涉及到的Java知识进行学习.Spring AOP使用了两种代理机制:一种是基于JDK的 ...

  4. Java基础知识总结(超级经典)

    Java基础知识总结(超级经典) 写代码: 1,明确需求.我要做什么? 2,分析思路.我要怎么做?1,2,3. 3,确定步骤.每一个思路部分用到哪些语句,方法,和对象. 4,代码实现.用具体的java ...

  5. 毕向东—Java基础知识总结(超级经典)

    Java基础知识总结(超级经典) 写代码: 1,明确需求.我要做什么? 2,分析思路.我要怎么做?1,2,3. 3,确定步骤.每一个思路部分用到哪些语句,方法,和对象. 4,代码实现.用具体的java ...

  6. 沉淀,再出发:Java基础知识汇总

    沉淀,再出发:Java基础知识汇总 一.前言 不管走得多远,基础知识是最重要的,这些知识就是建造一座座高楼大厦的基石和钢筋水泥.对于Java这门包含了编程方方面面的语言,有着太多的基础知识了,从最初的 ...

  7. Java基础知识常识总结

    Java基础知识常识总结 1.面向对象的特征以及对他的理解? 封装,继承,多态,如果再增加一条就是抽象. 2.Object有几种方法,分别是什么? 在JDK1.5中的11种方法,分别有: toStri ...

  8. java基础知识一览(二)

    一.java基础知识 1.一个文件中只能有一个public的类,因为他的类名要求和文件名相同. 2.classpath变量可以设置其它目录下的类. 例如:类文件所在目录是:F:\Javajdk,那么没 ...

  9. 主题:学习Spring必学的Java基础知识(9)----HTTP报文

    转: 引述要学习Spring框架的技术内幕,必须事先掌握一些基本的Java知识,正所谓“登高必自卑,涉远必自迩”.以下几项Java知识和Spring框架息息相关,不可不学(我将通过一个系列分别介绍这些 ...

随机推荐

  1. ppt调整三级标题的位置

    ---恢复内容开始--- 标题格式:一级标题   中文数字加.例如 一. 二级标题  中文数字加:   例如二: 三级标题  小写数字加.  例如3. 使用方法: 打开PPT  按alt+f11,打开 ...

  2. QTabWidget标签实现双击关闭(转)

    重载了QTabWidget(由于tabBar()是protected),这样就可以获取到标签了. 1 class Tab : public QTabWidget 2 { 3 Q_OBJECT 4 pu ...

  3. python日志实时分析

    python随着人工智能的发展,越来越火热.但其实python在运维测试方面,也是一把利器. 最近就碰到了个需求,就顺手写了个python程序.用惯了go,不过发现python好像更简单点 :-) 涉 ...

  4. openssh升级

    转载:(感谢作者) centos7 升级openssh到openssh-8.0p1版本 https://www.cnblogs.com/nmap/p/10779658.html centos 7 op ...

  5. CircularSlider半弧形滑动条

    前言 这边文章主要 是写 一.半圆弧型滑块的设计 最近项目中需要用到半圆弧形滑块,其作用和UISlider差不多,用于拖动改变播放音乐的播放进度. 大概样子是这样的: 效果展示 特点如下: 滑动响应区 ...

  6. impala 下的SQL函数

    #把时间转化成时间戳select cast('1966-07-30' as timestamp);select cast('1985-09-25 17:45:30.005' as timestamp) ...

  7. 【Hibernate】事务处理

    一.概述 一.概述 事务 事务就是逻辑上的一组操作,要么全都成功,要么全都失败!!! 事务特性 原子性:事务一组操作不可分割. 一致性:事务的执行前后,数据完整性要保持一致. 隔离性:一个事务在执行的 ...

  8. win10开机后将存在多个系统选择,改为直接进入系统无需选择

    win10系统安装后,可能出现每次开机都要选择操作系统,比较麻烦,所以就来设置下如何直接进入系统,无须选择 1.我的电脑右键“属性”—“高级系统设置”—“系统属性” 2.设置“启动和故障恢复”如下 选 ...

  9. linux 基础10-磁盘配额管理

    1. 基本概念 1.1 概念: 在linux系统中,由于是多人多任务的使用环境,所以会有多人共同使用一个硬盘空间的情况,如果其中少数几个人大量使用了硬盘空间的话,势必会压缩其他使用者的使用空间,因此管 ...

  10. ggplot2绘制Excel所有图

    出处:https://brucezhaor.github.io/blog/2016/06/13/excel2ggplot/#%E5%89%8D%E8%A8%80 目录 前言 1.用到的包 2.数据准备 ...