一、Java基础部分
1.java环境相关基本环境
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对异常进行了分类:
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. 回调函数 线程的语法
- 实例: ```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类的两大作用:
- 复制文件
- 当前线程等待(即回调函数)
*/
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){
} System.out.println(Thread.currentThread().getName() +”文件复制ing,即将结束”); } catch (FileNotFoundException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); }finally { inputStream.close(); outputStream.close(); }outputStream.write(buffer,0,bytesRead);
}
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 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){
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代码块同步关键代码即可。
- 使用特殊域变量(volatile)实现线程同步
- 示例: private volatile int count =0;//账户余额
- 多线程间可见:
- 由于每个线程都有自己的工作内存区,因此当一个线程改变自己的工作内存中的数据时,对其他线程来说,可能是不可见的。为此,可以使用volatile关键字破事所有线程军读写内存中的变量,从而使得volatile变量在多线程间可见。
- 声明为volatile的变量可以做到如下保证:
- 1、其他线程对变量的修改,可以及时反应在当前线程中;2、确保当前线程对volatile变量的修改,能及时写回到共享内存中,并被其他线程所见;3、使用volatile声明的变量,编译器会保证其有序性。
- 使用特殊域变量(volatile)实现线程同步
- 使用重入锁实现线程同步:java.util.concurrent.ReentrantLock类
- ReentrantLock类是可重入、互斥、实现了Lock接口的锁, 它与使用synchronized方法和快具有相同的基本行为和语义,并且扩展了其能力。
- ReentrantLock() : 创建一个ReentrantLock实例
- lock() : 获得锁
- unlock() : 释放锁
- 注:ReentrantLock()还有一个可以创建公平锁的构造方法,但由于能大幅度降低程序运行效率,不推荐使用
- 使用重入锁实现线程同步:java.util.concurrent.ReentrantLock类
- 线程间的通信—同步的实现方法
- Object类提供的这三个方法只有在 synchronized 方法或者 synchronized代码块 中才能使用。
- wait(): 放弃CPU\放弃锁对象,这样,别的线程就可以修改共享数据;
- notify():唤醒正在排队等待同步资源的线程中优先级最高者结束等待;
- notifyAll(): 唤醒正在排队等待资源的所有线程结束等待。
- Object类提供的这三个方法只有在 synchronized 方法或者 synchronized代码块 中才能使用。
- 线程间的通信—同步的实现方法
二、 JavaWeb部分
1. servlet定义、作用及生命周期
- 定义:
- 定义:
1. Tomcat的优化经验
- 去掉对web.xml的监视
- 有富余物理内存的情况,加大tomcat使用的jvm的内存
2. HTTP请求的GET与POST方式的区别
- get:
- post: