面试题
- java基础部分
- 基础知识
- 面向对象
- 访问修饰符 public,private,protected,以及不写(默认)时的区别
- &和&&的区别?
- this关键字的用法
- super关键字的用法
- static的独特之处
- static应用场景
- static注意事项
- 面向对象与面向过程的区别
- 面向对象的三大特性
- 接口和抽象类有什么区别?
- 面向对象五大基本原则是什么
- 抽象类和接口的对比
- 普通类和抽象类的区别
- 抽象类能使用 final 修饰吗?
- 成员变量与局部变量的区别
- 创建一个对象用什么关键字?对象实例与对象引用有何不同?
- 在Java中定义一个不做事且没有参数的构造方法的作用
- 在调用子类构造方法之前会先调用父类没有参数的构造方法的目的
- 一个类的构造方法的作用是什么?若一个类没有声明构造方法,改程序能正确执行吗?为什么?
- 构造方法有哪些特性?
- 静态变量和实例变量的区别
- 静态代码块、代码块(构造代码块)、构造方法的执行顺序
- 构造器(constructor)是否可被重写(override)
- 重载(Overload)和重写(Override)的区别。重载的方法能否根据返回类型进行区分?
- == 和 equals 的区别是什么
- hashCode()与equals()的相关规定
- 对象的相等与指向他们的引用相等,两者有什么不同?
- 值传递和引用传递有什么区别
- 什么时候应该使用接口,什么时候应该使用抽象类?
- 内部类有什么作用?有哪些分类?
- IO
- 反射
- 线程
- 字符串
- 集合
- 集合和数组的区别
- 常用的集合类有哪些?
- List,Set,Map三者的区别
- 集合框架底层数据结构
- Iterator 和 ListIterator 有什么区别?
- 遍历一个 List 有哪些不同的方式?每种方法的实现原理是什么?
- 如何实现数组和 List 之间的转换?
- Array和ArrayList的区别?
- ArrayList 和 LinkedList 的区别是什么?
- ArrayList 和 Vector 的区别是什么?
- List 和 Set 的区别
- 什么是Hash算法
- HashMap在jdk7和jdk8的区别
- 什么是哈希冲突?
- HashMap 与 HashTable 有什么区别?
- Collection 和 Collections 有什么区别?
- 什么是TreeMap
- 在使用 HashMap 的时候,用 String 做 key 有什么好处?
- 异常
- 泛型
- 其他
- JavaWeb
随着就业的到来,面试成为不可或缺的一部分,为此边学技术的同时,整理了一些常见的面试题。有不足之处请及时指正,面试题在实时的更新中
java基础部分
基础知识
Java有哪些数据类型
定义:Java语言是强类型语言,对于每一种数据都定义了明确的具体的数据类型,在内存中分配了不同大小的内存空间。
java的数据类型分类
- 数值型:整数型(byte、short、int、long),浮点型(float,double),字符型(char)、布尔型(Boolean)
- 应用数据类型:类、数组、接口
.switch 是否能作用在 byte 上,是否能作用在 long 上,是否能作用在 String上
在 Java 5 以前,switch(expr)中,expr 只能是 byte、short、char、int。从 Java5 开始,Java 中引入了枚举类型,expr 也可以是 enum 类型,从 Java 7 开始,expr 还可以是字符串(String),但是长整型(long)在目前所有的版本中都是不可以的。
Math.round(11.5) 等于多少?Math.round(-11.5)等于多少
Math.round(11.5)的返回值是 12,Math.round(-11.5)的返回值是-11。四舍五入的原理是在参数上加 0.5 然后进行下取整。
float f=3.4;是否正确
不正确。3.4 是双精度数,将双精度型(double)赋值给浮点型(float)属于下转型(downcasting,也称为窄化)会造成精度损失,因此需要强制类型转换float f =(float)3.4; 或者写成 float f =3.4F;。
short s1 = 1; s1 = s1 + 1;有错吗?short s1 = 1; s1 += 1;有错吗
- 对于 short s1 = 1; s1 = s1 + 1;由于 1 是 int 类型,因此 s1+1 运算结果也是 int型,需要强制转换类型才能赋值给 short 型。
- 而 short s1 = 1; s1 += 1;可以正确编译,因为 s1+= 1;相当于 s1 = (short(s1 + 1);其中有隐含的强制类型转换
面向对象
访问修饰符 public,private,protected,以及不写(默认)时的区别
定义:Java中,可以使用访问修饰符来保护对类、变量、方法和构造方法的访问。Java 支持 4 种不同的访问权限。
分类
private : 在同一类内可见。使用对象:变量、方法。 注意:不能修饰类(外部类)
default (即缺省,什么也不写,不使用任何关键字): 在同一包内可见,不使用任何修饰符。使用对象:类、接口、变量、方法。
protected : 对同一包内的类和所有子类可见。使用对象:变量、方法。 注意:不能修饰类(外部类)。
public : 对所有类可见。使用对象:类、接口、变量、方法
访问修饰符图
&和&&的区别?
答:①&具有按位与和逻辑与两个功能。②&&作为逻辑与具有短路的特点,当前面的条件表达式为false时就不会进行后面条件表达式的判断,可以用来避免空指针异常。
this关键字的用法
this是自身的一个对象,代表对象本身,可以理解为:指向对象本身的一个指针
this的用法在java中大体可以分为3种:
- 普通的直接引用,this相当于是指向当前对象本身。
- 形参与成员名字重名,用this来区分:
- 引用本类的构造函数
super关键字的用法
super可以理解为是指向自己超(父)类对象的一个指针,而这个超类指的是离自己最近的一个父
类。
super也有三种用法:
- 普通的直接引用:与this类似,super相当于是指向当前对象的父类的引用,这样就可以用super.xxx来引用父类的成员。
- 子类中的成员变量或方法与父类中的成员变量或方法同名时,用super进行区分
- 父类的构造函数
static的独特之处
- 被static修饰的变量或者方法是独立于该类的任何对象,也就是说,这些变量和方法不属于任何一个实例对象,而是被类的实例对象所共享。
- 在该类被第一次加载的时候,就会去加载被static修饰的部分,而且只在类第一次使用时加载并进行初始化,注意这是第一次用就要初始化,后面根据需要是可以再次赋值的。
- static变量值在类加载的时候分配空间,以后创建类对象的时候不会重新分配。赋值的话,是可以任意赋值的!
- 被static修饰的变量或者方法是优先于对象存在的,也就是说当一个类加载完毕之后,即便没有创建对象,也可以去访问。
static应用场景
因为static是被类的实例对象所共享,因此如果某个成员变量是被所有对象所共享的,那么这个成员变量就应该定义为静态变量。
因此比较常见的static应用场景有:
1、修饰成员变量 2、修饰成员方法 3、静态代码块 4、修饰类【只能修饰内部类也就是静态内部类】 5、静态导包
static注意事项
- 静态只能访问静态。
- 非静态既可以访问非静态的,也可以访问静态的。
面向对象与面向过程的区别
面向过程是具体化的,流程化的,解决一个问题,你需要一步一步的分析,一步一步的实现。
面向对象是模型化的,你只需抽象出一个类,这是一个封闭的盒子,在这里你拥有数据也拥有解决问题的方法。需要什么功能直接使用就可以了,不必去一步一步的实现,至于这个功能是如何实现的,管我们什么事?我们会用就 可以了。
面向对象的底层其实还是面向过程,把面向过程抽象成类,然后封装,方便我们使用的就是面向对象了。
面向对象的三大特性
继承
- 继承:多个类中存在相同属性和行为时,将这些内容抽取到单独一个类中,那么多个类无需再定义这些属性和行为,只要继承那个类即可
- 继承的好处
- 减少代码的冗余,提高代码的分复用性
- 便于功能的扩展
- 为后面多态性的使用提高了方便
- 继承的规定
- 只支持单继承和多层继承,不支持多继承
- java中类具有单继承性:一个类只能有一个父类
- 子类直接继承父类叫直接父类,间接继承的类叫间接父类
- 子类继承父类以后,就获取了直接父类以及间接父类的所有属性和方法
封装
- 概念:封装也称信息隐藏,是指利用抽象数据类型把数据和基于数据的操作封装起来,使其成为一个不可分割的整体,数据隐藏在抽象数据内部,尽可能的隐藏数据细节,只保留一些接口使其与外界发生联系。也就是说用户无需知道内部的数据和方法的具体实现细节,只需根据留在外部的接口进行操作就行。
- 封装的优点
- 将变化隔离
- 便于使用
- 提高重用性
- 提高安全性
多态
- 概念:多态是同一个行为具有多个不同表现形式或形态的能力。
多态就是同一个接口,使用不同的实例而执行不同操作,
父类的引用指向子类的对象(或子类的对象赋给父类的引用). - 多态的使用前提
- 类的继承关系
- 方法的重写
- 多态性只适用于方法,不适用于属性(使用和编译都看右边)
接口和抽象类有什么区别?
答:①接口中只能定义public staic final修饰的常量,抽象类中可以定义普通变量。②接口和抽象类都不能实例化,但接口没有构造器,抽象类有构造器。③接口可以多实现,抽象类只能单继承。④接口在JDK1.8之前只能定义public abstract修饰的方法,JDK1.8开始可以定义默认方法和静态方法,JDK1.9开始可以定义私有方法,抽象类中的方法没有限制。
面向对象五大基本原则是什么
- 单一职责原则SRP(Single Responsibility Principle):类的功能要单一,不能包罗万象,跟杂货铺似的。
- 开放封闭原则OCP(Open-Close Principle):一个模块对于拓展是开放的,对于修改是封闭的,想要增加功能热烈欢迎,想要修改,哼,一万个不乐意。
- 里式替换原则LSP(the Liskov Substitution Principle LSP):子类可以替换父类出现在父类能够出现的任何地方。比如你能代表你爸去你姥姥家干活。哈哈~~
- 依赖倒置原则DIP(the Dependency Inversion Principle DIP):高层次的模块不应该依赖于低层次的模块,他们都应该依赖于抽象。抽象不应该依赖于具体实现,具体实现应该依赖于抽象。就是你出国要说你是中国人,而不能说你是哪个村子的。比如说中国人是抽象的,下面有具体的xx省,xx市,xx县。你要依赖的抽象是中国人,而不是你是xx村的.
- 接口分离原则ISP(the Interface Segregation Principle ISP):设计时采用多个与特定客户类有关的接口比采用一个通用的接口要好。就比如一个手机拥有打电参数话,看视频,玩游戏等功能,把这几个功能拆分成不同的接口,比在一个接口里要好的多
抽象类和接口的对比
- 抽象类是用来捕捉子类的通用特性的。
- 接口是抽象方法的集合。
- 从设计层面来说,抽象类是对类的抽象,是一种模板设计,接口是行为的抽象,是一种行为的规范。
相同点
接口和抽象类都不能实例化
都位于继承的顶端,用于被其他实现或继承
都包含抽象方法,其子类都必须覆写这些抽象方法
参数 | 抽象类 | 接口 |
---|---|---|
声明 | 抽象类使用abstract关键字声明 | 接口使用interface关键字声明 |
实现 | 子类使用extends关键字来继承抽象类。如果子类不是抽象类的话,它需要提供抽象类中所有声明的方法的实现 | 子类使用implements关键字来实现接口。它需要提供接口中所有声明的方法的实现 |
构造器 | 抽象类可以有构造器 | 接口不能有构造器 |
访问修饰符 | 抽象类中的方法可以是任意访问修饰符 | 接口方法默认修饰符是public。并且不允许定义为private 或者protected |
多继承 | 一个类最多只能继承一个抽象类 | 一个类可以实现多个接口 |
字段声明 | 抽象类的字段声明可以是任意的 | 接口的字段默认都是 static 和 final的 |
普通类和抽象类的区别
普通类不能包含抽象方法,抽象类可以包含抽象方法。
抽象类不能直接实例化,普通类可以直接实例化。
抽象类能使用 final 修饰吗?
不能,定义抽象类就是让其他类继承的,如果定义为 final 该类就不能被继承,这样彼此就会产生矛盾,所以 final 不能修饰抽象类
成员变量与局部变量的区别
- 变量:在程序执行的过程中,在某个范围内其值可以发生改变的量。从本质上讲,变量其实是内存中的一小块区域
- 成员变量:方法外部,类内部定义的变量
- 局部变量:类的方法中的变量。
- 区别
- 作用域
成员变量:针对整个类有效。
局部变量:只在某个范围内有效。(一般指的就是方法,语句体内) - 存储位置
成员变量:随着对象的创建而存在,随着对象的消失而消失,存储在堆内存中。
局部变量:在方法被调用,或者语句被执行的时候存在,存储在栈内存中。当方法调用完,或者语句结束后,就自动释放。 - 生命周期
成员变量:随着对象的创建而存在,随着对象的消失而消失
局部变量:当方法调用完,或者语句结束后,就自动释放。 - 初始值
成员变量:有默认初始值。
局部变量:没有默认初始值,使用前必须赋值。
创建一个对象用什么关键字?对象实例与对象引用有何不同?
new关键字,new创建对象实例(对象实例在堆内存中),对象引用指向对象实例(对象引用存放在栈内存中)。一个对象引用可以指向0个或1个对象(一根绳子可以不系气球,也可以系一个气球);一个对象可以有n个引用指向它(可以用n条绳子系住一个气球)
在Java中定义一个不做事且没有参数的构造方法的作用
Java程序在执行子类的构造方法之前,如果没有用super()来调用父类特定的构造方法,则会调用父类中“没有参数的构造方法”。因此,如果父类中只定义了有参数的构造方法,而在子类的构造方法中又没有用super()来调用父类中特定的构造方法,则编译时将发生错误,因为Java程序在父类中找不到没有参数的构造方法可供执行。解决办法是在父类里加上一个不做事且没有参数的构造方法
在调用子类构造方法之前会先调用父类没有参数的构造方法的目的
帮助子类做初始化工作。
一个类的构造方法的作用是什么?若一个类没有声明构造方法,改程序能正确执行吗?为什么?
主要作用是完成对类对象的初始化工作。可以执行。因为一个类即使没有声明构造方法也会有默认的不带参数的构造方法。
构造方法有哪些特性?
名字与类名相同;
没有返回值,但不能用void声明构造函数;
生成类的对象时自动执行,无需调用。
静态变量和实例变量的区别
- 静态变量:随着类的加载而加载,一个静态变量可以被多个对象实例所公用
- 实例变量:随着对象的创建而创建,不同对象之间的实例变量互不影响
静态代码块、代码块(构造代码块)、构造方法的执行顺序
静态构造代码块、代码块、构造方法
当涉及到继承时,按照如下顺序执行:
- 执行父类的静态代码块,并初始化父类静态成员变量
- 执行子类的静态代码块,并初始化子类静态成员变量
- 执行父类的构造代码块,执行父类的构造函数,并初始化父类普通成员变量
- 执行子类的构造代码块, 执行子类的构造函数,并初始化子类普通成员变量
构造器(constructor)是否可被重写(override)
构造器不能被继承,因此不能被重写,但可以被重载。
重载(Overload)和重写(Override)的区别。重载的方法能否根据返回类型进行区分?
- 方法的重载和重写都是实现多态的方式,区别在于前者实现的是编译时的多态性,而后者实现的是运行时的多态性。
- 重载:发生在同一个类中,方法名相同参数列表不同(参数类型不同、个数不同、顺序不同),与方法返回值和访问修饰符无关,即重载的方法不能根据返回类型进行区分
- 重写:发生在父子类中,方法名、参数列表必须相同,返回值小于等于父类,抛出的异常小于等于父类,访问修饰符大于等于父类(里氏代换原则);如果父类方法访问修饰符为private则子类中就不是重写
== 和 equals 的区别是什么
- = = : 它的作用是判断两个对象的地址是不是相等。即,判断两个对象是不是同一个对象。(基本数据类型 = = 比较的是值,引用数据类型 = = 比较的是内存地址)
- equals() : 它的作用也是判断两个对象是否相等。但它一般有两种使用情况:
- 情况1:类没有覆盖 equals() 方法。则通过 equals() 比较该类的两个对象时,等价于通过“==”比较这两个对象。
- 情况2:类覆盖了 equals() 方法。一般,我们都覆盖 equals() 方法来两个对象的内容相等;若它们的内容相等,则返回 true (即,认为这两个对象相等)。
hashCode()与equals()的相关规定
- 如果两个对象相等,则hashcode一定也是相同的
- 两个对象相等,对两个对象分别调用equals方法都返回true
- 两个对象有相同的hashcode值,它们也不一定是相等的
- 因此,equals 方法被覆盖过,则 hashCode 方法也必须被覆盖
对象的相等与指向他们的引用相等,两者有什么不同?
对象的相等比的是内存中存放的内容是否相等,而引用相等比较的是他们指向的内存地址是否相等。
值传递和引用传递有什么区别
- 值传递:指的是在方法调用时,传递的是值的拷贝,也就是说传递后就互不相关了。
- 引用传递:指的是在方法调用时,其实传递的引用的地址,也就是变量所对应的内存空间的地址。传递的是值的引用,也就是说传递前和传递后都指向同一个引用(也就是同一个内存空间)
什么时候应该使用接口,什么时候应该使用抽象类?
答:①如果知道某个类应该成为基类,那么第一选择应该是让它成为一个接口,只有在必须要有方法定义和成员变量的时候,才应该选择抽象类。②在接口和抽象类的选择上,必须遵守这样一个原则:行为模型应该总是通过接口而不是抽象类定义。通过抽象类建立行为模型会出现的问题:如果有一个抽象类Moblie,有两个继承它的类Mobile1和Moblie2,分别有自己的功能1和功能2,如果出现一个既有功能1又有功能2的新产品需求,由于Java不允许多继承就出现了问题,而如果是接口的话只需要同时实现两个接口即可
内部类有什么作用?有哪些分类?
答:①内部类有更好的封装性,有更多的权限修饰符,封装性可以得到更多的控制。②静态内部类:由static修饰,属于类本身,只加载一次。类可以定义的成分静态内部类都可以定义,可以访问外部类的静态变量和方法,通过new 外部类.静态内部类构造器来创建对象。③成员内部类:属于外部类的每个对象,随对象一起加载。不可以定义静态成员和方法,可以访问外部类的所有内容,通过new 外部类构造器.new 成员内部类构造器来创建对象。④局部内部类:定义在方法、构造器、代码块、循环中。只能定义实例成员变量和实例方法,作用范围仅在局部代码块中。⑤匿名内部类:没有名字的局部内部类,可以简化代码,匿名内部类会立即创建一个匿名内部类的对象返回,对象类型相当于当前new的类的子类类型。
IO
java 中 IO 流分为几种?
- 按照流的流向分,可以分为输入流和输出流;
- 按照操作单元划分,可以划分为字节流和字符流;
- 按照流的角色划分为节点流和处理流。
BIO,NIO,AIO 有什么区别?
- BIO:Block IO 同步阻塞式 IO,就是我们平常使用的传统 IO,它的特点是模式简单使用方便,并发处理能力低。
- NIO:Non IO 同步非阻塞 IO,是传统 IO 的升级,客户端和服务器端通过 Channel(通道)通讯,实现了多路复用。
- AIO:Asynchronous IO 是 NIO 的升级,也叫 NIO2,实现了异步非堵塞 IO ,异步 IO 的操作基于事件和回调机制。
反射
什么是反射机制
- JAVA反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意一个方法和属性;这种动态获取的信息以及动态调用对象的方法的功能称为java语言的反射机制。
- 静态编译和动态编译
- 静态编译:在编译时确定类型,绑定对象
- 动态编译:运行时确定类型,绑定对象
反射机制优缺点
- 优点: 运行期类型的判断,动态加载类,提高代码灵活度。
- 缺点: 性能瓶颈:反射相当于一系列解释操作,通知 JVM 要做的事情,性能比直接的java代码要慢很多。
Java获取反射的三种方法
1.通过new对象实现反射机制 2.通过路径实现反射机制 3.通过类名实现反射机制
public class Student {
private int id; String name;
protected boolean sex;
public float score;
}
public class Get {
//获取反射机制三种方式
public static void main(String[] args) throws ClassNotFoundException {
//方式一(通过建立对象)
Student stu = new Student();
Class classobj1 = stu.getClass();
System.out.println(classobj1.getName());
//方式二(所在通过路径-相对路径)
Class classobj2 = Class.forName("fanshe.Student");
System.out.println(classobj2.getName());
//方式三(通过类名)
Class classobj3 = Student.class;
System.out.println(classobj3.getName()); } }
线程
使用并发编程的原因
提升多核CPU的利用率:一般来说一台主机上的会有多个CPU核心,我们可以创建多个线程,理论上讲操作系统可以将多个线程分配给不同的CPU去执行,每个CPU执行一个线程,这样就提高了CPU的使用效率,如果使用单线程就只能有一个CPU核心被使用。
简单来说就是:1. 充分利用多核CPU的计算能力;2. 方便进行业务拆分,提升应用性能
多线程应用场景
迅雷多线程下载、数据库连接池、分批发送短信等。
并发编程有什么缺点
并发编程的目的就是为了能提高程序的执行效率,提高程序运行速度,但是并发编程并不总是能提高程序运行速度的,而且并发编程可能会遇到很多问题,比如:内存泄漏、上下文切换、线程安全、死锁等问题。
并发编程三个必要因素是什么?
- 原子性:原子,即一个不可再被分割的颗粒。原子性指的是一个或多个操作要么全部执行成功要么全部执行失败。
- 可见性:一个线程对共享变量的修改,另一个线程能够立刻看到。(synchronized,volatile)
- 有序性:程序执行的顺序按照代码的先后顺序执行。(处理器可能会对指令进行重排序)
Java 程序中怎么保证多线程的运行安全?
出现线程安全问题的原因一般都是三个原因:
- 线程切换带来的原子性问题 解决办法:使用多线程之间同步synchronized或使用锁(lock)。
- 缓存导致的可见性问题 解决办法:synchronized、volatile、LOCK,可以解决可见性问题
- 编译优化带来的有序性问题 解决办法:Happens-Before 规则可以解决有序性问题
并行和并发有什么区别?
- 并发:多个任务在同一个 CPU 核上,按细分的时间片轮流(交替)执行,从逻辑上来看那些任务是同时执行。
- 并行:单位时间内,多个处理器或多核处理器同时处理多个任务,是真正意义上的“同时进行”。
- 串行:有n个任务,由一个线程按顺序执行。由于任务、方法都在一个线程执行所以不存在线程不安全情况,也就不存在临界区的问题。
做一个形象的比喻:
并发 = 俩个人用一台电脑。
并行 = 俩个人分配了俩台电脑。
串行 = 俩个人排队使用一台电脑。
什么是多线程
多线程:多线程是指程序中包含多个执行流,即在一个程序中可以同时运行多个不同的线程来执行不同的任务。
多线程的好处
可以提高 CPU 的利用率。在多线程程序中,一个线程必须等待的时候,CPU 可以运行其它的线程而不是等待,这样就大大提高了程序的效率。也就是说允许单个程序创建多个并行执行的线程来完成各自的任务。
多线程的劣势:
- 线程也是程序,所以线程需要占用内存,线程越多占用内存也越多;
- 多线程需要协调和管理,所以需要 CPU 时间跟踪线程;
- 线程之间对共享资源的访问会相互影响,必须解决竞用共享资源的问题。
线程与进程的区别
进程:每个进程都有独立的代码和数据空间(进程上下文),进程间的切换会有较大的开销,一个进程包含1–n个线程。(进程是资源分配的最小单位)
线程:同一类线程共享代码和数据空间,每个线程有独立的运行栈和程序计数器(PC),线程切换开销小。(线程是cpu调度的最小单位)
线程和进程一样分为五个阶段:创建、就绪、运行、阻塞、终止。
进程与线程的区别
- 根本区别:进程是操作系统资源分配的基本单位,而线程是处理器任务调度和执行的基本单位
- 资源开销:每个进程都有独立的代码和数据空间(程序上下文),程序之间的切换会有较大的开销;线程可以看做轻量级的进程,同一类线程共享代码和数据空间,每个线程都有自己独立的运行栈和程序计数器(PC),线程之间切换的开销小。
- 包含关系:如果一个进程内有多个线程,则执行过程不是一条线的,而是多条线(线程)共同完成的;线程是进程的一部分,所以线程也被称为轻权进程或者轻量级进程。
- 内存分配:同一进程的线程共享本进程的地址空间和资源,而进程与进程之间的地址空间和资源是相互独立的
- 影响关系:一个进程崩溃后,在保护模式下不会对其他进程产生影响,但是一个线程崩溃有可能导致整个进程都死掉。所以多进程要比多线程健壮。
- 执行过程:每个独立的进程有程序运行的入口、顺序执行序列和程序出口。但是线程不能独立执行,必须依存在应用程序中,由应用程序提供多个线程执行控制,两者均可并发执行
上下文切换
当前任务在执行完 CPU 时间片切换到另一个任务之前会先保存自己的状态,以便下次再切换回这个任务时,可以再加载这个任务的状态。任务从保存到再加载的过程就是一次上下文切换。
守护线程和用户线程有什么区别呢?
- 用户 (User) 线程:运行在前台,执行具体的任务,如程序的主线程、连接网络的子线程等都是用户线程
- 守护 (Daemon) 线程:运行在后台,为其他前台线程服务。也可以说守护线程是 JVM 中非守护线程的 “佣人”。一旦所有用户线程都结束运行,守护线程会随 JVM 一起结束工作
创建线程的四种方式
- 继承Thread类
public class FirstThreadTest extends Thread{
int i = 0;
//重写run方法,run方法的方法体就是现场执行体
public void run()
{
for(;i<100;i++){
System.out.println(getName()+" "+i);
}
}
public static void main(String[] args)
{
for(int i = 0;i< 100;i++)
{
System.out.println(Thread.currentThread().getName()+" : "+i);
if(i==20)
{
new FirstThreadTest().start();
new FirstThreadTest().start();
}
}
}
}
- 实现Runnable接口
public class MyRunnable implements Runnable
{
@Override
public void run()
{
System.out.println(Thread.currentThread().getName() + " run()方法执行 中...");
}
- 实现Callable接口
public class MyCallable implements Callable<Integer>
{
@Override public Integer call()
{
System.out.println(Thread.currentThread().getName() + " call()方法执行 中...");
return 1;
}
- 使用匿名内不类的方式
public class CreateRunnable {
public static void main(String[] args) {
//创建多线程创建开始
Thread thread = new Thread(new Runnable()
{
public void run()
{
for (int i = 0; i < 10; i++)
{
System.out.println("i:" + i);
}
}
});
thread.start(); } }
runnable和callable的区别
- 相同点
- 都是接口
- 都可以编写多线程程序
- 都采用Thread.start()启动线程
- 区别
- Runnable 接口 run 方法无返回值;Callable 接口 call 方法有返回值,是个泛型,和Future、FutureTask配合可以用来获取异步执行的结果
- Runnable 接口 run 方法只能抛出运行时异常,且无法捕获处理;Callable 接口 call 方法允许抛出异常,可以获取异常信息 注:Callalbe接口支持返回执行结果,需要调用FutureTask.get()得到,此方法会阻塞主进程的继续往下执行,如果不调用不会阻塞。
run方法和start方法的区别
- start()方法运行时,本地启动新的线程,线程中会调用run方法,程序不需要等待run方法执行完毕再执行后面的程序;
- run()方法是我们编写需要新的线程执行代码的方法,单独运行是不会有多线程效果的。
为什么我们调用 start() 方法时会执行 run() 方法,为什么我们不能直接调用run() 方法?
- new 一个 Thread,线程进入了新建状态。调用 start() 方法,会启动一个线程并使线程进入了就绪状态,当分配到 时间片 后就可以开始运行了。 start() 会执行线程的相应准备工作,然后自动执行run() 方法的内容,这是真正的多线程工作。
- 而直接执行 run() 方法,会把 run 方法当成一个 main 线程下的普通方法去执行,并不会在某个线程中执行它,所以这并不是多线程工作。
- 总结: 调用 start 方法方可启动线程并使线程进入就绪状态,而 run 方法只是 thread 的一个普通方法调用,还是在主线程里执行
sleep() 和 wait() 有什么区别?
- 类的不同:sleep() 是 Thread线程类的静态方法,wait() 是 Object类的方法。
- 是否释放锁:sleep() 不释放锁;wait() 释放锁。
- 用途不同:Wait 通常被用于线程间交互/通信,sleep 通常被用于暂停执行。
- 用法不同:wait() 方法被调用后,线程不会自动苏醒,需要别的线程调用同一个对象上的 notify()或者 notifyAll() 方法。sleep() 方法执行完成后,线程会自动苏醒。或者可以使用wait(long timeout)超时后线程会自动苏醒。
字符串
字符串拼接的方式以及效率?
答:①使用+直接拼接,String 是final对象,不会被修改,每次使用 +进行拼接都会创建新的对象,而不是改变原来的对象,效率低,是线程安全的。②使用StringBuffer可变字符串,效率较高,是线程安全的(StringBuffer的方法使用了synchronized关键字进行修饰)。③使用StringBuilder可变字符串,效率最高,但是线程不安全。
简述final,finally和finalize区别
答:①final可以修饰类,方法和变量,被final修饰的类不可继承,被final修饰的方法不可重写,被final修饰的变量引用不可更改,引用的内容可以更改。②finally用于try-catch代码块中,无论是否发生异常最后都将执行,作用是释放资源。③finalize是Object类的方法,在对象被垃圾回收之前将调用一次,一般用于资源的释放
String str="i"与 String str=new String(“i”)一样吗?
不一样,因为内存的分配方式不一样。String str="i"的方式,java 虚拟机会将其分配到常量池中;而 String str=new String(“i”) 则会被分到堆内存中。
集合
集合和数组的区别
- 数组是固定长度的;集合可变长度的。
- 数组可以存储基本数据类型,也可以存储引用数据类型;集合只能存储引用数据类型。
- 数组存储的元素必须是同一个数据类型;集合存储的对象可以是不同数据类型。
常用的集合类有哪些?
Map接口和Collection接口是所有集合框架的父接口:
- Collection接口的子接口包括:Set接口和List接口
- Map接口的实现类主要有:HashMap、TreeMap、Hashtable、LinkedHashMap、ConcurrentHashMap以及Properties等
- Set接口的实现类主要有:HashSet、TreeSet、LinkedHashSet等
- List接口的实现类主要有:ArrayList、LinkedList、Stack以及Vector等
List,Set,Map三者的区别
- Java 容器分为 Collection 和 Map 两大类,Collection集合的子接口有Set、List、Queue三种子接口。我们比较常用的是Set、List,Map接口不是collection的子接口。
- Collection集合主要有List和Set两大接口
- List:一个有序(元素存入集合的顺序和取出的顺序一致)容器,元素可以重复,可以插入多个null元素,元素都有索引。用的实现类有 ArrayList、LinkedList 和 Vector。
- Set:一个无序(存入和取出顺序有可能不一致)容器,不可以存储重复元素,只允许存入一个null元素,必须保证元素唯一性。Set 接口常用实现类是 HashSet、LinkedHashSet 以及TreeSet。
- Map是一个键值对集合,存储键、值和之间的映射。 Key无序,唯一;value 不要求有序,允许重复。Map没有继承于Collection接口,从Map集合中检索元素时,只要给出键对象,就会返回对应的值对象。Map 的常用实现类:HashMap、TreeMap、HashTable、LinkedHashMap
集合框架底层数据结构
- List:
- ArrayList:
特点:有序(有序指的是存储的顺序与取出来的顺序是一样的)、元素可重复、有索引,线程不安全,效率高。
数据结构:底层数据结构是数组、查询快,增删慢。 - LinkedList:
特点:有序(有序指的是存储的顺序与取出来的顺序是一样的)、元素可重复、有索引。
数据结构:链表结构>>>双向链(prev前指针域 e参数 next后指针域)、增删快、查询慢 - vector:
特点:有序(有序指的是存储的顺序与取出来的顺序是一样的)、元素可重复、有索引,线程安全,效率低。
- set:
- Hashset:作为set接口的主要实现类,线程不安全,可以存储null值,底层采用了HashMap,默认大小16。
- LinkedHashSet:作为HashSet子类,遍历其内部数据时,可以按照添加顺序遍历,底层采用LinkedHashMap
- TreeSet:可以按照添加对象属性进行排序,采用了红黑树的方式进行存储
- Map
- HashMap: JDK1.8之前HashMap由数组+链表组成的,数组是HashMap的主体,链表则是主要为了解决哈希冲突而存在的(“拉链法”解决冲突).JDK1.8以后在解决哈希冲突时有了较大的变化,当链表长度大于阈值(默认为8)时,将链表转化为红黑树,以减少搜索时间
- LinkedHashMap:LinkedHashMap 继承自 HashMap,所以它的底层仍然是基于拉链式散列结构即由数组和链表或红黑树组成。另外,LinkedHashMap 在上面结构的基础上,增加了一条双向链表,使得上面的结构可以保持键值对的插入顺序。同时通过对链表进行相应的操作,实现了访问顺序相关逻辑。
HashTable: 数组+链表组成的,数组是 HashMap 的主体,链表则是主要为了解决哈希冲突而存在的
TreeMap: 红黑树(自平衡的排序二叉树)
Iterator 和 ListIterator 有什么区别?
- Iterator 可以遍历 Set 和 List 集合,而 ListIterator 只能遍历 List。
- Iterator 只能单向遍历,而 ListIterator 可以双向遍历(向前/后遍历)。
- ListIterator 实现 Iterator 接口,然后添加了一些额外的功能,比如添加一个元素、替换一个元素、获取前面或后面元素的索引位置。
遍历一个 List 有哪些不同的方式?每种方法的实现原理是什么?
- for 循环遍历,基于计数器。在集合外部维护一个计数器,然后依次读取每一个位置的元素,当读取到最后一个元素后停止。
- 迭代器遍历,Iterator。Iterator 是面向对象的一个设计模式,目的是屏蔽不同数据集合的特点,统一遍历集合的接口。Java 在 Collections 中支持了 Iterator 模式。
- foreach 循环遍历。foreach 内部也是采用了 Iterator 的方式实现,使用时不需要显式声明Iterator 或计数器。优点是代码简洁,不易出错;缺点是只能做简单的遍历,不能在遍历过程中操作数据集合,例如删除、替换。
如何实现数组和 List 之间的转换?
- 数组转 List:使用 Arrays. asList(array) 进行转换。
- List 转数组:使用 List 自带的 toArray() 方法。
Array和ArrayList的区别?
答:①Array长度在定义之后就不运行改变了,而ArrayList是长度可变的,可以自动扩容。②Array只能存储相同类型的数据,ArrayList可以存储不同类型的数据。③ArrayList提供了更多操作数据的方法。
ArrayList 和 LinkedList 的区别是什么?
- 数据结构实现:ArrayList 是动态数组的数据结构实现,而 LinkedList 是双向链表的数据结构实现。
- 随机访问效率:ArrayList 比 LinkedList 在随机访问的时候效率要高,因为 LinkedList 是线性的数据存储方式,所以需要移动指针从前往后依次查找。
- 增加和删除效率:在非首尾的增加和删除操作,LinkedList 要比 ArrayList 效率要高,因为ArrayList 增删操作要影响数组内的其他数据的下标。
- 内存空间占用:LinkedList 比 ArrayList 更占内存,因为 LinkedList 的节点除了存储数据,还存储了两个引用,一个指向前一个元素,一个指向后一个元素。
- 线程安全:ArrayList 和 LinkedList 都是不同步的,也就是不保证线程安全;
- 综合来说,在需要频繁读取集合中的元素时,更推荐使用 ArrayList,而在插入和删除操作较多时,更推荐使用 LinkedList。
- LinkedList 的双向链表也叫双链表,是链表的一种,它的每个数据结点中都有两个指针,分别指向直接后继和直接前驱。所以,从双向链表中的任意一个结点开始,都可以很方便地访问它的前驱结点和后继结点
ArrayList 和 Vector 的区别是什么?
- 这两个类都实现了 List 接口(List 接口继承了 Collection 接口),他们都是有序集合
- 线程安全:Vector 使用了 Synchronized 来实现线程同步,是线程安全的,而 ArrayList 是非线程安全的。
- 性能:ArrayList 在性能方面要优于 Vector。
- 扩容:ArrayList 和 Vector 都会根据实际的需要动态的调整容量,只不过在 Vector 扩容每次会增加 1 倍,而 ArrayList 只会增加 50%。 默认大小都为10。
- Vector类的所有方法都是同步的。可以由两个线程安全地访问一个Vector对象、但是一个线程访问
- Vector的话代码要在同步操作上耗费大量的时间。
- Arraylist不是同步的,所以在不需要保证线程安全时时建议使用Arraylist。
List 和 Set 的区别
- List , Set 都是继承自Collection 接口
- List 特点:一个有序(元素存入集合的顺序和取出的顺序一致)容器,元素可以重复,可以插入多个null元素,元素都有索引。常用的实现类有 ArrayList、LinkedList 和 Vector。
- Set 特点:一个无序(存入和取出顺序有可能不一致)容器,不可以存储重复元素,只允许存入一个null元素,必须保证元素唯一性。Set 接口常用实现类是 HashSet、LinkedHashSet 以及TreeSet。
- 另外 List 支持for循环,也就是通过下标来遍历,也可以用迭代器,但是set只能用迭代,因为他无序,无法用下标来取得想要的值。
- Set和List对比
- Set:检索元素效率低下,删除和插入效率高,插入和删除不会引起元素位置改变。
- List:和数组类似,List可以动态增长,查找元素效率高,插入删除元素效率低,因为会引起其他元素位置改变
什么是Hash算法
哈希算法是指把任意长度的二进制映射为固定长度的较小的二进制值,这个较小的二进制值叫做哈希值。
HashMap在jdk7和jdk8的区别
不同 | jdk1.7 | jdk1.8 |
---|---|---|
存储结构 | 数组 + 链表 | 数组 + 链表 + 红黑树 |
初始化方式 | 单独函数: inflateTable() | 直接集成到了扩容函数 resize() 中 |
hash值计算方式 | 扰动处理 = 9次扰动 = 4次位运算 + 5次异或运算 | 扰动处理 = 2次扰动 = 1次位运算 + 1次异或运算 |
存放数据的规则 | 无冲突时,存放数组;冲突时,存放链表 | 无冲突时,存放数组;冲突 & 链表长度 <8:存放单链表;冲突 & 链表长度 > 8:树化并存放红黑树 |
插入数据方式 | 头插法(先讲原位置的数据移到后1位,再插入数据到该位置) | 尾插法(直接插入到链表尾部/红黑树) |
扩容后存储位置的计算方式 | 全部按照原来方法进行计算(即hashCode ->> 扰动函数 ->> (h&length-1)) | 按照扩容后的规律计算(即扩容后的位置=原位置 or 原位置 + 旧容量) |
什么是哈希冲突?
当两个不同的输入值,根据同一散列函数计算出相同的散列值的现象,我们就把它叫做碰撞(哈希碰撞)。
HashMap 与 HashTable 有什么区别?
- 线程安全: HashMap 是非线程安全的,HashTable 是线程安全的;HashTable 内部的方法基本都经过 synchronized 修饰。(如果你要保证线程安全的话就使用 ConcurrentHashMap );
- 效率: 因为线程安全的问题,HashMap 要比 HashTable 效率高一点。另外,HashTable 基本被淘汰,不要在代码中使用它;(如果你要保证线程安全的话就使用 ConcurrentHashMap );
- 对Null key 和Null value的支持: HashMap 中,null 可以作为键,这样的键只有一个,可以有一个或多个键所对应的值为 null。但是在 HashTable 中 put 进的键值只要有一个 null,直接抛NullPointerException。
- 初始容量大小和每次扩充容量大小的不同 :创建时如果不指定容量初始值,Hashtable 默认的初始大小为11,之后每次扩充,容量变为原来的2n+1。HashMap 默认的初始化大小为16。之后每次扩充,容量变为原来的2倍。
- 创建时如果给定了容量初始值,那么 Hashtable 会直接使用你给定的大小,而 HashMap 会将其扩充为2的幂次方大小。也就是说 HashMap 总是使用2的幂作为哈希表的大小,
- 底层数据结构: JDK1.8 以后的 HashMap 在解决哈希冲突时有了较大的变化,当链表长度大于阈值(默认为8)时,将链表转化为红黑树,以减少搜索时间。Hashtable 没有这样的机制。
Collection 和 Collections 有什么区别?
java.util.Collection 是一个集合接口(集合类的一个顶级接口)。它提供了对集合对象进行基本操作的通用接口方法。Collection接口在Java 类库中有很多具体的实现。Collection接口的意义是为各种具体的集合提供了最大化的统一操作方式,其直接继承接口有List与Set。
Collections则是集合类的一个工具类/帮助类,其中提供了一系列静态方法,用于对集合中元素进行排序、搜索以及线程安全等各种操作。
什么是TreeMap
- TreeMap 是一个有序的key-value集合,它是通过红黑树实现的。
- TreeMap基于红黑树(Red-Black tree)实现。该映射根据其键的自然顺序进行排序,或者根据创建映射时提供的 Comparator 进行排序,具体取决于使用的构造方法。
- TreeMap是线程非同步的。
在使用 HashMap 的时候,用 String 做 key 有什么好处?
HashMap 内部实现是通过 key 的 hashcode 来确定 value 的存储位置,因为字符串是不可变的,所以当创建字符串时,它的 hashcode 被缓存下来,不需要再次计算,所以相比于其他对象更快。
异常
异常有哪些分类?出现的原因是什么?
答:①Throwable是所有错误和异常的父类,Throwable分为Error和Exception。②Error指Java程序运行错误,出现Error通常是因为系统的内部错误或资源耗尽,Error不能在运行过程中被动态处理,如果程序运行中出现Error,系统只能记录错误的原因和安全终止。③Exception指Java程序运行异常,即运行中发生了不期望的情况,分为RuntimeException和CheckedException。RuntimeException指在Java虚拟机正常运行期间抛出的异常,可以被捕获并处理,例如空指针异常,数组越界等。CheckedException指编译阶段强制要求捕获并处理的异常,例如IO异常,SQL异常等。
有哪些异常处理方式?
答:①抛出异常:遇到异常不进行具体处理,而是将异常抛出给调用者,由调用者根据情况处理。抛出异常有2种形式,一种是throws,作用在方法上,一种是throw,作用在方法内。②使用try/catch进行异常的捕获处理,try中发生的异常会被catch代码块捕获,根据情况进行处理,如果有finally代码块无论是否发生异常都会执行,一般用于释放资源,JDK1.7开始可以将资源定义在try代码块中自动释放减少代码。
Error 和 Exception 区别是什么?
- Error 类型的错误通常为虚拟机相关错误,如系统崩溃,内存不足,堆栈溢出等,编译器不会对这类错误进行检测,JAVA 应用程序也不应对这类错误进行捕获,一旦这类错误发生,通常应用程序会被终止,仅靠应用程序本身无法恢复;
- Exception 类的错误是可以在应用程序中进行捕获并处理的,通常遇到这种错误,应对其进行处理,使应用程序可以继续正常运行。
JVM 是如何处理异常的?
- 在一个方法中如果发生异常,这个方法会创建一个异常对象,并转交给 JVM,该异常对象包含异常名称,异常描述以及异常发生时应用程序的状态。创建异常对象并转交给 JVM 的过程称为抛出异常。可能有一系列的方法调用,最终才进入抛出异常的方法,这一系列方法调用的有序列表叫做调用栈。
- JVM 会顺着调用栈去查找看是否有可以处理异常的代码,如果有,则调用异常处理代码。当 JVM发现可以处理异常的代码时,会把发生的异常传递给它。如果 JVM 没有找到可以处理该异常的代码块,JVM 就会将该异常转交给默认的异常处理器(默认处理器为 JVM 的一部分),默认异常处理器打印出异常信息并终止应用程序。
throw 和 throws 的区别是什么?
Java 中的异常处理除了包括捕获异常和处理异常之外,还包括声明异常和拋出异常,可以通过throws 关键字在方法上声明该方法要拋出的异常,或者在方法内部通过 throw 拋出异常对象。
throws 关键字和 throw 关键字在使用上的几点区别如下:
- throw 关键字用在方法内部,只能用于抛出一种异常,用来抛出方法或代码块中的异常,受查异常和非受查异常都可以被抛出。
- throws 关键字用在方法声明上,可以抛出多个异常,用来标识该方法可能抛出的异常列表。一个方法用 throws 标识了可能抛出的异常列表,调用该方法的方法中必须包含可处理异常的代码,否则也要在方法签名中用 throws 关键字声明相应的异常。
泛型
泛型和泛型擦除是什么?
答:①泛型的本质是参数化类型,泛型提供了编译时类型的安全检测机制,该机制允许程序在编译时检测非法的类型。②在编译阶段采用泛型时加上的类型参数,会被编译器在编译时去掉,这个过程就被称为类型擦除,因此泛型主要用于编译阶段,在编译后生成的Java字节代码文件中不包含泛型中的类型信息。
泛型标记的规范了解吗?
答:①E:值Element,在集合中使用,表示在集合中存放的元素。②T:指Type,表示Java类,包括基本的类以及自定义类。③K:指Key,表示键,例如Map集合中的Key。④V:指Value,表示值,例如Map集合中的Value。⑤N:指Number,表示数值类型。⑥?:表示不确定的Java类型。
泛型限定是什么?
答:①类型通配符使用?表示所有具体的参数类型,在使用泛型的时候,如果希望将类的继承关系加入泛型应用中就需要对泛型做限定,具体的泛型限定有对泛型上限的限定以及对泛型下限的限定。②对泛型上限的限定使用<? extends T>,它表示该通配符所代表的类型是T类的子类型或T接口的子接口。③对泛型下限的限定使用<? super T>,它表示该通配符所代表的类型是T类的父类型或T接口的父接口。
其他
自动装箱与拆箱
装箱:将基本类型用它们对应的引用类型包装起来;
拆箱:将包装类型转换为基本数据类型;
Integer a= 127 与 Integer b = 127相等吗
对于对象引用类型:= =比较的是对象的内存地址。
对于基本数据类型:= =比较的是值。
如果整型字面量的值在-128到127之间,那么自动装箱时不会new新的Integer对象,而是直接引用常量池中的 Integer对象,超过范围 a1==b1的结果是false
public static void main(String[] args)
{
Integer a = new Integer(3);
Integer b = 3; // 将3自动装箱成Integer类型
int c = 3; S
ystem.out.println(a == b); // false 两个引用没有引用同一对象
System.out.println(a == c); // true a自动拆箱成int类型再和c比较
System.out.println(b == c); // true
Integer a1 = 128;
Integer b1 = 128;
System.out.println(a1 == b1); // false
Integer a2 = 127;
Integer b2 = 127;
System.out.println(a2 == b2); // true }
JavaWeb
HTTP的特点
- HTTP是基于tcp/ip协议的
- http默认使用的是80端口
- http是请求/响应模型,一次请求对应一次响应
- http是无状态的,每次请求之间相互独立,不能交互数据
- http1.0每一次请求响应都会建立新的连接,HTTP1.1会复用连接
HTTP请求数据的数据格式是什么
- 请求行,包括了请求方式、请求url、请求协议、版本。HTTP有7中请求方式,常用的有2种,GET方式,请求参数的请求行中,在url后,请求的url长度是有限制的,不太安全;POST方式,请求参数的请求体中、请求url长度没有限制、相对安全
- 请求头,客户端浏览器告诉服务器的一些信息,常见的请求头例如:User-Agent,告诉服务器浏览器使用的版本信息,可以在服务器端获取该头的信息,解决浏览器的兼容性问题。Referer,告诉服务器,当前请求从哪里来,可以防盗链或者进行数据统计
- 请求空行,用于分隔POST请求的请求头和请求体
- 请求体(正文),封装POST请求的请求参数
转发和重定向的区别?
答:①转发的特点: 转发地址栏路径不变、 转发只能访问当前服务器下的资源、转发是一次请求,可以使用request对象来共享数据。②重定向的特点:地址栏发生变化、重定向可以访问其他站点(服务器)的资源、重定向是两次请求,不能使用request对象来共享数据。
讲一讲Cookie
答:①Cookie是客户端会话技术,将数据保存到客户端。②创建Cookie对象,绑定数据:new Cookie(String name, String value)
;发送Cookie对象:response.addCookie(Cookie cookie)
,一次可以发送多个Cookie;获取Cookie,拿到数据:request.getCookies()
。③浏览器对于单个cookie 的大小有限制(4kb) 以及对同一个域名下的总cookie数量也有限制(20个),cookie一般用于存出少量的不太敏感的数据,在不登录的情况下,完成服务器对客户端的身份识别。
Cookie的生命周期?
答:①默认情况下,当浏览器关闭后,Cookie数据被销毁。②如果想要持久化存储,可以使用setMaxAge(int seconds)
。正数:将Cookie数据写到硬盘的文件中,持久化存储,并指定cookie存活时间,时间到后,cookie文件自动失效。负数:默认值。零:删除cookie信息。
Cookie可以存储中文数据吗?
答:①在tomcat 8 之前cookie中不能直接存储中文数据,需要将中文数据转码—一般采用URL编码(%E3)。②在tomcat 8 之后,cookie支持中文数据,特殊字符还是不支持,建议使用URL编码存储,URL解码解析。
Cookie的共享范围是什么?
答:①假设在一个tomcat服务器中,部署了多个web项目,那么在这些web项目中cookie默认情况下不能共享。通过setPath(String path)
设置cookie的获取范围,默认情况下,设置为当前的虚拟目录,如果要共享,则可以将path设置为/。②不同的tomcat服务器间cookie共享问题:通过setDomain(String path)
设置一级域名,如果一级域名相同,那么多个服务器之间cookie可以共享。例如setDomain(".baidu.com")
,那么tieba.baidu.com和news.baidu.com中cookie可以共享。
讲一讲Session
答:①Session是服务器端会话技术,在一次会话的多次请求间共享数据,将数据保存在服务器端的对象中。②获取HttpSession对象:request.getSession();使用HttpSession对象:Object getAttribute(String name)、void setAttribute(String name, Object value)、void removeAttribute(String name)。③Session的实现是依赖于Cookie的,服务器是通过cookie中的JESSIONID判断session是否是同一个的。
Session的生命周期?当客户端关闭后,服务器不关闭,两次获取session是否为同一个?客户端不关闭,服务器关闭后,两次获取的session是同一个吗?
答:①服务器关闭、session对象调用invalidate() 时销毁,session默认失效时间 30分钟。②在默认情况下,当客户端关闭服务端不关闭时,两次获取session值不是同一个。③如果需要相同,则可以创建Cookie,键为JSESSIONID,设置最大存活时间,让cookie持久化保存。④客户端不关闭,服务端关闭,两次获取的session值也不是同一个。但是要确保数据不丢失。tomcat自动完成以下工作。session的钝化: 在服务器正常关闭之前,将session对象序列化到硬盘上。session的活化: 在服务器启动后,将session文件转化为内存中的session对象即可。但是IDEA不支持这种操作,因为每次用IDEA重启tomcat时会自动删除catalina_base中work目录(程序动态生成的文件),这样在关闭tomcat时生成的session序列化文件也会被删除。
Session的特点,和Cookie有什么区别?
答:①Session用于存储一次会话的多次请求的数据,存在服务器端。session可以存储任意类型,任意大小的数据。②Session存储数据在服务器端,Cookie存储数据在客户端。
Session没有存储数据的大小限制,Cookie有数据大小限制。Session存储数据是安全的,使用Cookie存储数据相对于使用Session来说不安全。
JSP9大隐视对象中四个作用域的大小与作用范围
- 四个作用域从大到小:appliaction>session>request>page
- application:全局作用范围,整个应用程序共享.生命周期为:应用程序启动到停止。
- session:会话作用域,当用户首次访问时,产生一个新的会话,以后服务器就可以记 住这个会话状态。
- request:请求作用域,就是客户端的一次请求。
- page:一个JSP页面。
以上作用范围使越来越小, request和page的生命周期都是短暂的,他们之间的区别就是:一个request可以包含多个page页(include,forward)。
后续持续更新中