【Java基础26】反射,动态代理,类加载器,JavaBean,内省,AOP,单例模式优化

一、什么是反射

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

二、Class类:

Class类-------很多的类

得到Class类的对象有三种方式:

1、Object类中的getClass()方法

2、类.class

3、通过Class类的forName方法

import org.junit.Test;
//显示程序包org.junit不存在,重启解决
import java.lang.reflect.*;

//测试类,导入junit4-12包
public class Refliction {

    //获取包
    @Test
    public void test05(){
        Dog d=new Dog("heihei",5,"black");
        Class<Dog> dogClass = Dog.class;
        Package aPackage = dogClass.getPackage();
        System.out.println(aPackage);

        Method[] methods = dogClass.getMethods();
        for (int i = 0; i < methods.length; i++) {
            //获取所有公共的方法,包括继承的方法
            System.out.println(methods[i].getName());
            if(methods[i].getName().equals("toString")){
                try {
                    String invoke = (String)methods[i].invoke(d);//invoke第一个参数指定调用方法的对象
                    System.out.println(invoke);
                } catch (IllegalAccessException e) {
                    e.printStackTrace();
                } catch (InvocationTargetException e) {
                    e.printStackTrace();
                }
            }
        }
        //获取本类中公有+私有的方法,不包括父类的方法
        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(d);//抛出一个异常,调用私有方法
                } catch (IllegalAccessException e) {
                    e.printStackTrace();
                } catch (InvocationTargetException e) {
                    e.printStackTrace();
                }
            }
        }

    }

    //获取所有的属性
    @Test
    public void test04(){
        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].getName());
        }
    }

    //获取所有构造方法
    @Test
    public void tets03(){
        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("xiaobai", 3, "black");
        } catch (NoSuchMethodException e) {
            e.printStackTrace();
        } catch (InvocationTargetException e) {
            e.printStackTrace();
        } catch (InstantiationException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        }
    }

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

    //获取Class的三种方式
    @Test
    public void test01(){
        //通过对象的getClass方法
        Dog dog=new Dog("huahua",1,"white");
        Class class1 =dog.getClass();


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

        //通过Class.forName方法
        try {
            Class<?> aClass = Class.forName("com.vince.Dog");
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
    }

}

//Dog类
public class Dog{
    public int Type;
    private String name;
    private int age;
    private String color;

    private void set(){
        System.out.println("私有set方法");
    }

    protected  void get(){
        System.out.println("保护get方法");
    }
    @Override
    public String toString() {
        return "Dog{" +
                "name='" + name + '\'' +
                ", age=" + age +
                ", color='" + color + '\'' +
                '}';
    }

    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 String getColor() {
        return color;
    }

    public void setColor(String color) {
        this.color = color;
    }

    public Dog(String name, int age, String color) {
        this.name = name;
        this.age = age;
        this.color = color;
    }

    public Dog() {
    }
}

三、动态代理

所谓动态代理,即通过代理类:Proxy的代理,接口和实现类之间不可以直接发生联系,而可以在运行期实现动态关联。

Java动态代理主要是使用java.lang.reflict包中的两个类。

InvocationHandler类 、Proxy类

动态代理在运行时生成class,所以我们必须提供一组interface,然后告诉他class已经实现了这些interface,而且在生成Proxy时,必须给它提供一个handler,r让他接管实际的工作。

//interface Subject
package proxy;

public interface Subject {
    void shopping();
}

//class Person
package proxy;

public class Person implements Subject{
    public void shopping(){
        System.out.println("付款,拿下一辆BBA");
    }
}

//Class CreateProxy
package proxy;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

