第六周Java知识总结

目录

反射

获取一个类的字节码文件的方式

反射的方式:动态获取类的构造器

有一个ArrayList集合里面存储的都是String,ArrayList如何通过反射给里面存储Integer类型的元素?

反射的jdk动态代理


反射

反射:(Relection),一个类在加载运行状态的时候,可以动态获取正在运行的类(Class)

创建正在运行类的对象(构造器-Constructor)

使用正在运行的这个类的对象去给成员变量赋值(Field)

调用正在运行的这个类中成员方法(Method)

反射应用----Java设计模式

正射 ---- 就是我们自己书写的代码的时候,  类名  对象名  =  new  类名 ();

获取一个类的字节码文件的方式

        1)调用Object类的getClass方法

        2)任意Java类型的class属性

        3)Java提供类Class:表示正在运行的Java应用程序中的累的接口

        有一种静态方法:

                参数:类的完全限定名称。(包名。类名)

                public static Class<?> forName (String className);

public class Person {
    private String name ; //私有的姓名
    int age ; //默认修饰符的年龄
    private String address ; //住址

    //公共的无参构造方法
    public Person(){}

    //默认修饰符的带有两个参数的构造方法
    Person(String name,int age){
        this.name = name ;
        this.age = age ;
    }

    //私有的:带有三个参数的构造方法
    private Person(String name,int age,String address){
        this.name = name ;
        this.age = age ;
        this.address = address ;
    }

    //一堆成员方法
    //是否带参/是否有返回值
    public void show(String name){
        System.out.println(name) ;
    }
    private String method(int number){
        return "hello"+number ;
    }
    protected void function(){
        System.out.println("function Person...");
    }
    //默认修饰符
    String myFunction(){
        return "今天很nice!" ;
    }

    @Override
    public String toString() {
        return "Person{" +
                "name='" + name + '\'' +
                ", age=" + age +
                ", address='" + address + '\'' +
                '}';
    }
}
public class ReflectDemo {
    public static void main(String[] args) throws ClassNotFoundException {
        //创建当前类对象
        Person p = new Person() ;
        System.out.println(p.getClass()) ;//class com.qf.reflect_02.Person
        Class c2 = Person.class ;
        System.out.println(c2) ;
        System.out.println(p.getClass() ==c2) ;
        System.out.println("-----------------------------") ;
		//Class<?> c3 = Class.forName("Person");//参数必须:类的全限定名称
        Class<?> c3 = Class.forName("com.qf.reflect_02.Person");
        System.out.println(c3);
        System.out.println(c3==c2);
    }
}

反射的方式:动态获取类的构造器

public class ReflectDemo2 {
    public static void main(String[] args)  throws Exception{
        System.out.println("------反射的方式:动态获取类的构造器并创建实例----");
        //1)获取正在运行的类的字节码文件对象
        Class c = Class.forName("com.qf.reflect_02.Person");
      
        //2)获取指定的构造器的Constructor对象,创建当前类实例
        //public Constructor<T> getConstructor(Class<?>... parameterTypes)
        //获取指定的公共的构造方法的Constructor对象,参数:指定参数类型的Class类对象,如果没有参数,可以不写
                        //举例:String类型的参数---java.lang.String
                        //int---->java.lang.Integer
        Constructor con = c.getConstructor();
        //System.out.println(con);//public com.qf.reflect_02.Person()
        //Constructor提供一个方法
        //参数:通过构造器里面给当前正在运行的类的成员变量赋值:实际参数
        //返回T---Type:代表任意Java对象
        //public T newInstance(Object... initargs):创建当前类实例
        Object obj = con.newInstance() ; // 多态 类似于 --->Object obj = new  Person() ;
        System.out.println(obj);

        System.out.println("----通过有参构造方法当前类实例------------");
        
        //通过当前类的字节码文件对象获取指定的构造方法
        //参数是:当前参数类型的字节码文件 String--->String.class
        //public Constructor<T> getDeclaredConstructor(Class<?>... parameterTypes)
        Constructor con2 = c.getDeclaredConstructor(String.class, int.class, String.class);
        //System.out.println(con2);

        //构造器所在Constructor继承AccessibleObject 提供
        // public void setAccessible(boolean flag) :参数为true:取消Java语言访问检查
        con2.setAccessible(true);
        //public T newInstance(Object... initargs):创建当前类实例
        Object obj2 = con2.newInstance("穆宁雪", 21, "梵雪山");
        System.out.println(obj2);

    }
    //public static void get(int...a){ //a代表多个参数:可变参数(当不明确具体有多个参数的时候,可以使用...)
}

有一个ArrayList集合里面存储的都是String,ArrayList<String>如何通过反射给里面存储Integer类型的元素?

public class ReflectTest {
    public static void main(String[] args) throws Exception {

        //创建一个ArrayList
        ArrayList<String> arrayList = new ArrayList<>() ;
        arrayList.add("hello") ;
        arrayList.add("world") ;

        //通过反射的方式,给里面添加任何元素,调用add(Object obj)
        Class c = arrayList.getClass() ;

        //通过字节码文件对象获取add方法所在的Method类对象
        Method m = c.getDeclaredMethod("add", Object.class) ;

        //取消Java语言访问检查
        m.setAccessible(true) ;
        //直接调用方法,里面传入实际参数
        m.invoke(arrayList,100) ;
        m.invoke(arrayList,'A') ;
        System.out.println(arrayList);
    }
}

