反射的核心Class类

Class类是一个特殊的类,不能手动创建,只能由jvm来创建。 jvm在类加载时会为每个类生成一个与之对应的Class对象在Java堆中(且每个类只会有一个对应的Class对象),用来保存该类的结构信息。该类的对象都要通过这个Class对象来进行实例化。

可以通过Class的对象来获得该类的结构信息(构造器、方法、属性等)。

反射是什么

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

Class对象就像是一面镜子,我们并不能直接得到加载的类里的内容,而是需要通过Class对象这面镜子反射内部的信息来得到的。

通过Class对象来获得类的结构信息并且把各个结构部分分别映射成各个对象这个过程就是反射了。

如何获得Class对象

创建一个User类来进行测试

package com.rainc.test.bean;

/**

* @Author rainc

* @create 2019/10/12 19:51

*/

public class User {

private int id;

private int age;

private String name;

public User() {

}

public User(int id, int age, String name) {

this.id = id;

this.age = age;

this.name = name;

}

public int getId() {

return id;

}

public void setId(int id) {

this.id = id;

}

public int getAge() {

return age;

}

public void setAge(int age) {

this.age = age;

}

public String getName() {

return name;

}

public void setName(String name) {

this.name = name;

}

}

public static void main(String[] args) {

User user=new User();

//1.通过该类的对象直接过得Class对象

Class clz=user.getClass();

System.out.println(clz);

//2.通过类.class获得

clz=User.class;

System.out.println(clz);

//3.调用Class的静态方法forName通过类全名来获得

try {

String path = "com.rainc.test.bean.User";

clz = Class.forName(path);

System.out.println(clz);

} catch (ClassNotFoundException e) {

e.printStackTrace();

}

}

Snipaste_2019-10-19_16-43-41.png

通过反射api来获得类的结构信息

public static void main(String[] args) {

String path = "com.rainc.test.bean.User";

try {

Class clz = Class.forName(path);

//获取类的名字

System.out.println(clz.getName());//获得类全名

System.out.println(clz.getSimpleName());//获得类名

//获取属性信息

Field[] fields = clz.getFields();//只能获得public的field

for (Field temp : fields) {

System.out.println("属性:" + temp);

}

fields = clz.getDeclaredFields();//获得所有的field

for (Field temp : fields) {

System.out.println("属性:" + temp);

}

//获得指定的属性信息

Field f = clz.getDeclaredField("name");

//获取方法信息

Method[] methods = clz.getDeclaredMethods();

//通过名字获取指定的方法信息

//获得无参的指定方法

for (Method temp : methods) {

System.out.println("方法:" + temp);

}

Method m1 = clz.getDeclaredMethod("getName");

//获得有参的指定方法

Method m2 = clz.getDeclaredMethod("setName", String.class);

//获得构造器信息

Constructor[] constructors = clz.getDeclaredConstructors();

//获得无参的构造器

Constructor c = clz.getDeclaredConstructor();

//获得有参的构造器

c = clz.getDeclaredConstructor(int.class, int.class, String.class);

} catch (Exception e) {

e.printStackTrace();

}

}

Snipaste_2019-10-20_09-33-17.png

通过反射api动态的操作构造器、方法、属性

public static void main(String[] args) {

String path = "com.rainc.test.bean.User";

try {

Class clz = (Class) Class.forName(path);

//获得构造器信息

//通过反射api调用构造方法,构造对象

clz.getDeclaredConstructor().newInstance();

//通过反射api调用普通方法

User u = clz.getDeclaredConstructor().newInstance();

Method method = clz.getDeclaredMethod("setName", String.class);

method.invoke(u, "rainc");//相当于 u.setName("rainc")

System.out.println(u.getName());

//通过反射api操作属性

User u2 = clz.getDeclaredConstructor().newInstance();

Field f = clz.getDeclaredField("name");

f.setAccessible(true);//解除安全检查,可以通过这个方法使用私有方法和属性等

f.set(u2, "rainc2");

System.out.println(u2.getName());

} catch (Exception e) {

e.printStackTrace();

}

}

Snipaste_2019-10-20_09-36-19.png

反射的效率

使用反射的效率会比直接通过对象调用方法效率低。通过setAccessible(true)方法解除安全检查可以提高反射的运行效率

创建TestBean类用来测试

/**

* @Author rainc

* @create 2019/10/20 9:19

*/

