Java 反射机制详解(下)
三、怎么使用反射
想要使用反射机制,就必须要先获取到该类的字节码文件对象(.class),通过字节码文件对象,就能够通过该类中的方法获取到我们想要的所有信息(方法,属性,类名,父类名,实现的所有接口等等),每一个类对应着一个字节码文件也就对应着一个Class类型的对象,也就是字节码文件对象。
获取字节码文件对象的三种方式。
1、Class class1= Class.forName("全限定类名"); //通过Class类中的静态方法forName,直接获取到一个类的字节码文件对象,此时该类还是源文件阶段,并没有变为字节码文件。
2、Class class2= User.class; //当类被加载成.class文件时,此时Person类变成了.class,在获取该字节码文件对象,也就是获取自己, 该类处于字节码阶段。
3、Class class3= user.getClass(); //通过类的实例获取该类的字节码文件对象,该类处于创建对象阶段。
代码实例:
//User类还没有加载,在源文件阶段 获取其字节码文件对象
Class class1 =Class.forName("com.reflect.test.User");
System.out.println("第一种:"+class1.getName());
//可以根据 实例对象获取我们想要的信息
Class class2 = User.class;
System.out.println("第二种:"+class2.getName()); User user = new User();
Class class3 = user.getClass();
System.out.println("第三种:"+class3.getName());
} 输出:
第一种:com.reflect.test.User
第二种:com.reflect.test.User
第三种:com.reflect.test.User
获取字节码文件对象
有了字节码文件对象才能获得类中所有的信息,我们在使用反射获取信息时,也要考虑使用上面哪种方式获取字节码对象合理,视不同情况而定。下面介绍Class类的功能。
首先生成一个User类对象
package com.reflect.test;
public class User {
private String name ;
private int age;
private String sex;
public User() {
}
public User(String name, int age, String sex) {
this.name = name;
this.age = age;
this.sex = sex;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public String getSex() {
return sex;
}
public void setSex(String sex) {
this.sex = sex;
}
@Override
public String toString() {
return "User{" +
"name='" + name + '\'' +
", age=" + age +
", sex='" + sex + '\'' +
'}';
}
}
User.java
3.1 通过字节码对象创建实例对象
public static void main(String[] args) throws ClassNotFoundException,InstantiationException,IllegalAccessException{
//User类还没有加载,在源文件阶段 获取其字节码文件对象
Class classz =Class.forName("com.reflect.test"); //forname 里面的参数完整文件路径,如果查不到改路径下的文件 会报 classNotFound异常
//创建实例,
User user = (User) classz.newInstance();
//可以根据 实例对象获取我们想要的信息
}
3.2获取指定构造器方法。constructor对象
知道对象构造函数的参数情况下,可以直接获取指定构造函数。
//User类还没有加载,在源文件阶段 获取其字节码文件对象
Class class1 =Class.forName("com.reflect.test.User");
//获取无参构造函数
Constructor constructor1 = class1.getConstructor();
//获取有参构造函数
Constructor constructor2 = class1.getConstructor(String.class,int.class,String.class);
User user1=(User)constructor1.newInstance();
System.out.println("user1: " + user1);
User user2 = (User) constructor2.newInstance("张三",23,"男");
System.out.println("user1: "+ user2); 输出:
user1: User{name='null', age=0, sex='null'}
user1: User{name='张三', age=23, sex='男'}
如果不知道 User类有哪些构造方法,以及参数,可以这样获取全部构造方法
//User类还没有加载,在源文件阶段 获取其字节码文件对象
Class class1 =Class.forName("com.reflect.test.User");
//获取所有构造方法
Constructor[] constructors = class1.getConstructors();
//遍历所有构造方法
int index = 0;
for(Constructor constructor : constructors){
Class[] parameterTypes = constructor.getParameterTypes();
index =index+1;
System.out.println("第" + index +"个构造函数");
for (Class parameterType : parameterTypes){
//获取构造函数中的参数类型
System.out.print(parameterType.getName()+",");
}
输出:
第1个构造函数
第2个构造函数
java.lang.String,int,java.lang.String,
3.2获取成员变量并使用。Field对象
获取指定成员变量
//User类还没有加载,在源文件阶段 获取其字节码文件对象
Class class1 =Class.forName("com.reflect.test.User");
//获取实例对象
User user = (User) class1.newInstance();
//获取成员变量class1.getField(name); 通过name获取指定变量
// 如果变量属性是私有的 那么应该使用class1.getDeclaredField(name);
Field field = class1.getDeclaredField("name");
//因为属性是私有的,获得对象属性后,还要打开其私有权限
field.setAccessible(true); // 这里也变相的破解了 面向对象的封装性
//对其变量进行操作
field.set(user,"张三");
//
System.out.println(field.get(user));
System.out.println(user.getName());
输出:
张三
张三
Class.getField(String)方法可以获取类中的指定字段(可见的), 如果是私有的可以用getDeclaedField("name")方法获取,通过set(obj, "李四")方法可以设置指定对象上该字段的值, 如果是私有的需要先调用setAccessible(true)设置访问权限,用获取的指定的字段调用get(obj)可以获取指定对象中该字段的值
获取全部属性 变量
//User类还没有加载,在源文件阶段 获取其字节码文件对象
Class class1 =Class.forName("com.reflect.test.User");
//获取实例对象
User user = (User) class1.newInstance();
user.setName("zhangsan");
user.setAge(23);
user.setSex("男");
//获取全部成员变量
Field[] fields = class1.getDeclaredFields(); for ( Field field : fields){
field.setAccessible(true);
System.out.println(field.get(user));
}
输出:
zhangsan
23
男
3.3 获得成员方法并使用。Method对象
//User类还没有加载,在源文件阶段 获取其字节码文件对象
Class class1 =Class.forName("com.reflect.test.User");
//获取实例对象
User user = (User) class1.newInstance();
user.setAge(23);
user.setSex("男");
/**
* Method getMethod(String name, Class<?>... parameterTypes)
* name : 为方法名字
* parameterTypes:方法的参数,为class类型,比如参数类型为String,则填string.class
* 没有则不填
*/
/**
* Object invoke(Object obj, Object... args)
* obj:方法的对象
* args:实际的参数值,没有则不填
*/
Method method1 = class1.getMethod("getAge");
System.out.println("method1 方法:" +method1.getName());
System.out.println("调用方法 : "+method1.invoke(user));
Method method2 = class1.getMethod("getSex");
System.out.println("method2 方法:" +method2.getName());
System.out.println("调用方法 : "+method2.invoke(user));
//我们将 User 类的setName()方法 改为私有的private void setName(String name) {this.name = name; } Method method3 = class1.getDeclaredMethod("setName", String.class);
method3.setAccessible(true);
method3.invoke(user,"zhangsan"); //可以调用 user对象的 私有方法setName
System.out.println("user.getName :" + user.getName()); // 获取 name属性值 输出:
method1 方法:getAge
调用方法 : 23
method2 方法:getSex
调用方法 : 男
user.getName :zhangsan
Class.getMethod(String, Class...) 和 Class.getDeclaredMethod(String, Class...)方法可以获取类中的指定方法,
如果为私有方法,则需要打开一个权限。setAccessible(true);
用invoke(Object, Object...)可以调用该方法,
同理可以 获取全部方法
//User类还没有加载,在源文件阶段 获取其字节码文件对象
Class class1 =Class.forName("com.reflect.test.User");
//获取实例对象
User user = (User) class1.newInstance();
user.setAge(23);
user.setSex("男"); Method [] methods = class1.getDeclaredMethods();
for (Method method : methods){
method.setAccessible(true);
System.out.println("方法名:"+method.getName());//获取 方法名
Class [] parameterTypes = method.getParameterTypes();//这里又回到了上面的获取参数代码
for (Class parameterType : parameterTypes){
System.out.println("获取参数名:"+parameterType.getName());
} }
输出:
方法名:toString
方法名:getName
方法名:setName
获取参数名:java.lang.String
方法名:getSex
方法名:getAge
方法名:setSex
获取参数名:java.lang.String
方法名:setAge
获取参数名:int
3.4 获得该类的所有接口
Class[] getInterfaces():确定此对象所表示的类或接口实现的接口
返回值:接口的字节码文件对象的数组
Java 反射机制详解(下)的更多相关文章
- Java 反射机制详解(上)
一.什么是反射 JAVA反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法:对于任意一个对象,都能够调用它的任意方法和属性:这种动态获取信息以及动态调用对象方法的功能称为java ...
- Java反射机制详解
Java反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法:对于任意一个对象,都能够调用它的任意一个方法和属性:这种动态获取的信息以及动态调用对象的方法的功能称为Java语言的反 ...
- Java反射机制详解(3) -java的反射和代理实现IOC模式 模拟spring
IOC(Inverse of Control) 可翻译为“控制反转”,但大多数人都习惯将它称为“依赖注入”.在Spring中,通过IOC可以将实现类.参数信息等配置在其对应的配置文件中,那么当 需要更 ...
- Java反射机制详解(1) -反射定义
首先,我们在开始前提出一个问题: 1.在运行时,对于一个java类,能否知道属性和方法:能否去调用它的任意方法? 答案是肯定的. 本节所有目录如下: 什么是JAVA的反射机制 JDK中提供的Refle ...
- [转]Java反射机制详解
目录 1反射机制是什么 2反射机制能做什么 3反射机制的相关API ·通过一个对象获得完整的包名和类名 ·实例化Class类对象 ·获取一个对象的父类与实现的接口 ·获取某个类中的全部构造函数 - 详 ...
- 【转载】Java反射机制详解
转自:http://baike.xsoftlab.net/view/209.html#3_8 1反射机制是什么 反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法:对于任意一个对 ...
- java反射机制详解 及 Method.invoke解释
JAVA反射机制 JAVA反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法:对于任意一个对象,都能够调用它的任意一个方法:这种动态获取的信息以及动态调用对象的方法的功能称为ja ...
- Java 反射机制详解
动态语言 动态语言,是指程序在运行时可以改变其结构:新的函数可以被引进,已有的函数可以被删除等在结构上的变化.比如众所周知的ECMAScript(JavaScript)便是一个动态语言.除此之外如Ru ...
- java异常处理机制详解
java异常处理机制详解 程序很难做到完美,不免有各种各样的异常.比如程序本身有bug,比如程序打印时打印机没有纸了,比如内存不足.为了解决这些异常,我们需要知道异常发生的原因.对于一些常见的异常,我 ...
随机推荐
- Network Booting
http://en.wikipedia.org/wiki/Network_booting Network booting Network booting is the process of booti ...
- 技术发展晴雨表 细数CPU接口10年变迁
http://cpu.zol.com.cn/160/1602240_all.html#p1602240 本文导航 第1页:10年磨10剑 CPU发展突飞猛进 第2页:462与423对垒 开启CPU竞争 ...
- uva 1567 - A simple stone game(K倍动态减法游戏)
option=com_onlinejudge&Itemid=8&page=show_problem&problem=4342">题目链接:uva 1567 - ...
- Linux安装程序Anaconda分析(续)
本来想写篇关于Anaconda的文章,但看到这里写的这么详细,转,原文在这里:Linux安装程序Anaconda分析(续) (1) disptach.py: 下面我们看一下Dispatcher类的主要 ...
- UnsatisfiedLinkError: No implementation found for , AndroidStudio使用*.so
今天工作的时候.发现了一个jni的问题,java.lang.UnsatisfiedLinkError: No implementation found for...... 问题1:后来查了资料后发现. ...
- iOS开发——高级篇——多线程的安全隐患
资源共享 1块资源可能会被多个线程共享,也就是多个线程可能会访问同一块资源 比如多个线程访问同一个对象.同一个变量.同一个文件 当多个线程访问同一块资源时,很容易引发数据错乱和数据安全问题 一.解 ...
- 初学unity 3D 遇到的一个问题--预制体选项没有找到。
没有找到预制体这个选项. 我的工程如下:
- 例子:两个表根据productID合并
- BZOJ2163: 复杂的大门
BZOJ2163: 复杂的大门 Description 你去找某bm玩,到了门口才发现要打开他家的大门不是一件容易的事……他家的大门外有n个站台,用1到n的正整数编号.你需要对每个站台访问一定次数以后 ...
- linux下自动创建设备文件节点---class
在驱动模块初始化函数中实现设备节点的自动创建 我们在刚开始写Linux设备驱动程序的时候,很多时候都是利用mknod命令手动创建设备节点,实际上Linux内核为我们提供了一组函数,可以用来在模块加载的 ...