反射的概念和原理

类字节码文件是在硬盘上存储的,是一个个的.class文件。我们在new一个对象时,JVM会先把字节码文件的信息读出来放到内存中,第二次用时,就不用在加载了,而是直接使用之前缓存的这个字节码信息。

字节码的信息包括:类名声明的方法、声明的字段等信息。在Java中“万物皆对象”,这些信息当然也需要封装一个对象,这就是Class类、Method类、Field类

通过Class类、Method类、Field类等等类 可以得到  这个类字节码的全部信息,甚至可以不用new关键字就创建一个实例,可以执行一个对象中的方法设置或获取字段的值这就是反射技术

注意:在反射技术中一个类的任何成员都有对应 的类进行描述。  比如:  成员变量(Field)   方法----> Method类

Class类

Class类解释说明:

Java中有一个Class类用于代表某一个类的字节码。通过获取这个class类的对象,就可以得到字节码的一些信息

得到class对象的三种方法

Java提供了三种方式获取类的字节码

forName():forName方法用于加载某个类的字节码到内存中,并使用class对象进行封装(推荐使用这个,一般配合配置文件读取类的全名 创建对象)

类名.class

对象.getClass()

例子:

Person类,用于被测试的类

package cn.itcast.reflect;

public class Person {

private int id;

String name;

public Person(int id,String name){

this.id = id;

this.name = name;

}

public Person(){}

private Person(int id){

this.id = id;

}

public void eat(int num){

System.out.println(name+"吃很"+num+"斤饭");

}

private static void sleep(int num){

System.out.println("明天睡上"+num+"小时");

}

public static void  sum(int[] arr){

System.out.println("长度是:"+ arr.length);

}

@Override

public String toString() {

return " 编号:"+ this.id +" 姓名:"+ this.name;

}

}

获取class对象的代码:

public static void main(String[] args) throws ClassNotFoundException {

//推荐使用: 获取Class对象的方式一

Class clazz1 = Class.forName("cn.itcast.reflect.Person");

System.out.println("clazz1:"+ clazz1);

//获取Class对象的方式二: 通过类名获取

Class clazz2 = Person.class;

System.out.println("clazz1==clazz2?"+ (clazz1==clazz2));

//获取Class对象的方式三 :通过对象获取

Class clazz3 = new Person(110,"狗娃").getClass();

System.out.println("clazz2==clazz3?"+ (clazz2==clazz3));

}

打印结果:

clazz1:class cn.itcast.reflect.Person

clazz1==clazz2?true

clazz2==clazz3?true

通过class对象获取一些信息

获取类的全名(包名+类名),类的简单名称(不带包名,只有类名),类的修饰符

API解释说明:

1. getName()类的名称(全名,全限定名)

2 getSimpleName()类的的简单名称(不带包名)

3. getModifiers(); 类的的修饰符

例子:

import java.lang.reflect.Constructor;

import java.lang.reflect.Modifier;

//获取到对应的Class对象

Class clazz = Class.forName("cn.itcast.reflect.Person");

System.out.println("-----------获取类的全名------------");

//通过Class对象获取类的全名(包含 包名)

String fullName = clazz.getName();

System.out.println(fullName);

//通过class对象获取类名(不包含包名)

String simpleName =  clazz.getSimpleName();

System.out.println(simpleName);

//通过class对象获取类的修饰符

int modifyName = clazz.getModifiers();

String retval = Modifier.toString(modifyName);

System.out.println("Class Modifier = " + retval);

打印结果:

-----------获取类的全名------------

cn.itcast.reflect.Person

Person

Class Modifier = public

获取类的全部构造函数,私有的,公有的

API:

getConstructors()获取一个类的所有公共的构造方法

getDeclaredConstructors(); //获取到一个类的所有构造方法,包括私有的在内 。

代码:

//通过Class对象获取对应的构造方法

Constructor[] constructors = clazz.getConstructors();  // getConstructors()获取一个类的所有公共的构造方法

