一、反射简介
之前讲的类加载:将类的类信息加载的JVM中,我们在运行时采用才可以使用这些类
前提的条件:JVM一定要知道它现在需要加载的是什么类
有一种情况:JVM在加载类的时候,它不知道该加载什么类,但是它在运行时, 却知道它现在需要什么类,此时就需要使用到反射机制,才可以解决它不知道的类
反射:在类加载时,不知道它要加载什么东西,但是在运行时,却知道了它需要用什么类,此时就反过头去重新加载的情况
举例说明
info.properties文件
girl=com.woniuxy.java33.study.bean.GentleGirl
package com.woniuxy.java33.study.bean;
public class Girl {
}
package com.woniuxy.java33.study.bean;
/**
* 温柔型女孩
* @author Administrator
*
*/
public class GentleGirl extends Girl{
}
package com.woniuxy.java33.study.bean;
/**
* 粗鲁型女孩
* @author Administrator
*
*/
public class BlodGirl extends Girl{
}
package com.woniuxy.java33.study.util;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.util.Properties;
/**
* properties文件 的加载类
* @author Administrator
*
*/
public class PropertiesUtil {
public static String getValue(String key) {
Properties props = new Properties();
FileInputStream fis = null;
try {
String path = System.getProperty("user.dir") + File.separatorChar + "src" + File.separatorChar +"info.properties" ;
File file = new File(path);
fis = new FileInputStream(file);
props.load(fis);
}catch (Exception e) {
// TODO: handle exception
e.printStackTrace();
}finally {
try {
fis.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
return props.getProperty(key);
}
public static void main(String[] args) {
System.out.println(getValue("girl"));
}
}
package com.woniuxy.java33.study.reflect;
import com.woniuxy.java33.study.util.PropertiesUtil;
public class MainEnter {
public static void main(String[] args) {
// TODO Auto-generated method stub
//妈妈安排相亲
String girl = PropertiesUtil.getValue("girl");
System.out.println(girl);
// Girl girl =
//用反射
try {
//forName() 调用 类加载器 去重新加载
Class cls = Class.forName(girl);
System.out.println(cls);
System.out.println(cls.newInstance());
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
反射中,最核心的方法:Class.forName()
该方法:Class.forName() 可以做到:在运行期去加载 需要的类
二、Class类
class类是反射中最重要的类
如果你在程序代码,需要使用到Class类,有3种方式获取:
1、Class.forName() 应用于反射
2、如果已知类的情况,使用类名.class 也可以获取到
3、如果已知类的对象,使用 对象.getClass() 同样可以获取到
三、如何使用Class 类来完成创建对象,调用方法,调用属性
3.1 创建对象
调用无参构造器,产生实例
//forName() 调用 类加载器 去重新加载
Class cls = Class.forName(girl);
//根据cls创建实例 newInstance() 调用无参构造器
Object obj = cls.newInstance();
调用有参构造器,产生实例
//forName() 调用 类加载器 去重新加载
Class cls = Class.forName(girl);
//返回有参构造器
Constructor cons = cls.getConstructor(String.class,Integer.class);
Object obj = cons.newInstance("三上",18);
System.out.println(obj);
3.2 调用属性
//返回有参构造器
Constructor cons = cls.getConstructor(String.class,Integer.class);
Object obj = cons.newInstance("三上",18);
System.out.println(obj);
// //不能返回私有属性
// Field field = cls.getField("girlName");
// System.out.println(field.get(obj));
//可以返回 私有属性
Field field = cls.getDeclaredField("girlName");
//给其他类,授权访问 私有属性
field.setAccessible(true);
System.out.println(field.get(obj));
//set 主要给属性赋新的值
field.set(obj, "市川**");
//get 主要用于获得属性的内容
System.out.println(field.get(obj));
3.3 调用方法
//获取私有方法
Method meth = cls.getDeclaredMethod("cry", null);
meth.setAccessible(true);//同样给私有方法,授权
System.out.println(meth);
//调用方法(第一个参数表示对象,第二个参数表示 具体的值)
Object result = meth.invoke(obj, null);
//输出方法的返回结果
System.out.println(result);
//获得非私有方法(第一个参数表示方法名,第二个参数表示 参数类型)
// Method meth = cls.getMethod("cry", null);
// System.out.println(meth);
// //调用方法(第一个参数表示对象,第二个参数表示 具体的值)
// Object result = meth.invoke(obj, null);
// //输出方法的返回结果
// System.out.println(result);
3.4 获得注解
//返回有参构造器
Constructor cons = cls.getConstructor(String.class,Integer.class);
Object obj = cons.newInstance("三上",18);
System.out.println(obj);
//根据方法对象,获得方法上的 注解
Method meth = cls.getMethod("cry", null);
MyLog mylog = meth.getAnnotation(MyLog.class);
System.out.println(mylog.menuName());
System.out.println(mylog.optType());