8.13

反射

关于java.lang.class 类的理解

类的加载过程

程序经过javac.exe 命令以后,会生成一个或多个字节码文件,接着我们使用java.exe命令对某个字节码文件进行解释运行。相当于将某个字节码文件加载到内存中,此过程称为类的加载。加载到内存中的类,我们就称为运行时类,此运行时类,就作为class的一个实例。

public void test() {
    方式一:调用运行时类的属性:.class
    Class clazz1 = Person.class ; 
    
    //方式二:通过运行时类的对象
    Person  p1 = new Person() ;
    Class clazz2 = p1.getrClass() ;
    
    // 方式三:调用Class的静态方法: forName(String classpath);
   Class clazz3 = Class.forName("java.lang.String");
    
     //方式四: 使用类的加载器 ClassLoader
        ClassLoader classLoader = ReflectionTest.getCloader();
        Class clazz4 = classLoader.loadClass("com.atguigu.java.person");
}

读取配置文件

public void test2() throws Exception {

    Properties pros = new Properties() ;
    //读取配置文件的方式一:
    FileInputStream fis = new FileInputSteam("jdbc.properties");
    pros.load(fis);
    
    //读取配置文件的方式二:使用ClassLoader 
    //配置文件默认识别为: 当前module的src下
    ClassLoader classLoader = ClassLoaderTest.class.getClassLoader();
    InputStream is = classLoader.getResourceAsStream("jdbc.properties");
    
    
}

创建运行时类的对象

 Class clazz  = Student.class;
// 调用此方法,创建对应的运行时类的对象。内部调用了运行时类的空参构造器
//要想此方法正常的创建运行类的对象,要求: 
    //1. 运行时类必须提供空参的构造器
    //2. 空参的构造器的访问权限得狗。通常,设置为public 。    
 Student student = clazz.newInstance();

getMetods(); 获取当前运行时类及其所有父类中声明为public权限的方法

getDeclaredMethods() ;获取当前运行时类中声明的所有方法。(不包含父类中声明的方法)

获得指定内容

属性值

public void test() throws Exception{
    Class clazz = Person.class;
    //创建运行时类的对象
    Person p = (Person)clazz.newInstance();
    //1. getDeclaredFiedld(String fieldName) ; 获取运行时类中指定变量名的属性
    Field name = clazz.getDeclaredField("name");
    //2.保证当前属性是可访问的
    name.setAccessible(true);
   //3.获取、设置指定对象的此属性值
    name.set(p,"Tom");
}

方法

public void test() throws Exception{
      Class clazz = Person.class;
    //创建运行时类的对象
    Person p = (Person)clazz.newInstance();
     
    1.获取指定的某个方法
    getDeclaredMethod() : 参数1:指明获取的方法的名称 参数2:致命获取的方法的形参列表
    Method show = clazz.getDeclaredMethod("show",String.class) ;
    2.保证当前方法是可访问的
    show.setAccessible(true);
    3.调用方法的invoke(): 参数1 : 方法的调用者 参数2:给方法形参赋值的实参
    invoke()的返回值即为对应类中调用的方法的返回值
    Object returnValue = show.invoke(p,"CHN");
    
    //调用静态方法
    Method showDesc = clazz.getDeclaredMethod("showDesc");
    //如果调用的运行时类没有返回值,则此invoke() 返回null
}

方法

public void test() throws Exception{
      Class clazz = Person.class;
    //创建运行时类的对象
    Person p = (Person)clazz.newInstance();
     
    1.获取指定的某个方法
    getDeclaredMethod() : 参数1:指明获取的方法的名称 参数2:指明获取的方法的形参列表
    Method show = clazz.getDeclaredMethod("show",String.class) ;
    2.保证当前方法是可访问的
    show.setAccessible(true);
    3.调用方法的invoke(): 参数1 : 方法的调用者 参数2:给方法形参赋值的实参
    invoke()的返回值即为对应类中调用的方法的返回值
    Object returnValue = show.invoke(p,"CHN");
    
    //调用静态方法
    Method showDesc = clazz.getDeclaredMethod("showDesc");
    //如果调用的运行时类没有返回值,则此invoke() 返回null
}

Lambda表达式的使用

1.举例  (o1,o2) -> compare(o1,o2)

左边:形参列表(其实就是接口中的抽象方法的形参列表)。参数类型可以省略;只有一个参数,可以省略小括号;

右边:lambdat体 其实就是重写的抽象方法的方法体。

四大函数式接口

消费型接口 Consumer void accept(T t)

供给型接口 Supplier  T get()

函数型接口 Function R apply(T t)

断定型接口 Predicate boolean test(T t) 

方法引用

  1. 使用情景:当要传递给Lambda体的操作,已经有实现的方法了,可以使用方法引用!

  2. 方法引用,本质上就是Lambda表达式,而Lambda表达式作为函数式接口的实例。所以方法引用,也是函数式接口的实例。

  3. 使用格式: 类(或对象) :: 方法名

  4. 具体分为如下的三种情况

对象 :: 非静态方法

类 :: 静态方法

类  :: 非静态方法  

  1. 方法引用使用的要求:要求接口中的抽象方法的参数列表和返回值类型与方法引用的方法的形参列表和返回值类型相同,对情况1和情况2;

Stream

  • Stream关注的是对数据的运算,与CPU打交道。集合关注的是数据的存储,与内存打交道

  1. 自己不会存储元素

  2. 不会改变源对象。相反,他们会返回一个持有结果的新Stream。

  3. 操作是延迟执行的。这意味着他们会等到需要结果的时候才执行

  • Stream 执行流程

  1. Stream的实例化

  2. 一系列的中间操作(过滤、映射、...)

  3. 终止操作

  • 说明

  1. 一个中间操作链,对数据源的数据进行处理

  2. 一旦执行终止操作,就执行中间操作链,并产生结果。之后,不会再被使用。

