一,概述
反射机制允许程序在运行期间获得任何类的任何内部信息,并直接操作任意对象的内部属性和方法。
正是由于反射机制的存在,使java被视为准动态语言。
动态编程语言(Dynamic programming Language):
动态语言是指程序在运行时可以改变其结构。比如,新的函数可以被引进,已有的函数可以被删除等在结构上的变化。
静态类型语言(Statically Typed Language):
静态类型语言数据类型是在编译其间检查的。即是,在写程序时要声明所有变量的数据类型。
Class类:
反射与Class类是有密切关系的,学习反射前先搞清楚这个Class类。它就像平时常用的String类一样,是java的某个包中的一个类,只是String类更常用。
因为Class是一个类,所以当然可以定义创建一个Class的对象,比如Class c = ...;
便定义了一个名为c的Class对象,又称类对象(只是把Class这个英文单词翻译成中文“类”)。
- 类的对象
- 任何的对象都叫类的对象;
String s = ...;
Person p = ...;
s和p都叫类的对象,上面的c也叫类的对象;- 只是,s是String类的对象,p是Person类的对象,c是Class类的对象;
- 而c又称类对象,s又称字符串对象,p又称人类对象。
Class是java.lang包中的类,该类的实例可以帮助程序创建其他类的实例。
创建对象最常用的方法是使用new运算符和类的构造函数,但使用Class对象也可以获得某个类的实例。
Class对象(类对象):
是类加载的产物,封装了一类的所有信息(包括类名、父类、接口、属性、方法、构造函数);即,将类看作对象,在每个类的基础上在抽象一个类——Class类。
- Class对象指向一个类,就如String对象指向一个字符串。
关于Class类和Class对象的更深层的内容,还需要对类的加载与ClassLoader学习之后研究。
二,获取类对象的三种方法
①通过类的对象获取类对象
Student stu = new Student();
Class<?> c = stu.getClass();
②通过类名获取类对象
Class c2 = Student.class;
③通过静态方法获取类对象
Class c3 = Class.forName("reflection.Student"); //"包名.类名"
方法①②在使用时需要类存在,依赖性较强,而方法③允许在编译时类可不存在,更方便使用。
Student stu = new Student();
Class<?> c1 = stu.getClass();
System.out.println(c1);
Class c2 = Student.class;
System.out.println(c2);
try {
Class c3 = Class.forName("reflection.Student");
System.out.println(c3);
} catch (ClassNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
运行结果 :
从运行结果可以看出,三中方法产生的Class对象相同。
一个类只有一个Class对象。(深层内容要研究类的加载)
三,与反射相关的方法
①使用Class的方法,获取包名、包、父类和实现的接口。
String cname = c.getName();//返回由类对象表示的实体的名称,作为 String
Package pack = c.getPackage(); //获得此类的包
Class<?> parent = c.getSuperclass(); //返回该类的父类
Class<?>[] interfaces = c.getInterfaces(); //返回由类对象表示的类实现的接口
System.out.println(cname);
System.out.println(pack);
System.out.println(parent);
for(Class<?> in : interfaces)
{
System.out.println(in);
}
②使用构造函数创建类的对象:
Class<?> c = null;
//1,获取类的类对象
try {
c = Class.forName("reflection.Student");
} catch (ClassNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
//2,获取类的所有构造方法
Constructor<?>[] cons = c.getConstructors();
//3,获取类的无参构造函数
Constructor<?> con = null;
Student s = null;
try {
con = c.getConstructor();
//4,使用构造函数构建类的对象
s = (Student)con.newInstance();
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println(s.toString());
//5,获取类的有参构造函数
Constructor<?> con2 = null;
Student s2 = null;
try {
con2 = c.getConstructor(String.class,int.class,boolean.class);
//6,使用类的有参构造函数创建类的对象
s2 = (Student)con2.newInstance("小明",12,true);
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println(s2.toString());
③使用Class对象调用newInstance()实例化类的对象
Class<?> c = null;
Student s = null;
try {
//1,获取类的类对象
c = Class.forName("reflection.Student");
//2,创建无参对象
s = (Student) c.newInstance();
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println(s.toString());
此时,Student类必须有无参构造方法。通过此方法好像不能创建有参的对象。
④ Method相关方法
1)获得类中的包括继承的在内的public方法
//2,获得Student类的public方法,(包括继承的)
Method[] mets = c.getMethods();
for(Method m : mets)
{
System.out.println(m);
}
2)获取类的所有的(private、default、protect、public)的方法,不包含继承的
//3,获得类Student的所有方法,不包括继承的
Method[] mets = c.getDeclaredMethods();
for(Method m:mets)
{
System.out.println(m);
}
3)获取指定的方法
Class<?> c = null;
Student s = null;
try {
//1,获取类的类对象
c = Class.forName("reflection.Student"); //现在c是指向类Student的类对象
s = (Student)c.newInstance();
//3,获得类Student的指定的方法,无参无返回值
Method studyMet = c.getMethod("study");
//3,调用对象s的study方法
studyMet.invoke(s);
//4,获得带返回值的方法
Method playMet1 = c.getMethod("play");
//4,调用对象s的play方法,有返回值
String res = (String)playMet1.invoke(s);
System.out.println(res);
//5,获得带参带返回值的方法
Method playMet2 = c.getMethod("play",String.class);
//5,调用对象s的play方法,有参有返回值
String res2 = (String)playMet2.invoke(s, "乒乓球");
System.out.println(res2);
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
4)获取类的私有方法
//6,获取类的私有方法
Method privateMet = c.getDeclaredMethod("fangfa");
privateMet.setAccessible(true); //设置访问权限无效
privateMet.invoke(s);
其中,私有方法在获取之后不能调用执行的,可通过setAccessible(true)
方法,设置该方法的访问权限无效,后方可调用私有方法。
5)类的静态方法
//1,获取类的类对象
c = Class.forName("reflection.Student"); //现在c是指向类Student的类对象
s = (Student)c.newInstance();
//7,获取类的静态方法
Method staticMet = c.getMethod("fun",String.class);
//7,调用静态方法
staticMet.invoke(null, "123");
staticMet.invoke(s, "234");
其中需要注意的是,调用静态方法时,可不传对象。
⑤获取属性相关方法
1)获取类中的所有public的属性,包括继承的
//获得类中的所有public属性,包括继承
Field[] fields = c.getFields();
for(Field f:fields)
{
System.out.println(f);
}
2)获取属性的所有方法,不包括继承
//获得类中的所属性,不包括继承
Field[] fields = c.getDeclaredFields();
for(Field f:fields)
{
System.out.println(f);
}
3)获取指定的属性并操作
//2,获取指定的属性
Field name = c.getDeclaredField("name");
//设置访问权限无效
name.setAccessible(true);
//3,给指定的对象的name赋值
name.set(s, "小明");
//4,读取指定对象的name的值
System.out.println(name.get(s));
四,实践——使用反射实现一个可以调用任何对象方法的通用方法
static Object invokeAny(Object obj,String methodName,Class<?>[] types,Object ...args)throws Exception
{
//1,获取类对象
Class<?> cs = obj.getClass();
//2,获取方法
Method method = cs.getMethod(methodName, types);
//调用
return method.invoke(obj, args);
}
调用:
Test.invokeAny(s,"play",new Class[]{String.class},"篮球");
以上内容是我个人在学习之后的梳理和总结,旨在使所学的内容更加清晰和方面后续复习,故请不勿喷语言表达不清和逻辑结构不清的地方,但虚心接受大家的交流和指导,如果本文能对大家的学习起到帮助,我深感荣幸!