一、Java基础部分

1.java环境相关基本环境

image.png
image.png

2. Java基础知识架构

  • 基本语法
  • 类相关的语法
  • 内部类的语法
  • 继承相关的语法
  • 异常的语法
  • 线程的语法
  • 集合的语法
  • io 的语法
  • 虚拟机方面的语法

1. 说说&和&&的区别。基本语法

备注:这道题先说两者的共同点,再说出&&和&的特殊之处,并列举一些经典的例子来表明自己理解透彻深入、实际经验丰富。
&和&&都可以用作逻辑与的运算符,表示逻辑与(and),当运算符两边的表达式的结果都为true时,整个运算结果才为true,否则,只要有一方为false,则结果为false。
&&还具有短路的功能,即如果第一个表达式为false,则不再计算第二个表达式,例如,对于if(str != null && !str.equals(“”))表达式,当str为null时,后面的表达式不会执行,所以不会出现NullPointerException如果将&&改为&,则会抛出NullPointerException异常。If(x==33 & ++y>0) y会增长,If(x==33 && ++y>0)不会增长
&还可以用作位运算符,当&操作符两边的表达式不是boolean类型时,&表示按位与操作,我们通常使用0x0f来与一个整数进行&运算,来获取该整数的最低4个bit位,例如,0x31 & 0x0f的结果为0x01。

2. Java中的异常处理机制的简单原理和应用异常的语法

提示:就按照三个级别去思考:虚拟机必须宕机的错误,程序可以死掉也可以不死掉的错误,程序不应该死掉的错误;

  • 概念: 异常是指java程序运行时(非编译)所发生的非正常情况或错误,与现实生活中的事件很相似,现实生活中的事件可以包含事件发生的时间、地点、人物、情节等信息,可以用一个对象来表示,Java使用面向对象的方式来处理异常,它把程序中发生的每个异常也都分别封装到一个对象来表示的,该对象中包含有异常的信息。
  • Java对异常进行了分类:
  • 异常.svg

image.png
image.png
image.png

3. sleep() 和 wait() 有什么区别?线程的语法

  • sleep是线程类(Thread)的方法;wait是Object类的方法
  • sleep就是正在执行的线程主动让出cpu,cpu去执行其他线程,在sleep指定的时间过后,cpu才会回到这个线程上继续往下执行,如果当前线程进入了同步锁,sleep方法并不会释放锁,即使当前线程使用sleep方法让出了cpu,但其他被同步锁挡住了的线程也无法得到执行。wait是指在一个已经进入了同步锁的线程内,让自己暂时让出同步锁,以便其他正在等待此锁的线程可以得到同步锁并运行,只有其他线程调用了notify方法(notify并不释放锁,只是告诉调用过wait方法的线程可以去参与获得锁的竞争了,但不是马上得到锁,因为锁还在别人手里,别人还没释放。如果notify方法后面的代码还有很多,需要这些代码执行完后才会释放锁,可以在notfiy方法后增加一个等待和一些代码,看看效果),调用wait方法的线程就会解除wait状态和程序可以再次得到锁后继续向下运行。


4. 同步和异步有何异同,在什么情况下分别使用他们?举例说明。线程的语法

  • 如果数据将在线程间共享。例如正在写的数据以后可能被另一个线程读到,或者正在读的数据可能已经被另一个线程写过了,那么这些数据就是共享数据,必须进行同步存取。
  • 当应用程序在对象上调用了一个需要花费很长时间来执行的方法,并且不希望让程序等待方法的返回时,就应该使用异步编程,在很多情况下采用异步途径往往更有效率。