public class TestBean {

long sum=0;

public long getSum() {

return sum;

}

public void setSum(int sum) {

this.sum+=sum;

}

}

创建Test类进行测试

import java.lang.reflect.Method;

/**

* @Author rainc

* @create 2019/10/20 9:19

*/

public class TestAccessiable {

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

test01();

test02();

test03();

}

/**

* 普通方法

*/

public static void test01() {

TestBean t=new TestBean();

long startTtime = System.currentTimeMillis();

for (int i = 0; i < 1000000000L; i++) {

t.setSum(i);

}

System.out.println("和:"+t.getSum());

long endTime = System.currentTimeMillis();

System.out.println("普通方法调用10亿次耗时:" + (endTime - startTtime) + "ms");

}

/**

* 反射调用

*/

public static void test02() throws Exception {

TestBean t=new TestBean();

Class clz=t.getClass();

Method m=clz.getDeclaredMethod("setSum", int.class);

long startTtime = System.currentTimeMillis();

for (int i = 0; i < 1000000000L; i++) {

m.invoke(t,i);

}

System.out.println("和:"+t.getSum());

long endTime = System.currentTimeMillis();

System.out.println("反射调用10亿次耗时:" + (endTime - startTtime) + "ms");

}

/**

* 解除安全检查,反射调用

*/

public static void test03() throws Exception {

TestBean t=new TestBean();

Class clz=t.getClass();

Method m=clz.getDeclaredMethod("setSum", int.class);

m.setAccessible(true);

long startTtime = System.currentTimeMillis();

for (int i = 0; i < 1000000000L; i++) {

m.invoke(t,i);

}

System.out.println("和:"+t.getSum());

long endTime = System.currentTimeMillis();

System.out.println("解除安全检查,反射调用10亿次耗时:" + (endTime - startTtime) + "ms");

}

}

Snipaste_2019-10-20_09-43-18.png

可以看出,普通的方法调用效率最高,其次是解除安全检查的,效率最低的是直接通过反射调用。

尽管反射的效率并不如普通的方法调用,但是由于其拥有动态性,在框架中有着大量的使用,而这些框架却能大大的提高我们的工作效率。因此牺牲一定的性能效率来提高工作效率也是必要的。

反射操作泛型

ParameterizedType:表示一种参数化的类型,比如Collection< String >(常用)

GenericArrayType:表示一种元素类型是参数化类型或者类型变量的数组类型

TypeVariable:是各种类型变量的公共父接口

WildcardType:代表一种通配符类型表达式,比如?、? extends Number、? super Integer。(wildcard是一个单词:就是”通配符“)

import com.rainc.test.bean.User;

import java.lang.reflect.Method;

import java.lang.reflect.ParameterizedType;

import java.lang.reflect.Type;

import java.util.List;

import java.util.Map;

/**

* @Author rainc

* @create 2019/10/20 10:10

*/

public class TestGenericity {

public void test01(Map map, List list){

}

public Map test02(){

return null;

}

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

Class clz=TestGenericity.class;

//获得指定方法的泛型

System.out.println("获得指定方法的泛型");

Method m=clz.getMethod("test01", Map.class, List.class);

//取得方法的所有参数类型

Type[] t=m.getGenericParameterTypes();

for (Type paramType:t){

System.out.println("#"+paramType);

//判断取得的参数是否为参数化类型

if (paramType instanceof ParameterizedType){

//是的话将其强制转型并获得泛型的真正类型

Type[] genericTypes=((ParameterizedType) paramType).getActualTypeArguments();

for (Type genericType:genericTypes){

System.out.println("泛型类型:"+genericType);

}

}

}

//获得指定方法返回值泛型

System.out.println("\n\n指定方法返回值泛型");

Method m2=clz.getMethod("test02");

//由于返回值只会有一个因此不需要数组

Type returnType =m2.getGenericReturnType();

if (returnType instanceof ParameterizedType){

Type[] genericTypes=((ParameterizedType) returnType).getActualTypeArguments();

for (Type genericType:genericTypes){

System.out.println("泛型类型:"+genericType);

}

}

}

}

Snipaste_2019-10-20_10-47-16.png

