1.介绍

反射为Java程序在执行时提供了动态的能力。利用反射能够在执行时对程序进行动态的控制。本篇博客着重解说一下Java中的反射。

2.Class类的使用

在Java执行过程中,每一个类被载入后都会在内存中产生一个相应的Class类对象,因此通过Class类的对象就能够拿到有关类的相关信息。

以下演示一个实例。

<span style="font-family:SimSun;font-size:18px;">package com.Reflect;

//用来被载入类的父类
class MyFather
{
//父类的公共成员变量
public int memberFather;
//父类的公共方法
public void methodFather()
{
System.out.println("我是从父类继承而来的方法methodFather。!!");
}
}
//用来被载入的类
class MySon extends MyFather
{ //子类的公共成员变量
public int memberSonPublic;
//子类的私有成员变量
private int memberSonPrivate;
//子类的公共方法
public void methodSonPublic()
{ System.out.println("我是子类自己的方法methodSonPublic!! !");
}
//子类的保护方法
protected void methodSonProtected()
{
System.out.println("我是子类自己的方法methodSonProtected! !!");
}
}
//主类
public class Sample34_1
{
public static void main(String args[])
{
try
{
//载入指定的类
Class c=Class.forName("com.Reflect.MySon");
//创建载入类的对象
MySon ms=(MySon)c.newInstance();
System.out.println(ms.getClass());
//调用创建对象的方法
System.out.println("===============调用创建对象的方法===================");
ms.methodSonProtected();
ms.methodSonPublic();
ms.methodFather();
//打印载入类的具体信息
System.out.println("==================载入类的信息======================");
System.out.println(c.getName()+"类自己声明了"
+c.getDeclaredFields().length+"个成员变量。 ");
System.out.println(c.getName()+"类对外发布的方法有"
+c.getMethods().length+"个。");
}
catch(Exception e)
{
e.printStackTrace();
}
}
}
</span>

上面的实例通过Class对象的ForName方法载入对应的class对象,并通过Class对象的newInstance方法创建了其对象,紧接着调用了对象中的方法,接着打印了载入类的一些信息。

3.Field类的使用

Field类的对象代表成员变量,携带成员变量的信息。注意的是与Class类类似,不能够通过构造器创建Field类的对象,对象都是通过Class类对象提供的get系列方法创建出来的。

<span style="font-family:SimSun;font-size:18px;">package com.Reflect;

import java.util.*;
import java.lang.reflect.*;
//自己定义用来測试的类
class Student
{
public int sage;//年龄
private int sno;//学号
public boolean gender;//性别 true-男 false-女
public String sname;//姓名
//构造器
public Student(int sage,int sno,boolean gender,String sname)
{ this.sage=sage;
this.sno=sno;
this.gender=gender;
this.sname=sname;
}
}
//主类
public class Sample34_4
{
public static void main(String args[])
{
try
{
//创建Student类对象
Student tom=new Student(21,10001,true,"Tom");
//获取Student类相应的Class对象
Class dc=tom.getClass();
//获取Student类全部能够訪问的成员变量相应的Field数组
Field[] fieldArray=dc.getFields();
//打印Student类对象各成员变量的具体信息
System.out.println("成员变量名\t成员变量类型\t\t成员变量值");
int size=fieldArray.length;
//循环处理Field数组
for(int i=0;i<size;i++)
{
Field tempf=fieldArray[i];
//打印成员变量名称
System.out.print(tempf.getName()+"\t\t");
//打印成员变量类型
System.out.print(tempf.getType().toString()
+((tempf.getType().toString().length()>7)? "\t":"\t\t\t"));
//打印成员变量值
System.out.println(tempf.get(tom));
}
}
catch(Exception e)
{
e.printStackTrace();
}
}
}
</span>

上述实例中。首先定义了Strudent类的对象,然后通过Student类相应的Class对象获取能够訪问的成员变量的Field数组。紧接着就是调用Field类的方法,对成员变量的信息进行打印操作

4.Method类的使用

Method类的对象代表一个方法,携带方法有关的信息。该对象仅仅能通过Class类对象的get方法进行得到

<span style="font-family:SimSun;font-size:18px;">package com.Reflect;

