反射
反射:框架设计的灵魂 ,动态语言的关键 (框架:简化编码----用框架不用使用反射)学习反射理解框架运行
反射:将类中各部分封装为其他对象
好处:
- 在程序的运行过程中操作这些对象
例如:eclipse 软件中
你在编写程序是建立了一个String str = “abs” 对象
你可以str. 直接调用许多方法
为什么能调用呢:软件已经将 String 这个编译出来的class文件中的所有方法提取出去封装为对象 在展示出来 并且eclipse程序在运行过程中 - 可以解耦,提高程序的可扩展性
Class对象功能:
获取方法:
- 获取成员变量们 java.lang.reflect.Field:代表类的成员变量
(1)Field[] getField()
(2)Field getField(String name)
(3)Field[] getDeclaredFields()
(4)Field getDeclaredFields(String name) - 获取构造方法们 java.lang.reflect.Constructor:代表类的构造方法
(1)Constructor<?>[] getConstructor()
(2)Constructor getConstructor(类<?>…paramterType) - 获取成员方法们: java.lang.reflect.Method:代表类的方法
(1)Method[] getDeclaredMethods()
(2)Method getDeclaredMethod(String name,类<?>…parmeterTypes) - 获取类名 java.lang.Class
(1)String getName()
Filed:成员变量
- 操作:
- 获取:
Filed.get()
修改:
Filed.set()
Constructor:构造方法
创建对象
T newInstance()
若果使用空参构造方法创建对象,可以简化
获取Class对象
java代码在计算机运行中有三个状态:
- 源代码状态:java代码通过javac编译为class文件(类的加载)
- Class类对象阶段:class文件通过类加载器分解为成员变量,构造器,成员方法 的类对象(类的连接)
- 运行时阶段 :调用对象,创建对象(类的初始化)
- 第一阶段:通过Class.forName(“全类名”) 多用于配置文件,将类名定义在配置文件中,读取文件,加载类
- 第二阶段:类名.class 多用于参数的传递
- 第三阶段:对象.getclass 获取
从程序的运行来看反射
正常:导包----->实例化----->获取对象
反射:实例化的对象 ------>getclass()方法 ---------->得到完整的类的包名
得出结论:同一个字节码文件(.class) 在一次程序运行中,只被加载一次,无论通过哪种方式获取的Class对象都是同一个。
一个class对象队形的是一个加载到JVM中的一个.class文件
使用Class对象
获取功能
1.获取成员变量们
2.获取构造方法们
3.获取成员方法们
4.获取类名
案例
反射案例:写一个”框架”,不改变该类的任何代码,可以创建任意类的对象,并执行其中任意方法
-
需要的创建的对象的全类名和需要执行的方法定义在配置文件中
-
创建配置文件的对象 (例如:Propertiees 配置文件)
Properties pro = new Properties(); -
找到要加载的配置文件
需要类加载器中找到指定资源并转换为流的方法
ClassLoader classLoader =本文件名.class.getClassloader();
InputStream in = classLoader.getResouceAsStream(“配置文件名”) -
配置文件对象的方法,启动加载配置文件
(例如 pro.load(is))将配置文件中的内容,转换为集合存放在pro对象中 -
获取配置文件中定义的数据
String className = pro.getProperty(“***”); -
加载该类进内存
Class cls = Class.forName(className); -
创建对象
Object obj = cls.newInstance; -
获取方法对象
Method method = cls.getMethod(“方法名”); -
执行方法
method.invoke(obj);
反射的一些基本方法的使用
/*
getConstructor()获取构造器
getDeclaredConstructors()获取所有构造器
getModifiers()获取访问权限
newInstance()实例化
getParameterTypes()返回所有参数类型
*/
try {
//1.获取到类,通过类名得到类
Class cls = User.class;
//2.获取类的构造方法,获取指定构造器时,需要填写对应的参数类型的类
//获取无参构造方法
Constructor cons = cls.getConstructor();
//获取带参构造方法
Constructor con = cls.getConstructor(String.class,String.class,int.class);
//获取到构造方法的访问权限
System.out.println("构造方法的访问权为:"+Modifier.toString(con.getModifiers()));
//通过带参构造方法实例化
User user = (User) con.newInstance("zhan","1236",8000);
System.out.println("用户名为:"+user.getName()+" ,密码为:"+user.getPassword());
//获取到所有的构造方法
//Constructor[] cons = clazz.getConstructors();
//忽略权限
Constructor[] co = cls.getDeclaredConstructors();
for (Constructor c : co) {
System.out.print(Modifier.toString(c.getModifiers())+" ");
//获取构造方法名称
System.out.print(c.getName()+"(");
//获取所有的参数
Class[] parType = c.getParameterTypes();
if(parType.length!=0){
for (int i=0;i<parType.length;i++) {
if(i<parType.length-1){
//获取到参数名称
System.out.print(parType[i].getSimpleName()+",");
}else{
System.out.println(parType[i].getSimpleName()+"){}");
}
}
}else{
System.out.println("){}");
//实例化之前开启忽略
c.setAccessible(true);
Object obj = c.newInstance();
System.out.println(obj);
}
}
} catch (Exception e) {
System.out.println(e.getMessage());
}
try {
Class cls = User.class;
Constructor con = clazz.getConstructor(int.class,String.class,String.class,int.class);
Object obj = con.newInstance(1001,"sasd","666666",88888);
//获取单个属性
Field field = clazz.getDeclaredField("name");
field.setAccessible(true);
//为对应的对象属性赋值,属性名叫name
field.set(obj, "张三");
//获取属性值
System.out.println(field.get(obj));
System.out.println("==================获取所有的属性======================");
Field[] fields = clazz.getDeclaredFields();
for (Field f : fields) {
System.out.print(Modifier.toString(f.getModifiers())+" ");
//获取属性类型
System.out.print(f.getType().getSimpleName()+" ");
System.out.println(f.getName()+";");
f.setAccessible(true);
//获取所有属性值
System.out.println(f.getName()+"的属性值为===="+f.get(obj));
}
} catch (Exception e) {
e.printStackTrace();
}
try {
Class clazz = User.class;
//实例化对象
Constructor con = clazz.getDeclaredConstructor(int.class,String.class,String.class,int.class);
con.setAccessible(true);
//创建实例
Object obj = con.newInstance(1001,"吕布","123",50000);
//获取一个方法
Method method = clazz.getDeclaredMethod("print");
System.out.println(Modifier.toString(method.getModifiers()));
method.setAccessible(true);
//执行方法,调用invoke方法 ,执行的是哪个对象的方法,对象作为参数
method.invoke(obj); //无参无返回值
Method method1 = clazz.getDeclaredMethod("setPassword", String.class);
method1.invoke(obj, "diaochan"); //调用设置密码的方法,带参数
Method method2 = clazz.getDeclaredMethod("getPassword");
Object password = method2.invoke(obj); //调用获取密码的方法,带返回值
System.out.println("新设置的密码为:"+password);
System.out.println("=======================获取所有方法========================");
Method[] methods = clazz.getDeclaredMethods();
for (Method m : methods) {
System.out.print(Modifier.toString(m.getModifiers())+" ");
//获取返回值类型
System.out.print(m.getReturnType().getSimpleName()+" ");
System.out.print(m.getName()+"(");
//获取所有参数类型
Class[] type = m.getParameterTypes();
if(type.length!=0){
for (int i = 0; i < type.length; i++) {
if(i<type.length-1){
System.out.print(type[i].getSimpleName()+", ");
}else{
System.out.println(type[i].getSimpleName()+"){}");
}
}
}else{
System.out.println("){}");
}
}
} catch (Exception e) {
e.printStackTrace();
}