5. 回调函数 线程的语法

  • image.png
  • image.png
  • 实例: ```java package com.SelfTest.CallBack;

import jdk.internal.org.objectweb.asm.tree.TryCatchBlockNode;

import java.io.*; import java.sql.SQLOutput; import java.util.concurrent.CountDownLatch; import java.util.concurrent.TimeUnit;

public interface FileHandlerCallable { // 复制完成后的回调事件 void afterCopy(); }

/**

  • FileUtils类的两大作用:
    1. 复制文件
    1. 当前线程等待(即回调函数) */ class FileUtils{ private static void copyFileUsingFileStreams(File source, File dest) throws IOException { System.out.println(Thread.currentThread().getName() +”function :1”); InputStream inputStream=null; OutputStream outputStream=null; try { inputStream = new FileInputStream(source); outputStream = new FileOutputStream(dest); int bytesRead; byte[] buffer = new byte[8192]; while((bytesRead=inputStream.read(buffer))!=-1){
      1. outputStream.write(buffer,0,bytesRead);
      } System.out.println(Thread.currentThread().getName() +”文件复制ing,即将结束”); } catch (FileNotFoundException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); }finally { inputStream.close(); outputStream.close(); }

    }

    public void callbackAfterCopy(FileHandlerCallable fhc, File source, File dest) throws IOException { new Thread(

    () -> {
        try {
            System.out.println(Thread.currentThread().getName() +"正式开始复制");
            copyFileUsingFileStreams(source,dest);
        } catch (IOException e) {
            e.printStackTrace();
        }
        fhc.afterCopy();   // I will call you back
    }
    

    ).start();

    } }

class ImpliedFileHandlerCallable implements FileHandlerCallable{ static volatile boolean isCompleted= false; static CountDownLatch latch = new CountDownLatch(1); void requestCopy(FileUtils tool, File source, File destination) throws IOException { System.out.println(Thread.currentThread().getName() +”请求复制,进而继续调用callbackAfterCopy方法”); tool.callbackAfterCopy(this,source,destination); // if you call me

}

@Override
public void afterCopy() {
    isCompleted=true;
    try {
        latch.await();
    } catch (InterruptedException e) {
        e.printStackTrace();
    }finally {
        System.out.println(Thread.currentThread().getName() + "复制完成后:after copy");
    }

}

public static void main(String[] args) throws IOException, InterruptedException {
    File source = new File("D:\\java_related\\base_package\\mysql-5.5.61-winx64.msi");
    File destination = new File("D:\\java_related\\base_package\\mysql-5.5.61-winx64_copy_can_delete.msi");
    System.out.println(Thread.currentThread().getName());
    new ImpliedFileHandlerCallable().requestCopy(new FileUtils(), source, destination);

    while(!isCompleted){
        System.out.println(Thread.currentThread().getName() +"文件复制还没完成,等待100ms");
        TimeUnit.MILLISECONDS.sleep(1000);
        if(isCompleted){
            System.out.println(Thread.currentThread().getName() +"100ms等待结束,文件复制完成");
            break;
        }
    }
    latch.countDown();  // 主线程-1:执行完了之后再执行回调函数
    System.out.println(Thread.currentThread().getName() +"当前主线程已执行完毕");
}

}


<a name="Ze2hI"></a>
### 6. 多线程有几种实现方法?同步有几种实现方法?线程的语法
<a name="hl8vm"></a>
#### 6.1、 多线程的应用场景:

   - ![image.png](https://cdn.nlark.com/yuque/0/2021/png/22435741/1629620331287-a2935cb1-5a26-4810-b060-50b01e670512.png#align=left&display=inline&height=819&margin=%5Bobject%20Object%5D&name=image.png&originHeight=819&originWidth=1001&size=109583&status=done&style=none&width=1001)


<a name="6SiFw"></a>
#### 6.2、 多线程的实现:[https://blog.csdn.net/baidu_41813368/article/details/87730723](https://blog.csdn.net/baidu_41813368/article/details/87730723)

   - 1. 多线程2种实现方法:
      - A、继承Thread类
      - B、实现接口:
         - 1、[实现Runnable接口](https://blog.csdn.net/baidu_41813368/article/details/87730723#Runnable_30)
         - 2、[实现Callable接口](https://blog.csdn.net/baidu_41813368/article/details/87730723#Callable_74)

![image.png](https://cdn.nlark.com/yuque/0/2021/png/22435741/1629619143342-8993a9d5-7ae6-4a1f-a0f4-2b5794022e2f.png#align=left&display=inline&height=579&margin=%5Bobject%20Object%5D&name=image.png&originHeight=579&originWidth=985&size=63877&status=done&style=none&width=985)<br />![image.png](https://cdn.nlark.com/yuque/0/2021/png/22435741/1629619166342-d10f10b7-386b-498e-be03-f9bc31fd5fed.png#align=left&display=inline&height=656&margin=%5Bobject%20Object%5D&name=image.png&originHeight=656&originWidth=996&size=73552&status=done&style=none&width=996)<br />![image.png](https://cdn.nlark.com/yuque/0/2021/png/22435741/1629619312341-613ee2e3-f5d1-4de8-b62b-85b5792730c7.png#align=left&display=inline&height=415&margin=%5Bobject%20Object%5D&name=image.png&originHeight=415&originWidth=1002&size=40733&status=done&style=none&width=1002)

![image.png](https://cdn.nlark.com/yuque/0/2021/png/22435741/1629619410550-c14b7f2e-de69-4c55-806c-df894f0f2866.png#align=left&display=inline&height=854&margin=%5Bobject%20Object%5D&name=image.png&originHeight=854&originWidth=981&size=82549&status=done&style=none&width=981)
<a name="pJMfl"></a>
#### 6.3、同步的实现方法

- 1. 为什么要实现同步
   - java允许多线程并发控制,当多个线程同时操作一个可共享的资源变量时(如数据的增删改查),      将会导致数据不准确,相互之间产生冲突,因此加入同步锁以避免在该线程没有完成操作之前,被其他线程的调用,      从而保证了该变量的唯一性和准确性。
   - 实例:举个例子,如果一个银行账户同时被两个线程操作,一个取100块,一个存钱100块。假设账户原本有0块,如果取钱线程和存钱线程同时发生,会出现什么结果呢?取钱不成功,账户余额是100.取钱成功了,账户余额是0。但哪个余额对应哪个呢?很难说清楚,因此多线程的同步问题就应运而生。
- 2. 实现同步的方法
   - 综述: 调用类、关键字修饰方法(及代码块)、关键字修饰变量
   - 1. synchronized关键字修饰方法
      - 即有synchronized关键字修饰的方法。
      - 由于java的每个对象都有一个内置锁,当用此关键字修饰方法时,      内置锁会保护整个方法。在调用该方法前,需要获得内置锁,否则就处于阻塞状态。
      - 代码如:      public synchronized void save(){}
      - 注: synchronized关键字也可以修饰静态方法,此时如果调用该静态方法,将会锁住整个类
   - 2. 同步代码块
      - 即有synchronized关键字修饰的语句块。
```java
public  void addMoney(int money){
        synchronized (this) {
            count +=money;
        }
}
  -  注:同步是一种高开销的操作,因此应该尽量减少同步的内容。 
  - 通常没有必要同步整个方法,使用synchronized代码块同步关键代码即可。 
    1. 使用特殊域变量(volatile)实现线程同步
      • 示例: private volatile int count =0;//账户余额
      • 多线程间可见:
        • 由于每个线程都有自己的工作内存区,因此当一个线程改变自己的工作内存中的数据时,对其他线程来说,可能是不可见的。为此,可以使用volatile关键字破事所有线程军读写内存中的变量,从而使得volatile变量在多线程间可见。
      • 声明为volatile的变量可以做到如下保证:
        • 1、其他线程对变量的修改,可以及时反应在当前线程中;2、确保当前线程对volatile变量的修改,能及时写回到共享内存中,并被其他线程所见;3、使用volatile声明的变量,编译器会保证其有序性。
    1. 使用重入锁实现线程同步:java.util.concurrent.ReentrantLock类
      • ReentrantLock类是可重入、互斥、实现了Lock接口的锁, 它与使用synchronized方法和快具有相同的基本行为和语义,并且扩展了其能力。
      • ReentrantLock() : 创建一个ReentrantLock实例
      • lock() : 获得锁
      • unlock() : 释放锁
      • 注:ReentrantLock()还有一个可以创建公平锁的构造方法,但由于能大幅度降低程序运行效率,不推荐使用


    1. 线程间的通信—同步的实现方法
      • Object类提供的这三个方法只有在 synchronized 方法或者 synchronized代码块 中才能使用。
        • wait(): 放弃CPU\放弃锁对象,这样,别的线程就可以修改共享数据;
        • notify():唤醒正在排队等待同步资源的线程中优先级最高者结束等待;
        • notifyAll(): 唤醒正在排队等待资源的所有线程结束等待。

二、 JavaWeb部分

1. servlet定义、作用及生命周期

    1. 定义:

1. Tomcat的优化经验

    1. 去掉对web.xml的监视
    1. 把jsp(javaServer pages)提前编辑成Servlet
      • 作用:JSP将Java代码和特定变动内容嵌入到静态的页面中,实现以静态页面为模板,动态生成其中的部分内容。
      • 解释:JSP部署于网络服务器上,可以响应客户端发送的请求,并根据请求内容动态地生成HTMLXML或其他格式文档的Web网页,然后返回给请求者。
    1. 有富余物理内存的情况,加大tomcat使用的jvm的内存

2. HTTP请求的GET与POST方式的区别

  • get:
  • post:

面试问到的问题 - 图9