Java学习笔记八(反射)
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学习笔记八(反射)的更多相关文章
- java学习笔记:反射
1.什么是反射? Reflection(反射)是被视为动态语言的关键,反射机制允许程序做执行期间借助于ReflectionAPI取得任何类的内部信息,并能直接操作任意对象内部属性及方法 2.反射相关的 ...
- 【java学习笔记】反射基础
一.反射 反射就是在剖析一个类,了解这个类的构造,创建这个类对应的对象. Class 代表字节码的类,代表类的类 Field 代表属性的类 Method 代表方法的类 Constructor 代表构造 ...
- 8.2(java学习笔记)反射
一.基础知识 对象是表示或封装一些数据,一个类被加载后JVM会创建一个对应该类的Class对象, 类的整个结构信息会被放在对应的对象中,通过这个对象我们可以获取改类的全部信息, 而这些操作称为反射. ...
- Java 学习笔记(15)——反射
Java中的类文件最终会被编译为.class 文件,也就是Java字节码.这个字节码中会存储Java 类的相关信息.在JVM执行这些代码时首先根据 java 命令中指定的类名找到.class 文件然后 ...
- java学习笔记之反射—Class类实例化和对象的反射实例化
反射之中所有的核心操作都是通过Class类对象展开的,可以说Class类是反射操作的根源所在,但是这个类的实例化对象,可以采用三种方式完成. java.lang.Class类的定义: public f ...
- Java 学习笔记 (八) Java 变量
head first java page85 实例变量是声明在类内而不是方法中 class Horse{ private double height=15.2; private String bree ...
- Java学习笔记八:Java的流程控制语句之循环语句
Java的流程控制语句之循环语句 一:Java循环语句之while: 生活中,有些时候为了完成任务,需要重复的进行某些动作.如参加 10000 米长跑,需要绕 400 米的赛道反复的跑 25 圈.在 ...
- Java学习笔记八
IO流:就是input/output输入/输出流. 一.字节流操作文件的便捷类:FileWriter和FileReader import java.io.FileWriter; import java ...
- java学习笔记之反射—反射和工厂模式
简单工厂模式又称为静态工厂方法模式,它是由工厂对象来决定要创建哪一种类的实例化对象. 静态工厂代码: class Factory{ private Factory() {} public static ...
随机推荐
- Jenkins的安装及使用(二)
介绍两个方面:编译本地项目和拉取git代码并编译 在这之前,先要进行一个配置. 一.编译本地项目 开始添加任务,任务类型选择自由风格: 点击项目进入详情,源码管理选择无 在构建的地方选择项目,然后注意 ...
- 【CTF REVERSE】WHCTF2017-CRACKME
1.前言 假装大学生水一下CTF题目,常规思路.程序没有加壳,是VC写的MFC程序. 2.破题思路 1.MessageBox 下断点 2.找到提示错误字符串的函数B 3.跟踪函数 4.跟踪算法 3.实 ...
- oracle日期、转换函数
转换函数 日期类型转换成字符类型 select to_char(sysdate) s1, --14-3月 -16 to_char(sysdate, 'yyyy-mm-dd') s2, - ...
- MAVEN:不能互相引用
工程A,工程B,工程C,这三个工程:C依赖B,B依赖A,这是没有问题的. 但是不能A依赖B,B又依赖A,这是不允许的.
- C++字符串完全指引
引言 毫无疑问,我们都看到过像 TCHAR, std::string, BSTR 等各种各样的字符串类型,还有那些以 _tcs 开头的奇怪的宏.你也许正在盯着显示器发愁.本指引将总结引进各种字符类型的 ...
- visual studio code插件精选
HTML Snippets 超级实用且初级的 H5代码片段以及提示 HTML CSS Support 让 html 标签上写class 智能提示当前项目所支持的样式 JavaScript Atom G ...
- SqlServer自定义函数Function中调用with as
SET QUOTED_IDENTIFIER ON 标识符可以由双引号分隔,而文字必须由单引号分隔 SET QUOTED_IDENTIFIER OFF 标识符不可加引号,且必须遵守所有 Transact ...
- Intellij IDEA调试功能总结
public class Demo { public static void f1() { System.out.println("one"); System.out.printl ...
- 如何简单区分Web前后端与MVC
MVC是开发所有软件所必须涉及的基本几个划分 M主要负责数据与模型,V主要负责显示C主要负责交互与业务所以不管是前端还是后端,都是有MVC的.MVC是一个对于软件简单的抽象,不管是M还是V,还是C都是 ...
- MyBatis使用示例
下面是一个简单的MyBatis使用DEMO. 整体结构 整体代码大致如下: POM依赖 需要引用两个jar包,一个是mybatis,另一个是mysql-connector-java,如果是maven工 ...