Everyone’s heart is a piece of sea,shining bottomless blue.
在开发android的路上,java的编程思想一直是android开发的指南。
java的反射机制,使得类的调用,方法的使用更加的灵活。
所以对java Reflect 进行整理。
注意:使用java反射机制,对于内存的开销会大。所以在程序中,非必要的情况下,尽量少用反射,用就要用的有价值。
反射基本使用
在java中,得到类,实例化类,然后使用对象调用类中方法。这是正常流程。
在java反射中,可以灵活的使用类。达到动态实现的效果。
/*在reflect中会主要使用到的类*/
//构造方法
import java.lang.reflect.Constructor;
//类中属性
import java.lang.reflect.Field;
//类中方法
import java.lang.reflect.Method;
Step1:创建java类,如下:
package com.example;
public class ReflectClass{
/*无参的构造函数*/
public ReflectClass() {
}
/*私有属性*/
private String s_name;
private String s_age;
private String s_number;
/*公有属性*/
public int s_grade;
/*保护类型属性*/
protected String s_degree;
/*含有参数的构造函数*/
public ReflectClass(String s_name, String s_age, String s_number) {
this.s_name = s_name;
this.s_age = s_age;
this.s_number = s_number;
}
public String getS_name() {
return s_name;
}
public void setS_name(String s_name) {
this.s_name = s_name;
}
public String getS_age() {
return s_age;
}
public void setS_age(String s_age) {
this.s_age = s_age;
}
public String getS_number() {
return s_number;
}
public void setS_number(String s_number) {
this.s_number = s_number;
}
@Override
public String toString() {
return "ReflectClass{" +
"s_name='" + s_name + '\'' +
", s_age='" + s_age + '\'' +
", s_number='" + s_number + '\'' +
'}';
}
}
Step2: 使用反射调方法
public static void main(String[] args){
Scanner scanner = new Scanner(System.in);
System.out.println("请您输入需要动态加载的类:\n");
String className = scanner.nextLine();
System.out.println("您输入的类名为:\n"+className);
/*动态加载类*/
try {
/*通过反射加载我们想到动态加载的类*/
/*1:获取要加载的类
*
* 获取class对象的三种方式
*
* 1> Class> clz = Class.forName(className);
* 2> Class> clz = ClassName.class;
* 3> ClassName className = new ClassName();
* Class> clz = className.getClass();
* */
Class> clz = Class.forName(className);
System.out.println("clz ===="+clz);
if(clz == null){
System.out.println("sorry,您的Class不存在!");
}
/*2:实例化该类,要添加异常处理*/
Object obj = clz.newInstance();
/*3:得到类,并且实例化后,便可以操作方法,属性。
先看看我们使用这种方式能够得到哪些内容
*/
/*public Method[] getDeclaredMethods() throws SecurityException
*
* 获取clz中的所有方法
* */
Method[] methods = clz.getDeclaredMethods();
for (int i = 0;i
//看看这里的所获取到所有的方法的名称,和我们的类中是否是一致
System.out.println(className +"中中定义的所有方法----"+i+"----"+methods[i]);
}
/* Method getDeclaredMethod(String name, Class>... parameterTypes)
*
* 获取到固定方法,现在我想获取到getS_name()方法
*
* */
Method method = clz.getDeclaredMethod("getS_name");
System.out.println("method------->"+method.getName()+"------>"+method);
/*
获取某个方法的返回类型
*/
Class> methodType = method.getReturnType();
System.out.println("methodType[getS_name]------------>"+methodType);
/*获取到类中的所有属性
*
* public Field[] getDeclaredFields() throws SecurityException
* */
Field[] fields = clz.getDeclaredFields();
for (int i=0;i
/*看看输出是否是我们的target class*/
System.out.println("fields["+i+"]"+"=========="+fields[i]);
}
/*获取单一确定属性
*
* public Field getDeclaredField(String name)
*
* */
Field field = clz.getDeclaredField("s_name");
System.out.println("Field_s_name----------------->"+field);
/*
* 获取所有的构造方法
* public Constructor>[] getDeclaredConstructors() throws SecurityException
*
*
* */
Constructor>[] constructors = clz.getDeclaredConstructors();
System.out.print("改类中的所有构造方法:\n");
for (int i=0;i
System.out.println("constructors["+i+"]"+"-------->"+constructors[i]);
}
/*获取具体的构造方法*/
Constructor> constructor =clz.getDeclaredConstructor(String.class,String.class,String.class);
System.out.println("constructor-------->"+constructor);
} catch (ClassNotFoundException e) {
e.printStackTrace();
System.out.print("sorry,The className is null point");
} catch (InstantiationException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (NoSuchMethodException e) {
e.printStackTrace();
} catch (NoSuchFieldException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}
}
Step3:我们现在Run Application,结果如下
summary:反射所得到的方法,属性十分的明确,所以我们是可以通过反射明确的获取到类中的每个方法。
反射的 类中继承ParentClass或者implement Interface
Step1: 创建你的parentClass类,Interface接口
Step2: 目标类extends ParentClass implements Interface
Step3: 前面步骤和上面基础一致。在代码中添加
/*
*
* 获取superParentClass
* public native Class super T> getSuperclass();
* 目前并没有父类方法
* */
Class> superClass = clz.getSuperclass();
System.out.println("superClass------->"+superClass);
/*
* 获取到该类所实现的接口
*
* public Class>[] getInterfaces() {
* */
Class>[] interfaceClasses = clz.getInterfaces();
System.out.println("获取到该类所实现的接口");
for(int i = 0;i
System.out.println("interfaceClasses["+i+"]------------>"+interfaceClasses[i]);
}
如何应用使用反射获取的方法或者属性
调用方法
在上面的代码中,我们实例化Class对象
Object obj = clz.newInstance();
一直没有使用。那么现在来看看它的用处:
1:获取到clz类中的getS_name(),并且得到它的返回值,并进行打印输出。
/*1:得到getS_name()方法*/
Method methodGetName = clz.getDeclaredMethod("getS_name");
/*2:使用方法,并且得到返回值
@param obj
@param args:如果你调用的方法需要传入参数就请传入相应类型的参数值
public Object invoke(Object obj, Object... args)
PS:因为目前调用的方法为无参方法,所以直接调用
*/
String result = methodGetName.invoke(obj);
System.out.println("result===="+result);
事实上,我们已经获得了getS_name()中返回的值了。之所以为null那是因为在java中,String类型的变量当没有为其赋值的时候,默认为null
那么现在我们为s_name赋值,然后在进行获取,看看变化:
/*1:获取setS_name(String)方法*/
Method methodSetName = clz.getDeclaredMethod("setS_name",String.class);
/*2:为setS_name(String)赋值 */
methodSetName.invoke(obj,"测试数据");
/*3:此时我们在获取getS_name()方法*/
Method methodGetName = clz.getDeclaredMethod("getS_name");
/*4: 打印输出getS_name()中的返回值*/
System.out.println("getS_name()===="+methodGetName.invoke(obj));
此时我们所赋值的数据被获取出来了。
操作属性
1:操作public属性或者protected属性
/*1:获取公有属性*/
Field field = clz.getDeclaredField("s_grade");
/*2:获取该属性的值
方法:
public Object get(Object obj)
*/
int grade = field.get(obj);
/*3:输出公有属性的值*/
System.out.println("public s_grade value is:----->"+grade );
java中默认的int类型值为0
为公有属性赋值:
/*1:获取公有属性*/
Field field = clz.getDeclaredField("s_grade");
/*2:设置该属性的值
方法:
public void set(Object obj, Object value)
*/
field.set(obj,10);
/*3:输出公有属性的值*/
System.out.println("public s_grade value is:----->"+field.get(obj));
此时该值已经被改变。
2:如果使用上述方法操作private属性,会出现错误如下:
field = clz.getDeclaredField("s_age");
System.out.println("private s_age value is:--------->"+field.get(obj));
run后的错误如下:
无法操作private属性
这种情况也是可以预见的,在 我们正常的使用Class的时候,是无法对其私有的属性或者方法来进行使用的。
但是,在反射中,可以通过设置
/*设置可访问权限*/
public void setAccessible(boolean flag)
来使得类对其进行访问并实现修改
如下:
field = clz.getDeclaredField("s_age");
field.setAccessible(true);
System.out.println("private s_age value is:--------->"+field.get(obj));
此时可以进行访问。值为null 相比不用在解释了吧!
关于Reflect反射的基础使用就告一段落。后续会更新关于使用Reflect工厂模式的使用。
END