当前位置: 首页 > news >正文

[Java开发之路](14)反射机制

1. Class类

普通对象构造方式:
 
   
// 创建Book实例对象
Book book = new Book();
对于Class的实例对象如何构造呢?
Class的构造函数是私有的,只有JVM才能创建实例对象
 
   
// Class的构造函数是私有的,只有JVM才能创建Class实例对象
Class class1 = new Class(); // 错误
 
   
public final class Class<T> implements java.io.Serializable,
java.lang.reflect.GenericDeclaration,
java.lang.reflect.Type,
java.lang.reflect.AnnotatedElement {
 
/*
* Constructor. Only the Java Virtual Machine creates Class
* objects.
*/
private Class() {}
 
....
}

Class有三种表示方式:

(1)XXX.class  XXX为类名  
实际再告诉我们任何一个类都有一个隐含的已经太成员变量class
 
    
Class class1 = Book.class;
(2)XXX.getClass()  XXX为对象名称
已知该类的实例对象,通过getClass()方法获取
 
    
Book book = new Book();
Class class2 = book.getClass();
(3)通过Class类的forName方法获取  
 
    
try {
Class class3 = Class.forName("com.qunar.bean.Book");
System.out.println(class1 == class2);
System.out.println(class1 == class3);
} catch (ClassNotFoundException e) {
e.printStackTrace();
}

