【JAVA - 基础】之反射的原理与应用
一、反射简介
反射机制指的是程序在运行时能够获取自身的信息。在JAVA中,只要给定类的名字,那么就可以通过反射机制来获取类的所有信息。
1、反射的应用
- JDBC编程中的:Class.forName("com.mysql.jdbc.Driver.class");
- 通过文件名找到项目中的文件;
- Hibernate、Struts、Dagger2等框架中都用到了反射机制。
2、反射的特点
- 优点:使用反射机制可以实现动态的创建对象和编译,体现出了很大的灵活性;
- 缺点:反射对性能有影响。
3、反射的原理
JAVA语言编译之后都会生成一个.class文件,而不是生成机器码。反射就是在程序编译之后,通过程序字节码文件找到某一个类、类中的方法以及属性等。
简单来说,反射是JAVA语言在运行的时候拥有的一项自观能力,其实现主要借助于以下四个类:
- Class:类的对象;
- Constructor:类的构造方法;
- Field:类中的属性对象;
- Method:类中的方法对象。
通过这四个类就可以找到并处理JAVA中的几乎所有东西了。
二、常用方法
1、获取类对象
- 通过类名获取Class对象:Class<?> c = Class.forName(“ClassName”);(这里的ClassName是完全的路径,需要包括包路径)
- 通过Class对象获得具体类对象:Object o = (Object) c.newInstance();
2、获取类中的构造方法
以下代码中的c是2.1中获得的Class<?>类型的变量
- 根据指定参数类型获取public构造方法:Constructor con = c.getConstructor(Class<?> … paramTypes);
- 获得所有public构造方法:Constructor[] cons = c.getConstructors();
- 根据指定参数类型获取任意访问权限的构造方法:Constructor con = c.getDeclaredConstructor(Class<?> … paramTypes);
- 获得所有任意访问权限的构造方法:Constructor[] cons = c.getDeclaredConstructors();
3、获取类中的方法
以下代码中的c是2.1中获得的Class<?>类型的变量
- 根据方法名和指定参数类型获取public方法:Method m = c.getMethod(String mName, Class<?> … paramTypes);
- 获得所有public方法:Method[] ms= c.getMethods();
- 根据方法名和指定参数类型获得任意访问权限的方法:Method m = c.getDeclaredMethod(String mName, Class<?> …paramTypes);
- 获得所有任意访问权限的方法:Method[] ms = c.getDeclaredMethods();
4、获取类中的变量
以下代码中的c是2.1中获得的Class<?>类型的变量
- 根据变量名获取public变量:Field f =c.getField(String name);
- 获得所有public变量:Field[] fs= c.getFields();
- 根据变量名获取所有任意访问权限的变量:Field f = c.getDeclaredField(String name);
- 获得所有任意访问权限的变量:Field[] fs = c.getDeclaredFields();
5、获取其他数据
- 获取类实现的所有接口:Class<?>[] interfaces = c.getInterfaces();
- 获取类继承的父类:Class<?> parent = c.getSuperclass();
- 获取修饰符:String modifier = Modifier.toString(X.getModifiers()); //X是类、方法、属性、构造方法等
- 获取方法的返回值类型:String returnType = m.getReturnType().getSimpleName();
- 获取属性的类型:String type = f.getType().getSimpleName();
- 获取名称:String name = X.getName(); //X是类、方法、属性、构造方法等
- 调用方法:m.invoke(clazz, Class<?> … paramTypes); //clazz是类对象
- 获取属性值:Object o = f.get(clazz); //clazz是类对象
三、代码演示
以下代码是目标类,我们的测试类会从这个类中取出各种数据做测试:
public class DemoClass {
// public修饰的int类型的变量
public Integer publicInteger;
// public修饰的String类型的变量
public String publicString;
// private修饰的int类型的变量
protected Integer privateInteger;
// private修饰的String类型的变量
protected String privateString;
// public修饰的无参构造方法
public DemoClass() {
this.publicInteger = 10;
this.privateInteger = 20;
this.publicString = "Public String";
this.privateString = "Private String";
}
// public修饰的四个参数的构造方法,参数类型:int,String,int,String
public DemoClass(Integer publicInteger, String publicString, Integer privateInteger, String privateString) {
this.publicInteger = publicInteger;
this.publicString = publicString;
this.privateInteger = privateInteger;
this.privateString = privateString;
}
// private修饰的两个参数的构造方法,参数类型:int,int
protected DemoClass(Integer publicInteger, Integer privateInteger) {
this.publicInteger = publicInteger;
this.privateInteger = privateInteger;
}
// public修饰的无参的方法,返回int变量
public int getPublicInteger() {
return publicInteger;
}
// public修饰的四个参数的方法,参数类型:int,int,String,String,无返回值
public void setParameters(Integer publicInteger, Integer privateInteger, String publicString,
String privateString) {
this.publicInteger = publicInteger;
this.privateInteger = privateInteger;
this.publicString = publicString;
this.privateString = privateString;
}
// private修饰的两个参数的方法,参数类型:int,int,返回boolean类型的变量
protected boolean setSomeParams(Integer publicInteger, Integer privateInteger) {
this.publicInteger = publicInteger;
this.privateInteger = privateInteger;
return true;
}
@Override
public String toString() {
return "DemoClass [publicInteger=" + publicInteger + ", publicString=" + publicString + ", privateInteger="
+ privateInteger + ", privateString=" + privateString + "]";
}
}
编写这个类需要注意的有以下几点:
- 变量和参数的类型、方法的返回值类型不能是int、float、double,必须是封装类Integer、Float、Double;
- 用private修饰的变量、方法和构造方法是不能通过反射获取的,使用其他修饰符都能获取到。
以下是测试类中的代码:
public class Test {
public static void main(String[] args) {
try {
/**
* 获取和类有关的数据
*/
// 通过类名得到Class<?>对象
Class<?> clazz = Class.forName("com.itgungnir.testreflect.democlass.DemoClass");
System.out.println("Class Created");
// 获取这个类实现的接口
System.out.println("----------------------------------------------------------------------------");
Class<?>[] interfaces = clazz.getInterfaces();
if (interfaces.length == 0) {
System.out.println("No Interfaces Implemented");
}
// 获取这个类的父类
System.out.println("----------------------------------------------------------------------------");
Class<?> parent = clazz.getSuperclass();
System.out.println("Parent -----> " + parent.getName());
/**
* 获取和构造方法有关的数据
*/
// 通过Class<?>对象获取DemoClass类的对象
// newInstance()方法调用的是无参的构造方法,如果没有无参的构造方法,则会报错
System.out.println("----------------------------------------------------------------------------");
DemoClass c = (DemoClass) clazz.newInstance();
System.out.println(c.toString());
// 获取DemoClass对象中public修饰的无参构造方法
System.out.println("----------------------------------------------------------------------------");
Constructor<?> con1 = clazz.getConstructor();
c = (DemoClass) con1.newInstance();
System.out.println(c.toString());
// 获取DemoClass对象中public修饰的四个参数的构造方法,参数类型:Integer,String,Integer,String
System.out.println("----------------------------------------------------------------------------");
Constructor<?> con2 = clazz.getConstructor(Integer.class, String.class, Integer.class, String.class);
c = (DemoClass) con2.newInstance(100, "", 100, "aaa");
System.out.println(c.toString());
// 获取DemoClass对象中protected修饰的两个参数的构造方法,参数类型:Integer,Integer
System.out.println("----------------------------------------------------------------------------");
Constructor<?> con3 = clazz.getDeclaredConstructor(Integer.class, Integer.class);
c = (DemoClass) con3.newInstance(55, 66);
System.out.println(c.toString());
// 获取DemoClass对象中所有public修饰的构造方法
System.out.println("----------------------------------------------------------------------------");
Constructor<?>[] cons1 = clazz.getConstructors();
c = (DemoClass) cons1[0].newInstance(0, "Hello", 111111, "World");
System.out.println(c.toString());
c = (DemoClass) cons1[1].newInstance();
System.out.println(c.toString());
// 获取DemoClass对象中所有任意访问权限的构造方法
System.out.println("----------------------------------------------------------------------------");
Constructor<?>[] cons2 = clazz.getDeclaredConstructors();
c = (DemoClass) cons2[0].newInstance(-1, -2);
System.out.println(c.toString());
c = (DemoClass) cons2[1].newInstance(0, "Hello", 111111, "World");
System.out.println(c.toString());
c = (DemoClass) cons2[2].newInstance();
System.out.println(c.toString());
/**
* 获取和变量有关的数据
*/
// 获取DemoClass对象中public修饰的Integer类型的变量publicInteger
// 获取属性值时传入的Object类型的参数是DemoClass类的对象
System.out.println("----------------------------------------------------------------------------");
Field f1 = clazz.getField("publicInteger");
System.out.println(f1.get(c));
// 获取DemoClass对象中public修饰的String类型的变量privateInteger
System.out.println("----------------------------------------------------------------------------");
Field f2 = clazz.getDeclaredField("privateInteger");
System.out.println(f2.get(c));
// 获取DemoClass对象中public修饰的Integer类型的变量publicString
System.out.println("----------------------------------------------------------------------------");
Field f3 = clazz.getField("publicString");
System.out.println(f3.get(c));
// 获取DemoClass对象中protected修饰的String类型的变量privateString
System.out.println("----------------------------------------------------------------------------");
Field f4 = clazz.getDeclaredField("privateString");
System.out.println(f4.get(c));
// 获取DemoClass对象中所有public修饰的变量
System.out.println("----------------------------------------------------------------------------");
Field[] fs1 = clazz.getFields();
for (Field f : fs1) {
System.out.println(Modifier.toString(f.getModifiers()) + " " + f.getType().getSimpleName() + " "
+ f.getName() + " = " + f.get(c) + ";");
}
// 获取DemoClass对象中所有任意访问权限的变量
System.out.println("----------------------------------------------------------------------------");
Field[] fs2 = clazz.getDeclaredFields();
for (Field f : fs2) {
System.out.println(Modifier.toString(f.getModifiers()) + " " + f.getType().getSimpleName() + " "
+ f.getName() + " = " + f.get(c) + ";");
}
/**
* 获取和方法有关的数据
*/
// 获取DemoClass对象中public修饰的无参方法getPublicInteger,返回Integer类型变量
System.out.println("----------------------------------------------------------------------------");
Method m1 = clazz.getMethod("getPublicInteger");
System.out.println(m1.invoke(c));
// 获取DemoClass对象中public修饰的四个参数的方法setParameters,参数类型:Integer,Integer,String,String,无返回值
System.out.println("----------------------------------------------------------------------------");
Method m2 = clazz.getMethod("setParameters", Integer.class, Integer.class, String.class, String.class);
m2.invoke(c, 111, 1111, "abc", "abcdef");
System.out.println(c.toString());
// 获取DemoClass对象中protected修饰的两个参数的方法setSomeParams,参数类型:Integer,Integer,返回boolean类型变量
System.out.println("----------------------------------------------------------------------------");
Method m3 = clazz.getDeclaredMethod("setSomeParams", Integer.class, Integer.class);
System.out.println(m3.invoke(c, 0, 0));
// 获取DemoClass对象中所有public修饰的方法(包括Object类中的public方法)
System.out.println("----------------------------------------------------------------------------");
Method[] ms1 = clazz.getMethods();
for (Method m : ms1) {
System.out.println(Modifier.toString(m.getModifiers()) + " " + m.getReturnType().getSimpleName() + " "
+ m.getName() + "(){...}");
}
// 获取DemoClass对象中所有任意访问权限的方法(所有自定义的方法)
System.out.println("----------------------------------------------------------------------------");
Method[] ms2 = clazz.getDeclaredMethods();
for (Method m : ms2) {
System.out.println(Modifier.toString(m.getModifiers()) + " " + m.getReturnType().getSimpleName() + " "
+ m.getName() + "(){...}");
}
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (InstantiationException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (NoSuchMethodException e) {
e.printStackTrace();
} catch (SecurityException e) {
e.printStackTrace();
} catch (IllegalArgumentException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
} catch (NoSuchFieldException e) {
e.printStackTrace();
}
}
}
要想得到不同的数据,只需要参照上面的代码进行编写即可。
唯一值得注意的是,当调用getFields()、getDeclaredFields()、getMethods()、getDeclaredMethods()、getConstructors()、getDeclaredConstructors()等能获取数组类型的结果的方法时,返回的数组中的方法、变量或构造方法的顺序和类中定义的顺序是反过来的!
以上就是对Java中反射的一些总结,希望对大家有帮助!
【JAVA - 基础】之反射的原理与应用的更多相关文章
- 黑马程序员:Java基础总结----反射
黑马程序员:Java基础总结 反射 ASP.Net+Android+IO开发 . .Net培训 .期待与您交流! 反射 反射的基石:Class类 Class类代表Java类,它的各个实例对象又分别 ...
- Java基础之一反射
反射是框架设计的灵魂 (使用的前提条件:必须先得到代表的字节码的Class,Class类用于表示.class文件(字节码)) 一.反射的概述 JAVA反射机制是在运行状态中,对于任意一个类,都能够 ...
- Java基础之—反射
反射是框架设计的灵魂 (使用的前提条件:必须先得到代表的字节码的Class,Class类用于表示.class文件(字节码)) 一.反射的概述 JAVA反射机制是在运行状态中,对于任意一个类,都能够 ...
- java基础之反射---重要
java反射: 反射是框架设计的灵魂 (使用的前提条件:必须先得到代表的字节码的Class,Class类用于表示.class文件(字节码)): 1:获取Class字节码文件对象的三种方式: /** ...
- 【Java基础】反射和注解
前言 在Java中,反射机制和注解机制一直是一个很重要的概念,那么他们其中的原理是怎么样呢,我们不仅仅需要会使用,更要知其然而之所以然. 目录 反射机制 反射如何使用 注解定义 注解机制原理 注解如何 ...
- JAVA基础知识|反射
一.理解反射 1.1.基础概念 反射:在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法:对于任意一个对象,都能够调用它的任意方法和属性:这种动态获取信息以及动态调用对象方法的功能称为ja ...
- java基础之反射机制
一.概念 JAVA反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法:对于任意一个对象,都能够调用它的任意一个方法和属性:这种动态获取的信息以及动态调用对象的方法的功能称为jav ...
- java基础(十一 )-----反射——Java高级开发必须懂的
本文我们通过一个实际的例子来演示反射在编程中的应用,可能之前大家对反射的学习,仅仅是停留在概念层面,不知道反射究竟应用在哪,所以是一头雾水.相信通过这篇教程,会让你对反射有一个更深层次的认知. 概念 ...
- java基础篇---反射机制
一.JAVA是动态语言吗? 一般而言,说到动态言,都是指在程序运行时允许改变程序结构或者变量类型,从这个观点看,JAVA和C++一样,都不是动态语言. 但JAVA它却有着一个非常突出的动态相关机制:反 ...
- Java 基础总结--反射的基本操作
一.反射的概念 JAVA反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法:对于任意一个对象,都能够调用它的任意一个方法和属性:这种动态获取的信息以及动态调用对象的方法的功能称为 ...
随机推荐
- Java学习----日期函数
Date Calendar public class TestDate { private Date date; Calendar calendar; public TestDate() { // ...
- jQuery.ajax() datatype:“json" 转换失败
当使用jQuery.ajax() 时,如果设置dataType:"json",如果返回的字符转换出错则不会调用success方法,而进入error方法,控制台中也不会出现错误信息 ...
- Ext.String 方法
1.Ext.String.htmlEncode(value); 编码字符串,对其中特殊字符进行转义 xt.String.htmlEncode("hello'world"); //& ...
- session与cookie的区别,有哪些不同之处
session与cookie的区别,根据自己的理解总结如下: (1)cookie是一种客户端的状态管理技术,将状态写在 浏览器端,而session是一种服务器端的状态管理技术,将 状态写在web服务器 ...
- jquery roundabout幻灯片插件3d图片切换支持图片旋转切换滚动
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/ ...
- PAT (Basic Level) 1002. 写出这个数 (20)
读入一个自然数n,计算其各位数字之和,用汉语拼音写出和的每一位数字. 输入格式:每个测试输入包含1个测试用例,即给出自然数n的值.这里保证n小于10100. 输出格式:在一行内输出n的各位数字之和的每 ...
- Hbase Java API程序设计步骤
http://www.it165.net/admin/html/201407/3390.html 步骤1:创建一个Configuration对象 包含了客户端链接Hbase服务所需的全部信息: zoo ...
- Lodash,你正在使用的JavaScript库
JavaScript工具库lodash发布了3.5版,成为了npm包仓库中依赖最多的库.它正在摆脱屌丝身份,成为开发者的不二之选. lodash一开始是Underscore.js库的一个fork,因为 ...
- Tomcat架构(三)
嵌套组件 这些组件是针对Tocmat做的特定实现,他们的主要目的是使各种Tomcat容器可以完成各自的工作. 1.阀(Valve) valve是处理元素,它可以被包含在每个Tomcat容器的处理路径中 ...
- 【HTTP】Speed and Mobility: An Approach for HTTP 2.0 to Make Mobile Apps and the Web Faster
This week begins face to face meetings at the IETF on how to approach HTTP 2.0 and improve the Inter ...