筛选与切片

filter(Predicate p) --  从流中排除某些元素

limit(n) ;  截断流,使其元素不超过给定数量

skip(n); 跳过元素,返回一个扔掉了前n个元素的流。若流中元素不足n个,则返回一个

distinct  :  筛选,通过流所生成元素的hashcode()和equals()去除重复元素

映射

map(Function f) -- 接收一个函数作为参数,将元素转换成其他形式或提取信息,该函数会被应用到每个元素上,并将其映射成一个新的元素

flatMap(Fuction f)  接收一个函数作为参数,将流中的每个值都换成另一个流,然后把所有流连接成一个流。

排序

终止操作

匹配与查找

allMatch(Predicate p) 检查是否匹配所有元素

anyMatch(Predicate p) 检查是否至少匹配一个元素

noneMatch(Predicate p) 价差是否没有匹配的元素

findFirst :返回第一个元素

findAny : 返回当前流中的任意元素

count : 返回流中的任意元素

max(Comparator c) :返回流中最大值

归约

reduce(T identity,BinaryOperator)  可以将流中元素反复结合起来,得到一个值。返回这个值

redece(BinaryOperator) : 可以将流中元素反复结合起来,得到一个值。返回Optional

收集

collect(Collector c) : 将流转换为其他形式。接收一个Collector 接口的实现,用于给Stram中的元素做汇总的方法

Html

a标签

target属性设置哪个目标进行跳转

self : 表示当前页面

blank: 新页面

列表

无序:ul  ; 有序:ol

iframe : 内签标签

Servlet

post下,要设置字符集编码,不然会乱码

继承关系

  1. 继承关系

Servlet 接口

GenericServlet 抽象类

http.HttpServlet  抽象子类

  1. 相关方法:

Servlet接口

  • void init(config) -- 初始化方法

  • void service(request,response) -- 服务方法

  • void destory() -- 销毁方法

GenericServlet 抽象类:

void service(request,response)  -- 仍然是抽象的

http.HttpServlet  抽象子类

void service(resquest,respon)  -- 不是抽象的

生命周期

servlet 是单例线程不安全的;尽量不要在servlet中定义成员变量。如果不得不定义成员变量,那么不要去:1 不要去不要去修改成员变量的值。2 不要根据成员变量的值做一些逻辑判断。

Http

http是无状态的:无法区分是同一个客户端还是不同客户端发送过来的;通过seesion id,跟踪技术来分别;

请求包含了三部分:请求行、请求消息头、请求主体: 普通的get方式请求-query string;post方式--form data;json格式--request

服务器内部转发以及客户端重定向

  1. 服务器内部转发:request.getRequestDispatcher("....").forward(request,response);

一次请求响应的过程,对于客户端而言,内部经过了多少次转发,客户端是不知道的

  1. 客户端重定向:reson.sendRedirect("....");

两次请求,url有变化,客户端是知道的。

作用域

page : 现在几乎不用

requeset (一次请求响应范围):

session (一次会话范围):

application(整个应用程序范围) : 

页数问题

8.13_第1张图片

 

MVC

优化

原问题:通过swtich(operate) {}  来写,导致代码量过长

解决:反射

//获取当前类中所有的方法
Method[] methods = this.getClass().getDeclaredMethods();
for(Method m : methods) {
    //获取方法名称
    String methodName = m.getName();
    if(operate.equals(methodName)) {
        // 找到和operate同名的方法,用反射调用
        m.invoke(this,request,response);
    }
}

DispatcherServlet  类

@WebServlet("*.do")
public class DispatcherServlet extends ViewBaseServlet{

    private Map beanMap = new HashMap<>();

    public DispatcherServlet(){
    }
 public void init() throws ServletException {
    super.init();
    try{
    //读取配置文件(存放的是dispatcher 映射到 controller 的内容) 
    InputStream inputStream = getClass().getClassLoader().getResourceAsStream("applicationContext.xml");
    // 1. 创建DocumentBuilderFactory 
    DocumentBuilderFactory documentBuilderFactory  = DocumentBuilderFactory.new Instance();
    //2. 创建DocumentBuilder 对象
    DocumentBuilder documentBuilder = documentBuilderFactory.newDocumentBuilder();
    //3. 创建Document对象
    Document document = documentBuilder.parse(inputStream);
    //4.获取所有的bean节点
    NodeList beanNodeList = document.getElementsByTagName("bean");
    for(int i=0;i   hello   或者  /fruit.do  -> fruit
  // 第2步: hello -> HelloController 或者 fruit -> FruitController
  String servletPath = request.getServletPath();
  servletPath = servletPath.substring(1);
  int lastDotIndex = servletPath.lastIndexOf(".do") ;
  servletPath = servletPath.substring(0,lastDotIndex);

  Object controllerBeanObj = beanMap.get(servletPath); // 将保存的对象取出来

  String operate = request.getParameter("operate");
  if(StringUtil.isEmpty(operate)){
      operate = "index" ;
  }

  try {
    Method[] methods = controllerBeanObj.getClass().getDeclaredMethods();
    for(Method method : methods) {
    if(operate.equals(method.getName())){
     // 1. 统一获取请求参数

        //1-1 获取当前锋昂发的参数,返回参数数组
        Parameter[] parameters = method.getParameters();
        //1-2 parameterValues 用来承载参数的值
        Object[] parameterValues = new Object[parameters.length];
        for(int i=0;i

 

你可能感兴趣的:(java,jvm,servlet)