java測試動態方法_java反射学习相关推荐

  1. java反射方法_java反射之方法反射的基本操作方法

    本文接上文"java反射之获取类的信息方法(推荐)",利用反射(invoke)来获取一个类中的方法来执行. 1.定义一个类,包含三个名称相同,参数不同的方法 class A{ pu ...

  2. java反射机制调用带参数的方法_Java反射机制:跟着代码学反射

    1. 前言 在OOP的世界里,万物皆对象.也就是说,我们可以将任何东西抽象成一个对象. 比如人,可以抽象成一个Person类,通过new Person()来实例化一个对象:再比如鸭子,可以抽象成一个D ...

  3. java私有属性和私有方法_Java 9中什么是私有的?

    java私有属性和私有方法 在进行面试时,我发现大多数应聘者都不知道Java中的private修饰符真正意味着什么. 他们对此有所了解,足以应付日常编码,但还远远不够. 这不成问题. 足够了解就足够了 ...

  4. java如何用c 的方法_JAVA如何调用C/C++方法

    JAVA以其跨平台的特性深受人们喜爱,而又正由于它的跨平台的目的,使得它和本地机器的各种内部联系变得很少,约束了它的功能.解决JAVA对本地操作的一种方法就是JNI. JAVA通过JNI调用本地方法, ...

  5. java中容易混淆的方法_java中容易混淆的概念

    java中容易混淆的概念 1. 谈谈 final, finally, finalize 的区别final-修饰符(关键字)如果一个类被声明为 final,意味着它不能再派生出新的子类,不 能作为父类被 ...

  6. java 创建文件夹的方法_Java创建文件夹的方法

    Java创建文件夹的方法 /** * 用于创建文件夹的方法 * @param mkdirName */ public void mkdir(String mkdirName) { try { File ...

  7. java私有属性和私有方法_Java接口–历年来Java 9之旅–默认方法和私有方法

    java私有属性和私有方法 介绍 Java接口已经比Java版本进行了更多的演变,而Java 8和Java 9则有所发展.在本文中,我们将介绍接口在Java 8之前的样子以及如何在Java 8和Jav ...

  8. java私有属性和私有方法_Java私有,受保护,公共和默认

    java私有属性和私有方法 您是Java程序员,所以您知道我在说什么. public修饰符使方法或字段可从应用程序中的任何位置访问. 那是简单的部分. 但是,您能告诉我protected和包私有的区别 ...

  9. java中容易混淆的方法_java中容易混淆的区别

    本文会随时更新一些java中容易混淆的关键字或者知识点,如有偏见之处,望留言! final和static的差别: 1,final的英语意思"最后的",在java中修饰类,方法和变量 ...

最新文章

  1. esri.views.2d.layers.features.controllers.OnDemandController 记一次ArcGIS Server的问题
  2. docker基础命令
  3. 【转】全排列算法非递归实现和递归实现
  4. mybatis学习教程(二)初级的增、删、查、改
  5. 《当90后遇上创业》导读
  6. codeforces1451 D. Circle Game
  7. 线段树-Count on a Treap-神题
  8. 你真的懂线程同步么?
  9. PowerBI Report Server 自定义视图无法显示故障解决
  10. 让美国颤抖的5G,到底牛在哪里?
  11. ReentrantLock深入学习
  12. 【波束形成】MMSE波束形成,自适应MMSE波束形成以及自适应MBER波束形成
  13. 电梯运行控制模式:如何做到人脸识别、刷卡、二维码?
  14. 面向交付的IT软件管理流程
  15. 如何制作校园平面图及路线导图
  16. 安卓模拟ibeacon_【首发】联接真实与虚拟世界:Estimote Beacons Developer Kit 低功耗蓝牙开发套件...
  17. 什么是云原生中台业务架构?
  18. 软件测试面试必看宝典(含面试题和笔试题)
  19. IIC的OLED显示程序
  20. H3C模拟器---HCL使用心得

热门文章

  1. c语言位操作大小写转换,C语言实现大小写转换的三种方法
  2. ueditor php 网络链接错误,ueditor使用editor.execCommand( 'link', {})插入链接无效的问题...
  3. 中相对路径与绝对路径的写法_相对路径和绝对路径?简洁易懂解释+实例
  4. python ju_如何使用jupy设置python路径
  5. mysql noinstall 安装_mysql-noinstall安装指南
  6. python123温度转换-python二级备考 day2
  7. 儿童手表怎么删除联系人_双11儿童手表选购指南:全天候24小时定位,做孩子的贴身保镖...
  8. Linux 下shell中exec解析
  9. Eclipse如何提高开发效率
  10. 自定义的Android EditText