for(Constructor constructor : constructors){

System.out.println(constructor);

}

System.out.println("\n-------------获取所有的构造方法,包括私有的-------------");

Constructor[] constructors2 =  clazz.getDeclaredConstructors(); //获取到一个类的所有构造方法,包括私有的在内 。

for(Constructor constructor2 : constructors2){

System.out.println(constructor2);

}

打印的结果:

----------获取所有的公共构造方法--------------

public cn.itcast.reflect.Person()

public cn.itcast.reflect.Person(int,java.lang.String)

-------------获取所有的构造方法,包括私有的-------------

private cn.itcast.reflect.Person(int)

public cn.itcast.reflect.Person()

public cn.itcast.reflect.Person(int,java.lang.String)

获取指定的构造对象,然后new出一个对象(这个是不能new出private修饰的构造函数)

API:

newInstance方法构造对象,默认使用的是无参数的构造方法

举例:Object ins = clazz.newInstance();

getConstructor(参数类型的.class)获取单个指定的构造方法。

举例:clazz.getConstructor(int.class,String.class);

局限地方:不能获取private的构造函数

例子:

System.out.println("\n获取指定的构造方法,然后new出一个对象");

//newInstance方法构造对象,默认使用的是无参数的构造方法

Object ins = clazz.newInstance();

Person p = (Person) ins;

System.out.println(p);

//getConstructor 获取单个指定的构造方法。

clazz.getConstructor(int.class,String.class);

Constructor constructor = clazz.getConstructor(int.class,String.class);  //

Person p2  = (Person) constructor.newInstance(999,"小城"); // newInstance()创建一个对象

System.out.println(p2);

打印结果:

获取指定的构造方法,然后new出一个对象

编号:0 姓名:null

编号:999 姓名:小城

获取指定的私有构造函数

API:

getDeclaredConstructor 方法:获取指定的私有构造函数

例子:

System.out.println("\n获取指定的私有构造函数");

Constructor constructor1 =  clazz.getDeclaredConstructor(int.class);

System.out.println(constructor1);

打印结果:

获取指定的私有构造函数

private cn.itcast.reflect.Person(int)

暴力反射:

System.out.println("暴力反射");

Constructor constructor2 =  clazz.getDeclaredConstructor(int.class);

System.out.println(constructor2);

constructor2.setAccessible(true);//设置为true表示可以进行暴力反射,强行用private 构造函数new对象

Person p3  =(Person) constructor2.newInstance(100);

System.out.println(p3);

打印结果:

暴力反射

private cn.itcast.reflect.Person(int)

编号:100 姓名:null

获取构造函数的完整代码:

package cn.itcast.reflect;

import java.lang.reflect.Constructor;

import java.lang.reflect.Modifier;

/*

如何通过Class对象获取构造方法。

*/