我们完全可以通过类的类类型创建该类的对象实例,通过class1, class2以及 class3创建Book的实例
 
   
try {
Class class3 = Class.forName("com.qunar.bean.Book");
// 通过类类型的newInstance方法创建实例对象
Book book2 = (Book)class3.newInstance();
book2.setPrice("23.4");
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (InstantiationException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
}

2. Class动态加载类

Class.forName("类的全称")  不仅表示了类的类类型,还代表了动态加载类。
编译时刻加载类是静态加载类,运行时刻加载类是动态加载类。

3.反射

反射机制--用来检查可用的方法,并返回方法名。

人们想要在运行时获取类的信息的另一个动机,便是希望提供在跨网络的远程平台上创建和运行对象的能力。这被称为远程方法调用,它允许 一个Java程序将对象分布到多台机器上。

class类与java.lang.reflect类库一起对反射的概念进行了支持,该类库包含了Filed,Method以及Constructor类(每个类都实现了Member接口)。这些类型的对象是由JVM在运行时创建的,用以表示未知类里对应的成员。这样你就可以使用 Constructor创建新的对象,用get()和set()方法读取和修改与Field对象关联的字段,用invoke()方法调用与method对象关联的方法。另外,还可以调用getFields(),getMethods()和get Constructors()等很便利的方法,以返回表示字段,方法以及构造器的对象的数组。这样,匿名对象的类信息就能在运行时被完全确定下来,而在编译时不需要知道任何事情。

其实,反射机制并没有什么神奇之处。当通过反射与一个未知类型的对象打交道时,JVM只知道简单的检查这个对象,看它属于哪个特定的类。在用它做其他事情之前,我们必须先加载这个类的class对象。因此,那个类的.class文件对于JVM来说必须是可获取的,要么在本地机器上,要么可以通过网络可以获得。对于反射机制而言,在编译时不能取得.class文件,只能在运行时打开和检查.class文件。

3.1 获取方法信息

 
   
package com.qunar.reflect;
 
public class ReflectDemo {
 
public static void main(String[] args) {
// int的类类型
Class class1 = int.class;
Class class2 = String.class;
Class class3 = double.class;
Class class4 = Double.class;
Class class5 = void.class;
System.out.println("class1->" + class1.getName());
System.out.println("class2->" + class2.getName());
System.out.println("class3->" + class3.getName());
System.out.println("class4->" + class4.getName());
System.out.println("class5->" + class5.getName());
}
}
运行结果:

class1->int
class2->java.lang.String
class3->double
class4->java.lang.Double
class5->void

 
   
// 只打印简单名称(不包含包名称)
System.out.println("class2->" + class2.getSimpleName()); // String

 
   
/**
* 打印类成员方法信息(public函数,包括父类继承而来的)
* @param object
*/
public static void PrintClassPublicFunction(Object object){
// 获取类的信息,首先获取类的类类型
// 传递的是哪个子类的对象 c 就是该子类的类类型
Class c = object.getClass();
System.out.println("类的全称是:" + c.getName());
// 一个成员方法就是一个method对象
// getMethods方法是获取的是所有public的函数,包括父类继承而来的
Method[] methods = c.getMethods();
for (Method method : methods) {
// 获取方法返回值类型的类类型
Class returnType = method.getReturnType();
System.out.print(returnType.getName() + " ");
// 获取方法的名称
System.out.print(method.getName() + "(");
// 获取方法参数
// 得到方法参数列表中类型的类类型
Class[] paramTypes = method.getParameterTypes();
int size = paramTypes.length;
for (int i = 0;i < size;++i) {
if(i != 0){
System.out.print(",");
}//if
System.out.print(paramTypes[i].getName());
}//for
System.out.println(")");
}//for
}
运行结果:
boolean startsWith(java.lang.String)
boolean startsWith(java.lang.String,int)
java.lang.CharSequence subSequence(int,int)
java.lang.String substring(int,int)
java.lang.String substring(int)
[C toCharArray()
java.lang.String toLowerCase(java.util.Locale)
java.lang.String toLowerCase()
java.lang.String toUpperCase()
java.lang.String valueOf([C)
java.lang.Class getClass()
void notify()
void notifyAll()
void wait(long)
void wait(long,int)
void wait()
....

3.2 获取成员变量信息

 
   
/**
* 打印类成员变量信息
* @param object
*/
public static void PrintClassFiled(Object object){
// 获取类的信息,首先获取类的类类型
// 传递的是哪个子类的对象 c 就是该子类的类类型
Class c = object.getClass();
/* 成员变量也是对象,java.lang.reflect.Field 类封装了关于成员变量的操作
* getFields()方法获取的是所有的public的成员变量的信息
* getDeclaredFields()获取的是该类自己声明的成员变量的信息
*/
Field[] fields = c.getDeclaredFields();
for (Field field : fields) {
// 得到成员变量的类型的类类型
Class fieldType = field.getType();
// 得到成员变量的类型
System.out.print(fieldType.getName() + " ");
// 得到成员变量的名称
System.out.println(field.getName());
}//for
}
运行结果:

int MIN_VALUE
int MAX_VALUE
java.lang.Class TYPE
[C digits
[C DigitTens
[C DigitOnes
[I sizeTable
int value
int SIZE
long serialVersionUID
boolean $assertionsDisabled

3.3 获取构造函数信息

 
   
/**
* 打印类构造函数信息
* @param object
*/
public static void PrintClassConstructor(Object object){
// 获取类的信息,首先获取类的类类型
// 传递的是哪个子类的对象 c 就是该子类的类类型
Class c = object.getClass();
/* 构造函数也是对象,java.lang.reflect.Constructor 类封装了关于构造函数的操作
* getConstructors()方法获取的是所有的public的构造函数的信息
* getDeclaredConstructors()获取的是该类自己声明的构造函数的信息
*/
Constructor[] constructors = c.getConstructors();
for (Constructor constructor : constructors) {
// 构造函数的名称
System.out.print(constructor.getName() + "(");
// 获取构造函数的参数列表,得到的是参数列表的类类型
Class[] paramTypes = constructor.getParameterTypes();
int size = paramTypes.length;
for(int i = 0;i < size;++i){
if(i != 0){
System.out.print(",");
}//if
// 得到参数名称
System.out.print(paramTypes[i].getName());
}//for
System.out.println(")");
}//for
}
运行结果:

java.lang.String([B)
java.lang.String([B,int,int)
java.lang.String([B,java.nio.charset.Charset)
java.lang.String([B,java.lang.String)
java.lang.String([B,int,int,java.nio.charset.Charset)
java.lang.String(java.lang.StringBuilder)
java.lang.String(java.lang.StringBuffer)
java.lang.String([I,int,int)
java.lang.String([C,int,int)
java.lang.String([C)
java.lang.String(java.lang.String)
java.lang.String()
java.lang.String([B,int,int,java.lang.String)
java.lang.String([B,int)
java.lang.String([B,int,int,int)

3.4 方法的反射

如何获取某个方法?方法的名称和方法的参数列表才能唯一决定某个方法。
如何进行操作?通过method.invoke(对象,参数列表)

 
   
package com.qunar.reflect;
 
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
 
import com.qunar.bean.Calculates;
 
 
public class ReflectDemo {
 
public static void main(String[] args) {
// 获取类的信息,首先获取类的类类型
Calculates calculates = new Calculates();
calculates.setNum1(20);
calculates.setNum2(40);
Class c = calculates.getClass();
/* getMethod()方法获取的是public的方法信息
* getDeclaredMethod()获取的是该类自己声明的方法的信息
*/
try {
// 获取方法 名称和参数列表共同决定
// Method method = c.getDeclaredMethod("add", new Class[]{int.class,int.class});
Method method = c.getDeclaredMethod("add", int.class,int.class);
// 方法的反射
// 对于calculates.add(10,40)来说,方法的反射操作是用method方法调用 和 calculates.add(10,40)的效果一样
// int result = (int)method.invoke(calculates, new Object[]{10,40});
int result = (int)method.invoke(calculates, 10,40);
System.out.println(result);
// 对于没有参数的方法
Method method2 = c.getDeclaredMethod("print");
method2.invoke(calculates);
} catch (NoSuchMethodException e) {
e.printStackTrace();
} catch (SecurityException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (IllegalArgumentException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}
}
}






相关文章:

  • MDEV Primer
  • 闹心的变量
  • [转载]项目风险管理七种武器-碧玉刀
  • 会声会影简易相册制作教程
  • Spark学习之基于MLlib的机器学习
  • zabbix在centos6下的编译安装
  • C语言 百炼成钢1
  • 【Linux】环境变量设置
  • Apache安装教程
  • 数众数
  • Struts的属性驱动和模型驱动
  • 基于OpenResty的Lua Web框架lor0.0.2预览版发布
  • RHCA CL220实战系列(一)之KVM部署CloudForms
  • C 指针函数
  • 使用visualvm的插件btrace的一个例子
  • 时间复杂度分析经典问题——最大子序列和
  • 《剑指offer》分解让复杂问题更简单
  • 3.7、@ResponseBody 和 @RestController
  • Babel配置的不完全指南
  • Docker容器管理
  • golang中接口赋值与方法集
  • java概述
  • Java精华积累:初学者都应该搞懂的问题
  • mysql中InnoDB引擎中页的概念
  • Python打包系统简单入门
  • Ruby 2.x 源代码分析:扩展 概述
  • Service Worker
  • Sublime text 3 3103 注册码
  • thinkphp5.1 easywechat4 微信第三方开放平台
  • TypeScript实现数据结构(一)栈,队列,链表
  • 阿里云Kubernetes容器服务上体验Knative
  • 使用 Xcode 的 Target 区分开发和生产环境
  • 通信类
  • 线性表及其算法(java实现)
  • 译自由幺半群
  • 掌握面试——弹出框的实现(一道题中包含布局/js设计模式)
  • 2017年360最后一道编程题
  • 3月7日云栖精选夜读 | RSA 2019安全大会:企业资产管理成行业新风向标,云上安全占绝对优势 ...
  • 7行Python代码的人脸识别
  • 我们雇佣了一只大猴子...
  • ​ssh-keyscan命令--Linux命令应用大词典729个命令解读
  • # 学号 2017-2018-20172309 《程序设计与数据结构》实验三报告
  • ###C语言程序设计-----C语言学习(6)#
  • #LLM入门|Prompt#2.3_对查询任务进行分类|意图分析_Classification
  • (4)logging(日志模块)
  • (4)STL算法之比较
  • (html转换)StringEscapeUtils类的转义与反转义方法
  • (WSI分类)WSI分类文献小综述 2024
  • (附源码)ssm本科教学合格评估管理系统 毕业设计 180916
  • (四)【Jmeter】 JMeter的界面布局与组件概述
  • (原創) 如何安裝Linux版本的Quartus II? (SOC) (Quartus II) (Linux) (RedHat) (VirtualBox)
  • (轉貼) UML中文FAQ (OO) (UML)
  • .NET Core Web APi类库如何内嵌运行?
  • .Net IE10 _doPostBack 未定义
  • .NET/C# 利用 Walterlv.WeakEvents 高性能地定义和使用弱事件