反射——整理好的学习资料

    xiaoxiao2022-07-12  142

     

    是 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 对象代表方法信息

    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);

    }

    }

    使用invoke

    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支持注解

    强行执行私有方法(访问私有属性)

    JUnit4 原型:

    @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);

    }

    }


     

     

    最新回复(0)