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. 服务器环境配置安装(mysql+redis+nodejs+nginx)

    公司用来测试的服务器挂了,最后重装了系统,需要重新配置程序运行环境,linux上安装不是很熟悉,特此记录一下. 首先获取系统版本信息: 参考:获取Linux系统版本信息 一.mysql 1. 安装 安 ...

  2. [Alg::DP] Square Subsequence

    题目如下: #include <iostream> #include <string> #include <vector> using namespace std; ...

  3. 使用/dev/uinput的简要介绍(含demo程序)【转】

    转自:https://blog.csdn.net/zhongkunjia/article/details/75142699 uinput机制有2个很大的优点: 1) 不用自己写驱动(比如弄个红外遥控器 ...

  4. docker stack 部署nginx

    =============================================== 2018/7/29_第1次修改                       ccb_warlock == ...

  5. jenkins 使用Git持续构建

    为jenkins添加git插件. 在Available tab页中找到Git Plugin 点击下方的Install without Restart安装插件. 插件安装完毕后,我们需要在jenkins ...

  6. KNN算法的感受 2

    (1):先将上述代码保存为kNN.py (2):再在IDLE下的run菜单下run一下,将其生成python模块 (3):import  kNN(因为上一步已经生成knn模块) (4):kNN.cla ...

  7. java 异常 throw

    throw UnsupportedOperationException(); //没有支持的操作NoSuchElementException(); //没有这样的元素

  8. IE下css bug集合-翻译自haslayout.net

    概述IE浏览器以不支持大量的css 属性出名,同时也因其支持的css属性中存在大量bug. 本页列举了IE下的一些问题,实例样本和一些我们已知的解决方法. 尽管我已经尽力按照它们本来的性质对它们进行分 ...

  9. Vue.Js的用户体验优化

    一次基于Vue.Js的用户体验优化   一.写在前面 半年以前,第一次在项目上实践VueJs,由于在那之前,没有Angular,avalon等框架的实践经验,所以在Vue的使用上,没有给自己总结出更多 ...

  10. bzoj 1178 [Apio2009]CONVENTION会议中心

    这题好难啊! 我好菜啊! 思路:对于最多线段不相交, 我们可以按左端点sort之后,贪心取. 但是这个题要求选取的线段排序之后序号的字典序最小. 那么我们如果按序号贪心地从大往小往里放, 那么对于第k ...