//动态生成一个代理对象
public class CreateProxy implements InvocationHandler {
    public Object target;
    //创建代理对象的方法
    public Object createProxy(Object target){
        this.target=target;
        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 {
        System.out.println("寻找客户所需要的产品...");
        System.out.println("跟客户确定要买的产品...");
        method.invoke(target,args);
        System.out.println("完成本次寻找");
        return null;
    }
}

//class TestDemo
import org.junit.Test;
import proxy.CreateProxy;
import proxy.Person;
import proxy.Subject;

public class TestDemo {
    @Test
    public void testProxy(){
        CreateProxy cp=new CreateProxy();//创建代理对象的对象
        Subject person=new Person();
        Subject proxy = (Subject) cp.createProxy(person);
        proxy.shopping();
    }
}

四、类加载器原理分析

1、类的加载过程

三个步骤:

装载:查找并加载类的二进制数据

链接:验证(确保被加载类的正确性)、准备(为类的静态变量分配内存,并将其初始化为默认值)、解析(把类中的符号引用转换为直接引用)

初始化:为类的静态变量赋予正确的初始值

2、类的初始化

(1)创建类的实例,也就是new一个对象时。

(2)访问某个类或接口的静态变量,或者对该静态变量赋值。

(3)调用类的静态方法。

(4)反射。

(5)初始化一个类的子类。

(6)JVM启动时标明的启动类,即文件名和类名相同的那个类。

3、类的加载

指的是将类的class文件中的二进制数据读入到内存中,将其放在运行时数据区的方法区内,然后在堆区创建一个这个类的java.lang.Class对象,用来封装类在方法区类的对象。

五、JavaBean

Java组件,广泛的理解就是一个类,对于组件来说,关键在于要具有“能够被IDE构建工具(Maven等)侦测其属性和事件”的能力。

Bean的普通方法必须是public的

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

//class Emp
package bean;

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


    @Override
    public String  toString() {
        return "Emp{" +
                "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 Emp(String name, int age, int salary) {
        this.name = name;
        this.age = age;
        this.salary = salary;
    }

    public Emp() {
    }
}

//class BeanTestDemo 
package bean;

import org.apache.commons.beanutils.BeanUtils;
import org.junit.Test;

import java.lang.reflect.InvocationTargetException;

public class BeanTestDemo  {
    @Test
    public void test(){
        String name="bin";
        String age="19";
        String salary="10000";
        Emp e=new Emp();
        try {
            BeanUtils.setProperty(e,"name",name);
            BeanUtils.setProperty(e,"age",age);
            BeanUtils.setProperty(e,"salary",salary);
        } catch (IllegalAccessException ex) {
            ex.printStackTrace();
        } catch (InvocationTargetException ex) {
            ex.printStackTrace();
        }
        System.out.println(e.toString());
    }
}

六、内省

内省是Java语言对Bean类属性、事件的一种缺省处理方法。

Introspector类为通过工具学习有关受目标JavaBean支持的属性、事件和方法的知识提供了一个标准方法。

BeanInfo类

PropertyDescriptor类

MethodDescriptor类

//config.properties
bean.name=introspector.Config
bean.username=admin
bean.password=123
bean.url=http://www.baidu.com

//class Config
package introspector;

public class Config {
    private String username;
    private String password;
    private String url;

