JAVA进阶之旅(二)——认识Class类,反射的概念,Constructor,Field,Method,反射Main方法,数组的反射和实践
JAVA进阶之旅(二)——认识Class类,反射的概念,Constructor,Field,Method,反射Main方法,数组的反射和实践
我们继续聊JAVA,这次比较有意思,那就是反射了
一.认识Class类
想要反射,你就必须要了解一个类——Class,我们知道,java程序中的各个java类都属于同一事物,我们通常用Classliability描述对吧,反射这个概念从JDK1.2就出来了,历史算是比较悠久了,这个Class可不是关键字哦,这个是一个类,他代表的是一类事物;
- 我们归根结底就是拿到字节码对象
这里我们有三种方式是可以得到对应的实例对象(Class类型)
- 1.类名.class
- 2.对象.getClass
- 3.Class.forName(“类名”);—常用
我们写一个小程序来过一遍
public class CalssTest {
public static void main(String[] args) throws ClassNotFoundException {
String str1 = "liu";
Class class1 = str1.getClass();
Class class2 = String.class;
Class class3 = Class.forName("java.lang.String");
System.out.println(class1 == class2);
System.out.println(class1 == class3);
System.out.println(class2 == class3);
}
}
通过打印的结果我们可以知道我们都是输出同一份字节码,所以结果都是true,我们再来看,我们的Class其实还有一个方法
System.out.println(class1.isPrimitive());
System.out.println(Integer.class == int.class);
System.out.println(int.class == Integer.TYPE);
打印的结果是true,false,true,那这三又是什么意思呢?这个就留给大家猜想一下,应该很容易就知道了的
- isPrimitive是否是基础类型或者原始类型
那我们的数组是什么类型呢?
宗旨,只要是在源程序中出现的类型,都有各自的Class类型,列入int[],Void等
二.反射的概念
好的。了解了Class类的神奇,我们就可以来看看反射的机制了
反射的概念:反射就是把JAVA类中的各种成分映射成相应的JAVA类,例如,一个java类中用一个Class类的对象来表示,一个类中的组成部分,成员变量,方法,构造方法,包等信息,也用一个个的JAVA类来表示,就像汽车是一个类,汽车中的发动机,变速箱也是一个类,表示JAVA的Class类要提供一系列的方法,来获取其中的变量,方法,构造方法,修饰符,包等信息,这些信息是用来相应类的实例对象表示,衙门是Field,Method,Contructor,Package等
一个类中的每一个成员都可以用相应的反射API类的一个实例对象来表示,通过调用Class来调用各种方法,我们接下来一个个讲
三.Constructor
代表的是某一个类的构造方法,我们用代码来看
public class CalssTest {
public static void main(String[] args)throws NoSuchMethodException, InstantiationException, IllegalAccessException, IllegalArgumentException, InvocationTargetException {
//得到String的StringBuffer构造方法
Constructor<String> constructor = String.class.getConstructor(StringBuffer.class);
String str = constructor.newInstance(new StringBuffer("str"));
System.out.println(str);
}
}
通过获得的方法用到上面相同类型的实例,再看newInstance,得到我们设置参数的构造方法,我们再来看下成员变量的反射
四.Field
这里我们就模拟了一个类,作为反射的对象
public class FieldClass {
public int x;
publicint y;
public FieldClass(int x,int y) {
this.x = x;
this.y = y;
}
}
那我们实际的操作就是:
public class CalssTest {
public static void main(String[] args){
try {
//首先为x,y 赋值
FieldClass fClass = new FieldClass(10, 20);
//反射成员变量
Field field1 = fClass.getClass().getField("x");
Field field2 = fClass.getClass().getField("y");
//指定对象
System.out.println(field1.get(fClass));
System.out.println(field2.get(fClass));
} catch (NoSuchFieldException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
} catch (SecurityException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
} catch (IllegalArgumentException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IllegalAccessException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
这样我们就可以直接反射到成员变量的值了,这里我们来做一个小练习来测试一下我们成员变量的反射的理解
练习题
- 假设我们有一个对象中,有许多的String类型成员变量,我们的需求就是把所有对应的字符串内容”b”改成”a”
题目有了我们整理下思路,首先要做的就是定义一个对象咯
public class FieldClass {
public int x;
public int y;
public String str1 = "boy";
public String str2 = "bbq";
public String str3 = "hello";
public FieldClass(int x,int y) {
this.x = x;
this.y = y;
}
@Override
public String toString() {
return "FieldClass [x=" + x + ", y=" + y + ", str1=" + str1 + ", str2="
+ str2 + ", str3=" + str3 + "]";
}
}
好的,这里有三个string类型的成员变量,那我们该怎么去反射呢?
/**
* 假设我们有一个对象中,有许多的String类型成员变量,我们
* 的需求就是把所有对应的字符串内容"b"改成"a"
* @author LGL
*
*/
public class CalssTest {
public static void main(String[] args) throws Exception{
FieldClass fClass = new FieldClass(5, 10);
//得到所有的成員变量
Field[] fields = fClass.getClass().getFields();
for(Field field : fields){
//过滤下String类型
if(field.getType() == String.class){
//取值
String oldValue = (String) field.get(fClass);
String newValue = oldValue.replace("b", "a");
field.set(fClass, newValue);
}
}
System.out.println(fClass);
}
}
这里思路还是比较清晰的,我们一步步的去过滤,最终更改了值
五.Method
如果前面的都是不怎么常用的,那这个我相信你绝对会喜欢,也就是方法,Method,我们来看看怎么用吧!
public class CalssTest {
public static void main(String[] args) throws Exception{
String str1 = "abc";
//反射charAt方法
Method method = String.class.getMethod("charAt", int.class);
//作用对象 第几个
System.out.println(method.invoke(str1, 2));
}
}
这里我反射的是String的方法charAt,取第二个char,所以打印出来是c
这其实套用了一种专家模式,谁调用了这个数据,谁就是这个专家,现在我们思考一下,如果我们代码是这样写:
System.out.println(method.invoke(null, 2));
这里我们不传对象,而是传一个null进去,那我们知道这个Method是调用什么吗?而纵观之下,只有static修饰的静态方法是不需要对象的,那就说明他调用的是对象了;
在JDK1.4和JDK1.5中,invoke的参数是有些区别的,不过我们现在都1.8了,自然而然这个我们不需要去考虑和追究;
六.反射Main方法
我们现在来思考一下,如何通过反射去执行一个类的Main方法,这就比较好玩了,这里就相当于一个练习题了,而题目就是:
- 写一个程序,这个程序能够根据用户提供的类名,去执行该类的main方法
而我们的在写这段程序之前,我们就要思考一下了,我们观察main方法:
public static void main(String[] args) {
//main方法
}
你是否已经发现,这个main方法的参数是一个数组,,如果我们通过反射来调用这个方法,那我们该如何为invoke方法传递参数呢?
在以前的老程序员可能会在纠结JDK1.4和JDK1.5的invoke区别,但是我们倒不用去考虑这些,因为我们的版本是JDK1.8,这样吧,我们先写个需要调用的类:
public class MainClass {
public static void main(String[] args) {
for (String arg : args) {
System.out.println("Main:" + arg);
}
}
}
OK,这个类就是打印下数组的值,那我们真正的反射应该怎么去写尼?传统的调用方法是这样的:
MainClass.main(new String[] { "Hello" });
我们反射的话,就不是这么简单了,我们需要这样:
public class CalssTest {
public static void main(String[] args) throws Exception {
// MainClass.main(new String[] { "Hello" });
// 指定类名
// String className = args[0];
// 指定Main方法
Method main = Class.forName("MainClass").getMethod("main",
String[].class);
// 调用main方法
main.invoke(null, (Object) new String[] { "Hello", "LGL" });
}
}
这里为什么需要强转为Object?不是说好的传递数组吗?吗是因为JDK为了兼容老版本,如果你传递的是一个数组有多个值会进行拆包,我现在声明一个Object就是告诉他我这里只是一个对象,避免对象异常,我们看下输出的结果:
说明我们是调用成功了的;那这里就牵引出数组的反射和Object的关系了,我们继续来看;
七.数组的反射
数组实际上也是一个对象,这点我们一定要清楚,是吧
- 具有相同维数和元素类型的数组术语同一类型,即具有相同的Class实例对象
- 代表数组的Class实例对象的getSuperClass()方法返回的父类Object为对象的Class
这里我们以数组为例子就好了,我们来验证一下字节码:
int[] arr1 = { 3 };
int[] arr2 = { 4 };
//true
System.out.println(arr1.getClass() == arr2.getClass());
//[I
System.out.println(arr1.getClass().getName());
第一个为true也就验证了第一条,第二个输出的结果是[I,这个代表的是什么意思呢?[代表的是数组,I代表的是Int类型,也就是这个是int类型的数组
看一下JDK对照文档就行了
接下来,我们来看下数组的反射具体实践是什么样子的!
八.数组反射实践
我们出道题目好了在这样看起来可能更加生动形象一点
- 题目:怎么得到数组中的元素?
通过查看API文档,我们知道可以反射这个Array
那这个Array要怎么用呢?
假设我现在封装一个打印的方法,这个打印的方法很简单,我定义一个Object参数,你传进来什么,我就打印什么,那要是传递数组,我就一个个的打印,这样的理解应该就比较清晰了,那我们实际的操作你怎样的呢?
public class CalssTest {
public static void main(String[] args) throws Exception {
int[] arr = { 1, 3, 5, 7, 9, 2, 4, 6, 8, 10 };
printObject(arr);
}
private static void printObject(Object obj) {
// 拿到字节码
Class<? extends Object> classs = obj.getClass();
// 判断是否是数组
if (classs.isArray()) {
// 得到长度
int len = Array.getLength(obj);
// 取出每一个
for (int i = 0; i < len; i++) {
System.out.print(Array.get(obj, i));
}
} else {
System.out.println(obj);
}
}
}
但是如何你要问我这个数组的数据类型,我倒是没有获取到,不知为何!!!
好的,比较浅显的反射基础就偷偷的路过了,有兴趣的朋友可以了解下,也可以进群:555974449 一起来探讨探讨!
JAVA进阶之旅(二)——认识Class类,反射的概念,Constructor,Field,Method,反射Main方法,数组的反射和实践的更多相关文章
- JAVA进阶之旅(一)——增强for循环,基本数据类型的自动拆箱与装箱,享元设计模式,枚举的概述,枚举的应用,枚举的构造方法,枚举的抽象方法
JAVA进阶之旅(一)--增强for循环,基本数据类型的自动拆箱与装箱,享元设计模式,枚举的概述,枚举的应用,枚举的构造方法,枚举的抽象方法 学完我们的java之旅,其实收获还是很多的,但是依然还有很 ...
- 当我们说线程安全时,到底在说什么——Java进阶系列(二)
原创文章,同步发自作者个人博客,转载请以超链接形式在文章开头处注明出处http://www.jasongj.com/java/thread_safe/ 多线程编程中的三个核心概念 原子性 这一点,跟数 ...
- Java进阶(五十二)利用LOG4J生成服务日志
Java进阶(五十二)利用LOG4J生成服务日志 前言 由于论文写作需求,需要进行流程挖掘.前提是需要有真实的事件日志数据.真实的事件日志数据可以用来发现.监控和提升业务流程. 为了获得真实的事件日志 ...
- Java进阶(三十二) HttpClient使用详解
Java进阶(三十二) HttpClient使用详解 Http协议的重要性相信不用我多说了,HttpClient相比传统JDK自带的URLConnection,增加了易用性和灵活性(具体区别,日后我们 ...
- Java进阶(四十二)Java中多线程使用匿名内部类的方式进行创建3种方式
Java中多线程使用匿名内部类的方式进行创建3种方式 package cn.edu.ujn.demo; // 匿名内部类的格式: public class ThreadDemo { public st ...
- java基础(十二)常用类总结(二)
这里有我之前上课总结的一些知识点以及代码大部分是老师讲的笔记 个人认为是非常好的,,也是比较经典的内容,真诚的希望这些对于那些想学习的人有所帮助! 由于代码是分模块的上传非常的不便.也比较多,讲的也是 ...
- Java进阶知识点8:高可扩展架构的利器 - 动态模块加载核心技术(ClassLoader、反射、依赖隔离)
一.背景 功能模块化是实现系统能力高可扩展性的常见思路.而模块化又可分为静态模块化和动态模块化两类: 1. 静态模块化:指在编译期可以通过引入新的模块扩展系统能力.比如:通过maven/gradle引 ...
- Java 网络编程(二) 两类传输协议:TCP UDP
链接地址:http://www.cnblogs.com/mengdd/archive/2013/03/09/2951841.html 两类传输协议:TCP,UDP TCP TCP是Transfer C ...
- 转: 深入Java虚拟机】之二:Class类文件结构
转载请注明出处:http://blog.csdn.net/ns_code/article/details/17675609 平台无关性 Java是与平台无关的语言,这得益于Java源代码编译后生成的存 ...
随机推荐
- css清除浮动方法小结
清除浮动其实主要解决的就是高度塌陷问题,具体在此不再赘述~~~那些年我们一起清除过的浮动(大佬博客,写的挺不错) 方法小结:1. 1)添加额外标签 这是在学校老师就告诉我们的 一种方法,通过在浮动元素 ...
- 百度API-------热力图
<!DOCTYPE html><html><head> <meta http-equiv="Content-Type" content=& ...
- [HEOI2015]小Z的房间
Description 你突然有了一个大房子,房子里面有一些房间.事实上,你的房子可以看做是一个包含n*m个格子的格状矩形,每个格子是一个房间或者是一个柱子.在一开始的时候,相邻的格子之间都有墙隔着. ...
- HDU2222 自动机(学习中)
题目大意: 给你很多个单词,然后给你一篇文章,问给出的单词在文章中出现的次数. 解题思路: AC自动机入门题.需要注意的就是可能有重复单词 代码如下: #include<iostream> ...
- 【网络流问题·我就想建好模】
·为了有助于你读后文,在写题前先列出一些大米饼的代码习惯: 一个提醒:所有的ADD函数无特殊说明均如图:(没有w就直接跳过) 以及: go(i,a,b)=====for(int i=a;i<=b ...
- 主席树(BZOJ2653)
考虑二分答案,设为k,将大于等于k的元素设为1,小于的设为-1,如果某一段的和>=0,说明这段的中位数>=k. 对于每组询问,二分完后查询新序列的最大子段和即可. 但是不能开n棵线段树,观 ...
- mysql 使用问题?
linux中安装了mysql客户端和服务器端,为什么无法使用,总是报错呢 解决办法:使用dpkg -r mysql命令删除掉mysql-client和mysql-server了,还是不行,而且查看软件 ...
- Java后缀数组-求sa数组
后缀数组的一些基本概念请自行百度,简单来说后缀数组就是一个字符串所有后缀大小排序后的一个集合,然后我们根据后缀数组的一些性质就可以实现各种需求. public class MySuffixArrayT ...
- SpringMVC 处理映射
一.Spring MVC控制器名称处理映射 以下示例展示如何利用Spring MVC 框架使用控制器名称处理程序映射. ControllerClassNameHandlerMapping类是基于约定的 ...
- ChatGirl is an AI ChatBot based on TensorFlow Seq2Seq Model
Introduction [Under developing,it is not working well yet.But you can just train,and run it.] ChatGi ...