public class Demo2 {

public static void main(String[] args) throws Exception {

//获取到对应的Class对象

Class clazz = Class.forName("cn.itcast.reflect.Person");

// System.out.println("-----------获取类的全名------------");

// //通过Class对象获取类的全名(包含 包名)

// String fullName = clazz.getName();

// System.out.println(fullName);

//

//

// //通过class对象获取类名(不包含包名)

// String simpleName =  clazz.getSimpleName();

// System.out.println(simpleName);

//

// //通过class对象获取类的修饰符

// int modifyName = clazz.getModifiers();

// String retval = Modifier.toString(modifyName);

//     System.out.println("Class Modifier = " + retval);

//     System.out.println("----------获取所有的公共构造方法--------------");

//

// //通过Class对象获取对应的构造方法

// Constructor[] constructors = clazz.getConstructors();  // getConstructors()获取一个类的所有公共的构造方法

// for(Constructor constructor : constructors){

// System.out.println(constructor);

// }

//

// System.out.println("\n-------------获取所有的构造方法,包括私有的-------------");

// Constructor[] constructors2 =  clazz.getDeclaredConstructors(); //获取到一个类的所有构造方法,包括私有的在内 。

// for(Constructor constructor2 : constructors2){

// System.out.println(constructor2);

// }

// System.out.println("\n获取指定的构造方法,然后new出一个对象");

//

// //newInstance方法构造对象,默认使用的是无参数的构造方法

// Object ins = clazz.newInstance();

// Person p = (Person) ins;

// System.out.println(p);

//

// //getConstructor 获取单个指定的构造方法。

// clazz.getConstructor(int.class,String.class);

// Constructor constructor = clazz.getConstructor(int.class,String.class);  //

// Person p2  = (Person) constructor.newInstance(999,"小城"); // newInstance()创建一个对象

// System.out.println(p2);

// System.out.println("\n获取指定的私有构造函数");

// Constructor constructor1 =  clazz.getDeclaredConstructor(int.class);

// System.out.println(constructor1);

// //

System.out.println("暴力反射");

Constructor constructor2 =  clazz.getDeclaredConstructor(int.class);

System.out.println(constructor2);

constructor2.setAccessible(true);//设置为true表示可以进行暴力反射,强行用private 构造函数new对象

Person p3  =(Person) constructor2.newInstance(100);

System.out.println(p3);

}

}

通过class类获取 字节码中的方法信息

获取全部的方法部分

Api详解:

getMethods() 获取所有 的公共方法(不包括私有的)包括父类继承的。

getDeclaredMethods()//获取到所有的方法(私有的也有),但是不包含父类的方法。

例子:

//获取到对应的Class对象

Class clazz = Class.forName("cn.itcast.reflect.Person");

//获取到所有公共的方法

Method[] methods = clazz.getMethods(); // getMethods() 获取所有 的公共方法(不包括私有的)包括父类继承的。

//Method[] methods = clazz.getDeclaredMethods(); //获取到所有的方法(私有的也有),但是不包含父类的方法。

for(Method method  : methods){

System.out.println(method);

}

获取指定的方法,并执行它

API:

getMethod("eat", int.class);//获取指定的方法,但是不能获取私有的方法

getDeclaredMethod("sleep",int.class);////执行私有的方法

setAccessible(true);//设置访问权限允许访问

invoke(p, 6);//invoke 执行一个方法。 第一个参数:方法的调用对象。 第二参数: 方法所需要的参数。

用法:

Person p = new Person(110,"狗娃");

//获取指定的方法,但是不能获取私有的方法

Method m = clazz.getMethod("eat", int.class);

//invoke 执行一个方法。 第一个参数:方法的调用对象。 第二参数: 方法所需要的参数。

m.invoke(p, 3);

//执行私有的方法

Method m2 =clazz.getDeclaredMethod("sleep",int.class);

//设置访问权限允许访问

m2.setAccessible(true);

//静态的方法第一个参数写null,表示没有对象调用,类本身会调用

m2.invoke(p, 6);

暴力反射:

//暴力反射,获取私有的方法,并执行它

Method m = clazz.getDeclaredMethod("sleep", int.class);

System.out.println(m);

m.setAccessible(true);

m.invoke(p, 8);

获取方法部分完整代码:

package cn.itcast.reflect;

import java.lang.reflect.Method;

/*

通过Class对象获取到对应的方法。

在反射技术中使用了Method类描述了方法的。

*/