    @Override
    public String toString() {
        return "Config{" +
                "username='" + username + '\'' +
                ", password='" + password + '\'' +
                ", url='" + 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() {
    }
}


//class BeanFactory 
package introspector;

import java.beans.BeanInfo;
import java.beans.IntrospectionException;
import java.beans.Introspector;
import java.beans.PropertyDescriptor;
import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Properties;

import static java.lang.Class.forName;

//通过内省API装配一个Bean对象,其值通过配置文件获取
public class BeanFactory {
    private static Properties pp=new Properties();
    //使用静态代码块读取配置文件
    static{
        InputStream resourceAsStream = Thread.currentThread().getContextClassLoader().
                getResourceAsStream("introspector/Config.properties");
        try {
            pp.load(resourceAsStream);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    public static Object getBean(String name){
        Object bean=null;
        String property = pp.getProperty(name);
        try {
            Class<?> aClass = Class.forName(property);
            bean = aClass.newInstance();
            //内省,通过类信息获取JavaBean的描述信息
            BeanInfo beanInfo = Introspector.getBeanInfo(aClass);
            //通过Javabean描述信息,获取该类的所有属性描述器
            PropertyDescriptor[] propertyDescriptors = beanInfo.getPropertyDescriptors();
            for (int i = 0; i < propertyDescriptors.length; i++) {
                String name1 = propertyDescriptors[i].getName();
                Method writeMethod = propertyDescriptors[i].getWriteMethod();
                if("username".equals(name1)){
                    //调用属性set方法
                    writeMethod.invoke(bean,pp.getProperty("bean.username"));
                }else if("password".equals(name1)){
                    writeMethod.invoke(bean,pp.getProperty("bean.password"));
                }else if("url".equals(name1)){
                    writeMethod.invoke(bean,pp.getProperty("bean.url"));
                }
            }
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        } catch (IntrospectionException e) {
            e.printStackTrace();
        } catch (InstantiationException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (InvocationTargetException e) {
            e.printStackTrace();
        }
        return bean;
    }
}


//class BeanTest
package introspector;

import org.junit.Test;

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

七、AOP

AOP的概念:Aspect Oriented Programming(面向切面编程),不是核心代码。

可配置AOP框架实现

AOP框架的简单实现:

核心业务(一个接口,一个实现类)

切面(一个接口,一个实现类)

配置文件

动态代理类(ProxyFactoryBean)

装配对象类 (BeanFactory)

测试类

//配置文件
bean.target=aop.ImanagerImpl
bean.advice=aop.LogAdvice
bean=aop.ProxyFactoryBean

//核心业务接口
package aop;

public interface Imanager {
    public void add(String item);
}

//核心业务实现类
package aop;

import java.util.ArrayList;
import java.util.List;
//核心业务类
public class ImanagerImpl implements Imanager{
    private ArrayList<String> list=new ArrayList<>();
    @Override
    public void add(String item) {
        //将切面代码交给代理完成
//        System.out.println("add start--"+System.currentTimeMillis());
        list.add(item);
        System.out.println("item");
//        System.out.println("add end--"+System.currentTimeMillis());
    }
}


//切面接口
package aop;

//进入业务之前通知
public interface Advice {
    public void beforeAdvice();
    public void afterAdvice();

}

//切面实现类
package aop;
//切面类
public class LogAdvice  implements Advice{

    @Override
    public void beforeAdvice() {
        System.out.println("开始时间:"+System.currentTimeMillis());
    }

    @Override
    public void afterAdvice() {
        System.out.println("结束时间:"+System.currentTimeMillis());
    }
}

//动态代理类
package aop;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

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

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

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

//装配对象类
package aop;

import java.beans.BeanInfo;
import java.beans.IntrospectionException;
import java.beans.Introspector;
import java.beans.PropertyDescriptor;
import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Properties;

public class BeanFactory {
    Properties prop=new Properties();
    public BeanFactory(InputStream in){
        try {
            prop.load(in);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
    //获取一个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) {
            e.printStackTrace();
        } catch (InstantiationException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (IntrospectionException e) {
            e.printStackTrace();
        } catch (InvocationTargetException e) {
            e.printStackTrace();
        }
        return bean;
    }
}

//测试类
package aop;

import org.junit.Test;

import java.io.InputStream;

public class AOPTest {
    @Test
    public void test(){
        //读取配置文件
        InputStream in = Thread.currentThread().getContextClassLoader().getResourceAsStream("aop/bean.properties");
        //创建bean的工厂类对象
        BeanFactory beanFactory = new BeanFactory(in);
        //获取代理对象
        ProxyFactoryBean proxyFactoryBean =(ProxyFactoryBean) beanFactory.getBean("bean");
        Imanager proxy = (Imanager) proxyFactoryBean.getProxy();
        proxy.add("我真棒 ");
    }
}

AOP使用场景:封装横切关注点

具体场景:权限、缓存、 错误处理、调试、记录跟踪、持久化、同步、事务等。

八、单例模式优化

/*单例模式优化:
1、使用同步保证多线程安全问题
2、让单例类序列化安全
3、防止反射调用私有构造方法
4、volatile关键字保证变量一致性*/

package singleton;

import java.io.Serializable;

public class Singleton implements Serializable {//让单例类可以被序列化
    private volatile static Singleton singleton;//volatile关键字保证变量的一致性
    private Singleton() {
        //防止反射调用私有构造方法
        if(singleton!=null){
            throw new RuntimeException("此类对象是单例模式,已经被实例化!");
        }
    }
    public static Singleton getInstance(){
        //解决多线程访问的安全问题
        if(singleton==null) {//判断防止已经new过
            synchronized (Singleton.class) {
                if (singleton == null) {
                    singleton = new Singleton();
                }
            }
        }
        return singleton;
    }


}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值