反射的jdk动态代理

代理设计模式---属于"结构型设计模式"
代理核心思想:代理角色帮助真实角色对他的业务功能进行增强!
   静态代理
   特点:代理角色和真实角色必须实现同一个接口!
   弊端:业务功能和 增强的功能没有完全分离!
   动态代理
    jdk动态代理--->jdk提供的
          java.lang.reflect.Proxy:动态代理类
          静态方法:

         public static Object newProxyInstance(
               ClassLoader loader, //获取接口实例的类加载器
               Class<?>[] interfaces,//实现的接口列表的字节码文件(代理类要的实现接口列表的Class)
                InvocationHandler h)//有代理实例调用 接口方法的处理程序:接口类型 throws IllegalArgumentException
              InvocationHandler:接口
  public Object invoke(Object proxy, Method method, Object[] args)
   参数1:调用该方法的代理实例
   参数2:调用该代理实例的接口方法的Method类对象
   参数3:调用接口方法中所有的参数,组成数组,没有参数,可不写
       cglib动态代理----不需要接口,基于类就可以实现动态代理
    必须提供第三方jar包  (cglib-3.3.0.jar)

针对用户的数据访问接口

public interface UserDao {

    /**
     * 添加用户操作
     */
    void add() ;

    /**
     * 修改用户
     */
    void update() ;

    /**
     * 删除用户
     */
    void delete() ;

    /**
     * 查询所有用户
     */
    void findAll() ;
}

针对用户的数据接口实现

public class UserDaoImpl  implements UserDao{
    /**
     * 添加用户操作
     */
    @Override
    public void add() {
        System.out.println("添加用户操作") ;
    }

    /**
     * 修改用户
     */
    @Override
    public void update() {
        System.out.println("修改用户") ;
    }

    /**
     * 删除用户
     */
    @Override
    public void delete() {
        System.out.println("删除用户") ;
    }

    /**
     * 查询所用
     */
    @Override
    public void findAll() {
        System.out.println("查询所有用户") ;
    }
}

优化实现类:多功能进行增强

public class UserDaoImpl2  implements UserDao{
    private  UserDao ud ;
    public UserDaoImpl2(UserDao ud){
        this.ud = ud ;
    }
    @Override
    public void add() {
        System.out.println("权限校验") ; //---->第三方提供的: 系统监控代码 shiro框架:权限框架/SpringSecurity权限框架
        //自己的业务功能
        ud.add() ;
        System.out.println("产生日志记录");
    }

    @Override
    public void update() {
        System.out.println("权限校验" ) ;
        //自己的业务功能
        ud.update(); ;
        System.out.println("产生日志记录");
    }

    @Override
    public void delete() {
        System.out.println("权限校验" ) ;
        //自己的业务功能
        ud.delete(); ;
        System.out.println("产生日志记录");
    }

    @Override
    public void findAll() {
        System.out.println("权限校验" ) ;
        //自己的业务功能
        ud.findAll(); ;
        System.out.println("产生日志记录");
    }
}

代理实例要调用接口方法的处理程序

//自定义一个类实现InvocationHandler接口
//实现invoke方法---->就是调用接口方法
public class MyInvocationHandler implements InvocationHandler {

    //声明Object变量
    private  Object  target ;
    public MyInvocationHandler(Object target){// 传入真实角色
        this.target =  target ;
    }

    /**
     * @param proxy  调用该方法的代理实例
     * @param method 调用该代理实例的接口方法的Method类对象
     * @param args 调用接口方法中所有的参数,组成数组,没有参数,可不写
     * @return 从代理实例上的方法调用返回的值
     * @throws Throwable 可能调用方法失败!
     */
    @Override
    public Object invoke(Object proxy, Method method, Object[] args)
            throws Throwable {
        System.out.println("操作业务功能之前,先权限校验!" );

        //反射的写法调用接口方法--add()/delete()/udate()/findAll()
        Object obj = method.invoke(target, args);

        System.out.println("操作业务功能之后,产生日志记录!");
        return obj; //方法的返回值
    }
}

对用户进行测试

public class UserTest {
    public static void main(String[] args) {
        //创建UserDao接口对象---子实现类创建
        UserDao ud = new UserDaoImpl() ; //ud:真实角色
        ud.add() ;
        ud.update() ;
        ud.delete() ;
        ud.findAll();
        System.out.println("------------------优化后:对业务功能增强(静态代理)-------------------") ;
        UserDaoImpl2 ud2 = new UserDaoImpl2(ud) ; //代理角色
        ud2.add() ;
        ud2.delete();
        ud2.update();
        ud2.findAll();

        System.out.println("---------------------JDK动态代理实现--------------------------------------------") ;

        //接口多态
        InvocationHandler handler = new MyInvocationHandler(ud) ;
        UserDao ud3 = (UserDao) Proxy.newProxyInstance(
                ud.getClass().getClassLoader(),//代理实例要实现的接口的字节码文件---类加载
                //代理实例要实现接口列表的Class--->Class类中--public 类<?>[] getInterfaces()
                ud.getClass().getInterfaces(),
                //代理实例调用接口方法的处理程序
                handler);

        ud3.add() ;
        ud3.delete() ;
        ud3.update() ;
        ud3.findAll() ;
    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值