1.全局变量和静态(全局和局部)变量 什么时候初始化?
-
静态变量的初始化是在编译时进行,变量的赋值是在函数或程序运行时进行。
-
静态变量只初始化一次,但可以通过赋值的方式多次修改静态变量的值。
-
全局变量和静态变量 在进入 main 前被初始化
2.你被问到静态变量和静态类的用法时,可以说出如下要点。
要点1,由于可以不同new就能使用方法,一些程序员为了图省事,会大量定义静态方法,这样做会破坏类的封装性,而且会增加类之间的耦合度,所以只能在需要的场景下定义静态类。
要点2,静态变量相当于全局变量,所以只该把整个项目里都会用到变量设置成静态的。
要点3,在尽可能小的范围里使用静态类和静态方法。
3. cookie和session的区别?
cookie的原理:
cookie的执行原理:就是当客户端访问服务器的时候(服务器运用了cookie),服务器会生成一份cookie传输给客户端,客户端会自动把cookie保存起来,以后客户端每次访问服务器,都会自动的携带着这份cookie。
session原理:
当客户端第一次请求服务器的时候,服务器生成一份session保存在服务端,将该数据(session)的id以cookie的形式传递给客户端;以后的每次请求,浏览器都会自动的携带cookie来访问服务器(session数据id)。
cookie和session的共同点
cookie和session都是用来跟踪浏览器用户身份的会话方式。
cookie和session区别
cookie是保存在客户端的
cookie有大小限制
session是保存在服务器端
session更加安全
session会比较占用服务器性能,当访问增多时应用cookie
4.单例模式
一、饿汉式单例类
public class HungrySingleton {
// 类加载,初始化
private static final HungrySingleton instance = new HungrySingleton();private HungrySingleton() {}
public static HungrySingleton getInstance() {
return instance;
}
}
饿汉式的特点就是当类被加载是,静态变量instance就会被初始化,此时类的私有构造方法会被调用,单例类的唯一实例将被创建。
二、懒汉式单例类
public class LazySingleton {
private static LazySingleton instance = null;
private LazySingleton() {}
public static LazySingleton getInstance() {
// 如果实例没被创建,就创建
if(instance == null) {
instance = new LazySingleton();
}
return instance;
}
}
这是极简版的懒汉式单例类,它的构造方法同样是私有的。但是,它与饿汉式不同的是,它在第一次被引用的时候才会实例化,即在类加载的时候不会将自己实例化。它在第一次调用getInstance方法的时候实例化,这种技术又称为延迟加载技术,即在需要的时候才加载实例。这段代码存在线程问题,下面开始解决这个问题,优化代码。
为了避免多个线程同时调用getInstance方法,可以使用关键字synchronized包裹。
// 确保任意时刻只有一个线程可以执行该方法
synchronized public static LazySingleton getInstance() {
// 如果实例没被创建,就创建
if(instance == null) {
instance = new LazySingleton();
}
return instance;
}
上诉代码虽然加了synchronized锁定线程,但是每次调用getInstance都需要进行线程锁定判断,在多线程高并发访问环境下会导致系统性能大大降低。分析发现,核心代码是instance = new LazySingleton(),所以我们仅需锁定这段代码即可。
public static LazySingleton getInstance() {
// 如果实例没被创建,就创建
if(instance == null) {
synchronized(LazySingleton.class) {
instance = new LazySingleton();
}
}
return instance;
}
这段代码看似解决了性能问题,实际上,还存在问题,可能存在单例对象不唯一的情况。比如说,在某一时刻,线程A和线程B同时调用getInstance方法。因为加锁的原因,有一个线程(A)先执行代码,另一个(B)需要等待。因为锁定的是实例化的那块代码,没有锁定If(instance == null)这块代码,也就是说两个线程都通过了这个判断语句。那么线程A执行完,创建了一个实例,该线程B去执行了,那么B又会创建一个实例。这两个实例肯定不是同一个,他们都是单独new出来的。
因此,需要加一个双重判断检查锁定来解决这个问题。
public class LazySingleton {
// 被volatile修饰的变量可以确保多个线程能正常处理
private volatile static LazySingleton instance = null;
private LazySingleton() {}
public static LazySingleton getInstance() {
// 第一层判断,如果实例已经创建,跳过
if(instance == null) {
synchronized(LazySingleton.class) {
// 第二层判断,如果实例创建,跳过
if(instance == null) {
instance = new LazySingleton();
}
}
}
return instance;
}
}
通过两层判断,解决了实例对象可能不唯一的问题。这里可能有人会疑惑,第一层可以不要。实际这里也是一个性能问题。第一层我们要解决的是实例是否已经创建的问题,创建了,就可以不用去判断线程锁定问题。第二层触发条件就是第一层没通过,即没有创建实例,是为了解决多个线程同一时刻调用创建对象的方法时可能造成对象不唯一的问题的。
如果使用双重检查锁定来实现懒汉式,需要在静态成员instance前加上volatile修饰,该修饰符在JDK1.5以上才能用,它会屏蔽Java虚拟机所做的一些代码优化,可能会导致系统运行效率降低,所以这种办法似乎也不是最完美的。
3.饿汉式和懒汉式对比
饿汉式的优点是无需考虑多个线程同时访问的问题,可以确保实例的唯一性。从调用速度和反应时间来说,因为它一开始就创建了对象,它是优于懒汉式的。但是从资源利用角度来说,它不如懒汉式,因为饿汉式无论你是否能用到这个单例对象,它都会给你创建,懒汉式是在你用到才会给你创建,而且系统加载时就需要创建饿汉式单例对象,可能会造成加载时间变长。
懒汉式,需要去解决多线程的问题,特别是当单例类作为资源控制器,在实例化时必然涉及到资源初始化的问题,可能会耗费大量时间,意味着多线程首次引用此类几率变大,所以要通过双重判断来进行控制,就会导致性能下降。