public class Demo3 {

public static void main(String[] args) throws Exception {

//获取到对应的Class对象

Class<?> clazz = Class.forName("cn.itcast.reflect.Person");

// //获取到所有公共的方法

// Method[] methods = clazz.getMethods(); // getMethods() 获取所有 的公共方法(不包括私有的)包括父类继承的。

//// Method[] methods = clazz.getDeclaredMethods(); //获取到所有的方法(私有的也有),但是不包含父类的方法。

// for(Method method  : methods){

// System.out.println(method);

// }

Person p = new Person(110,"狗娃");

//

// //获取指定的方法,但是不能获取私有的方法

// Method m = clazz.getMethod("eat", int.class);

// //invoke 执行一个方法。 第一个参数:方法的调用对象。 第二参数: 方法所需要的参数。

// m.invoke(p, 3);

//

//

// //执行私有的方法

// Method m2 =clazz.getDeclaredMethod("sleep",int.class);

// //设置访问权限允许访问

// m2.setAccessible(true);

// //静态的方法第一个参数写null,表示没有对象调用,类本身会调用

// m2.invoke(p, 6);

// Method m = clazz.getMethod("sum", int[].class);

// m.invoke(p,new int[]{12,5,9});

//暴力反射,获取私有的方法,并执行它

Method m = clazz.getDeclaredMethod("sleep", int.class);

System.out.println(m);

m.setAccessible(true);

m.invoke(p, 8);

}

}

通过class对象获取到字段信息

代码;

public static void main(String[] args) throws Exception {

//获取到对应的Class对象

Class clazz = Class.forName("cn.itcast.reflect.Person");

//获取 到所有的成员变量(包含私有的)

// Field[] fields = clazz.getDeclaredFields();

// for(Field field  : fields){

// System.out.println(field);

// }

Person p = new Person();

Field field = clazz.getDeclaredField("id");

//设置访问权限可以访问

field.setAccessible(true);

field.set(p, 110); //第一个参数: 设置该数据 的成员变量, 第二个参数:属性值。

System.out.println(p);

}

反射API总结:

Class类

1. getName()类的名称(全名,全限定名)

2 getSimpleName()类的的简单名称(不带包名)

  1. getModifiers(); 类的的修饰符

4.getConstructors()获取一个类的所有公共的构造方法

5.getDeclaredConstructors(); //获取到一个类的所有构造方法,包括私有的在内 。

6.newInstance方法构造对象,默认使用的是无参数的构造方法

举例:Object ins = clazz.newInstance();

7.getConstructor(参数类型的.class)获取单个指定的构造方法。

举例:clazz.getConstructor(int.class,String.class);

局限地方:不能获取private的构造函数

8.getDeclaredConstructor 方法:获取指定的私有构造函数

方法部分

getMethods() 获取所有 的公共方法(不包括私有的)包括父类继承的。

getDeclaredMethods()//获取到所有的方法(私有的也有),但是不包含父类的方法。

getMethod("eat", int.class);//获取指定的方法,但是不能获取私有的方法

clazz.getDeclaredMethod("sleep",int.class);//执行私有的方法

m2.invoke(p, 6); //表示m2这个方法被p这个对象执行了,后面的参数是m2这个方法需要的参数

字段部分

1.获取公共字段

Field[] getFields()

2.获取指定参数的公共字段

Field getField(String name)

3.获取所有的字段

Field[] getDeclaredFields()

4.获取指定参数的字段,包括私用

Field getDeclaredField(String name)

一般用getDeclaredConstructor方法进行获取构造函数,一般不获取private修饰的构造函数

