JAVA反射专题

JAVA反射专题

文章目录

  • 一、Class类 和 面向对象
    • 1.1. 一个普通的类的实例对象表示
    • 1.2. Class类的实例对象介绍
    • 1.3 任何类都是Class的实例对象,下面三种方式:
  • 二、Java 动态加载类信息
  • 三、方法的反射
  • 四、反射和泛型

从主要以下几点开始学习

Class类的使用
方法的反射
成员变量的反射
构造器的反射
Java类加载机制

一、Class类 和 面向对象

在面向对象的环境中,万事万物皆对象,但也总有例外,Java中有两个不属于对象,一个是普通数据类型,一个是静态的成员

普通数据类型有封装类的弥补,静态的属于类,那么类是不是对象呢?
类是对象,是java.lang.Class类的实例对象,看文字还比较容易理解,中文说出来就比较绕口, 英文: there is a class named Class

1.1. 一个普通的类的实例对象表示

public class Coo {//Foo的实例对象 以doo表示Foo doo=new Foo();
}class Foo{}

1.2. Class类的实例对象介绍

  • 一个Class类的实例对象有三种表示方式但不能是new Class,因为下面源码中也解释为什么?
/** Private constructor. Only the Java Virtual Machine creates Class objects.* This constructor is not used and prevents the default constructor being* generated.*/
private Class(ClassLoader loader) {// Initialize final field for classLoader.  The initialization value of non-null// prevents future JIT optimizations from assuming this final field is null.classLoader = loader;
}

上面是Class类中的一个构造器,是私有的,而且注释说只有JVM创建Class对象,在以前的Java版本中你可能会看到一个无参的构造器,没关系,那你的构造器也绝对是私有,不能直接创建,在上面中出现了一个JIT编译的关键词,有兴趣的小伙伴可以研究扩展

1.3 任何类都是Class的实例对象,下面三种方式:

package com.gblfy.reflect;/*** @author gblfy* @ClassNme ClassDemo1* @Description TODO* @Date 2019/7/1 23:09* @version1.0*/
public class ClassDemo1 {//Foo 的实例对象如何表示?public static void main(String[] args) {Foo foo1 = new Foo();//foo1就表示出来了//Foo这个类,也是一个实例对象 Class类的实例对象,如何表示呢?//任何一个雷都是Class的实例对象,这个实例对象有三种表示方式//第一种表示方式--->>>实际告诉我们任何一个类,// 都有一个隐含的静态成员变量classClass c1 = Foo.class;//第二种表示方式 已经知道该类的对象通过getClass方法Class c2 = foo1.getClass();/***   官网c1,c2 表示了Foo类的类类型(class type)*   万事万物接对象*   类也是对象,是Class类的实例对象*   这个对象我们称为该类的类类型*//*** Foo类的对象指的就是foo1* Foo类的类类型指的就是c1 c2*//*不管c1 c2 都代表了Foo类的类类型一个类只可能是Class类的一个实例对象*/System.out.println(c1 == c2);//第三种表示方式 Class.forNameClass c3 = null;try {c3 = Class.forName("com.gblfy.reflect.Foo");} catch (ClassNotFoundException e) {e.printStackTrace();}System.out.println(c2 == c3);//我么完全可以通过类的类类型创建该类的对象实例--->>>// 通过c1 or c2 or c3 创建Foo的实例try {Foo foo = (Foo) c1.newInstance();//需要有无参数的构造方法foo.print();} catch (InstantiationException e) {e.printStackTrace();} catch (IllegalAccessException e) {e.printStackTrace();}}
}class Foo {void print() {System.out.print("foo");}
}

二、Java 动态加载类信息

三种表示Class的实例对象中,第三种具有很好的动态加载类③

可以表示类的类类型,还可以动态加载类
区分编译、运行
编译时加载类属于静态加载类
运行时加载类属于动态加载类
很多时候,大家都是通过工具(idea、eclipse等)进行办公或者学习,编译和运行都是由工具来辅助完成的,那么我们需要知道编译、运行的区别

只要是在类里面用到的,都隐含class,对应的类的类类型,如下:

public class Coo {Class c0=int.class;Class c1=String.class;Class c2=Fouble.class;Class c3=void.class;}

在Foo类中,写个方法

