反射与内省

反射

  • java反射机制是在运行状态中,对于任意一个类,都能知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意一个方法和属性,这种动态获取的信息以及动态调用对象方法的功能称为反射
  • 把类信息映射成对象

Class类

  • Class类是一切的反射根源

得到Class对象

  • Object类中的getClass()方法
  • 类.class
  • 通过Class类的forName方法
public class ReflectionDemo {
    public void test1(){
        //通过对象的getClass()方法
        Dog dog = new Dog("wangwang",4,"白色");
        Class aClass = dog.getClass();

        //通过类.class
        Class dogClass = Dog.class;

        //通过Class.forName方法
        try {
            Class aClass1 = Class.forName("com.vince.Dog");
        } catch (ClassNotFoundException e) {
            throw new RuntimeException(e);
        }
    }
}

对象的实例化操作

  • 调用无参构造进行实例化

​ public T newInstance() throws InstantiationException,IllegalAccessException

  • 调用有参构造进行实例化

​ public Constructor<?>[] getConstructors() throws SecurityException

public class ReflectionDemo {

    /**
     * 获取Class对象的三种形式
     */
    @Test
    public void test1(){
        //通过对象的getClass()方法
        Dog dog = new Dog("wangwang",4,"白色");
        Class aClass = dog.getClass();

        //通过类.class
        Class dogClass = Dog.class;

        //通过Class.forName方法
        try {
            Class aClass1 = Class.forName("com.vince.Dog");
        } catch (ClassNotFoundException e) {
            throw new RuntimeException(e);
        }
    }

    /**
     * 通过反射来实例化对象
     */
    @Test
    public void test2(){
        Class<Dog> dogClass = Dog.class;
        try {
            //通过Class对象实例化类对象,调用默认无参构造方法
            Dog dog = ((Dog) dogClass.newInstance());
        } catch (InstantiationException e) {
            throw new RuntimeException(e);
        } catch (IllegalAccessException e) {
            throw new RuntimeException(e);
        }
    }

    @Test
    public void test3(){
        Class<Dog> dogClass = Dog.class;
        Constructor<?>[] constructors = dogClass.getConstructors();
        for (int i = 0; i < constructors.length; i++) {
            System.out.println(constructors[i].getName());
            System.out.println(constructors[i].getParameterCount());
        }
        try {
            //获取一个指定的构造方法
            Constructor<Dog> constructor = dogClass.getConstructor(String.class, int.class, String.class);
            //调用带参数的构造器来实例化对象
            Dog dog = constructor.newInstance("小白", 5, "白色");
        } catch (NoSuchMethodException e) {
            throw new RuntimeException(e);
        } catch (InvocationTargetException e) {
            throw new RuntimeException(e);
        } catch (InstantiationException e) {
            throw new RuntimeException(e);
        } catch (IllegalAccessException e) {
            throw new RuntimeException(e);
        }
    }

    @Test
    public void test4(){
        Class<Dog> dogClass = Dog.class;
        //获取非私有属性
        Field[] fields = dogClass.getFields();
        System.out.println(fields.length);

        //获取所有属性(包括私有属性)
        Field[] declaredFields = dogClass.getDeclaredFields();
        System.out.println(declaredFields.length);
        for (int i = 0; i < declaredFields.length; i++) {
            int modifiers = declaredFields[i].getModifiers();
            System.out.println(Modifier.toString(modifiers)+" "+declaredFields[i].getType()+" "+declaredFields[i].getName());
        }
    }

}

通过Class类取得类信息

  • 取得类所在的包
public Package getPackage()  //得到一个类所在的包
public String getName()		//得到名字
  • 取得一个类中的全部方法
public Method[] getMethods();
public int getModifiers();		//Modifier.toString(mod);  //还原修饰符
public Class<?> getReturnType();
public Class<?>[] getParameterTypes();
public Class<?>[] getExceptionTypes();
public static String toString(int mod);
  • 取得一个类中的全部属性
public Field[] getFields();
public Field[] getDeclaredFields();
public Class<?> getType();
public int getModifiers();
public String getName()
  • 通过Class类调用属性或方法
