是 JAVA API, 是Java提供的现成的类!!
接受API提供的功能!
是Java提供的动态执行机制, 动态加载类, 动态创建对象, 动态访问属性, 动态调用方法.
静态: 事先约定的规则, 执行期间按照固定规则执行.
动态: 事先没有约定, 在执行期间动态确定执行规则.
JAVA 中的静态执行: 编译已经就确定执行规则(执行次序), 在运行期间按照编译结果顺序执行.
Foo foo = new Foo();
foo.hello();
JAVA 中的动态执行: 运行期间才能确定加载哪些类, 创建哪些对象, 执行哪些方法...
Java 提供了动态加载类的API
Class cls=Class.forName(类名);
如:
Class cls=Class.forName("demo.Foo");
案例:
Scanner in= new Scanner(System.in);
System.out.print("输入类名:");
String className=in.nextLine();
//动态加载类
Class cls=Class.forName(className);
System.out.println(cls);
语法
Object obj = cls.newInstance();
执行cls引用的类信息中的无参数构造器, 动态创建实例. 如果类没有无参数构造器, 则抛出异常!
提示: 反射可以调用有参数构造器.
案例:
Scanner in= new Scanner(System.in);
System.out.print("输入类名:");
String className=in.nextLine();
//动态加载类
Class cls=Class.forName(className);
System.out.println(cls);
//动态创建对象
Object obj = cls.newInstance();
System.out.println(obj);
发射API提供了动态获取类中方法信息的API:
Method[] ary= cls.getDeclaredMethods();
案例:
Scanner in= new Scanner(System.in);
System.out.print("输入类名:");
String className=in.nextLine();
//动态加载类
Class cls=Class.forName(className);
System.out.println(cls);
//动态获取类的方法信息
//从cls代表的类信息中获取全部的方法信息
Method[] ary=
cls.getDeclaredMethods();
//每天一个Method代表一个方法信息
//方法的所有要素都在这个对象中
for (Method method : ary) {
System.out.println(method);
}
Method提供了获取方法详细信息的方法:
//获取方法名
String name = method.getName();
//获取返回值类型
Class type = method.getReturnType();
案例:
Scanner in= new Scanner(System.in);
System.out.print("输入类名:");
String className=in.nextLine();
//动态加载类
Class cls=Class.forName(className);
System.out.println(cls);
//动态获取类的方法信息
//从cls代表的类信息中获取全部的方法信息
Method[] ary=
cls.getDeclaredMethods();
//每天一个Method代表一个方法信息
//方法的所有要素都在这个对象中
for (Method method : ary) {
System.out.println(method);
//获取方法的详细信息:
System.out.println(
method.getName());
System.out.println(
method.getReturnType());
String name=method.getName();
//检查一个字符串是否以test为开头
if(name.startsWith("test")){
System.out.println("找到了");
}
}
invoke: 调用 method: 方法
语法:
method.invoke(执行方法的对象, 传递的参数)
//正确的情况
购买饮料.invoke(小卖铺, 钱)
//错误的情况
购买饮料.invoke(达内前台, 钱)
必须在对象上执行一个非静态方法, 调用方法时候必须有对象.
在invoke方法执行时候, 必须传递包含当前方法的对象!!!
案例:
业务需求: 执行某个类中全部的以test为开头的无参数无返回值的非静态方法.
//动态加载类
Scanner in= new Scanner(System.in);
System.out.print("输入类名:");
String className=in.nextLine();
Class cls=Class.forName(className);
//动态获取全部方法信息
Method[] ary=
cls.getDeclaredMethods();
//迭代全部方法查找以test为开头的方法
Object obj = cls.newInstance();//"";
for (Method method : ary) {
if(method.getName()
.startsWith("test")){
System.out.println(method);
//动态执行方法
method.invoke(obj);
}
}
Object obj=
method.invoke(对象, 参数1, 参数2...)
invoke 方法有返回值, 返回被调用方法执行的结果, 对象后面参数是执行方法时候传递的参数.
invoke 可以调用私有方法.
案例:
//动态加载类
Scanner in = new Scanner(System.in);
System.out.print("输入类名:");
String className=in.nextLine();
Class cls = Class.forName(className);
//1. 找到demo方法
// Class 提供了根据方法签名找到指定
// 方法信息的API
String name="demo";//方法名
//类型列表 Class[]
// String.class 表示字符串的类型
// int.class 表示int类型
// 任何.class 表示任何的类型
Class[] types={String.class,int.class};
//根据方法签名在cls查找方法信息
Method method=
cls.getDeclaredMethod(name, types);
//找到了私有方法
System.out.println(method);
//执行私有方法
//打开方法的执行权限!!!违反封装!
method.setAccessible(true);
Object obj = cls.newInstance();
Object value=
method.invoke(obj, "Tom", 12);
System.out.println(value);
eclipse 中解析类的结构使用了反射
JUnit识别被测试方法使用了反射
JUnit3利用反射查找test开头的方法
JUnit4利用反射解析@Test查找测试方法
Spring管理Bean对象, 注入Bean属性使用了反射
利用反射创建Bean对象实例
利用反射注入Bean的属性
注解的解析使用了反射
利用反射API支持注解
强行执行私有方法(访问私有属性)
@Retention(RetentionPolicy.RUNTIME)
public @interface Demo {
}
public class TestCase {
public void test(){
System.out.println("test");
}
@Demo
public void hello(){
System.out.println("Hello");
}
@Demo
public void helloKitty(){
System.out.println("Hello Kitty");
}
}
/*
* 动态执行一个类中全部以@Demo注解标注的方法
*/
public class Demo05 {
public static void main(String[] args)
throws Exception{
//动态加载类
//动态获取全部方法
//动态检查方法的注解信息
Scanner in=new Scanner(System.in);
System.out.print("类名:");
String className=in.nextLine();
Class cls = Class.forName(className);
Method[] ary=
cls.getDeclaredMethods();
Object obj = cls.newInstance();
for (Method method : ary) {
//检查一个方法的注解信息
//method.getAnnotation(被检查的注解类型)
//返回注解类型对象, 如果为空表示没有注解
//不为空表示找到了被检查的注解Annotation
Demo ann=method.getAnnotation(
Demo.class);
System.out.println(method);
System.out.println(ann);
if(ann!=null){
method.invoke(obj);
}
}
}
}
Spring 原型
public class ApplicationContext {
//是缓存Spring容器的Bean对象
private Map<String, Object> beans=
new HashMap<String, Object>();
/**
* 利用配置文件初始化当前容器
* 利用xml配置文件, 初始化全部的Bean对象
*/
public ApplicationContext(String xml)
throws Exception{
//利用DOM4j, 读取XML文件
//解析XML文件内容, 得到Bean的类名
//和Bean的ID:
// 根据类名动态加载类并且创建对象
// 将对象和对应的ID添加到map中
//从 Resource(classpath) 中读取流
InputStream in=getClass()
.getClassLoader()
.getResourceAsStream(xml);
SAXReader reader=new SAXReader();
Document doc=reader.read(in);
in.close();
//解析xml :<beans><bean><bean>....
Element root=doc.getRootElement();
//读取根元素中全部的bean子元素
List<Element> list=
root.elements("bean");
for (Element e : list) {
//e 就是 bean 元素 id属性和class属性
String id=e.attributeValue("id");
String className=
e.attributeValue("class");
//动态加载类, 动态创建对象
Class cls=Class.forName(className);
Object bean=cls.newInstance();
beans.put(id, bean);
}
}
public Object getBean(String id){
//根据id在map查找对象, 并返回对象
return beans.get(id);
}
//泛型方法: 优点是可以减少一次类型转换
public<T> T getBean(
String id, Class<T> cls){
return (T)beans.get(id);
}
}
<?xml version="1.0" encoding="UTF-8"?>
<beans>
<bean id="foo"
class="demo.Foo"></bean>
<bean id="date"
class="java.util.Date"></bean>
<bean id="testCase"
class="demo.TestCase"></bean>
</beans>
public class Demo06 {
public static void main(String[] args)
throws Exception {
ApplicationContext ctx=
new ApplicationContext(
"spring-context.xml");
Foo foo = (Foo)ctx.getBean("foo");
Foo f2 = ctx.getBean(
"foo", Foo.class);
System.out.println(foo);
System.out.println(f2);
}
}