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 ...
随机推荐
- 前端学PHP之正则表达式函数
前面的话 正则表达式不能独立使用,它只是一种用来定义字符串的规则模式,必须在相应的正则表达式函数中应用,才能实现对字符串的匹配.查找.替换及分割等操作.前面介绍了正则表达式的基础语法,本文将详细介绍正 ...
- python垃圾回收三之标记清除
#第一组循环引用# a = [1,2] b = [3,4] a.append(b) b.append(a) del a ## #第二组循环引用# c = [4,5] d = [5,6] c.appen ...
- GDB命令
recursiveDescription 打印view层次结构
- gitminer
https://github.com/UnkL4b/GitMiner + Autor: UnK + Blog: https://unkl4b.github.io + Github: https://g ...
- 【Python】HackBack(获取暴力破解服务器密码的IP来源)
1.前言 又在0x00sec上翻到好东东. https://0x00sec.org/t/python-hackback-updated/882 帖子里的脚本会得到那些暴力服务器密码失败的IP和用户名, ...
- eclipse安装阿里巴巴java开发规范插件
阿里巴巴java开发规范插件 作为JAVA开发人员,始终没有一个明确的规范,何为好代码,何为坏代码,造成不同人的代码风格不同,接手别人代码后改造起来相当困难.前不久,阿里巴巴发布了<阿里巴巴Ja ...
- idea项目左边栏只能看到文件看不到项目结构
1.点击file->project structure..->Modules 点击右上角+加号 ->import Modules 2.选择你的项目,点击确定 3.在如下页面选择imp ...
- HTTPS-加密SSL证书
从第一部分HTTP工作原理中,我们可以了解到HTTPS核心的一个部分是数据传输之前的握手,握手过程中确定了数据加密的密码.在握手过程中,网站会向浏览器发送SSL证书,SSL证书和我们日常用的身份证类似 ...
- poj 2524 求连通分量(并查集模板题)
求连通分量 Sample Input 10 91 21 31 41 51 61 71 81 91 1010 42 34 54 85 80 0Sample Output Case 1: 1Case 2: ...
- K8S Dashborad登陆认证文档
K8S Dashboard是官方的一个基于WEB的用户界面,专门用来管理K8S集群,并可展示集群的状态.因为我们使用kubeadm搭建的集群会默认开启RABC(角色访问控制机制),所以我们必须要进行额 ...