//调用类中的方法  传入实例化对象,以及具体的参数内容
public Object invoke(Object obj,Object..args);  
//直接调用属性
public Object get(Object obj);
//设置属性,等同于使用“=”完成操作
public void set(Object obj,Object value)
//让属性对外部可见
public void setAccessible(boolean flag)
    @Test
    public void test5(){
        Dog dog = new Dog("wangwang",4,"white");
        Class<Dog> dogClass = Dog.class;
        //获取类的包名
        Package aPackage = dogClass.getPackage();
        System.out.println(aPackage.getName());
        //获取公共的方法,包括继承的公有方法
        Method[] methods = dogClass.getMethods();
        for (int i = 0; i < methods.length; i++) {
            System.out.println(methods[i]);
            if(methods[i].getName().equals("toString")){
                try {
                    String s = (String) methods[i].invoke(dog);
                    System.out.println(s);
                } catch (IllegalAccessException e) {
                    throw new RuntimeException(e);
                } catch (InvocationTargetException e) {
                    throw new RuntimeException(e);
                }
            }
        }
        //访问私有方法 获取到本类中定义的所有方法(不包括父类)
        Method[] declaredMethods = dogClass.getDeclaredMethods();
        for (int i = 0; i < declaredMethods.length; i++) {
            System.out.println(declaredMethods[i]);
            if(declaredMethods[i].getName().equals("set")){
                //设置 私有方法可以被访问(去除访问修饰符的检查)
                declaredMethods[i].setAccessible(true);

                try {
                    declaredMethods[i].invoke(dog);
                } catch (IllegalAccessException e) {
                    throw new RuntimeException(e);
                } catch (InvocationTargetException e) {
                    throw new RuntimeException(e);
                }
            }
        }
    }

动态代理模式

  • 通过代理类:Proxy的代理,接口和实现类之间可以不直接发生联系,而可以在运行期(Runtime)实现动态关联
  • 主要是使用java.lang.reflect包中的两个类
  • 动态代理:在运行时生成class
//InvocationHandler类 [代理类、被代理的方法、被代理的方法的参数组]
public Object invoke(Object obj,Method method,Object[] obs)
    
//Proxy类
protected Proxy(InvocationHandler h);
static Class getProxyClass(ClassLoader loader,Class[] interfaces);
static Object newProxyInstance(ClassLoader loader,Class[] interfaces,InvocationHandler)
/**
 * 动态生成一个代理对象
 */
public class CreateProxy implements InvocationHandler {

    private Object target;  //被代理的对象

    //创建代理对象的方法
    public Object create(Object target){
        this.target = target;
        Object o = Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(), this);
        return o;
    }


    /**
     * 代理对象要执行的方法
     * @param proxy 代理类对象
     * @param method 被代理对象的方法
     * @param args 被代理对象方法的参数
     * @return
     * @throws Throwable
     */
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println("上海外寻找客户需要的产品...");
        System.out.println("跟客户确定物品");
        method.invoke(target,args);
        System.out.println("完成本次海淘");
        return null;
    }
}

public interface Subject {
    public void shopping();
}
/**
 * 动态生成一个代理对象
 */
public class CreateProxy implements InvocationHandler {

    private Object target;  //被代理的对象

    //创建代理对象的方法
    public Object create(Object target){
        this.target = target;
        Object o = Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(), this);
        return o;
    }


    /**
     * 代理对象要执行的方法
     * @param proxy 代理类对象
     * @param method 被代理对象的方法
     * @param args 被代理对象方法的参数
     * @return
     * @throws Throwable
     */
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println("上海外寻找客户需要的产品...");
        System.out.println("跟客户确定物品");
        method.invoke(target,args);
        System.out.println("完成本次海淘");
        return null;
    }
}
    @Test
    public void testProxy(){
        CreateProxy cp = new CreateProxy();  //创建代理对象的对象
        Subject person = new Person();
        Subject proxy = (Subject) cp.create(person);
        proxy.shopping();
    }

类加载器

  • JVM将类加载分为三个步骤:
    • 装载【Load】—— 查找并加载类的二进制数据
    • 链接【Link】
      • 验证——确保被加载类的正确性
      • 准备——为类的静态变量分配内存,并将其初始化为默认值
      • 解析——把类中的符号引用转换为直接引用
    • 初始化【Initialize】——为类的静态变量赋予正确的初始值
  • 类的初始化
    • 创建类的实例,new一个对象
    • 访问某个类或接口的静态变量,或者对该静态变量赋值
    • 调用类的静态方法
    • 反射【Class.forName(“”)】
    • 初始化一个类的子类(会首先初始化子类的父类)
    • JVM启动时标明的启动类,即文件名和类名相同的那个类
  • 类的加载
    • 将类的.class文件中的二进制数据读入到内存中,将其放在运行时数据区的方法区内,然后在堆区创建一个这个类的java,lang,Class对象,用来封装类在方法区中类的对象

JavaBean

  • java组件,一个类【能够被IDE构建工具侦测其属性和事件】

  • getXxx()和setXxx()方法

  • 对于布尔型属性,get可以替换为is

  • 普通方法必须是public

  • 对于事件,要使用Swing中的处理监听器的方式,addWindowListener、removeWindowListener

Download
在这里插入图片描述

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

public class Emp {
    private String name;
    private int age;
    private int salary;

    public String getInfo(){
        return "name="+name+",age="+age+",salary="+salary;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    public int getSalary() {
        return salary;
    }

    public void setSalary(int salary) {
        this.salary = salary;
    }
}
public class BeanTest {

