zoukankan      html  css  js  c++  java
  • 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("成员变量名	成员变量类型		成员变量值");
    	        int size=fieldArray.length;
    	        //循环处理Field数组
    	        for(int i=0;i<size;i++)
    	        {
    	        	Field tempf=fieldArray[i];
    	        	//打印成员变量名称
    	        	System.out.print(tempf.getName()+"		");
    	        	//打印成员变量类型
    	        	System.out.print(tempf.getType().toString()
    	        	+((tempf.getType().toString().length()>7)?

    " ":" ")); //打印成员变量值 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("方法名称	返回值类型		參数列表");
    	        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)?"	":"		"));
    	        	//打印方法的返回值类型
    	        	String mReturnType=tempm.getReturnType().getName();
    	        	System.out.print(mReturnType+((mReturnType.length()>15)?"	":
    	        	                    (mReturnType.length()>10)?

    " ":" ")); //循环打印方法的參数序列 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("构造器名称		參数列表");
    	        int size=ca.length;
    	        for(int i=0;i<size;i++)
    	        {
    	        	Constructor tempc=ca[i];
    	        	//打印构造器名称
    	        	String cname=tempc.getName();
    	        	System.out.print(cname+"		");
    	        	//循环打印构造器的參数序列
    	        	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>

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



  • 相关阅读:
    hmac
    struct模块-黏包的解决方法
    PHPCMS快速建站系列
    Notepad++搜索中的正则应用
    用var 变量=函数名 方式调用函数时如何传值的问题
    ThInkPHP中的常量
    css cursor 的可选值(鼠标的各种样式)
    JS实现用键盘控制DIV上下左右+放大缩小与变色
    PHP定义数组常量
    FormData实现文件上传实例
  • 原文地址:https://www.cnblogs.com/bhlsheji/p/5395765.html
Copyright © 2011-2022 走看看