java 反射详解的更多相关文章

  1. Java基础13:反射详解

    本节主要介绍Java反射的原理,使用方法以及相关的技术细节,并且介绍了关于Class类,注解等内容. 具体代码在我的GitHub中可以找到 https://github.com/h2pl/MyTech ...

  2. Java基础-面向接口编程-JDBC详解

    Java基础-面向接口编程-JDBC详解 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 一.JDBC概念和数据库驱动程序 JDBC(Java Data Base Connectiv ...

  3. java基础(3)--详解String

    java基础(3)--详解String 其实与八大基本数据类型一样,String也是我们日常中使用非常频繁的对象,但知其然更要知其所以然,现在就去阅读源码深入了解一下String类对象,并解决一些我由 ...

  4. Linux基础知识之挂载详解(mount,umount及开机自动挂载)

    Linux基础知识之挂载详解(mount,umount及开机自动挂载) 转载自:http://www.linuxidc.com/Linux/2016-08/134666.htm 挂载概念简述: 根文件 ...

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

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

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

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

  7. JAVA基础知识|java虚拟机(JVM)

    一.JVM简介 java语言是跨平台的,兼容各种操作系统.实现跨平台的基石就是虚拟机(JVM),虚拟机不是跨平台的,所以不同的操作系统需要安装不同的jdk版本(jre=jvm+类库:jdk=jre+开 ...

  8. [java基础知识]java安装步骤

    jre:  java运行环境.  jre =  java虚拟机 + 核心类库(辅助java虚拟机运行的文件).如果只是运行java程序,只需要安装jre.    jdk: java开发工具集   jd ...

  9. java基础知识——Java的定义,特点和技术平台

    (作者声明:对于Java编程语言,很多人只知道怎么用,却对其了解甚少.我也是其中一员.所以菜鸟的我,去查询了教科书以及大神的总结,主要参考了<Java核心技术>这本神作.现在分享给大家!) ...

  10. 计算机基础知识和tcp详解

    计算机基础知识 作为应用软件开发程序员是写应用软件的,而应用软件必须应用在操作系统之上,调用操作系统接口,由操作系统控制硬件 比如客户端软件想要基于网络发送一条消息给服务端软件,流程是: 1.客户端软 ...

随机推荐

  1. ArrayList 和Vector ,HashTable和HashMap异同

    相同点: 1.都实现了List接口(List接口继承自Collection接口) 2.有序集合,数据可重复,可按索引号取值(而HashSet无序,不可重复) 不同点: 1.Vector是线程安全的,而 ...

  2. 福科田led漫反射灯条生产工序

    led漫反射灯条简称透镜灯条,它两个其实是一种产品.下面我来讲讲led漫反射灯条的生产工序.首先介绍的是led漫反射灯条的生产总流程. 一.      led漫反射灯条的生产总流程: 1.       ...

  3. HDU 6006 Engineer Assignment:状压dp

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=6006 题意: 在Google中,有个n项目,m个专家.第i个项目涉及c[i]个领域,分别为a[i][0 ...

  4. 一步一步学多线程-ThreadLocal源码解析

    上网查看了很多篇ThreadLocal的原理的博客,上来都是文字一大堆,费劲看了半天,大脑中也没有一个模型,想着要是能够有一张图明确表示出来ThreadLocal的设计该多好,所以就自己看了源码,画了 ...

  5. MATLAB实现聚类

    %% Cluster x = data; % 传入数据 [h, w] = size(x); num_cluster = 12; % 聚类数 T = clusterdata(x, num_cluster ...

  6. 【二次开发jumpserver】——整合jumpserver与zabbix推送主机功能

    jasset/forms.py "ip", "other_ip", "hostname", "port", " ...

  7. 利用Div+CSS(嵌套+盒模型)布局页面完整实例流程

    Div+CSS(嵌套+盒模型)布局页面完整实例流程: <!DOCTYPE html><html> <head>  <meta charset="UT ...

  8. MySQL视图了解

    视图是什么 视图是一种虚拟存在的表,不会在数据库中实际存在.相比较普通的表,有如下优势 简单:使用视图的用户完全不需要关心后面对应的表的结构.关联条件和筛选条件,对用户来说已经是过滤好的复合条件的结果 ...

  9. Linux学习总结(六)—— CentOS软件包管理:源代码安装

    源代码包安装方式相对RPM/YUM安装方式较为复杂,并且安装过程更长,一般只在源码研究的时候才会使用这种方式去编译. 源码安装分为解压缩包.配置信息.编译安装三个步骤,安装地址地址一般是/usr/lo ...

  10. javascript DOM 笔记

    以下内容来自<javasript DOM 编程艺术>第二版 dom中三种重要的节点:元素节点.属性节点.文本节点. 几种节点的重要属性:nodeValue,nodeType(为数字1.2. ...