续: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 反射机制详解(下)的更多相关文章

  1. Java 反射机制详解(上)

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

  2. Java反射机制详解

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

  3. Java反射机制详解(3) -java的反射和代理实现IOC模式 模拟spring

    IOC(Inverse of Control) 可翻译为“控制反转”,但大多数人都习惯将它称为“依赖注入”.在Spring中,通过IOC可以将实现类.参数信息等配置在其对应的配置文件中,那么当 需要更 ...

  4. Java反射机制详解(1) -反射定义

    首先,我们在开始前提出一个问题: 1.在运行时,对于一个java类,能否知道属性和方法:能否去调用它的任意方法? 答案是肯定的. 本节所有目录如下: 什么是JAVA的反射机制 JDK中提供的Refle ...

  5. [转]Java反射机制详解

    目录 1反射机制是什么 2反射机制能做什么 3反射机制的相关API ·通过一个对象获得完整的包名和类名 ·实例化Class类对象 ·获取一个对象的父类与实现的接口 ·获取某个类中的全部构造函数 - 详 ...

  6. 【转载】Java反射机制详解

    转自:http://baike.xsoftlab.net/view/209.html#3_8 1反射机制是什么 反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法:对于任意一个对 ...

  7. java反射机制详解 及 Method.invoke解释

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

  8. Java 反射机制详解

    动态语言 动态语言,是指程序在运行时可以改变其结构:新的函数可以被引进,已有的函数可以被删除等在结构上的变化.比如众所周知的ECMAScript(JavaScript)便是一个动态语言.除此之外如Ru ...

  9. java异常处理机制详解

    java异常处理机制详解 程序很难做到完美,不免有各种各样的异常.比如程序本身有bug,比如程序打印时打印机没有纸了,比如内存不足.为了解决这些异常,我们需要知道异常发生的原因.对于一些常见的异常,我 ...

随机推荐

  1. Erlang进程堆垃圾回收机制

    原文:Erlang进程堆垃圾回收机制 作者:http://blog.csdn.net/mycwq 每一个Erlang进程创建之后都会有自己的PCB,栈,私有堆.erlang不知道他创建的进程会用到哪种 ...

  2. 拒绝干扰 解决Wi-Fi的最大问题

    本文转载至:http://www.ciotimes.com/net/rdjs/WI-FI/201006301920.html 射频干扰英文:RFI,(Radio Frequency Interfere ...

  3. Appium,IOS 模拟器,Java工程搭建

    首先进入sample code Test App 有TestApp.xcodeproj文件的工程目录下 下编译出TestApp.app文件 1.新建 java 工程 2.import需要的包 新建cl ...

  4. bash_profile打不开怎么办,用nano .bash_profile打开

    I’ve spent years curating a collection of Mac bash aliases and shortcuts to make my life easier. My ...

  5. delphi中的HOOK [转贴]

    按事件分类,有如下的几种常用类型的钩子: 1)键盘钩子可以监视各种键盘消息. 2)鼠标钩子可以监视各种鼠标消息. 3)外壳钩子可以监视各种Shell事件消息. 4)日志钩子可以记录从系统消息队列中取出 ...

  6. SpringCloud遇到的坑

    1. 今天使用Feign 调用其他项目,结果一直跳转到断路器,跟踪发现是接口响应时间较长,解决方案 解决:# 在 Feign 模块中,单独设置这个超时时间不行,还要额外设置 Ribbon 的超时时间, ...

  7. mysql 免安装配置问题

    摘要: MySQL是一个小型关系型数据库管理系统,MySQL被广泛地应用在Internet上的中小型网站中.由于其体积小.速度快.总体拥有成本低,尤其是开放源码这一特点,许多中小型网站为了降低网站总体 ...

  8. GSON的简单示例

    https://github.com/google/gson package com.example.wolf; import com.google.gson.JsonArray; import co ...

  9. YTU 2442: C++习题 矩阵求和--重载运算符

    2442: C++习题 矩阵求和--重载运算符 时间限制: 1 Sec  内存限制: 128 MB 提交: 1457  解决: 565 题目描述 有两个矩阵a和b,均为2行3列.求两个矩阵之和.重载运 ...

  10. SPFA 最短路 带负权边的---- 粗了解

    SPFA(Shortest Path Faster Algorithm)是Bellman-Ford算法的一种队列实现,减少了不必要的冗余计算. 算法大致流程是用一个队列来进行维护. 初始时将源加入队列 ...