import java.util.*;
import java.lang.reflect.*;
//自己定义用来測试的类
class ForMethod
{
//声明静态方法sayHello,功能为在屏幕上打印字符串
public static void sayHello(String name)
{
System.out.println("你好。"+name+"!!!");
}
//声明非静态方法generateNum,功能为产生min与max之间的随机数
public String generateNum(int max,int min)
{
return (Math.random()*(max-min)+min)+"";
}
}
//主类
public class Sample34_5
{
public static void main(String args[])
{
try
{
//创建ForMethod类对象
ForMethod fm=new ForMethod();
//获取ForMethod类相应的Class对象
Class fmc=fm.getClass();
//获取能够訪问的方法相应的Method数组
Method[] ma=fmc.getMethods();
//对数组进行扫描打印方法的信息
System.out.println("方法名称\t返回值类型\t\t參数列表");
int size=ma.length;
for(int i=0;i<size;i++)
{
Method tempm=ma[i];
//打印方法名称
String mname=tempm.getName();
System.out.print(mname+((mname.length()>7)?"\t":"\t\t"));
//打印方法的返回值类型
String mReturnType=tempm.getReturnType().getName();
System.out.print(mReturnType+((mReturnType.length()>15)?"\t":
(mReturnType.length()>10)? "\t\t":"\t\t\t"));
//循环打印方法的參数序列
Class[] ca=tempm.getParameterTypes();
int csize=ca.length;
if(csize==0)
{
System.out.print("没有參数");
}
for(int j=0;j<csize;j++)
{
System.out.print(ca[j].getName()+((j==csize-1)?"":", "));
}
//换行
System.out.println();
}
//通过反射调用静态方法sayHello
System.out.println("==========通过反射调用静态方法sayHello===========");
ma[0].invoke(null,new Object[]{"王强"});
//通过反射调用非静态方法generateNum
System.out.println("========通过反射调用非静态方法generateNum========");
System.out.println(ma[1].invoke(fm,
new Object[]{new Integer(100),new Integer(1000)}));
}
catch(Exception e)
{
e.printStackTrace();
}
}
}
</span>

该实例中首先创建了ForMethod类的对象。然后通过反射打印了Formethod类的全部能够訪问到的方法,最后通过反射调用了ForMethod类中声明的两个方法

5.Constructor类的使用

Constructor类代表一个构造器。携带有关构造器的相关信息,也是仅仅能通过Class类对象的get系列方法获得。

<span style="font-family:SimSun;font-size:18px;">package com.Reflect;

import java.util.*;
import java.lang.reflect.*;
//自己定义用来測试的类
class Student1
{
String sname;//姓名
int sage;//年龄
//声明无參构造器
public Student1()
{
sname="Tom";
sage=23;
}
//声明有參构造器
public Student1(String sname,int sage)
{
this.sname=sname;
this.sage=sage;
}
//声明一个普通方法
public void sayHello()
{
System.out.println("您好,我是"+sname+",今年"+sage+"岁!!!");
}
}
//主类
public class Sample34_6
{
public static void main(String args[])
{
try
{
//获取Student类相应的Class对象
Class sc=Student1.class;
//获取能够訪问的构造器相应的Constructor数组
Constructor[] ca=sc.getConstructors();
//对数组进行扫描打印构造器的信息
System.out.println("构造器名称\t\t參数列表");
int size=ca.length;
for(int i=0;i<size;i++)
{
Constructor tempc=ca[i];
//打印构造器名称
String cname=tempc.getName();
System.out.print(cname+"\t\t");
//循环打印构造器的參数序列
Class[] pa=tempc.getParameterTypes();
int psize=pa.length;
if(psize==0)
{
System.out.print("没有參数");
}
for(int j=0;j<psize;j++)
{
System.out.print(pa[j].getName()+((j==psize-1)?"":", "));
}
//换行
System.out.println();
} //使用反射调用有參构造器创建对象
Student1 stu=(Student1)ca[0].newInstance(new Object[0]);
//调用创建对象的sayHello方法
stu.sayHello();
//使用反射调用有參构造器创建对象
stu=(Student1)ca[1].newInstance(new Object[]{"王强",new Integer(25)});
//调用创建对象的sayHello方法
stu.sayHello();
}
catch(Exception e)
{
e.printStackTrace();
}
}
}
</span>

上述实例中,首先获得了Student类相应的Class对象,紧接着打印了全部Student类能够訪问的构造器的信息,最后通过反射调用了Student类的构造器创建了两个对象并调用了SayHello方法。

6.取消訪问限制

当用Class对象的getDeclaredXXXs方法获得Field、Method或Constructor时,因为訪问修饰符的限制,可能有些字段、方法或者构造器訪问不到。假设要訪问的话,须要先解除限制,然后再訪问

若希望解除限制,须要使用java.lang.reflect.AccessibleObject类。

<span style="font-family:SimSun;font-size:18px;">package com.Reflect;

import java.lang.reflect.*;
//自己定义用来測试的类
class Employee1
{
private String sname;//员工姓名
//私有方法
private void sayHello()
{
System.out.println("您好,我是"+sname
+",恭喜您成功訪问了private的方法sayHello!!!");
}
}
//主类
public class Sample34_8
{
public static void main(String args[])
{
try
{
//创建Employee对象
Employee1 tom=new Employee1();
//获取Employee类相应的Class对象
Class ec=tom.getClass();
//获取Employee类声明的成员变量相应的Field数组
Field[] fa=ec.getDeclaredFields();
//设置sname成员变量的訪问限制为同意
fa[0].setAccessible(true);
//设置sname成员变量的值
fa[0].set(tom,"Tom");
//获取Employee类声明的方法相应的Method数组
Method[] ma=ec.getDeclaredMethods();
//设置全部方法的訪问限制为同意
//ma[0].setAccessible(true);
AccessibleObject.setAccessible(ma,true);
//调用sayHello方法
ma[0].invoke(tom,new Object[0]);
}
catch(Exception e)
{
e.printStackTrace();
}
}
}
</span>

