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字段标识的信息 |
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) | 获得特定的构造方法 |
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)方法,否则会抛出异常。