开发者社区> 游客5cswve2ky2ieu> 正文

强哥说Java--反射(一)

简介: 强哥说Java--反射(一)
+关注继续查看

一、反射的概述



1.关于反射的理解


Reflection(反射)是被视为动态语言的关键,反射机制允许程序在执行期借助于ReflectionAPI取得任何类的内部信息,并能直接操作任意对象的内部属性及方法


框架 = 反射 + 注解 + 设计模式


2.体会反射机制的“动态性”


@Test
public void test2(){
    for(int i = 0;i < 100;i++){
        int num = new Random().nextInt(3);//0,1,2
        String classPath = "";
        switch(num){
            case 0:
                classPath = "java.util.Date";
                break;
            case 1:
                classPath = "java.lang.Object";
                break;
            case 2:
                classPath = "com.atguigu.java.Person";
                break;
        }
        try {
            Object obj = new classPath
            Object obj = getInstance(classPath);
            System.out.println(obj);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}


你会发现这个程序啊,到运行的时候才确定创建的是那个对象


而且啊,人家是根据字符串创建对象,我刚开始学的时候就疑问?


通过这种方式用new的方式不也是可以吗?


结果自己试试就知道了,classPath是一个路径人家是字符串!


用new的方式后面只能跟实际存在的类!


/*
创建一个指定类的对象。
classPath:指定类的全类名
 */
public Object getInstance(String classPath) throws Exception {
   Class clazz =  Class.forName(classPath);
   return clazz.newInstance();
}


同上~


3.反射机制能提供的功能


image.png


4.相关API


java.lang.Class:反射的源头
java.lang.reflect.Method
java.lang.reflect.Field
java.lang.reflect.Constructor


二、Class类的理解与获取Class的实例



1.Class类的理解


Class就是一个类名叫做Class的类(你品,你细品)


理解这个类,首先要理解类的加载过程。


java源代码经过javac的编译会变成java.class文件(字节码文件)之后呢在经过java.exe命令对字节码文件进行解释运行,这个过程就是将类加载到内存中,也叫类的加载。被加载到内存中的类被称为运行时类,这个运行时类就是Class类的实例


换句话说,Class类的实例就对应着一个运行时类


加载到内存中的类会缓存一定时间。这个时间内我们可以通过不同的方式来获取此运行时类


2.获取Class实例的几种方式


类名.class


对象.getClass


Class.forName(“想要获取运行时类,类的全路径”)


ReflectionTest.class.getClassLoader();使用类的加载器,了解即可


3.创建类的对象的方式


new


反射


4.Class实例可以是哪些结构的说明


image.png


三、了解ClassLoader



1.类的加载过程


当程序主动使用某个类时,如果该类还未被加载到内存中,则系统会通过如下三个步骤来对该类进行初始化


image.png


2.类的加载器的作用


类加载的作用:将class文件字节码内容加载到内存中,并将这些静态数据转换成方法区的运行时数据结构,然后在堆中生成一个代表这个类的java.lang.Class对象,作为方法区中类数据的访问入口。

**类缓存:**标准的JavaSE类加载器可以按要求查找类,但一旦某个类被加载到类加载器中,它将维持加载(缓存)一段时间。不过JVM垃圾回收机制可以回收这些Class对象。


四、反射应用一:创建运行时类的对象



1.代码举例


Class<Person> clazz = Person.class;
Person obj = clazz.newInstance();
System.out.println(obj);


2.说明


newInstance():调用此方法,创建对应的运行时类的对象。内部调用了运行时类的空参的构造器。


要想此方法正常的创建运行时类的对象,要求:

1.运行时类必须提供空参的构造器

2.空参的构造器的访问权限得够。通常,设置为public。


在javabean中要求提供一个public的空参构造器。原因:

1.便于通过反射,创建运行时类的对象

2.便于子类继承此运行时类时,默认调用super()时,保证父类此构造器



package com.caq.spring5;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
/**
 * 动态代理的举例
 */
interface Human {
    String getBelief();
    void eat(String food);
}
//被代理类
class SuperMan implements Human {
    @Override
    public String getBelief() {
        return "I believe I can fly!";
    }
    @Override
    public void eat(String food) {
        System.out.println("我喜欢吃" + food);
    }
}
/**
 * 想要实现动态代理,需要解决的问题?
 * 问题一:如何根据加载到内存中的被代理类,动态的创建一个代理类及其对象
 * 问题二:当通过代理类的对象调用方法a时,如何动态的去调用被代理类中的同名方法a
 */
class ProxyFactory {
    //    调用此方法,返回一个代理类对象,解决问题一
    public static Object getProxyInstance(Object obj) {//被代理类的对象
        MyInvocationHandler hander = new MyInvocationHandler();
        hander.bind(obj);
        return Proxy.newProxyInstance(obj.getClass().getClassLoader(), obj.getClass().getInterfaces(), hander);
    }
}
class MyInvocationHandler implements InvocationHandler {
    private Object obj;
    public void bind(Object obj) {
        this.obj = obj;
    }
    //    当我们通过代理类的对象,使用方法a时,就会自动的调用如下方法invoke
//    将被代理类要执行的方法a的功能就声明在invoke()中
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
//        method:即为代理类对象调用的方法,此方法也就作为了被代理类对象要调用的方法
//        obj:被代理类的对象
        Object returnValue = method.invoke(obj, args);
        return returnValue;
    }
}
public class ProxyTest {
    public static void main(String[] args) {
        SuperMan superMan = new SuperMan();//创建被代理类的对象
//        proxyInstance:代理类的对象
        /**
         * 1.通过反射提供的API动态的创建一个代理类
         * 2.首先new一个被代理类的对象,传入创建代理类对象的方法中
         * 3.创建代理类的方法中的参数handler其实就抽象化了被代理类要执行的方法
         * 4.handler参数是一个接口,我们创建handler接口的实现类,实例化handler接口的实现类的时候参数为被代理类对象
         * 5.handler接口的实现类重写了handler的invoke方法,
         * 6.invoke方法第二个参数是Method类的method对象,我们通过这个对象可以调用运行时类的方法(运行时类就是我们的加载到内存中的被代理类)
         * 7.之后我们通过method.invoke(obj,args),第一个obj参数就是被代理类的对象,调用invoke方法时的参数(不知道invoke的可以回顾下反射)
         * 8.这样就可以实现调用代理类对象的invoke方法时,也调用被代理类的方法
         * 反射的主要特点就是体会到它的动态性,就是因为我们的代理类没有显示的给它定义出来,而是在运行的时候根据你传入的被代理类的对象是谁
         * 我们动态的帮你创建的,体现了反射的动态性
         */
       
        Human proxyInstance = (Human) ProxyFactory.getProxyInstance(superMan);
        String belief = proxyInstance.getBelief();
        System.out.println(belief);
        proxyInstance.eat("鸡蛋");
    }
}

版权声明:本文内容由阿里云实名注册用户自发贡献,版权归原作者所有,阿里云开发者社区不拥有其著作权,亦不承担相应法律责任。具体规则请查看《阿里云开发者社区用户服务协议》和《阿里云开发者社区知识产权保护指引》。如果您发现本社区中有涉嫌抄袭的内容,填写侵权投诉表单进行举报,一经查实,本社区将立刻删除涉嫌侵权内容。

相关文章
阿里云服务器如何登录?阿里云服务器的三种登录方法
购买阿里云ECS云服务器后如何登录?场景不同,阿里云优惠总结大概有三种登录方式: 登录到ECS云服务器控制台 在ECS云服务器控制台用户可以更改密码、更换系.
28951 0
阿里云服务器ECS登录用户名是什么?系统不同默认账号也不同
阿里云服务器Windows系统默认用户名administrator,Linux镜像服务器用户名root
16303 0
阿里云服务器端口号设置
阿里云服务器初级使用者可能面临的问题之一. 使用tomcat或者其他服务器软件设置端口号后,比如 一些不是默认的, mysql的 3306, mssql的1433,有时候打不开网页, 原因是没有在ecs安全组去设置这个端口号. 解决: 点击ecs下网络和安全下的安全组 在弹出的安全组中,如果没有就新建安全组,然后点击配置规则 最后如上图点击添加...或快速创建.   have fun!  将编程看作是一门艺术,而不单单是个技术。
20612 0
腾讯云服务器 设置ngxin + fastdfs +tomcat 开机自启动
在tomcat中新建一个可以启动的 .sh 脚本文件 /usr/local/tomcat7/bin/ export JAVA_HOME=/usr/local/java/jdk7 export PATH=$JAVA_HOME/bin/:$PATH export CLASSPATH=.
14893 0
阿里云服务器ECS远程登录用户名密码查询方法
阿里云服务器ECS远程连接登录输入用户名和密码,阿里云没有默认密码,如果购买时没设置需要先重置实例密码,Windows用户名是administrator,Linux账号是root,阿小云来详细说下阿里云服务器远程登录连接用户名和密码查询方法
22326 0
阿里云服务器怎么设置密码?怎么停机?怎么重启服务器?
如果在创建实例时没有设置密码,或者密码丢失,您可以在控制台上重新设置实例的登录密码。本文仅描述如何在 ECS 管理控制台上修改实例登录密码。
23572 0
阿里云服务器如何登录?阿里云服务器的三种登录方法
购买阿里云ECS云服务器后如何登录?场景不同,云吞铺子总结大概有三种登录方式: 登录到ECS云服务器控制台 在ECS云服务器控制台用户可以更改密码、更换系统盘、创建快照、配置安全组等操作如何登录ECS云服务器控制台? 1、先登录到阿里云ECS服务器控制台 2、点击顶部的“控制台” 3、通过左侧栏,切换到“云服务器ECS”即可,如下图所示 通过ECS控制台的远程连接来登录到云服务器 阿里云ECS云服务器自带远程连接功能,使用该功能可以登录到云服务器,简单且方便,如下图:点击“远程连接”,第一次连接会自动生成6位数字密码,输入密码即可登录到云服务器上。
36407 0
242
文章
0
问答
文章排行榜
最热
最新
相关电子书
更多
JS零基础入门教程(上册)
立即下载
性能优化方法论
立即下载
手把手学习日志服务SLS,云启实验室实战指南
立即下载