    @Test
    public void test(){
        //从客户端获取到的数据是这样的
        String name = "bin";
        String age = "18";
        String salary = "20000";

        Emp emp = new Emp();

        try {
            BeanUtils.setProperty(emp,"name",name);
            BeanUtils.setProperty(emp,"age",age);
            BeanUtils.setProperty(emp,"salary",salary);
        } catch (IllegalAccessException e) {
            throw new RuntimeException(e);
        } catch (InvocationTargetException e) {
            throw new RuntimeException(e);
        }
        System.out.println(emp.getInfo());
    }

}

内省

  • Introspector是java语言对Bean类属性、事件的一种缺省处理方法

  • java中提供了一套API用来访问某个属性的getter/setter方法,通过这些API可以使你不需要了解这个规则,这些API存放于包java.beans中,一般的做法是通过类Introspector的getBeanInfo方法来获取某个对象的BeanInfo信息,然后通过BeanInfo来获取属性的描述器(PropertyDescriptor),通过这个属性描述器就可以获取某个属性对应的getter/setter方法,然后我们就可以通过反射机制来调用这些方法

  • 相关API

    • Introspector类
    static BeanInfo getBeanInfo(Class<?> beanClass);  //在java bean上进行内省,了解其所有属性、公开的方法和事件
    
    • BeanInfo类——提供有关其bean的方法、属性、事件等显式信息
    MethodDescriptor[] getMethodDescriptor();  //获得beans MethodDescriptor
    PropertyDescriptor[] getPropertyDescriptor();		//获得beans getPropertyDescriptor
    
  • PropertyDescriptor类

    • 描述Java Bean通过应对存储器方法导出的一个属性
    Method getReadMethod();		//获得应该用于读取属性值的方法
    Method getWriteMethod();		//获得应该用于写入属性值的方法
    
  • MethodDescriptor类

    • 描述一种特殊方法——Java Bean支持从其他组件对其进行外部访问
    Method getMethod()  //获得此MethodDescriptor封装的方法
    
public class Config {
    private String username;
    private String password;
    private String url;

    public String getUsername() {
        return username;
    }

    public void setUsername(String username) {
        this.username = username;
    }

    public String getPassword() {
        return password;
    }

    public void setPassword(String password) {
        this.password = password;
    }

    public String getUrl() {
        return url;
    }

    public void setUrl(String url) {
        this.url = url;
    }

    public Config(String username, String password, String url) {
        this.username = username;
        this.password = password;
        this.url = url;
    }

    public Config() {
    }

    @Override
    public String toString() {
        return "Config{" +
                "username='" + username + '\'' +
                ", password='" + password + '\'' +
                ", url='" + url + '\'' +
                '}';
    }
}
bean.name=com.vince.Introspector.Config
bean.username=admin
bean.password=123
bean.url=http://www.163.com
public class BeanFactory {

    private static Properties prop = new Properties();

    //使用静态代码块读取配置文件
    static {
        InputStream in = Thread.currentThread().getContextClassLoader()
                .getResourceAsStream("com/vince/Introspector/config.properties");

        try {
            prop.load(in);
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }

    /**
     * 获取一个Bean
     */
    public static Object getBean(String name){
        Object bean = null;
        String beanName = prop.getProperty(name);

        try {
            Class<?> aClass = Class.forName(beanName);
            bean = aClass.newInstance();

            //通过类信息获取javaBean的描述信息
            BeanInfo beanInfo = Introspector.getBeanInfo(aClass);
            //通过javaBean描述信息,获取该类的所有属性描述器
            PropertyDescriptor[] propertyDescriptors = beanInfo.getPropertyDescriptors();

            for (int i = 0; i < propertyDescriptors.length; i++) {
                String propertyName = propertyDescriptors[i].getName();
                Method writeMethod = propertyDescriptors[i].getWriteMethod();

                if("username".equals(propertyName)){
                    //调用属性的set方法
                    writeMethod.invoke(bean,prop.getProperty("bean.username"));
                }else if("password".equals(propertyName)){
                    writeMethod.invoke(bean,prop.getProperty("bean.password"));
                }else if("url".equals(propertyName)){
                    writeMethod.invoke(bean,prop.getProperty("bean.url"));
                }

            }

        } catch (ClassNotFoundException e) {
            throw new RuntimeException(e);
        } catch (InstantiationException e) {
            throw new RuntimeException(e);
        } catch (IllegalAccessException e) {
            throw new RuntimeException(e);
        } catch (IntrospectionException e) {
            throw new RuntimeException(e);
        } catch (InvocationTargetException e) {
            throw new RuntimeException(e);
        }

        return bean;
    }


}
public class BeanTest {

    @Test
    public void getBeanTest(){
        Config bean = (Config) BeanFactory.getBean("bean.name");
        System.out.println(bean);
    }

}

AOP框架