class Foo{public static void staticVoidMethod(Object o){//传递的是什么类型,就是什么类型Class co=o.getClass();}
}

o传递的是什么对象,co就是该类的类类型,那么底层怎么实现的,可能会比较复杂,贴一份源码

public final native Class<?> getClass();

这是一个native声明的一个方法,称为本地方法,Java中有一项技术JNR,使用Java声明,C语言实现,Java 中调用…一堆,有兴趣的可以了解了解,效果就是上面说的,返回类的类类型

下面是简单的通过Class获取类的信息:

class Foo {public static void staticVoidMethod(Object o) {//传递的是什么类型,就是什么类型Class co = o.getClass();System.out.println("类的全名称:" + co.getName());System.out.println("类的名字:" + co.getSimpleName());//Method类,方法对象//一个成员方法 就是 一个Method对象//getMethods 获取所有public的方法,其中包括父类继承的函数Method[] allMethods = co.getMethods();//getFeclaredMethods获取该类自己声明的方法Method[] thisMethods = co.getFeclaredMethods();for (Method method : allMethods) {//method.getReturnType()得到的是类的类类型//比如返回值是String,那么得到的是String.class的类类型,通过getName获取名称System.out.println("返回类型:" + method.getReturnType().getName());System.out.println("方法名称:" + method.getName());//获取参数类型Class[] parameterTypes = method.getParameterTypes();for (Class c : parameterTypes) {System.out.println("参数类型:" + c.getName());}System.out.println("====================================");}//成员变量 =》对象//属于java.lang.reflect.Field//Field封装了关于成员变量的操作//getFields获取所有public的成员变量Field[] field=co.getFields();//得到自己声明的成员变量Field[] declaredFields=co.getFeclaredFields();for (Field fields:field) {System.out.println("成员变量类型"+fields.getType());System.out.println("成员变量名称"+fields.getName());}}
}

简单来一个main方法,加入一个String类

public class Coo {public static void main(String[] args) {String hello=new String();Foo.staticVoidMethod(hello);}
}

控制台打印 , 所有String内的方法信息:

类的全名称:java.lang.String
类的名字:String
返回类型:boolean
方法名称:equals
参数类型:java.lang.Object
====================================
返回类型:java.lang.String
方法名称:toString
====================================
返回类型:int
方法名称:hashCode
====================================
返回类型:int
方法名称:compareTo
参数类型:java.lang.Object
====================================
//......

可以总结出来,getFeclaredXXX()方法都是获取自己声明的内容,包括成员变量,构造器,方法等等,直接的getXXX()方法部分会获取所有内容包括父类的内容,另外数组是一个特殊的存在,打印的是“0]”差不多的样子,在JVM对数组的存储方式也比较VIP,有兴趣的可以理解扩展

三、方法的反射

上面有获取所有的方法的示例,下面来学习如何获取某一个方法以及方法的反射操作

①方法的名称和方法的参数列表可以唯一定位某一个方法

②method.invoke(对象,参数列表)

public class MethodReflect {//获取getMethod方法,获取①号public static void main(String[] args) {MethodFemo demo = new MethodFemo();//1.获取类信息Class c0 = demo.getClass();//2.获取方法try {//第一种写法Method method1 = c0.getFeclaredMethod("getMethod", new Class[]{String.class, String.class});//第二种写法Method method2 = c0.getFeclaredMethod("getMethod", String.class, String.class);//平时正常的调用方法: demo.getMethod(str0,str1)//现在使用method1来调用--public Object invoke(Object obj, Object... args)//第一个参数是调用的类,第二个参数是可用可无,按定义的方法来录入(str0,str1)//invoke的方法如果有返回值,则返回Object的值,void的返回值为nulltry {Object object1 = method1.invoke(demo, new Object[]{"hello", " world"});Object object2 = method2.invoke(demo, "hello", " world");} catch (IllegalAccessException e) {e.printStackTrace();} catch (InvocationTargetException e) {e.printStackTrace();}} catch (NoSuchMethodException e) {e.printStackTrace();}}}class MethodFemo {//①public void getMethod(String a, String b) {System.out.println("concat: " + a + b);}//②public void getMethod(int a, int b) {System.out.println("sum: " + a + b);}
}

四、反射和泛型

泛型不说了,非常的常用,比如list,map等等,约定类型,不多做解释,直接先来一个操作,比对List和List是否相等

public class Coo {public static void main(String[] args) {//无泛型List list0=new ArrayList();//String泛型List<String> list1=new ArrayList<>();list1.add("hello");Class c0=list0.getClass();Class c1=list1.getClass();//输出System.out.println(c0==c1);}
}

输出的结果是true, 编译后的class文件也可以当成字节码,说明反射的操作都是编译之后的操作,而且返回true说明编译之后list的泛型被抹去了,去泛型化的,得到Java的泛型是一种规范,只在编译时有效,跳过编译编译就无效了,为了验证这一点,刚好可以使用反射来做一个验证

//获取list1<String> 中的 add方法 ,向里面加一个int类型的值
Method method=c1.getMethod("add",Object.class);
method.invoke(list1,100);System.out.println(list1.size());

list1的大小改变了,说明添加成功了,也验证了Java泛型只在编译期有效,运行时则去泛型化,如果去遍历这个list1是会报类型转化异常的

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/523729.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

漫画:图的 “多源” 最短路径

戳蓝字“CSDN云计算”关注我们哦&#xff01;技术头条&#xff1a;干货、简洁、多维全面。更多云计算精华知识尽在眼前&#xff0c;get要点、solve难题&#xff0c;统统不在话下&#xff01;————— 第二天 —————小灰的思路如下&#xff1a;第一步&#xff0c;利用迪…

C++实现单链表的反序

引言 将一个没有空结点作为头的单链表实现反转。其实质就是将结点的指针域指向反转。定义指向当前结点的指针&#xff0c;指向前一个结点的指针&#xff0c;指向当前结点的后一个结点的指针&#xff0c;这个过程中包含只有一个结点的单链表&#xff0c;那么反转之后还是它本身…

Git版本控制管理系统_企业实战上篇

Git专题 文章目录一、Git 介绍1.2. Linux 环境安装并配置Git1.3. 在windows安装git1.4. Windows配置Git 篇1.5. 创建git仓库二、时光机穿梭2.1. 版本回退2.2. 工作区和暂存区2.3. 管理修改2.4. 撤销修改2.5. 删除文件三、远程仓库3.1. 添加远程库3.2. 从远程库克隆四、分支管理…

vs2010中引入boost库

引言 在vs2010中无法使用C11中的大多数特性&#xff0c;像mutex互斥锁&#xff0c;要想使用需要引入boost库。下面记录一下boost库引入到vs2010中。 实现 分为以下几步&#xff1a; 下载boost压缩包 可以采用下面的地址下载适合自己的版本。下载地址&#xff1a; https://…

立足国产自主可控技术 达梦DM8数据库新品化繁为简

戳蓝字“CSDN云计算”关注我们哦&#xff01;面对技术日新月异的发展&#xff0c;如今俨然已经演变成为数据发展引来的潮流&#xff0c;而数据库的建立对企业的发展有着举足轻重的作用&#xff0c;对数据库的有效开发和管理是企业正常运行的保障&#xff0c;作为现代化经济发展…

Windows 配置Git 篇

Windows配置git 查看配置git config --list 全局配置Git git config --global user.name "用户名" git config --global user.email "邮箱" git config --list某个项目配置Git git config --local user.name "用户名" git config --local user…

C++中关于隐藏的理解

引言 在使用中弄清楚隐藏的区别之后&#xff0c;还需要明白怎么使用。下面说以下隐藏&#xff0c;重写&#xff0c;重载的区别&#xff1a; 与重载的区别&#xff1a; 在父类与子类中&#xff0c;函数名相同&#xff0c;参数不同&#xff0c;无论父类中的同名函数是否含有virt…

183条地铁线路,3034个地铁站,发现中国地铁名字的秘密。

戳蓝字“CSDN云计算”关注我们哦&#xff01;技术头条&#xff1a;干货、简洁、多维全面。更多云计算精华知识尽在眼前&#xff0c;get要点、solve难题&#xff0c;统统不在话下&#xff01;作者&#xff1a;小F转载&#xff1a;法纳斯特最近看了新周刊的一篇推送&#xff0c;有…

创建Git仓库的三种形式

创建Git仓库的三种形式&#xff1a; 2种本地创建和远程拉取 文章目录1. 在idea中初始化仓库1.1. 进入目录&#xff0c;初始化仓库1.2. git init 目录名1.3.1 远程拉取1. 在idea中初始化仓库 1.1. 进入目录&#xff0c;初始化仓库 进入目录git init 创建test1目录&#xff0c;…

C++中常用字符串相关的编程题

索引 找出字符串中的数字&#xff0c;字母和符号&#xff0c;并分别存储 找出字符串中所有不重复的字符&#xff0c;并输出 统计字符串中每个字符的个数&#xff0c;并输出 编译环境 以下所用的开发环境是vs2010,创建的都为控制台输出程序。下面只贴出创建项目后修改了的c…

刷了一个半月算法题,我薪资终于Double了

戳蓝字“CSDN云计算”关注我们哦&#xff01;技术头条&#xff1a;干货、简洁、多维全面。更多云计算精华知识尽在眼前&#xff0c;get要点、solve难题&#xff0c;统统不在话下&#xff01;前言很多人感觉大公司都是要手写算法&#xff0c;那刷题是必不可少了&#xff0c;你技…

创建版本库

什么是版本库呢&#xff1f;版本库又名仓库&#xff0c;英文名repository&#xff0c;你可以简单理解成一个目录&#xff0c;这个目录里面的所有文件都可以被Git管理起来&#xff0c;每个文件的修改、删除&#xff0c;Git都能跟踪&#xff0c;以便任何时刻都可以追踪历史&#…

mac上用qt调用自己生成的qt动态库,该动态库又依赖第三方库

qt下依赖于第三方库生成的动态库的调用概述基于声网的sdk如何在自己的动态库中使用使用基于第三方库的动态库下面看pro文件中的设置概述 初次使用mac上的qtCreator生成动态库&#xff0c;该动态库编写时调用了第三方库&#xff0c;基于生成的该动态库&#xff0c;编写测试程序…

版本回退

现在&#xff0c;你已经学会了修改文件&#xff0c;然后把修改提交到Git版本库&#xff0c;现在&#xff0c;再练习一次&#xff0c;修改readme.txt文件如下&#xff1a; i am gblfy i am yuxin然后&#xff0c;【工作区】-【暂存区】-【本地仓库】尝试提交&#xff1a; 修改…

Docker精华问答 | 数据库为什么不适合放在 Docker 中运行?

戳蓝字“CSDN云计算”关注我们哦&#xff01;Docker 是一个开源的应用容器引擎&#xff0c;让开发者可以打包他们的应用以及依赖包到一个可移植的容器中&#xff0c;然后发布到任何流行的 Linux或Windows 机器上&#xff0c;也可以实现虚拟化。今天就让我们一起看看关于Docker …

Mac下使用macdeployqt打包qt程序:

概述 初次在Mac上使用qt的macdeployqt来打包生成的可执行程序&#xff0c;这里记录下。由于我的程序是调用之前生成的qt动态库&#xff0c;而动态库又依赖于第三方库&#xff0c;相对于没有库文件依赖的程序&#xff0c;这里有一些需要注意的点&#xff0c;下面是打包的步骤。…

路透社:谷歌已停止与华为部分合作;联想否认断供华为PC;微软计划直供Linux内核;谷歌无人机快递Wing进军芬兰……...

关注并标星星CSDN云计算极客头条&#xff1a;速递、最新、绝对有料。这里有企业新动、这里有业界要闻&#xff0c;打起十二分精神&#xff0c;紧跟fashion你可以的&#xff01;每周三次&#xff0c;打卡即read更快、更全了解泛云圈精彩newsgo go go 阿里巴巴联合欧莱雅发布移动…

cmake简单使用

概述 cmake是一种跨平台编译工具&#xff0c;除了可以编译c&#xff0c;c代码也可以编译其他语言的代码&#xff0c;其主要就是通过cmake执行CMakeLists.txt从而生成Makefile。下面就自己了解到的简单的一点知识&#xff0c;做以记录。更多可查看官网&#xff1a;https://cmak…

管理修改

现在&#xff0c;假定你已经完全掌握了暂存区的概念。下面&#xff0c;我们要讨论的就是&#xff0c;为什么Git比其他版本控制系统设计得优秀&#xff0c;因为Git跟踪并管理的是修改&#xff0c;而非文件。 你会问&#xff0c;什么是修改&#xff1f; 比如你新增了一行&#x…

npm install安装依赖报错——常见报错解决方案

小伙伴在开发前端项目过程中&#xff0c;执行npm install安装项目依赖时&#xff0c;往往会遇到各种各样的报错&#xff0c;接下来建仔给大家总结一下几种常见报错解决方案! 第一种报错&#xff1a;无法将“npm”项识别为 cmdlet、函数、脚本文件或可运行程序的名称。 报错详…