目录
6.Statement(下面用S表示),PrepareStatement(下面用PS表示)和CallableStatement(下面用CS表示)的区别
1.Servlet的生命周期
1.加载:Tomcat容器通过类加载使用Servlet类对应的文件加载Servlet(.class文件)
2.创建:通过调用Servlet构造函数创建一个Servlet对象(实例化)
3.初始化:调用init()进行初始化,是Servlet的生命起点
4.处理客户请求:每当有一个客户请求,容器会创建一个线程处理客户请求
5.卸载:调用destory(),让Servlet释放其占用资源
补充:
是先进行实例化,然后再用init进行初始化,然后调用Service方法
关于stop():当Applet被覆盖时,使用该方法停止线程,典型的一个案例就是当最小化网页时,挂起这个线程
Servlet是多线程不安全的
2.forword和redirect
forward(接下来用F表示):直接转发,是RequestDispatcher类的forward()方法
redirect(接下来用R表示):间接转发,是HttpServletRequest类的sendRedirect()方法
F:客户端浏览器只发送一次请求,Servlet请求转发给Servlet,HTML,Jsp或者其他资源,由资源2相应资源1,两资源共享同一个request对象
R:服务器端相应第一次请求时,让浏览器在向另一个URL发出请求,达到转发目的地,本质是两次HTTP请求,对应两个request对象
3.加载驱动的方法
1.Class.forName("com.microsorft.sqlserver."jdbc.SQLServerDrier");
2.DriverManager.registerDriver(new com.mysql.jdbc.Driver());
3.System.setProperty("jdbc.drivers", "com.mysql.jdbc.Driver");
4.sleep()和wait()
两者都是在多线程情况下,在程序的调用处阻塞指定的毫秒数并返回,都可以通过interrupt()打断线程的暂停状态,抛出InterruptedException·,区别在下面用图表对比的方式说明
5.JVM内存配置参数
eg: -Xml10240m-Xms10240m-Xmn5120-XXSurvivorRadio = 3
-Xmx:最大堆大小
-Xms:初始堆大小,即最小内存值
-Xmn:年轻代大小(新生代)-------每个年轻代都有两个Survivor区和一个Eden区
-XXSurvivorRadio:年轻袋中Eden区与Survivor区的比值
6.Statement(下面用S表示),PrepareStatement(下面用PS表示)和CallableStatement(下面用CS表示)的区别
三种方式查询语句:S用于通用查询,PS用于参数化查询,CS用于存储过程
S和PS相比较:PS效率更高,因为它会被数据库解析并放入命令缓冲区,如果命令相同,就不会再被编译,可重复使用;且可读性和维护性更好;最重要的是安全性更好,可以预防SQL注入攻击
CS:允许从Java程序中调用数据存储过程,其对象包含了对存储过程的调用,但不包含存储本身。因为存储过程是存储在数据库中,有prepareCall()所创建,继承自PrepareStatement,增加了调用数据库中的存储过程和函数以=以及设置输出参数类型的功能
7.interrupt()
interrupt()的作用是中断本线程。对于执行一般逻辑的线程,调用该方法是没有任何影响的,该方法真正影响的是wait(),sleep()和join()这三个方法。
如果线程调用wait(),sleep()等方法进入阻塞状态,调用了它的interrupt()方法,那么它的“中断状态”会被清除并收到一个InterruptException异常。例如:线程通过wait()进入阻塞状态,此时通过interrupt()中断该线程,并立即将线程的中断标记为“true”
本线程中断自己是被允许的,其他线程调用本线程的interrupt() 方法时,会通过checkAccess()检查权限,这有可能会抛出SecurityException异常
8.Arrays.asList()
将数组转化成为一个LIst集合,这个方法会返回到一个ArrayList类型的对象,这个ArrayList类并非java.util.ArrayList类,而是Arrays的静态内部类!如果用这个对象进行对列表的增删改操作,就会出现UnsupportedOperationException异常,因为这个类没有实现add/remove/clear方法,而是直接使用它的父类AbstractList的相应方法,而AbstractList中的add()和remove()是直接抛出java.lang.UnsupportedOperationException异常的所以,不能使用add/remove/clear方法,因此如果如果只是遍历就可以用,但是你的List还要增删元素,那么就还是乖乖new一个java.util.ArrayList,然后一个一个添加元素吧~
补充一句:这个方法不适用于基本数据类型
9.抽象类和接口区别
1.抽象类中的方法必须使用abstract关键字声明为抽象,而接口中的方法默认被修饰为public abstract类型
2.抽象类中既可以有抽象方法,也可以有非抽象的方法,而接口中必须只有抽象方法
3.抽象类中可以有构造方法(但是不能直接创建抽象类的实例对象,可以在继承该抽象类的子类中用super(参数列表)调用抽象类中的构造方法),而接口中没有构造方法
4.一个类只能继承一个抽象类,但却可以实现多个接口,也就是接口可以多继承
10.单例模式
顾名思义,单例模式就是一个类有且只有一个实例,一般使用 .getInstance()创建对象
步骤: 构造方法私有化,提供一个私有的该类型的变量,提供一个公共的返回类型为该类类型的静态方法,用于返回这个唯一的变量(必须是静态方法,一般使用getInstance这个名称)
注意:单例模式在多线程情况下必须小心使用。如果当唯一实例尚未创建时,有两个线程同时调用创建方法,那么它们同时没有检测到唯一实例的存在,从而同时各自创建了一个实例,这样就有两个实例被构造出来,从而违反了单例模式的事宜唯一原则。因为要解决这个问题,就需要为指示类是否已经实例化的变量提供一个互斥锁,但是会降低效率
方式一:饿汉式单例(立即加载方式)
在类加载初始化时就创建好了一个静态的对象供外部使用,除非系统重启,否则该对象不会改变,所以本身就是线程安全的。但是由于在类加载的时候就完成了实例化,而不在乎是否需要使用,很容易损耗内存
public class HungrySingleton {
private HungrySingleton() {}
private static HungrySingleton single = new HungrySingleton();
public static HungrySingleton getInstance() {
return single;
}
}
方式二:懒汉式单例
懒汉式(普通)单例虽然用延迟加载凡是实现了懒汉单例,但是在多线程环境下,一个线程进入了if(single == null)语句,还未来得及往下执行,另一个线程也通过这个语句,那么就会产生多个实例,因此不可以在多线程环境下使用
public class LazySingleton {
//构造方法私有化
private LazySingleton() {}
private static LazySingleton single = null;
public static LazySingleton getInstance() {
if(single == null) {
single = new LazySingleton();
}
return single;
}
}
方式三:使用synchronized同步锁
这种方法虽然解决了多个实例对象的问题,但是运行效率却十分低下,下一个线程想要获取对象,就必须要等待上一个锁释放之后才可以
public class LazySingleton {
//构造方法私有化
private LazySingleton() {}
private static LazySingleton single = null;
public static LazySingleton getInstance() {
//锁住对象,也等同于 synchronized public static LazySingleton getInstance()
synchronized (LazySingleton.class) {
if(single == null) {
single = new LazySingleton();
}
}
return single;
}
}
方式四:使用双重检查
进行两次if (singleton == null)检查,这样,实例化代码只用执行一次,后面再次访问时,判断if (singleton == null),直接return实例化对象,既实现了延迟加载和线程安全,而且效率较高,但是没有解决反序列化破坏单例的问题
public class LazySingleton {
//构造方法私有化
private LazySingleton() {}
private static LazySingleton single = null;
public static LazySingleton getInstance() {
if(single == null) {
synchronized (LazySingleton.class) {
if(single == null) {
single = new LazySingleton();
}
}
}
return single;
}
}
方式五:静态内部类的方式
这种方式采用了类加载的机制保证初始化实例时只有一个线程,在这一点上和懒汉式相似,但是并不会立即实例化, 而是在需要实例化时,调用getInstance方法,才会装载内部类,从而完成实例化。避免了线程不安全,延迟加载,效率高
public class InnerStaticSingleton {
private InnerStaticSingleton() {}
private static class InnerClass {
private static InnerStaticSingleton single = new InnerStaticSingleton();
}
public static InnerStaticSingleton getInstance() {
return InnerClass.single;
}
}
方式六:静态代码块的方式
与饿汉式其实是差类似的,只不过将类实例化的过程放在了静态代码块中,也是在类装载的时候,就执行静态代码块中的代码,初始化类的实例,优缺点同饿汉式
public class StaticBlockSingleton {
//构造方法私有化
private StaticBlockSingleton() {}
private static StaticBlockSingleton single = null;
static {
single = new StaticBlockSingleton();
}
public static StaticBlockSingleton getInstance() {
return single;
}
}
方式七:使用枚举
代码精简,能保证单例和线程安全,不怕被反序列化,但是想实例化一个单例类的时候,必须记住相应的获取对象的方法,而不是用new,可能会给其他开发人员造成困扰,尤其是看不到源码的时候
不过,枚举显然是实现单例的一种很好的方法!
public enum Singleton {
INSTANCE;
public void whateverMethod() {
}
}
关于枚举实现单例更详尽的内容推荐看这篇博文:https://blog.youkuaiyun.com/moakun/article/details/80688851
11.java内存划分及各自作用
主要分为下面五部分:
程序计数器(线程私有)
保存的是当前指令的地址,当CPU需要执行指令时,需要从程序计数器中得到当前需要执行指令所在储存单元的地址,单后根据得到的地址获得指令,在得到指令后,程序计数器自动加一或者根据指针得到下一条指令的地址,如此循环,直至执行完所有的指令。所以可以看做是当前线程所执行的字节码的指令指令器
当执行native方法时:计数值为空
当执行java方法(非native方法)时:记录的是正在执行的虚拟机字节码指令的地址
由于程序计数器存储数据所占用的空间大小不会随着程序的执行而发生改变,所以程序计数器是不会发生内存溢出现象的,该区域也是唯一无规定任何OutOfMemoryError情况的区域
Java虚拟机栈(线程私有)
描述的是Java方法执行的内存模型。方法执行时会创建栈帧用于储存局部变量表,操作数栈,动态链接,方法出口等,方法从调用到执行完成,对应栈帧从入栈到出栈。
我们口中经常说的栈就是该栈,或者说是其中的局部变量表部分,存放了基本的数据类型和对象引用(不是对象本身)
本地方法栈(与虚拟机栈作用十分相似)
虚拟机栈是为Java方法服务,而本地方法栈则是为虚拟机所使用的到的java方法服务。
在Sun HotSpot虚拟机中把虚拟机栈和本地方法栈合二为一
Java堆(被所有线程共享)
在虚拟机启动时创建,用于存放对象实例,在JVM中只有一个堆
是垃圾回收器管理的主要区域,也被称为“GC堆”。在C语言中,程序员要通过malloc函数和free函数对空间进行申请和释放,但在java中,程序员不用去关心空间的释放问题,因为垃圾回收器会自动处理
堆处于物理不连续空间中,只需要逻辑连续即可
方法区(线程共享)
储存已被jvm加载的类信息,常量,静态变量和编译器编译后的代码等
该区域内存回收目标主要是针对常量池的回收和对类型的卸载
在方法区中有一个非常重要的部分就是运行时常量池
运行时常量池(线程共享)
是方法区的一部分
是类和接口的运行时表示形式,在类和接口被加载到jvm后,对应的运行时常量池就会被创建出来,并对编译期生成的引用等进行存放。相对于Class文件常量池的另一个特征是:具有动态性