  • 面向切面编程
  • 使用场景:权限、缓存、错误处理、调试、记录跟踪、持久化、同步、事务

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-USIYcp6l-1683448449277)(重温java.assets/image-20230507161639320.png)]

public interface IManager {
    public void add(String item);
}
public class IManagerImpl implements IManager {
    private ArrayList<String> list = new ArrayList<>();

    @Override
    public void add(String item) {
        list.add(item);
        System.out.println(item);
    }
}
/**
 * 通知
 */
public interface Advice {
    public void beforeAdvice();
    public void afterAdvice();
}
public class LogAdvice implements Advice{

    @Override
    public void beforeAdvice() {
        System.out.println("start time:"+System.currentTimeMillis());
    }

    @Override
    public void afterAdvice() {
        System.out.println("end time:"+System.currentTimeMillis());
    }
}
public class ProxyFactoryBean implements InvocationHandler {
    private Object target;
    private Advice advice;

    public Object getProxy(){
        Object proxy = Proxy.newProxyInstance(target.getClass().getClassLoader(),target.getClass().getInterfaces(),
                this);
        return proxy;
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        advice.beforeAdvice();
        Object obj = method.invoke(target,args);
        advice.afterAdvice();
        return obj;
    }

    public Object getTarget() {
        return target;
    }

    public void setTarget(Object target) {
        this.target = target;
    }

    public Advice getAdvice() {
        return advice;
    }

    public void setAdvice(Advice advice) {
        this.advice = advice;
    }
}
public class BeanFactory {

    Properties prop = new Properties();
    public BeanFactory(InputStream in) {
        try {
            prop.load(in);
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }

    /**
     * 获取一个bean示例
     */
    public Object getBean(String name){
        String className = prop.getProperty(name);
        Object bean = null;

        try {
            //获取ProxyFactoryBean的class对象
            Class<?> aClass = Class.forName(className);
            //实例化对象
            bean = aClass.newInstance();
            //根据配置文件实例化target和advice对象
            Object target = Class.forName(prop.getProperty(name+".target")).newInstance();
            Object advice = Class.forName(prop.getProperty(name+".advice")).newInstance();
            //通过内省实现对ProxyFactoryBean的属性赋值
            BeanInfo beanInfo = Introspector.getBeanInfo(aClass);
            PropertyDescriptor[] propertyDescriptors = beanInfo.getPropertyDescriptors();
            for(PropertyDescriptor pd:propertyDescriptors){
                String propertyName = pd.getName();
                Method writeMethod = pd.getWriteMethod();
                if("target".equals(propertyName)){
                    writeMethod.invoke(bean,target);
                }else if("advice".equals(propertyName)){
                    writeMethod.invoke(bean,advice);
                }
            }

        } catch (ClassNotFoundException e) {
            throw new RuntimeException(e);
        } catch (InstantiationException e) {
            throw new RuntimeException(e);
        } catch (IllegalAccessException e) {
            throw new RuntimeException(e);
        } catch (IntrospectionException e) {
            throw new RuntimeException(e);
        } catch (InvocationTargetException e) {
            throw new RuntimeException(e);
        }

        return bean;
    }
}
bean.target=com.vince.aop.IManagerImpl
bean.advice=com.vince.aop.LogAdvice
bean=com.vince.aop.ProxyFactoryBean
public class AOPTest {

    @Test
    public void test(){
        //读取配置文件
        InputStream in = Thread.currentThread().getContextClassLoader()
                .getResourceAsStream("com/vince/aop/bean.properties");
        //创建Bean的工厂对象
        BeanFactory beanFactory = new BeanFactory(in);
        //获取代理对象
        ProxyFactoryBean proxyFactoryBean = (ProxyFactoryBean) beanFactory.getBean("bean");
        IManager proxy = (IManager) proxyFactoryBean.getProxy();
        proxy.add("我是一只猫");
    }

}

单例模式优化

  • 使用同步保证线程安全 synchronized
  • 使用volatile关键字 【volatile提醒编译器它后面定义的变量随时都可能改变,因此编译后的程序每次需要存储或读取这个变量的时候,都会直接从变量地址中读取数据,如果没有volatile关键字,编译器可能优化读取和存储,可能暂时使用寄存器中的值,如果这个变量由别的程序更新了的话,将出现不一致的现象】
  • 防止反射调用私有构造方法
  • 让单例类序列化安全
public class Singleton {
    
    private volatile static Singleton singleton = null;
    private Singleton(){
        if(singleton != null){
            throw new RuntimeException("此对象为单例模式,已经被实例化了");
        }
    }
    public static Singleton getInstance(){
        if(singleton == null){
            synchronized (Singleton.class){
                if(singleton == null){
                    singleton = new Singleton();
                }
            }
        }
        return singleton;
    }
    
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值