反射入门

java反射入门

                                                                                                      ————纸上得来终觉浅,绝知此事要躬行

引入:“万物皆对象”,任何一个事物都是一个对象,那么,类是哪个的对象呢?回答:类是Class的对象

反射简述

Class 属于java.lang包,所以在使用的时候不需要使用import引入。

另外Class中“C”是大写,小写就变成关键字了。

获得Class实例

(1)第一种  ----通过类名

Class c=<类名>.class;
例如:Class c=int.class;

(2)第二种---通过对象名得到类的类类型

Class c=<对象>.getclass();
e.g:String str="hellowrold";
Class c=str.getclass();

(3)第三种-----通过类所在的路径来得到类的类类型

Class c=Class.forName("java.lang.String");

获得类的成员信息

Part one 获得类成员方法信息

getMethod(String name,Class ...PararmeterTypes)

返回洗个Method对象(注意里面形参的类型,使用的时候不要混淆)

成员方法必须是public类型的

getDeclaredMethod(String name,Class ...PararmeterTypes)此成员方法是已声明的任何类型(不管是public还是private都可以)
getMethods()返回一个Method数组
getDeclaredMrthods()返回一个Method数组

用Method表示成员方法,

Method   getMethod(String name,Class...parameterType)

解释:该方法返回一个Method类型的对象,name参数表示成员方法名称,parameterType表示方法的形参

...三个连续的点表示参数个数不固定。

getName()返回Methodf方法所表示的名称
getParameterTypes()以Class数组的形式返回所表示方法形参类型
getReturnType()以Class对象 的形式返回方法的返回类型
getModifiers() 
invoke(Object obj,Object...args)用给定的参数调用给定对象的方法
package Fl;
public class People {
    String name;
    int age;
    public void setName(String name) {
        this.name=name;
    }
    public void setAge(int age) {
        this.age=age;
    }
    public int getAge() {
        return age;
    }
    public String getName() {
        return name;
    }
}
-------------------------------------------------
package Fl;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.math.*;
public class Main {
public static void main(String[] args) throws IllegalAccessException, 
IllegalArgumentException, InvocationTargetException, NoSuchMethodException,
SecurityException, ClassNotFoundException {
	Class c=Class.forName("Fl.People");
	Method[] methods=c.getMethods();//获得所有public的方法
	for(Method m:methods) {
		//得到方法的返回类型
		Class returntype=m.getReturnType();
		System.out.print(returntype.getSimpleName());//得到每一个方法的返回类型
		System.out.print("   "+m.getName());//输出方法名称
		//得到每一个方法的返回类型
		Class[] parameter=m.getParameterTypes();//得到方法的形参类型
		//遍历输出方法的返回类型
		System.out.print("(");
		for(Class p:parameter) {
			System.out.print(p.getSimpleName());
		}
		System.out.println(");");
	}		
}	
}
输出效果:
String   getName();
void   setName(String);
int   getAge();
void   setAge(int);
void   wait();
void   wait(longint);
void   wait(long);
boolean   equals(Object);
String   toString();
int   hashCode();
Class   getClass();
void   notify();
void   notifyAll();

如何使用invoke方法(important)

public Object invoke(Object obj,
                     Object... args)
              throws IllegalAccessException,
                     IllegalArgumentException,
                     InvocationTargetException
对带有指定参数的指定对象调用由此 Method 对象表示的底层方法。个别参数被自动解包,以便与基本形参相匹配,基本参数和引用参数都随需服从方法调用转换。

如果底层方法是静态的,那么可以忽略指定的 obj 参数。该参数可以为 null。

如果底层方法所需的形参数为 0,则所提供的 args 数组长度可以为 0 或 null。 

如果底层方法是静态的,并且尚未初始化声明此方法的类,则会将其初始化。

如果方法正常完成,则将该方法返回的值返回给调用者;如果该值为基本类型,则首先适当地将其包装在对象中。但是,如果该值的类型为一组基本类型,则数组元素 被包装在对象中;换句话说,将返回基本类型的数组。如果底层方法返回类型为 void,则该调用返回 null。

obj - 从中调用底层方法的对象(简单的说就是调用谁的方法用谁的对象)args - 用于方法调用的参数 

下面通过程序调用类中的方法,成功设置类中的成员姓名:

