Java笔试题知识点总结(1)

目录

1.Servlet的生命周期   2.forword和redirect     3.加载驱动的方法    4.sleep()和wait()     5.JVM内存配置参数      6.Statement(下面用S表示),PrepareStatement(下面用PS表示)和CallableStatement(下面用CS表示)的区别     7.interrupt()    8.Arrays.asList()     9.抽象类和接口区别     10.单例模式

1.Servlet的生命周期

1.加载:Tomcat容器通过类加载使用Servlet类对应的文件加载Servlet(.class文件)

2.创建:通过调用Servlet构造函数创建一个Servlet对象(实例化)

3.初始化:调用init()进行初始化,是Servlet的生命起点

4.处理客户请求:每当有一个客户请求,容器会创建一个线程处理客户请求

5.卸载:调用destory(),让Servlet释放其占用资源

Java笔试题知识点总结(1)

补充:

是先进行实例化,然后再用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对象

Java笔试题知识点总结(1)

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·,区别在下面用图表对比的方式说明

Java笔试题知识点总结(1)

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.csdn.net/moakun/article/details/80688851