转载说明出处:http://blog.csdn.net/a15286856575/article/details/53330821
JAVA反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意一个方法;这种动态获取的信息以及动态调用对象的方法的功能称为Java语言的反射机制。
Java反射机制是Java语言被视为“准动态”语言的关键性质。Java反射机制的核心就是允许在运行时通过Java Reflection APIs来取得已知名字的class类的内部信息(包括其modifiers(诸如public, static等等)、superclass(例如Object)、实现interfaces(例如Serializable),也包括fields和methods的所有信息),动态地生成此类,并调用其方法或修改其域(甚至是本身声明为private的域或方法)。
Java反射机制提供如下功能:
People people = new People();
people.setName("sdff");
Classextends People> aClass = people.getClass();
Class aclass =Class.forName(“com.wenjutian.injectleaning.refect.People”);
注意:当使用Class.forName()方法时,你必须提供完全限定类名。即类名要包括所有包
名。如果在运行时类路径上找不到类,Class.forName()方法会抛出一个ClassNotFoundExcepton。
Class aclass= People.class;
类字面常量不仅可以应用于普通的类,也可以应用于接口、数组以及基本数据类型
这种方式不仅更简单,而且更安全,因为它在编译时就会受到检查,并且根除了对forName方法的调用,所以也更高效,建议使用“.class”的形式。
Class c = Integer.TYPE;(TYPE是基本数据类型的包装类型的一个标准字段,它是一
个引用,指向对应的基本数据类型的Class对象),附表如下,两边等价:
class | TYPE
---|---
boolean.class| Boolean.TYPE
char.class |Character.TYPE
short.class | Short.TYPE
int.class | Integer.TYPE
long.class | Long.TYPE
float.classs| Float.TYPE
double.class |Double.TYPE
void.class | Void.TYPE
通过Class对象我们能拿到:类名,
类修饰符 (public, private, synchronized等)
,包信息
,父类
,实现的接口
,构造函数
,方法
,字段
,注解。
aClass.getName();//带包名
aClass.getSimpleName();//不带包名
输入结果:com.wenjutian.injectleaning.refect.People, people
使用Class对象可以获取一个类的修饰符.类的修饰符即关键字”public”,”private”, “static”等. 如下:
int modifiers = aClass.getModifiers();
修饰符被包装进一个int内,每一个修饰符都是一个标志位(置位或清零)。可以使用java.lang.reflect.Modifier类中的以下方法来检验修饰符:
Modifier.isAbstract(int modifiers)
Modifier.isFinal(int modifiers)
Modifier.isInterface(int modifiers)
Modifier.isNative(int modifiers)
Modifier.isPrivate(int modifiers)
Modifier.isProtected(int modifiers)
Modifier.isPublic(int modifiers)
Modifier.isStatic(int modifiers)
Modifier.isStrict(int modifiers)
Modifier.isSynchronized(int modifiers)
Modifier.isTransient(int modifiers)
Modifier.isVolatile(int modifiers)
Package package = aClass.getPackage();
String packageName = package.getname();
从Package对象中你可以访问诸如名字等包信息。您还可以访问类路径上这个包位于JAR文件中Manifest这个文件中指定的信息。例如,你可以在Manifest文件中指定包的版本号。可以在java.lang.Package中了解更多包类信息。
Class superclass = aClass.getSuperclass();
父类的Class对象和其它Class对象一样是一个Class对象,可以继续使用反射.
通过给定的类可以获取这个类所实现的接口列表,如下:
Class[] interfaces = aClass.getInterfaces();
一个类可以实现多个接口。因此返回一个Class数组。在Java反射机制中,接口也由Class对象表示。即使,子类重写了父类的接口,这时候拿不到父类的接口。
获取构造方法的api
public Constructor<T> getConstructor(Class... parameterTypes)
因为参数可能有多个所以传入的时候可以是个动态数组。
public T newInstance(Object... args)
初始化对象的方法,里面传入的是构造方法的可变参数。
* 无参数的构造方法
/**
* 无参数的构造方法
*/
Constructorextends People> constructor = aClass.getConstructor(null);
People people1 = constructor.newInstance(null);
people1.setName("dsf");
System.out.println(people1.getName());
如果参数为空传入null;
* 有参数的构造方法
Constructorextends People> constructor1 = aClass.getConstructor(String.class, int.class);
//可变参数最后在编译后,会变成数组,所以也可以传数组
//Constructorextends People> constructor2 = aClass.getConstructor(new Class[]{String.class, int.class});
constructor1.newInstance("王五",100);
System.out.println("有参数的构造方法"+constructor1);
public方法
Method[] methods = aClass.getMethods();
for (Method method : methods) {
System.out.println("公共方法"+method.getName());
}
此种方法会获取子类和父类所有的公共方法
相关api
“`
public Method getMethod(String name, Class
Method[] declaredMethods = aClass.getDeclaredMethods();
for (Method declaredMethod : declaredMethods) {
declaredMethod.setAccessible(true);
System.out.println("在此类中所有的方法"+declaredMethod.getName());
}
Method buyMethod = aClass.getDeclaredMethod("buy", String.class);
buyMethod.setAccessible(true);
buyMethod.invoke(people,"bananer");
总结:此方法只能调用当前类的所有方法,如果是私有方法,要设置setAccessible(true).如果是想要拿父类中的方法可以用getSuperClass();
eg:
Class superclass = aClass.getSuperclass();
Method eat = superclass.getDeclaredMethod("eat", null);
eat.setAccessible(true);
eat.invoke(people,null);
Field[] fields = aClass.getFields();
Field nameField = aClass.getField("name");
nameField.getName()
nameField.set(people,"liming");
nameField.get(people);
Field[] declaredFields = aClass.getDeclaredFields();
for (Field declaredField : declaredFields) {
System.out.println("所有字段"+declaredField.getName());
}
Field idField = aClass.getDeclaredField("id");
idField.set(people,33);
idField.get(people);
idField.setAccessible(true);
对于注解不熟悉的同学请参考:
注解
* 类上的注解
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface CAnnotation {
String name() default "张三";
int age() default 10;
}
@CAnnotation(name = "王五",age = 12)
public class People{
}
拿该类上的注解
CAnnotation annotation = aClass.getAnnotation(CAnnotation.class);
if (annotation != null) {
System.out.println("类上的注解"+annotation.age()+annotation.name());
}
该类上所有的注解
Annotation[] annotations = aClass.getAnnotations();
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface FAnnotaion {
String name() default "张三";
}
@FAnnotaion(name = "xiaoming")
public String name;
拿注解并赋值
Field field = aClass.getField("name");
FAnnotaion fannotation = field.getAnnotation(FAnnotaion.class);
if (fannotation != null) {
System.out.println(fannotation.name());
field.set(people,fannotation.name());
}
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface MAnnotaion {
String name() default "张三";
}
@MAnnotaion(name = "sdfsdf")
public void setName(String name) {
this.name = name;
}
拿注解并调用方法
Method msetName = aClass.getMethod("setName", String.class);
MAnnotaion mannotion = msetName.getAnnotation(MAnnotaion.class);
if (mannotion != null) {
msetName.invoke(people,mannotion.name());
}
方法参数的注解
@Target(ElementType.PARAMETER)
@Retention(RetentionPolicy.RUNTIME)
public @interface PAnnotion {
String name() default "张三";
}
用法
public void setName(@PAnnotion(name = "hahah") String name) {
this.name = name;
}
调用
/**
* 第一个坐标代表有几个参数,第二个坐标代表一个参数有几个注解
*/
Annotation[][] parameterAnnotations = msetName.getParameterAnnotations();
for (int i = 0; i < parameterAnnotations.length; i++) {
Annotation[] parameterAnnotation = parameterAnnotations[i];
for (int j = 0; j < parameterAnnotation.length; j++) {
if (parameterAnnotation[j] != null) {
if (parameterAnnotation[j] instanceof PAnnotion) {
pAnnotion = ((PAnnotion) parameterAnnotation[j]);
msetName.invoke(people, pAnnotion.name());
System.out.println("参数注解"+people.getName());
}
}
}
}
源码传送门