知识点
- 反射的基本概念
- 反射中class类的获取
- 反射中field类属性的获取
- 反射中method类方法的获取
- 反射中consturct类构造方法的获取
- 反射中implement类接口的获取
- 反射获取父类,调用方法
一、反射的基本概念
1.1 概念
反射是一种强大的工具,它使得我们可以灵活的构建代码,这些代码可以在运行时装配,无需在组件之间进行源代码链接。反射允许我们在编写执行时,使我们的程序能够接入装载到JVM中的类的内部信息,而不是源代码中选定的类协作的代码,这使得反射成为构建灵活的应用的主要工具。但是需要注意,如果反射使用不当,成本会很高
1.2 反射涉及到的相关包
java.lang.Class; //对应就是类
java.lang.Field; //对应就是类中的成员变量
java.lang.Method; //对应就是类中的方法
java.lang.Modifier; //对应就是类中的变量/方法的定义域
1.3反射的作用
反射可以实现常说的反编译功能
通过反射可以获得java对象的属性,方法,构造方法等
二、获取class的三种方式
2.1 获取方法如下:
public static void main(String[] args) throws Exception{
//通过类的包名获取
Class clazz=Class.forName("com.dongdian.jj.myjavalib.reflect.ReflectTestBean");
//通过class属性获取,每个类对象都会有个class属性
Class clazz2=ReflectTestBean.class;
//通过getClass方法获取,每个类对象都会该方法
ReflectTestBean reflectTestBean=new ReflectTestBean();
Class clazz3=reflectTestBean.getClass();
System.out.println((clazz==clazz2)+"");
System.out.println((clazz2==clazz3)+"");
// System.out.printf("clazz="+clazz+"--clazz2="+clazz2+"--clazz3="+clazz3);
}
//输出结果
true
true
注意:由于jvm中只会加载一次reflectTestBean这个对象,他只会存在一个class实例,所以三种方式获取到的class对象地址都是相同的,上面代码输出结果肯定是相等的
2.2 通过class对象获取实例
在2.1中我们获取到了class对, 那么我们可以直接通过如下方法获取对象实例
Class clazz2=ReflectTestBean.class;
clazz2.newInstance();
注意: class.newsInstance()调用的原java对象的无参构造方法,如果该对象没有无参构造方法则无法成功创建实例
三、反射中field类属性的获取
3.1获取类属性主要通过class类中的4个方法:
//返回所有public的属性
Field[] getFields();
//返回指定的public的属性
Field getField(String s);
//返回所有属性
Field[] getDeclaredFields();
//返回指定的属性
Field getDeclaredField(String s);
3.2通过field对象获取对应属性的修饰符已经字段类型
//返回属性的修饰符(public,private等)
getModifiers();
//返回属性的类型(Stirng,int 等)
getType();
//返回属性的名称
getName();
3.3例子,获取java.lang.String类中所有属性
Class clazz=Class.forName("java.lang.String");
Field[] fields=clazz.getDeclaredFields();
for (Field field : fields) {
System.out.println(Modifier.toString(field.getModifiers())
+" "+field.getType().getSimpleName()
+" "+field.getName());
}
//输出结果
private final char[] value
private int hash
private static final long serialVersionUID
private static final ObjectStreamField[] serialPersistentFields
public static final Comparator CASE_INSENSITIVE_ORDER
(ps:Modifier.toString(int i)
该方法可以将对应的值转换为我们常见的修饰符类型 )
四、反射中method类方法的获取
其实获取方式和上面属性的获取方式是类似的,这里接直接上例子了
4.1获取java.lang.String类的所有方法
Class clazz=Class.forName("java.lang.String");
Method[] mothods=clazz.getDeclaredMethods();
StringBuilder stringBuilde=new StringBuilder();
for (Method mothod : mothods) {
stringBuilde.append(Modifier.toString(mothod.getModifiers())).append(" ");
stringBuilde.append(mothod.getReturnType().getSimpleName()).append(" (");
Class[] classParameters=mothod.getParameterTypes();
for (int i = 0; i < classParameters.length; i++) {
if(i==classParameters.length-1){
stringBuilde.append(classParameters[i].getSimpleName());
}else {
stringBuilde.append(classParameters[i].getSimpleName()).append(",");
}
}
stringBuilde.append(")");
System.out.println(stringBuilde);
stringBuilde.setLength(0);
}
//输出结果
public boolean (Object)
public String ()
public int ()
public volatile int (Object)
public int (String)
public int (String,int)
static int (char[],int,int,String,int)
static int (char[],int,int,char[],int,int,int)
....
五、反射中consturct类构造方法的获取
构造方法也同上,例子如下:
Class clazz=Class.forName("java.lang.String");
Constructor[] constructors=clazz.getDeclaredConstructors();
StringBuilder stringBuilder=new StringBuilder();
for (Constructor constructor : constructors) {
stringBuilder.append(Modifier.toString(constructor.getModifiers())).append(" ");
stringBuilder.append(clazz.getSimpleName()).append("(");
Class[] params=constructor.getParameterTypes();
for (int i = 0; i < params.length; i++) {
if(i==params.length-1){
stringBuilder.append(params[i].getSimpleName()).append(")");
}else {
stringBuilder.append(params[i].getSimpleName()).append(",");
}
}
stringBuilder.append("\n");
}
System.out.println(stringBuilder);
//输出结果
public String(byte[],int,int)
public String(byte[],Charset)
public String(byte[],String)
public String(byte[],int,int,Charset)
public String(byte[],int,int,String)
...
六、 反射中implement类接口的获取
同上
Class clazz=Class.forName("java.lang.String");
Class[] interfaces=clazz.getInterfaces();
StringBuilder stringBuilder=new StringBuilder();
for (Class anInterface : interfaces) {
stringBuilder.append(anInterface.getName()).append("\n");
}
System.out.println(stringBuilder);
//输出结果
java.io.Serializable
java.lang.Comparable
java.lang.CharSequence
七、反射获取父类,调用方法
7.1 获取父类
Class clazz=Class.forName("java.lang.String");
Class surperClazz=clazz.getSuperclass();
7.2通过反射调用方法
准备一个对象
public class Persion {
public String name;
private int age;
protected boolean gender;
private String change(String newName){
this.name=newName;
return name;
}
private String change(String newName,boolean gender){
this.name=newName;
this.gender=gender;
return name;
}
}
通过反编译调用对象的私有方法
Class clazz=Persion.class;
//根据传入的形参类型找到对应的方法
Method method=clazz.getDeclaredMethod("change",String.class);
//设置为true才可以调用private修饰的方法
method.setAccessible(true);
//invoke就是调用方法,注意newInstance只能调用无参构造
Object object=method.invoke(clazz.newInstance(),"Kiana Kaslana ");
System.out.println(object.toString());
//输出结果
Kiana Kaslana
总结
- 反射基础中,比较需要注意的就是,每个class类对象只会存在一个实例,
class.newInstance
方法必须要有无参构造,想调用私有方法必须设置method.setAccessible(true);
- 在熟悉了上面的反射基础之后,我们也能自己动手实现简单的反编译
- 这里只是对反射中常用到的基本方法做了一些介绍,反射的应用场景并没有涉及到,后续会继续学习反射在开发中所发挥的作用
网友评论