package Fl;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.math.*;
public class Main {
public static void main(String[] args) throws IllegalAccessException, 
IllegalArgumentException, InvocationTargetException, NoSuchMethodException,
SecurityException, ClassNotFoundException {
	Class c=Class.forName("Fl.People");
	Method m=c.getMethod("setName",String.class);
	Object t=m.invoke(new People(),"xiaoli");			
}	
}

Part two获得成员变量信息(与Method类似)

使用Field来 表示成员变量,提供了成员变量的api,使用的方法和成员方法类似,大体上是相同的:

getField(String name)返回一个Field类型的对象,必须是public类型的,name是成员变量的名称
getFields()返回一个Field数组
getDeclaredField(String name)可以是一个已声明任何类型的成员变量
getDeclaredFields()返回一个Field数组
getType()返回一个Class类型的对象,标识字段的声明类型
getName()返回Field字段标识的信息
  
  
使用getField获得变量信息:
public class Main {
public static void main(String[] args) throws IllegalAccessException, 
IllegalArgumentException, InvocationTargetException, NoSuchMethodException,
SecurityException, ClassNotFoundException {
	Class c=Class.forName("Fl.People");
	java.lang.reflect.Field[] f=c.getDeclaredFields();	
	for(java.lang.reflect.Field s:f) {
		    Class type=s.getType();//类型变量
        System.out.print(type.getSimpleName()+" ");
        System.out.println(s.getName()+";");
	}
}	
}
String name;
int age;

创建对象实例

创建对象实例更像一个逆向的思考过程,在应用的时候可以减少判断,提高代码的整洁度。

创建对象实例有两种方法:(1)无参数的构造方法(2)有参数的构造方法。其中无参构造方法较为简单。

(1)调用Class的newInstance();方法即可

(2)较为复杂,首先通过Class[]参数获得包含此参数的构造方法 ,然后准备一个Object[]作为参数调用Constrctor对象的newInstance()方法。

newInstance()不带参构造方法
getConstrcutor()获得public类型的构造方法
getConstructor(Class[] parameterTypes)获得特定的构造方法
注意:Class和Constructor类中都拥有newInstance()方法,Class中的是不带参数的,Constructor中的newInstance是带参数的(和前面说的类似)
package Fl;

public class People {
	
	String name;
	int age;
	String sex;
	public People(String name,int age,String sex) {
		this.name=name;
		this.age=age;
		this.sex=sex;
	}
	public People() {
		this.name=null;
		this.age=0;
		this.sex=null;
	}
	public void display() {
		System.out.println("信息展示卡:\n姓名:"+name+"\n年龄"+age+"\n性别:"+sex);
	}
	}

第一种无参构造(最简单的那种)

package Fl;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.math.*;
import java.text.DateFormat.Field;
public class Main {
public static void main(String[] args) throws IllegalAccessException, 
IllegalArgumentException, InvocationTargetException, NoSuchMethodException,
SecurityException, ClassNotFoundException, InstantiationException {
	Class c=Class.forName("Fl.People");
	java.lang.reflect.Field[] f=c.getDeclaredFields();	
	//第一种无参构造
	People p=(People)c.newInstance();
	p.display();
	}
}	
信息展示卡:
姓名:null
年龄 0
性别:null

(2)有参构造------(分为两部分:first ,sceond)

package Fl;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.math.*;
import java.text.DateFormat.Field;
public class Main {
public static void main(String[] args) throws IllegalAccessException, 
IllegalArgumentException, InvocationTargetException, NoSuchMethodException,
SecurityException, ClassNotFoundException, InstantiationException {
	Class c=Class.forName("Fl.People");
	Constructor m=c.getDeclaredConstructor(new Class[] {String.class,int.class,String.class});
	People p=(People)m.newInstance("zhangping",12,"男");//返回类型为Object,需要做强制类型转换
	p.display();
	}
}	
信息展示卡:
姓名:zhangping
年龄12
性别:男

如何应用反射

访问类变量

通过反射机制,可以轻松的访问类型变量所有的信息,并可以修改其中的值,如果是private或者是protected,(缺省的话相当于protected),必须设置setAccessible(true)方法,否则会抛出异常。







posted @ 2018-04-25 21:07  sunchongwei  阅读(105)  评论(0编辑  收藏  举报