上述实例就是通过解除訪问修饰符的限制来訪问到私有变量。

Java学习笔记八(反射)的更多相关文章

  1. java学习笔记:反射

    1.什么是反射? Reflection(反射)是被视为动态语言的关键,反射机制允许程序做执行期间借助于ReflectionAPI取得任何类的内部信息,并能直接操作任意对象内部属性及方法 2.反射相关的 ...

  2. 【java学习笔记】反射基础

    一.反射 反射就是在剖析一个类,了解这个类的构造,创建这个类对应的对象. Class 代表字节码的类,代表类的类 Field 代表属性的类 Method 代表方法的类 Constructor 代表构造 ...

  3. 8.2(java学习笔记)反射

    一.基础知识 对象是表示或封装一些数据,一个类被加载后JVM会创建一个对应该类的Class对象, 类的整个结构信息会被放在对应的对象中,通过这个对象我们可以获取改类的全部信息, 而这些操作称为反射. ...

  4. Java 学习笔记(15)——反射

    Java中的类文件最终会被编译为.class 文件,也就是Java字节码.这个字节码中会存储Java 类的相关信息.在JVM执行这些代码时首先根据 java 命令中指定的类名找到.class 文件然后 ...

  5. java学习笔记之反射—Class类实例化和对象的反射实例化

    反射之中所有的核心操作都是通过Class类对象展开的,可以说Class类是反射操作的根源所在,但是这个类的实例化对象,可以采用三种方式完成. java.lang.Class类的定义: public f ...

  6. Java 学习笔记 (八) Java 变量

    head first java page85 实例变量是声明在类内而不是方法中 class Horse{ private double height=15.2; private String bree ...

  7. Java学习笔记八:Java的流程控制语句之循环语句

    Java的流程控制语句之循环语句 一:Java循环语句之while: 生活中,有些时候为了完成任务,需要重复的进行某些动作.如参加 10000 米长跑,需要绕 400 米的赛道反复的跑 25 圈.在 ...

  8. Java学习笔记八

    IO流:就是input/output输入/输出流. 一.字节流操作文件的便捷类:FileWriter和FileReader import java.io.FileWriter; import java ...

  9. java学习笔记之反射—反射和工厂模式

    简单工厂模式又称为静态工厂方法模式,它是由工厂对象来决定要创建哪一种类的实例化对象. 静态工厂代码: class Factory{ private Factory() {} public static ...

随机推荐

  1. Jenkins的安装及使用(二)

    介绍两个方面:编译本地项目和拉取git代码并编译 在这之前,先要进行一个配置. 一.编译本地项目 开始添加任务,任务类型选择自由风格: 点击项目进入详情,源码管理选择无 在构建的地方选择项目,然后注意 ...

  2. 【CTF REVERSE】WHCTF2017-CRACKME

    1.前言 假装大学生水一下CTF题目,常规思路.程序没有加壳,是VC写的MFC程序. 2.破题思路 1.MessageBox 下断点 2.找到提示错误字符串的函数B 3.跟踪函数 4.跟踪算法 3.实 ...

  3. oracle日期、转换函数

    转换函数 日期类型转换成字符类型 select to_char(sysdate) s1, --14-3月 -16        to_char(sysdate, 'yyyy-mm-dd') s2, - ...

  4. MAVEN:不能互相引用

    工程A,工程B,工程C,这三个工程:C依赖B,B依赖A,这是没有问题的. 但是不能A依赖B,B又依赖A,这是不允许的.

  5. C++字符串完全指引

    引言 毫无疑问,我们都看到过像 TCHAR, std::string, BSTR 等各种各样的字符串类型,还有那些以 _tcs 开头的奇怪的宏.你也许正在盯着显示器发愁.本指引将总结引进各种字符类型的 ...

  6. visual studio code插件精选

    HTML Snippets 超级实用且初级的 H5代码片段以及提示 HTML CSS Support 让 html 标签上写class 智能提示当前项目所支持的样式 JavaScript Atom G ...

  7. SqlServer自定义函数Function中调用with as

    SET QUOTED_IDENTIFIER ON 标识符可以由双引号分隔,而文字必须由单引号分隔 SET QUOTED_IDENTIFIER OFF 标识符不可加引号,且必须遵守所有 Transact ...

  8. Intellij IDEA调试功能总结

    public class Demo { public static void f1() { System.out.println("one"); System.out.printl ...

  9. 如何简单区分Web前后端与MVC

    MVC是开发所有软件所必须涉及的基本几个划分 M主要负责数据与模型,V主要负责显示C主要负责交互与业务所以不管是前端还是后端,都是有MVC的.MVC是一个对于软件简单的抽象,不管是M还是V,还是C都是 ...

  10. MyBatis使用示例

    下面是一个简单的MyBatis使用DEMO. 整体结构 整体代码大致如下: POM依赖 需要引用两个jar包,一个是mybatis,另一个是mysql-connector-java,如果是maven工 ...