反射机制(动态代理、泛型)、握手挥手

一、反射机制 

Java反射机制_Benett-Chen的博客-CSDN博客

前言

反射机制是学习编程过程中必须掌握的一项本领,用到反射机制最多的地方就是框架,它能够提高代码的灵活性和可扩展性,像 Spring/Spring Boot、MyBatis 等框架中大量使用了动态代理,而动态代理的实现依赖反射。比如在用eclipse编程时,当你按下快捷键时,出现的提示就是通过反射来实现的。

什么是反射呢

Java反射机制可以在运行时动态地获取类的信息并操作类的成员,实现动态加载类(编译时刻加载类是静态加载、运行时刻加载类是动态加载、创建实例、调用方法以及访问字段、动态代理等功能。在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意一个方法和属性

反射有哪些作用呢

反射的作用和使用场景

这么说,通过反射可以获取一个类的所有信息,比如成员变量,成员函数,构造方法以及父类的泛型,生成动态代理

AOP、拦截器(拦截器是AOP思想的具体实现)、IOC、注解的实现、tomcat调用具体的servlet、HandlerAdapter调用具体的处理器Handler(Handler,也叫后端控制器即Controller)、子类获取父类的泛型、等都是基于反射

在单元测试中,我们可以使用反射技术来访问私有或受保护的类成员,使测试更加全面

许多Java序列化和反序列化工具都是基于Java反射机制实现的,例如ObjectInputStream和ObjectOutputStream,ObjectInputStream类的readObject()方法是一个私有方法,在反序列化过程中,Java虚拟机会通过反射机制调用该方法,反序列化不会调用构造函数,反射会调用构造函数

Spring框架中,IOC也是使用了反射机制实现的。当我们在配置文件中定义了一个Bean时,Spring就会根据该Bean的配置信息,利用反射机制创建出该Bean的实例,并将其注入到需要该Bean的地方

通常工厂设计模式都会用到反射,工厂(

定义一个工厂类,用于根据传入的名称生成相应的 bean 实例,
在工厂类中,使用 Java 的反射机制获取指定名称的类,并创建相应实例作为 bean 返回。

在使用反射时,通常结合配置文件会使程序更加灵活,比如通过配置文件来读取数据库连接信息,反射+泛型+配置文件,会使得我们所编写的代码更加灵活,修改起来十分容易。

动态代理(Dynamic Proxy)

是一种在运行时动态生成代理对象的技术。它是一种设计模式,用于在不修改原始对象的情况下,通过代理对象来间接访问原始对象,并在访问前后执行额外的操作。动态代理通常用于实现横切关注点(cross-cutting concerns),如日志记录、性能监控、事务管理等。通过反射,可以动态地创建代理对象,并在代理对象上调用方法,从而实现动态代理的功能。

获取父类的泛型
前言
1.通配符限定

<? extends T>:即传入实际的类必须是T或者T的子类

<? super T>:即传入实际的类必须是T或者T的父类

2.类型擦除

类型擦除指的是,你在给类型参数<T>赋值时,编译器会将实参类型擦除为Object(这里假设没有限定符,限定符下面会讲到)

所以这里我们要明白一个东西:虚拟机中没有泛型类型对象的概念,在它眼里所有对象都是普通对象。比如下面的代码:



获取父类的泛型

获取父类的泛型  指的是  获取(子类继承父类时指定的)父类的泛型,即

class Son extends Father<String,Integer>{ 

,而不是泛型类的类型

class Son <T extends Father> { 

package com.genertech.plm.aia.portaladmin.entity;

import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;

public class TestGeneric {

  //泛型形参:<T,U>
  class Father<T,U>{

  }
  //子类继承父类并指定泛型实参:<String,Integer>
  class Son extends Father<String,Integer>{

  }

  public static void main(String[] args) {
    //需求:在运行时,获取Son类型的泛型父类的泛型形参<String,Integer>

    //(1)还是先获取Class对象
    Class clazz = Son.class;//四种形式任意一种都可以

    //(2)获取泛型父类 -- getSuperclass()只能得到父类名,无法得到父类的泛型形参列表
    // Class superclass = clazz.getSuperclass();
    Type type = clazz.getGenericSuperclass();

    // 泛型父类Father<String,Integer>属于ParameterizedType
    ParameterizedType pt = (ParameterizedType) type;

    //(3)获取泛型父类Father<String,Integer>的泛型形参列表
    Type[] typeArray = pt.getActualTypeArguments();
    for (Type type2 : typeArray) {
      System.out.println(((Class)type2).getName());
      
      //【输出(子类指定的)父类的泛型】:
      //java.lang.String
      //java.lang.Integer
    }
  }
}

1.反射机制动态加载获取类有4种方法

User user = new User();
//第一种方式: 
Class c1 = User.class;
System.out.println("c1-->"+c1);

//第二种方式: 
Class c2 = user.getClass();
System.out.println("c2-->"+c2);

//第三种方式: 
Class c3 = Class.forName("cn.benett.reflection.User");
System.out.println("c3-->"+c3);
//可以通过类的类型创建该类的实例对象
User u = (User)c3.newInstance();
System.out.println("u-->"+u);

//第四种方式:通过通过类加载器得到,ClassLoader.getSystemClassLoader()
//用得很少,基本只有底层加载类时会用到,我们一般不用,只做了解。
Class c4 =  ClassLoader.getSystemclassLoader().loadclass("java.util.ArrayList");

运行结果:

如何获取Class对象?

  1. 使用Class.forName("全类名")Class c3 = Class.forName("cn.benett.reflection.User");。
  2. 通过对象的getClass()方法Class c2 = user.getClass();
  3. 调用类的class属性Class c1 = User.class;
  4. 通过类加载器Class c4 =  ClassLoader.getSystemclassLoader().loadclass("java.util.ArrayList");

通过反射创建对象的方法?

  • 1.通过类对象的.newInstance方法。【使用Class对象的newInstance()方法来创建类的实例,这种方式要求该Class对象的对应类有默认构造器即无参构造器,执行newInstance()实际上是利用默认构造器来创建该类的实例。】
  • 2.通过类对象的构造器对象的.newInstance方法。【先使用Class对象获取到Constructor对象,再调用Constructor对象的newInstance()方法来创建对应Class对象对应类的实例。采用这种方法可以指定构造函数来创建。】

如何通过反射获取和设置对象私有字段的值?

  • 先通过getDeclaredFields();方法获取属性列表。
  • 再通过field.setAccessible(true);打开访问权限。
  • 再通过field.set(obj, value);将值填入。

反射中,Class.forName和classLoader.loadClass的区别?

  • Class.forName除了将类的.class文件加载到jvm中之外,还会执行类中的static块Class.forName(className)方法,内部实际调用的方法是Class.forName(className,true,classloader);第2个boolean参数表示类是否需要初始化,Class.forName(className)默认是需要初始化。一旦初始化,就会触发目标对象的static块代码执行,static参数也会被赋值。
  • ClassLoader.loadClass是将.class文件加载到jvm中,不会执行static块中的内容,只有在newInstance时才会去执行static块。ClassLoader.loadClass(className)方法,内部实际调用的方法是ClassLoader.loadClass(className,false);第2个 boolean参数,表示目标对象是否进行链接,false表示不进行链接。根据jvm类加载过程可知,不进行链接意味着不进行包括初始化等一些列步骤,那么静态块就不会得到执行,static参数也不会被赋值。
  • ClassLoader就是遵循双亲委派模型最终调用启动类加载器的类加载器,实现的功能是“通过一个类的全限定名来获取描述此类的二进制字节流”,获取到二进制流后放到JVM中。Class.forName()方法实际上也是调用CLassLoader来实现的

 2.反射机制获取成员方法、构造方法、父类父接口信息:

Class c=object.getClass();
System.out.println("类的名称:"+c.getName());
 
Method[] methods=c.getMethods();//获取方法
//获取所有的public方法,包括从父类继承的public方法
 
for(int i=0;i<methods.length;i++){
  //得到方法的返回类型
  Class returnType=methods[i].getReturnType();
  System.out.print(returnType.getName());
  //得到方法名:
  System.out.print(methods[i].getName()+"(");
 
  //获取参数名:
  Class[] parameterTypes=methods[i].getParameterTypes();
  for(Class class1:parameterTypes){
    System.out.print(class1.getName()+",");
  }
  System.out.println(")");
}

运行结果:

getMethods()获取所有的public方法,包括从父类继承的public方法

getDeclaredMethods()获取该类所有的方法,包括private ,但不包括继承的方法

 3.反射机制获取成员变量信息:

Class c=o.getClass();
//获取成员变量
Field[] fileds=c.getDeclaredFields();
for(Field f:fileds){
  //获取成员变量的类型
  Class filedType=f.getType();
  System.out.println(filedType.getName()+" "+f.getName());
}

getFileds()获取public,getDeclaredFields()获取所有,

运行结果:

 4.反射机制调用方法的操作

public class User implements Serializable{
     ......
     public void add(int a,int b){
        System.out.print(a+b);
    }
    .......
}
User user = new User();
Class c =  user.getClass();
Method method = c.getMethod("add", int.class,int.class);
//invoke()调用方法
method.invoke(user, 10,10);
//运行结果:20

5.缺点

性能:反射会带来一定的性能损失,因为反射需要在运行时动态地获取类的信息,并且需要进行类型转换和方法调用等操作,这些都会增加程序的运行时间和内存开销

安全性:反射可以破坏封装性和安全性,让程序访问和修改类的私有属性和方法。

可读性:反射代码通常比普通代码更难理解和维护,增加代码的复杂性,影响程序的可读性和可维护性

二、3次握手4次挥手

TCP FLAG 位由 bit 组成,分别代表 SYN、ACK 、   FIN URG、  PSH 、RST ,都以置1表示有效。
我们重点关注 SYN, ACK、  FIN。  SYN ( Synchronize Sequence Numbers )用作建立连接时的同步信号;
ACK ( Acknowledgement )用于对 收到的数据进行确认,所确认的数据由确认序列号表示;
FIN ( Finish )表示后面没有数据需要发送,通常意味着所建立的连接需要关闭了。

【超详细分析】关于三次握手与四次挥手面试官想考我们什么?_帅地的博客-CSDN博客

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值