Java基础知识面试题2021

这里写目录标题

📝java基础分割线

java基础

基本数据类型

数据类型关键字字节取值范围默认包装类
整数byte1-2^7 – 2^7-1 (-128 – 127)0Byte
short2-2^15 – 2^15-1 ( -32768 – 32767)0Short
int(默认)4-2^31 – 2^31-10Integer
long8-2^63 – 2^63-10LLong
浮点float4负数:-3.402823E+38到-1.401298E-45 正数: 1.401298E-45到3.402823E+380.0fFloat
double (默认)8负数:-1.797693E+308到-4.9000000E-324 正数:4.9000000E-324 到1.797693E+3080.0dDouble
字符char2\u0000 – \uffff (0-65535)\u0000’ (空格)Character
布尔boolean1true,falseFALSEBoolean

数据范围小的可以直接赋值给数据范围大的
数据范围大的不可以直接赋值给数据范围小的,需要进行类型转换
e+38表示是乘以10的38次方,同样,e-45表示乘以10的负45次方。

终止循环的方法,如何跳出当前的多重嵌套循环

  1. break:直接强行跳出当前循环,不再执行剩余代码。但在多重循环的情况下,若break在内层循环中,则仅仅终止了内层循环,外循环照常执行。
  2. continue:仅仅终止此次循环。
  3. return:使程序返回到调用某方法的地方。
  4. break+标签:可用于终止多重循环。在多重循环前设置一个标签,配合break即可终止整个循环。
  5. System.exit(0) ;终止当前运行的 Java 虚拟机 参数传入一个数字即可。通常传入0记为正常状态,其它为异常状态。

jvm对其支配的内存空间进行了哪些区域划分

程序计数器(program counter register),本地方法栈(native method stack),虚拟机栈(VM stack),堆(heap),方法区(method area)

解释内存中的栈(stack)、堆(heap)和静态区(static area)的用法。

通常我们定义一个基本数据类型的变量,一个对象的引用,还有就是函数调用的现场保存都使用内存中的栈空间;

而通过new关键字和构造器创建的对象放在堆空间;

程序中的字面量(literal)如直接书写的100、"hello"和常量都是放在静态区中。

栈空间操作起来最快但是栈很小,通常大量的对象都是放在堆空间,理论上整个内存没有被其他进程使用的空间甚至硬盘上的虚拟内存都可以被当成堆空间来使用。

JDK 和 JRE 的区别是什么?

Java 开发工具包(JDK)是完整的 Java 软件开发包,包含了 JRE,编译器和其他的工具(比如:JavaDoc,Java 调试器),可以让开发者开发、编译、执行 Java 应用程序。Java 运行时环境(JRE)是将要执行 Java 程序的 Java 虚拟机。它同时也包含了执行 applet 需要的浏览器插件。

说出 JDK 1.7 中的新特性?

  1. switch 语句可以用字符串
  2. 泛型简化,菱形泛型,菱形操作符(<>)用于类型推断,不再需要在变量声明的右边申明泛型,因此可以写 出可读写更强、更简洁的代码。
  3. 允许在同一个 catch 块中捕获多个异常。
  4. try-with-resource 语句,这样你在使用流或者资源的时候,就不需要手动关闭,Java 会自动关闭。
  5. 数字字面量可以出现下划线 int one_million = 1_000_000;
  6. 二进制字面量 int binary = 0b1001_1001;

说出 5 个 JDK 1.8 引入的新特性?

  1. Lambda 表达式,允许像对象一样传递匿名函数
  2. Stream API,充分利用现代多核 CPU,可以写出很简洁的代码
  3. Date 与 Time API,最终,有一个稳定、简单的日期和时间库可供你使用
  4. 扩展方法,现在,接口中可以有静态、默认方法。
  5. 重复注解,现在你可以将相同的注解在同一类型上使用多次。

在.java 源文件中可以有多个类吗(内部类除外)?

一个.java 源文件中可以包括多个类(不是内部类),但是单个文件中只能有一个 public 类,并且该 public 类必须与文件名相同

深拷贝和浅拷贝的区别是什么?

浅拷贝:被复制对象的所有变量都含有与原来的对象相同的值,而所有的对其他对象的引用 仍然指向原来的对象,换言之,浅拷贝仅仅复制所考虑的对象,而不复制它所引用的对象.

深拷贝:被复制对象的所有变量都含有与原来的对象相同的值,而那些引用其他对象的变量 将指向被复制过的新对象,而不再是原有的那些被引用的对象.换言之.深拷贝把要复制的对 象所引用的对象都复制了一遍.

switch 能否作用在 byte、long、string 上?

switch(expr1)中,expr1 是一个整数表达式。因此传递给switch 和case语句的参数应该是int、short、char 、byte这类整数。
long,string 都不能作用于swtich。
switch 可以是枚举类型(JDK1.5 之后)
**string在JDK1.7之后可以,**但是long还是不行,呢么为什么其他整数类型就行呢?
因为switch的参数可以是int 基本类型或Integer 包装类型,byte,short,char 都可以隐含转换为int

什么是值传递和引用传递?

值传递传递的是值,即使修改了,也影响原来的值
引用传递传递的地址,这样修改了的话,原来的值也会改变

Java 中==和 equals()的区别?

使用==比较原生类型如:boolean、int、char 等等,使用 equals()比较对象。

1、==是判断两个变量或实例是不是指向同一个内存空间。equals 是判断两个变量或实例所指向的内存空间的值是不是相同。

2、==是指对内存地址进行比较。equals()是对字符串的内容进行比较。

3、==指引用是否相同,equals()指的是值是否相同。

&和&&的区别?

&是位运算符,表示按位与运算,&&是逻辑运算符,表示逻辑与(and)。

Java 中的编译期常量是什么?使用它又什么风险?

公共静态不可变(public static final )变量也就是我们所说的编译期常量,这里的 public 可选的。实际上这些变量在编译时会被替换掉,因为编译器知道这些变量的值,并且知道这些 变量在运行时不能改变。这种方式存在的一个问题是你使用了一个内部的或第三方库中的公有编译时常量,但是这个值后面被其他人改变了,但是你的客户端仍然在使用老的值,甚至 你已经部署了一个新的 jar。为了避免这种情况, 当你在更新依赖 JAR 文件时,确保重新编译你的程序。

Java 中 ++ 操作符是线程安全的吗?

不是线程安全的操作。它涉及到多个指令,如读取变量值,增加,然后存储回内存,这个过 程可能会出现多个线程交差。

== 和 equals的区别:

== 应用在普通数据类型时,比较值是否相等,应用在引用数据类型时,比较地址是否相等

equals 应用在引用数据类型,当对象所属的类重写equals方法时,就按照重写的方式比较两个对象是否相等,未重写时, 比较两个对象地址是否相等(不是内容)。

java在声明一个数组的过程中,是如何分配内存的,初始化方式有几种

数组在初始化过程中,有两种初始化方式:静态和动态初始化,两者的区别在于由系统指定长度还是由程序员指定长度,然后系统根据指定的长度在堆内存中寻找一块大小符合的连续内存块分配给数组,并根据数组类型初始化每个数组元素的值,初始化完之后,数组长度不可改变

你知道基本类型数组和引用类型数组之间,在初始化时内存分配机制有什么区别?

对于基础类型数组而言,它的元素就是一个固定的值,而对于引用类型数组而言,他的数组元素是一个引用类型变量,可以指向任何有效的内存,即你的引用类型是A,那么A对象数组的元素也需要指向一个A对象。

所以在两种类型初始化时,还需为引用类型数组元素额外初始化另外一块内存,再把元素变量指向该内存地址

数组排序法

冒泡排序,选择排序,插入排序

面向对象

请简述一下面向对象(OOP)的特征

**封装:**类中将资源(全局变量、方法)私有化,使用private关键字实现,隐藏一切可隐藏的东西,只向外界提供最简单的编程接口。提高数据的安全性,提高代码整洁度,提高代码的复用性,降低了程序之间的耦合性

**继承:**发生在两个类中的关系,一个类继承另一个类中具有访问权限的属性(成员变量)和行为(方法),使用extends关键字实现,只能单继承,提高了代码的复用性,并且可以实现子类对父类进行扩展和修改(方法的重写)

**多态:**多态首先是建立在继承的基础上的,先有继承才能有多态。多态是指不同的子类在继承父类后分别都重写覆盖了父类的方法。这样当同一个行为(方法调用)执行时可以根据不同对象,当有父类引用指向子类对象(上转型对象), 此为多态 。(继承,重写,父类引用指向子类对象)

抽象:抽象是将一类对象的共同特征总结出来构造类的过程,包括数据抽象和行为抽象两 方面。抽象只关注对象有哪些属性和行为,并不关注这些行为的细节是什么。

多态的优点?

可替换性(substitutability)。多态对已存在代码具有可替换性。例如,多态对圆 Circle 类工作,对其他任何圆形几何体,如圆环,也同样工作。

可扩充性(extensibility)。多态对代码具有可扩充性。增加新的子类不影响已存在类的 多态性、继承性,以及其他特性的运行和操作。实际上新加子类更容易获得多态功能。

Java 创建对象的几种方式?

new 创建新对象;通过反射机制;采用 clone 机制;通过序列化机制

请说明一个JAVA类中主要包含哪几个元素?并说明每种元素的作用

JAVA类中主要包含属性、方法、构造方法、块以及内部类。

  • 属性用来定义对象的数据;
  • 方法用来定义对象的行为;
  • 构造方法可以用来创建对象;
  • 块能够用来在类加载时执行操作或者在每次实例化前执行通用操作;
  • 内部类作为类的一个成员存在,能够访问外部类的属性和方法。

抽象类和接口的区别?

1、接口中所有的方法隐含的都是抽象的。而抽象类则可以同时包含抽象和非抽象的方法。

2、类可以实现很多个接口,但是只能继承一个抽象类

3、类如果要实现一个接口,它必须要实现接口声明的所有方法。但是,类可以不实现 抽象类声明的所有方法,当然,在这种情况下,类也必须得声明成是抽象的。

4、抽象类可以在不提供接口方法实现的情况下实现接口。

5、Java 接口中声明的变量默认都是 final 的。抽象类可以包含非 final 的变量。

6、Java 接口中的成员函数默认是 public 的。抽象类的成员函数可以是 private,protecte 或者是 public 。

7、接口和抽象类都不可以实例化。但是接口中不能有构造方法,抽象类可以有构造方法

接口组成

1、 静态常量:public static final

2、 抽象方法:public abstract

3、 默认方法(Java8):default

4、 静态方法(Java8):static

5、 私有方法(Java9):private或者private static

方法重载/方法重写的规则?

重载:发生在一个类中,方法名相同,参数列表不同(类型,个数,顺序) ,与访问修饰符,返回值无关

重写:发生在继承类中,方法名相同,参数列表和返回值 相同
构造方法不能被重写;声明为 final 的方法不能被重写;声明为 static 的方法不存在重写(重写和多态联合才有意义);访问权限不能比父类更低;重写之后的方法不能抛出更宽泛的异常

你为什么重写 equals 时必须重写 hashCode 方法?

hashCode是用于查找位置使用的,而equals是用于比较两个对象的是否相等的

hashCode() 的作用是获取哈希码,也称为散列码;它实际上是返回一个 int 整数。这个哈希码的作用是确定该对象在哈希表中的索引位置。

如果两个对象相等,则 hashcode 一定也 是相同的。但是hascode相同,类却不一定相同,所以重写 equals 时必须重写 hashCode

就好比说,我在衣柜里找两件相同的衣服,第一步我肯定是通过hash值确定在衣柜的那个盒子里,第二部才是使用equal比较衣服一样不

new 一个对象的过程和 clone 一个对象的过程?

new 操作符的本意是分配内存。程序执行到 new 操作符时,首先去看 new 操作符后面的类型,因为知道了类型,才能知道要分配多大的内存空间。分配完内存之后,再调用构造函数, 填充对象的各个域,这一步叫做对象的初始化,构造方法返回后,一个对象创建完毕,可以把他的引用(地址)发布到外部,在外部就可以使用这个引用操纵这个对象。

clone 在第一步是和 new 相似的,都是分配内存,调用 clone 方法时,分配的内存和原对象(即调用 clone 方法的对象)相同,然后再使用原对象中对应的各个域,填充新对象的域,填充完成之后,clone 方法返回,一个新的相同的对象被创建,同样可以把这个新对象的引用发布到外部。

静态类型有什么特点?

1、静态的属性:随着类的加载而加载,该属性不在属于某个对象,属于整个类

2、静态的方法:直接用类名调用,静态方法里不能访问非静态成员变量

3、静态类:不能直接创建对象,不可被继承

Java中内部类的结构

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-LrVV7EDW-1635166712554)(asset/img/java基础面试题 - 副本/image-20210903201509955.png)]

为什么使用内部类?

使用内部类最吸引人的原因是:每个内部类都能独立地继承一个(接口的)实现,所以无论外围类是否已经继承了某个(接口的)实现,对于内部类都没有影响,使用内部类最大的优点就在于它能够非常好的解决多重继承的问题,使用内部类还能够为我们带来如下特性:

  1. 内部类可以用多个实例,每个实例都有自己的状态信息,并且与其他外围对象的信息相互独。
  2. 在单个外围类中,可以让多个内部类以不同的方式实现同一个接口,或者继承同一个类。
  3. 创建内部类对象的时刻并不依赖于外围类对象的创建。
  4. 内部类并没有令人迷惑的“is-a”关系,他就是一个独立的实体。
  5. 内部类提供了更好的封装,除了该外围类,其他类都不能访问。

内部类分类

成员内部类,局部内部类,匿名内部类

Anonymous Inner Class(匿名内部类)是否可以继承其它类?是否可以实现接口?

可以继承其他类或实现其他接口,在Swing编程和Android开发中常用此方式来实现事件监听和回调。

static 的用法?

Static 可以修饰内部类、方法、变量、代码块;

Static 修饰的类是静态内部类;Static 修饰的方法是静态方法,表示该方法属于当前类的,而不属于某个对象的,静态方法也不能被重写,可以直接使用类名来调用。

在 static 方法中不能使用 this 或者 super 关键字。

Static 修饰变量是静态变量或者叫类变量,静态变量被所有实例所共享,不会依赖于对象。静态变量在内存中只有一份拷贝,在 JVM 加载类的时候,只为静态分配一次内存。

Static 修饰的代码块叫静态代码块,通常用来做程序优化的。静态代码块中的代码在整个类加载的时候只会执行一次。静态代码块可以有多个,如果有多个,按照先后顺序依次执行。

为什么不可以在 static 环境中访问非 static 变量?

static 变量在 Java 中是属于类的,它在所有的实例中的值是一样的。当类被 Java 虚拟机载入的时候,会对 static 变量进行初始化。如果你的代码尝试不用实例来访问非 static 的变量,编译器会报错,因为这些变量还没有被创建出来,还没有跟任何实例关联上。

成员变量和局部变量的区别有哪些?

1、从语法形式上,看成员变量是属于类的,而局部变量是在方法中定义的变量或是方法的 参数;成员变量可以被 public,private,static 等修饰符所修饰,而局部变量不能被访问控制修饰符及 static 所修饰;成员变量和局部变量都能被 final 所修饰;

2、从变量在内存中的存储方式来看,成员变量是对象的一部分,而对象存在于堆内存,局 部变量存在于栈内存

3、从变量在内存中的生存时间上看,成员变量是对象的一部分,它随着对象的创建而存在, 而局部变量随着方法的调用而自动消失。

4、成员变量如果没有被赋初值,则会自动以类型的默认值而赋值(一种情况例外被 final 修饰但没有被 static 修饰的成员变量必须显示地赋值);而局部变量则不会自动赋值。

静态方法和实例方法有何不同?

1、在外部调用静态方法时,可以使用"类名.方法名"的方式,也可以使用"对象名.方法名"的方 式。而实例方法只有后面这种方式。也就是说,调用静态方法可以无需创建对象。

2、静态方法在访问本类的成员时,只允许访问静态成员(即静态成员变量和静态方法),而不允许访问实例成员变量和实例方法;实例方法则无此限制

接口为什么必须是常量而不能变量 ,又为什么只能是静态常量

接口的作用就是提供规范,也就是接口就是作为纯抽象的,抽象的概念在于不能有可变的内容,如果接口中存在变量就违背了纯抽象的定义。

因为非静态的常量可以通过对象调用,而接口不能被实例化,非静态的常量对接口本身无意义

那么对于其实现类呢?由于实现类可以实现多个接口,如果多个接口中都有同一个非静态常量,实现类使用时会出现冲突,所以,对实现类也无法使用,故接口中只能是静态常量

抽象类为什么不能实例化

因为这是规定。抽象:就是不具体的意思。类是对对象的具体描述,而抽象类不具体,没有方法体,(提供的成员不足以生成一个具体对象),那么就无法生成一个不具体的对象。就好比,你可以实例化一个苹果,但你不能实例化一个水果(这个现实中存在的实物)。

常用api类

String、StringBuilder、StringBuffer 区别?

String 字符串常量 不可变 使用字符串拼接时是不同的 2 个空间

StringBuffer 字符串变量 可变 线程安全 字符串拼接直接在字符串后追加

StringBuilder 字符串变量 可变 非线程安全 字符串拼接直接在字符串后追加

执行效率: StringBuilder > StringBuffer > String.

java.lang.String 是一个常量,是不可变的,所以对于每一次+=赋值都会创建一个新的对象, StringBuffer 和 StringBuilder 都是可变的,当进行字符串拼接时采用 append 方法,在原来的基础上进行追加,所以性能比 String 要高,又因为 StringBuffer 是线程安全的而 StringBuilder 是线程非安全的,所以 StringBuilder 的效率高于StringBuffer.

对于大数据量的字符串的拼接,采用 StringBuffer,StringBuilder.

字符串常量池到底存在于内存空间的哪里?

jdk 6.0 字符串常量池在方法区,方法区的具体体现可以看做是堆中的永久区。
jdk 7.0 java 虚拟机规范中不再声明方法区,字符串常量池存放在堆空间中
jdk 8.0 java 虚拟机规范中又声明了元空间,字符串常量池存放在元空间中

Object 中有哪些公共方法?

clone:是一个native方法,native方法的效率一般来说都是远高于Java中的非native方法,实现对象的浅复制,只有实现了Cloneable接口才可以调用该方法,否则抛出CloneNotSupportedException异常
equals:Object中与==是一样的,子类一般需要重写该方法
hashCode();返回对象的哈希代码值
getClass(); 返回此对象的运行时类。
toString(); 返回对象的字符串表示形式。
wait():使当前线程等待该对象的锁,当前线程必须是该对象的拥有者,也就是具有该对象的锁。一直等待,直到获得锁或者被中断
wait(long timeout)设定一个超时间隔,如果在规定时间内没有获得锁就返回。
调用该方法后当前线程进入睡眠状态,直到以下事件发生:
1、其他线程调用了该对象的notify方法
2、其他线程调用了该对象的notifyAll方法
3、其他线程调用了interrupt中断该线程
4、时间间隔到了 ,此时该线程就可以被调度了,如果是被中断的话就抛出一个InterruptedException异常
notify(); 唤醒正在等待此对象监视器的单个线程。如果有线程正在等待这个对象,那么会选择唤醒其中一个线程。选择是任意的,并由实施者自行决定。线程通过调用其中一个等待方法来等待对象的监视器。
notifyAll(); 唤醒正在等待此对象监视器的所有线程。线程通过调用其中一个等待方法来等待对象的监视器。

什么是拆箱和装箱?

JDK1.5提供了自动装箱和自动拆箱功能

  • 装箱就是自动将基本数据类型转换为包装器类型

  • 拆箱就是自动将包装器类型转换为基本数据类型

异常

什么是Java中的异常?

异常就是有异于常态,和正常情况不一样,有错误出现。在java中,阻止当前方法或作用域的情况,称之为异常。异常可能来自不同类型的情况,例如用户输入的错误数据,硬件故障,网络连接故障等。

每当执行java语句时发生任何错误,都会创建一个异常对象,然后JRE会尝试查找异常处理程序来处理异常。如果找到合适的异常处理程序,则将异常对象传递给处理程序代码以处理异常,称为捕获异常。如果未找到处理程序,则应用程序将异常抛出到运行时环境,JRE将终止该程序。

Java异常处理框架仅用于处理运行时错误,编译时错误不由异常处理框架处理。

Java中的异常处理关键字是什么?

java异常处理中使用了四个关键字

throw:throw 语句用在方法体内,表示抛出异常,由方法体内的语句处理。throw 是具体向外抛出异常的动作,所以它抛出的是一个异常实例,执行 throw 一定是抛出了某种异常。

throws:throws 语句是用在方法声明后面,表示如果抛出异常,由该方法的调用者来进行异常的处理。throws 主要是声明这个方法会抛出某种类型的异常,让它的使用者要知道需要捕获的异常的类型。throws 表示出现异常的一种可能性,并不一定会发生这种异常。

try-catch:我们在代码中使用try-catch块进行异常处理。try是块的开始,catch是在try块的末尾处理异常。我们可以使用try有多个catch块,try-catch块也可以嵌套。catch块需要一个应该是Exception类型的参数。

finally:finally块是可选的,只能用于try-catch块。由于异常会暂停执行过程,因此我们可能会打开一些不会关闭的资源,因此我们可以使用finally块。finally块总是被执行,无论是否发生异常

运行时异常与一般异常有何异同

异常表示程序运行过程中可能出现的非正常状态,运行时异常表示虚拟机的通常操作中可能 遇到的异常,是一种常见运行错误。java 编译器要求方法必须声明抛出可能发生的非运行时异常,但是并不要求必须声明抛出未被捕获的运行时异常。

说几个常见的编译时异常?

SQLException 提供有关数据库访问错误或其他错误的信息的异常。

IOexception 表示发生了某种 I / O 异常的信号。此类是由失败或中断的 I / O 操作产生的一般异常类

FileNotFoundException 当试图打开指定路径名表示的文件失败时,抛出此异常。ClassNotFoundException 找不到具有指定名称的类的定义。

EOFException 当输入过程中意外到达文件或流的末尾时,抛出此异常。

列出一些常见的运行时异常?

ArithmeticException(算术异常) ClassCastException (类转换异常) IllegalArgumentException (非法参数异常) IndexOutOfBoundsException (下标越界异常) NullPointerException (空指针异常) SecurityException (安全异常)

解释Java异常层次结构?

Java异常是分层的,继承用于对不同类型的异常进行分类。如下

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-31gKYyEr-1635166712556)(asset/img/java基础面试题 - 副本/image-20210831212935764-1630582100705-16349091116431.png)]

Java中所有异常,都继承自java.lang.Throwable类。

异常主要分为:错误、一般性异常、运行时异常

  • Error:错误是超出应用程序范围的特殊情况,并且无法预测并从中恢复,例如硬件故障,JVM崩溃或内存不足错误。

    通常有Virtual MachineError(虚拟机运行错误)、NoClassDefFoundError(类定义错误)等。比如说当jvm耗完可用内存时,将出现OutOfMemoryError。此类错误发生时,JVM将终止线程。非代码性错误。因此,当此类错误发生时,应用不应该去处理此类错误。

  • Exception::程序本身可以捕获并且可以处理的异常。

  • 运行时异常(不受检异常):JVM在运行期间可能出现的错误,此类异常属于不可查异常,一般是由程序逻辑错误引起的,在程序中可以选择捕获处理,也可以不处理。

    比如用空值对象的引用(NullPointerException)、数组下标越界(ArrayIndexOutBoundException)。

  • 非运行时异常(受检异常):Exception中除RuntimeException极其子类之外的异常。编译器会检查此类异常(编译期间),如果程序中出现此类异常,比如说IOException,必须对该异常进行处理,要么使用try-catch捕获,要么使用throws语句抛出,否则编译不通过。

将三种异常类型再次划分,将派生于Error或者RuntimeException的异常称为unchecked异常 (非受检异常),所有其他的异常(CheckedException)成为checked异常(受检异常)。

Java异常类的重要方法是什么?

异常及其所有子类不提供任何特定方法,并且所有方法都在基类Throwable中定义。

  1. String getMessage() - 此方法返回消息String of Throwable,并且可以在通过构造函数创建异常时提供消息。
  2. String getLocalizedMessage() - 提供此方法,以便子类可以覆盖它以向调用程序提供特定于语言环境的消息。此方法getMessage()的可抛出类实现只是使用方法来返回异常消息。
  3. synchronized Throwable getCause() - 此方法返回异常的原因或null id,原因未知。
  4. String toString() - 此方法以String格式返回有关Throwable的信息,返回的String包含Throwable类和本地化消息的名称。
  5. void printStackTrace() - 此方法将堆栈跟踪信息打印到标准错误流,此方法已重载,我们可以将PrintStream或PrintWriter作为参数传递,以将堆栈跟踪信息写入文件或流。=>打印的数据和正常报错信息一样

如何在Java中编写自定义异常

我们可以扩展Exception类或其任何子类来创建我们的自定义异常类。自定义异常类可以拥有自己的变量和方法,我们可以使用它们将错误代码或其他与异常相关的信息传递给异常处理程序。

Java中的OutOfMemoryError是什么?

Java中的OutOfMemoryError是java.lang.VirtualMachineError的子类,当JVM用完堆内存时,它会抛出它。我们可以通过提供更多内存来通过java选项运行java应用程序来修复此错误。

谈谈final,finally,finalize的区别

  1. 被 final 修饰的类不可以被继承,被 final 修饰的方法不可以被重写,被 final 修饰的变量不可以被改变。如果修饰引用,那么表示引用不可变,引用指向的内容可变.被 final 修饰的方法,JVM 会尝试将其内联,以提高运行效率,被 final 修饰的常量,在编译阶段会存入常量池中.

  2. finally是异常处理语句结构的一部分,表示总是执行,通常最终也会用来关闭资源。

  3. finalize是Object类的一个方法,当垃圾回收器 要回收对象所占内存之前,会调用 被回收对象的此方法,可以覆盖此方法提供垃圾收集时的其他资源回收,例如关闭文件等

    finalize()的调用具有不确定行,只保证方法会调用,但不保证方法里的任务会被执行完(比如一个对象手脚不够利索,磨磨叽叽,还在自救的过程中,被杀死回收了)。

我们可以有一个空的catch块吗?

我们可以有一个空的catch块,但它是最差编程的例子。我们永远不应该有空的catch块,因为如果异常被该块捕获,我们将没有关于异常的信息,并且它将成为调试它的噩梦。应该至少有一个日志记录语句来记录控制台或日志文件中的异常详细信息。

try-catch-finally-return执行顺序

  1. 不管是否有异常产生,finally块中代码都会执行;
  2. 当try和catch中有return语句时,finally块仍然会执行;
  3. finally是在return后面的表达式运算后执行的(此时并没有返回运算后的值,而是先把要返回的值保存起来,管finally中的代码怎么样,返回的值都不会改变,任然是之前保存的值),所以函数返回值是在finally执行前确定的;
  4. finally中最好不要包含return,否则程序会提前退出,返回值不是try或catch中保存的返回值。

集合

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-9Wh10uOJ-1635166712558)(asset/img/java基础面试题 - 副本/image-20210923113435852.png)]

Java集合框架是什么?说出一些集合框架的优点?

每种编程语言中都有集合,最初的Java版本包含几种集合类:Vector、Stack、HashTable和Array。 随着集合的广泛使用,Java1.2提出了囊括所有集合接口、实现和算法的集合框架。在保证线程安全的情况下使用泛型和并发集合类,Java 已经经历了很久。它还包括在Java并发包中,阻塞接口以及它们的实现。集合框架的部分优点如下:

  1. 使用核心集合类降低开发成本,而非实现我们自己的集合类。
  2. 随着使用经过严格测试的集合框架类,代码质量会得到提高。
  3. 通过使用JDK附带的集合类,可以降低代码维护成本。
  4. 复用性和可操作性

⭐List , Set 和 map 比较,各自的子类比较

List 底层为数组结构,有序的可重复集合,元素可以重复因为每个元素有自己的角标(索引),可以在任意位置增加删除元素,用 Iterator 实现单向遍历,也可用ListIterator 实现双向遍历。

  • ArrayList:底层的数据结构是数组结构,特点是:查询很快,增 删 稍微慢点,线程不同步 。
  • LinkedList:底层使用的是双向链表数据结构,特点是:增 删很快,查询慢。
  • Vector:底层是数组数据结构,线程同步,被 ArrayList 代替了,现在用的只有他的枚举。

Set:底层是红黑树,无序的不包含重复元素的集合(用对象的 equals() 方法来区分元素是否重复),set 中最多包含一个 null 元素,只能用 Iterator 实现单项遍历,线程不同步 。

  • HashSet:底层是哈希表数据结构。HashSet 的实现是依赖于 HashMap 的,HashSet 的值都是存储在 HashMap 中的。在 HashSet 的构造法中会初始化一个 HashMap 对象,HashSet 不允许值重复。因此,HashSet 的值是作为 HashMap 的 key 存储在 HashMap 中的,当存储的值已经存在时返回 false。根据 hashCode 和 equals 方法来确定元素的唯一性
  • TreeSet:底层的数据结构是二叉树,可以对 Set 集合中的元素进行排序(自然循序),也可以自己写个类实现 Comparable 或者 Comparator 接口,定义自己的比较器,将其作为参数传递给 TreeSet 的构造函数。

Map:JDK1.7及之前:数组+链表,JDK1.8:数组+链表+红黑树。这个集合是存储键值对的, 而且要确保键的唯一性

  • HashTable:底层是哈希表数据结构,不可以存入 null 键和 null 值,该集合线程是同步的,效率比较低。出现于 JDK1.0 。
  • HashMap:底层是哈希表数据结构,可以存入 null 键和 null 值,线程不同步,效率较高,代替了 HashTable,出现于 JDK 1.2 。
  • TreeMap:底层是二叉树数据结构,不可以存入 null 键但是可以存入null 值,线程不同步,具体顺序可以由指定的Comparator来决定,或者根据键的自然顺序来判断。

TreeMap 可以保证顺序,HashMap 不保证顺序,即为无序的,Map 中可以将 Key 和 Value 单独抽取出来,其中 KeySet()方法可以将所有的 keys 抽取成一个 Set,而 Values()方法可以将 map 中所有的 values 抽取成一个集合。

⭐Java 集合类: queue、 stack 的特点与用法?

Queue:队列, 遵从先进先出原则,使用时尽量避免 add()和 remove()方法,而是使用offer()来添加元素,使用 poll()来移除元素,它的优点是可以通过返回值来判断是否成功,LinkedList 实现了 Queue 接口,Queue 通常不允许插入 null 元素。

Stack:堆栈, 遵从后进先出原则,Stack 继承自 Vector,它通过五个操作对类 Vector 进行扩展,允许将向量视为堆栈,它提供了通常的 push 和 pop 操作,以及取堆栈顶点的 peek()方法、测试堆栈是否为空的 empty 方法等。

用法:

​ 如果涉及堆栈,队列等操作,建议使用 List。

​ 对于快速插入和删除元素的,建议使用 LinkedList。

​ 如果需要快速随机访问元素的,建议使用 ArrayList。

Vector、ArrayList、LinkedList读写机制(扩容)/ 底层原理

这三者都是实现集合框架中的List,也就是所谓的有序集合,因此具体功能也比较近似,比如都提供按照位置进行定位、添加或者删除的操作,都提供迭代器以遍历其内容等。但因为具体的设计区别,在行为、性能、线程安全等方面,表现又有很大不同。

ArrayList 是一种变长的集合类,基于定长数组实现,使用默认构造方法初始化出来的容量是 10 ( 1.7 之后都是延迟初始化, 即第一次调用 add 方法添加元素的时候才将elementData 容量初始化为 10)。 ArrayList在执行插入元素是超过当前数组预定义的最大值时,数组需要扩容,扩容过程需要调用底层System.arraycopy()方法进行大量的数组复制操作(1.5倍);在删除元素时并不会减少数组的容量(如果需要缩小数组容量,可以调用trimToSize()方法);在查找元素时要遍历数组,对于非null的元素采取equals的方式寻找。

LinkedList在插入元素时,须创建一个新的Entry对象,并更新相应元素的前后元素的引用;在查找元素时,需遍历链表;在删除元素时,要遍历链表,找到要删除的元素,然后从链表上将此元素删除即可。

Vector与ArrayList仅在插入元素时容量扩充机制不一致。对于Vector,默认创建一个大小为10的Object数组,并将capacityIncrement设置为0;当插入元素数组大小不够时,如果capacityIncrement大于0,则将Object数组的大小扩大为现有size + capacityIncrement;如果capacityIncrement<=0,则将Object数组的大小扩大为现有大小的2倍。

HashSet如何检查重复

当你把对象加入HashSet时,HashSet会先计算对象的hashcode值来判断对象加入的位置,同时也会与其他加入的对象的hashcode值作比较,如果没有相符的hashcode,HashSet会假设对象没有重复出现。但是如果发现有相同hashcode值的对象,这时会调用equals()方法来检查hashcode相等的对象是否真的相同。如果两者相同,HashSet就不会让加入操作成功。

为何Collection不从Cloneable和Serializable接口继承?

Collection接口指定一组对象,对象即为它的元素。如何维护这些元素由Collection的具体实现决定。例如,一些如List的Collection实现允许重复的元素,而其它的如Set就不允许。很多Collection实现有一个公有的clone方法。然而,把它放到集合的所有实现中也是没有意义的。这是因为Collection是一个抽象表现。重要的是实现。
​当与具体实现打交道的时候,克隆或序列化的语义和含义才发挥作用。所以,具体实现应该决定如何对它进行克隆或序列化,或它是否可以被克隆或序列化。在所有的实现中授权克隆和序列化,最终导致更少的灵活性和更多的限制。特定的实现应该决定它是否可以被克隆和序列化。

为何为何Map接口不继承Collection接口?

尽管Map接口和它的实现也是集合框架的一部分,但Map不是集合,集合也不是Map。因此,Map继承Collection毫无意义,反之亦然。

Iterater和ListIterator之间有什么区别?

  1. 我们可以使用Iterator来遍历Set和List集合,而ListIterator只能遍历List。
  2. Iterator只可以向前遍历,而LIstIterator可以双向遍历。
  3. ListIterator从Iterator接口继承,然后添加了一些额外的功能,比如添加一个元素、替换一个元素、获取前面或后面元素的索引位置。

😔什么是迭代器(Iterator)?

一些集合类提供了内容遍历的功能,通过java.util.Iterator接口。这些接口允许遍历对象的集合。依次操作每个元素对象。当使用Iterators时,在获得Iterator的时候包含一个集合快照。通常在遍历一个Iterator的时候不建议修改集合本省。

Iterator 接口提供了很多对集合元素进行迭代的方法。每一个集合类都包含了可以返回迭代器实例的

迭代方法。迭代器可以在迭代的过程中删除底层集合的元素。

克隆(cloning)或者是序列化(serialization)的语义和含义是跟具体的实现相关的。因此, 应该由集合类的具体实现来决定如何被克隆或者是序列化。

😔ConcurrentHashMap 源码分析?

ConcurrentHashMap 所使用的锁分段技术,首先将数据分成一段一段的存储,然后给每一段数据配一把锁,当一个线程占用锁访问其中一个段数据的时候,其他段的数据也能被其他线程访问。有些方法需要跨段,比如 size()和 containsValue(),它们可能需要锁定整个表而而不仅仅是某个段,这需要按顺序锁定所有段,操作完毕后,又按顺序释放所有段的锁。这里“按顺序”是很重要的,否则极有可能出现死锁,在 ConcurrentHashMap 内部,段数组是 final 的, 并且其成员变量实际上也是 final 的,但是,仅仅是将数组声明为final 的并不保证数组成员也是 final 的,这需要实现上的保证。这可以确保不会出现死锁,因为获得锁的顺序是固定的。

ConcurrentHashMap 是由 Segment 数组结构和 HashEntry 数组结构组成。Segment 是一种可重入锁 ReentrantLock,在 ConcurrentHashMap 里扮演锁的角色,HashEntry 则用于存储键值对数据。一个 ConcurrentHashMap 里包含一个 Segment 数组,Segment 的结构和 HashMap 类似,是一种数组和链表结构, 一个 Segment 里包含一个 HashEntry 数组,每个 HashEntry 是一个链表结构的元素, 每个 Segment 守护者一个 HashEntry 数组里的元素,当对 HashEntry 数组的数据进行修改时,必须首先获得它对应的 Segment 锁。

什么叫做快速失败特性

从高级别层次来说快速失败是一个系统或软件对于其故障做出的响应。一个快速失败系统设计用来即时报告可能会导致失败的任何故障情况,它通常用来停止正常的操作而不是尝试继续做可能有缺陷的工作。当有问题发生时,快速失败系统即时可见地发错错误告警。在Java中,快速失败与iterators有关。如果一个iterator在集合对象上创建了,其它线程欲“结构化”的修改该集合对象,并发修改异常 (ConcurrentModificationException) 抛出。

😔如何保证容器是线程安全的?ConcurrentHashMap如何实现高效地线程安全?

Java提供了不同层面的线程安全支持。在传统集合框架内部,除了Hashtable等同步容器,还提供了所谓的同步包装器(Synchronized Wrapper),我们可以调用Collections工具类提供的包装方法,来获取一个同步的包装容器(如Collections.synchronizedMap),但是它们都是利用非常粗粒度的同步方式,在高并发情况下,性能比较低下。 另外,更加普遍的选择是利用并发包提供的线程安全容器类,它提供了:

  • 各种并发容器,比如ConcurrentHashMap、CopyOnWriteArrayList。

  • 各种线程安全队列(Queue/Deque),如ArrayBlockingQueue、SynchronousQueue。

  • 各种有序容器的线程安全版本等。

具体保证线程安全的方式,包括有从简单的synchronize方式,到基于更加精细化的,比如基于分离锁实现的ConcurrentHashMap等并发实现等。具体选择要看开发的场景需求,总体来说,并发包内提供的容器通用场景,远优于早期的简单同步实现。

😔HashMap 源码分析?

jdk1.8 之前 list + 链表

jdk1.8 之后 list + 链表(当链表长度到 8 时,转化为红黑树)

HashMap 的扩容因子

默认 0.75,也就是会浪费 1/4 的空间,达到扩容因子时,会将 list 扩容一倍,0.75 是时间与空间一个平衡值;

😔HashMap 的底层实现和 ConcurrentHashMap 的底层实现

在 Java 编程语言中,最基本的结构就是两种,一个是数组,另外一个是模拟指针(引用),所有的数据结构都可以用这两个基本结构来构造的,HashMap 也不例外。

HashMap实际上是一个“链表的数组”的数据结构,每个元素存放链表头结点的数组,即数组和链表的结合体。HashMap底层就是一个数组,数组中的每一项又是一个链表。当新建一个HashMap的时候,就会初始化一个数组。

ConcurrentHashMap是由Segment数组结构和 HashEntry 数组结构组成。Segment 是一种可重入ReentrantLock,在ConcurrentHashMap里扮演锁的角色,HashEntry 则用于存储键值对数据。一个ConcurrentHashMap里包含一个Segment数组,Segment的结构和 HashMap类似,是一种数组和链表结构,一个Segment里包含一个HashEntry 数组,每个 HashEntry是一个链表结构的元素, 每个Segment守护者一个HashEntry数组里的元素,

当对HashEntry数组的数据进行修改时,必须首先获得它对应的Segment锁。

😔HashTable 和 ConcurrentHashMap 的区别?

HashTable容器使用synchronized来保证线程安全,但在线程竞争激烈的情况下 HashTable 的效率非常低下。因为当一个线程访问HashTable的同步方法时,其他线程访问HashTable的同步方法时,能会进入阻塞或轮询状态。如线程1使用put进行添加元素,线程 2 不但不能使用 put 方法添加元素,并且也不能使用get方法来获取元素,所以竞争越激烈效率越低。

ConcurrentHashMap 使用的锁分段技术,首先将数据分成一段一段的存储,然后给每一段数据配一把锁,当一个线程占用锁访问其中一个段数据的时候,其他段的数据也能被其他线程访问。

Collection 和 Collections 的区别?

Collection 是集合类的上级接口,继承与他的接口主要有 Set 和 List.

Collections 是针对集合类的一个帮助类,他提供一系列静态方法实现对各种集合的搜索、排序、线程安全化等操作。

Comparable 和 Comparator 接口的区别?

Comparable 接口只包含一个 compareTo()方法。这个方法可以个给两个对象排序。具体来说, 它返回负数,0,正数来表明输入对象小于,等于,大于已经存在的对象。Comparator 接口包含 compare()和 equals()两个方法。

用哪两种方式来实现集合的排序?

你可以使用有序集合,如 TreeSet 或 TreeMap,你也可以使用有顺序的的集合,如 list,然后通过 Collections.sort() 来排序。

Enumeration 接口和 Iterator 接口的区别有哪些?

Enumeration 速度是 Iterator 的 2 倍,同时占用更少的内存。但是, Iterator 远远比Enumeration 安全,因为其他线程不能够修改正在被 iterator 遍历的集合里面的对象。同时,Iterator 允许调用者删除底层集合里面的元素,这对 Enumeration 来说是不可能的。

Collection接口的remove()方法和Iterator接口的remove()方法区别?

性能方面

  • Collection的remove方法必须首先找出要被删除的项,找到该项的位置采用的是单链表结构查询,单链表查询效率比较低,需要从集合中一个一个遍历才能找到该对象;Iterator的remove方法结合next()方法使用,比如集合中每隔一项删除一项,Iterator的remove()效率更高

容错方面

  • 在使用Iterator遍历时,如果使用Collection的remove则会报异常,会出现ConcurrentModificationException,因为集合中对象的个数会改变而Iterator 内部对象的个数不会,不一致则会出现该异常在使用Iterator遍历时,不会报错,因为iterator内部的对象个数和原来集合中对象的个数会保持一致。

io

IO流的分类

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-fegpldOp-1635166712561)(asset/img/java基础面试题 - 副本/image-20210912230744933.png)]

什么是 IO 流?

它是一种数据的流从源头流到目的地。比如文件拷贝,输入流和输出流都包括了。输入流从 文件中读取数据存储到进程(process)中,输出流从进程中读取数据然后写入到目标文件。

有哪些可用的 Filter 流?

在 java.io 包中主要由 4 个可用的 filter Stream。两个字节 filter stream,两个字符 filter stream. 分别是 FilterInputStream, FilterOutputStream, FilterReader and FilterWriter.这些类是抽象类,不能被实例化的。

如何实现对象克隆?

有两种方式:

1). 实现 Cloneable 接口并重写 Object 类中的 clone()方法;

2). 实现 Serializable 接口,通过对象的序列化和反序列化实现克隆,可以实现真正的深度克隆

谈谈Java IO里面的常见类,字节流,字符流、接口、实现类、方法阻塞

输入流就是从外部文件输入到内存,输出流主要是从内存输出到文件。

IO里面常见的类,第一印象就只知道IO流中有很多类,IO流主要分为字符流和字节流。字符流中有抽象类InputStream和OutputStream,它们的子类FileInputStream,FileOutputStream,BufferedOutputStream等。字符流BufferedReader和Writer等。都实现了Closeable, Flushable, Appendable这些接口。程序中的输入输出都是以流的形式保存的,流中保存的实际上全都是字节文件。

java中的阻塞式方法是指在程序调用改方法时,必须等待输入数据可用或者检测到输入结束或者抛出异常,否则程序会一直停留在该语句上,不会执行下面的语句。比如read()和readLine()方法。

什么是java序列化,如何实现java序列化?

序列化就是一种用来处理对象流的机制,所谓对象流也就是将对象的内容进行流化(将对象转换成二进制)。可以对流化后的对象进行读写操作,也可将流化后的对象传输于网络之间。序列化是为了解决在对对象流进行读写操作时所引发的问题。

序列化的实现:将需要被序列化的类实现 Serialize 接口,没有需要实现的方法,此接口只是为了标注对象可被序列化的,然后使用一个输出流(如:FileOutputStream)来构造一个ObjectOutputStream(对象流)对象,再使用 ObjectOutputStream 对象的 write(Object obj)方法就可以将参数 obj 的对象写出

什么叫对象序列化,什么是反序列化,实现对象序列化需要做哪些工作?

对象序列化:将对象以二进制的形式保存到硬盘上;

反序列化:将二进制文件转化为对象读取.

将需要序化的类实现Serializable接口

字节流和字符流的区别?

字符流和字节流的使用非常相似,但是实际上字节流的操作不会经过缓冲区(内存)而是直 接操作文本本身的,而字符流的操作会先经过缓冲区(内存)然后通过缓冲区再操作文件以字节为单位输入输出数据,字节流按照 8 位传输

以字符为单位输入输出数据,字符流按照 16 位传输

什么是节点流,什么是处理流,各有什么好处,处理流的创建有什么特征?

节点流 直接与数据源相连,用于输入或者输出

处理流:在节点流的基础上对之进行加工,进行一些功能的扩展 处理流的构造器必须要 传入节点流的子类

怎么样把输出字节流转换成输出字符流,说出它的步骤?

利用转换流outputstreamwriter.创建一个字节流对象,将其作为参数传入转换流outputstreamwriter中,得到字符流对象.

谈一谈io流中用到的适配器模式和装饰者模式

装饰器模式:就是动态地给一个对象添加一些额外的职责(对于原有功能的扩展)。

  1. 它必须持有一个被装饰的对象(作为成员变量)。

  2. 它必须拥有与被装饰对象相同的接口(多态调用、扩展需要)。3.它可以给被装饰对象添加额外的功能。

适配器模式:将一个类的接口转换成客户期望的另一个接口,让原本不兼容的接口可以合作无间。

  1. 适配器对象实现原有接口

  2. 适配器对象组合一个实现新接口的对象

  3. 对适配器原有接口方法的调用被委托给新接口的实例的特定方法(重写旧接口方法来调用新接口功能。

什么是缓冲区?有什么作用?

缓冲区就是一段特殊的内存区域,很多情况下当程序需要频繁地操作一个资源(如文件或数据库)则性能会很低,所以为了提升性能就可以将一部分数据暂时读写到缓存区,以后直接从此区域中读写数据即可,这样就显著提升了性。对于 Java 字符流的操作都是在缓冲区操作的,所以如果我们想在字符流操作中主动将缓冲区刷新到文件则可以使用 flush() 方法操作。

PrintStream、BufferedWriter、PrintWriter的比较?

PrintStream类的输出功能非常强大,通常如果需要输出文本内容,都应该将输出流包装成PrintStream后进行输出。它还提供其他两项功能。与其他输出流不同,PrintStream 永远不会抛出 IOException;而是,异常情况仅设置可通过 checkError 方法测试的内部标志。另外,为了自动刷新,可以创建一个 PrintStream

BufferedWriter:将文本写入字符输出流,缓冲各个字符从而提供单个字符,数组和字符串的高效写入。通过write()方法可以将获取到的字符输出,然后通过newLine()进行换行操作。BufferedWriter中的字符流必须通过调用flush方法才能将其刷出去。并且BufferedWriter只能对字符流进行操作。如果要对字节流操作,则使用BufferedInputStream

PrintWriter的println方法自动添加换行,不会抛异常,若关心异常,需要调用checkError方法看是否有异常发生,PrintWriter构造方法可指定参数,实现自动刷新缓存(autoflush)

谈谈对 NIO 的认知?

NIO(Non-blocking I/O,在Java领域,也称为New I/O),是一种同步非阻塞的I/O模型,也是I/O多路复用的基础,已经被越来越多地应用到大型应用服务器,成为解决高并发与大量连接、I/O处理问题的有效方式。

NIO主要有三大核心部分

Channel(通道),Buffer(缓冲区), Selector。传统IO基于字节流和字符流进行操作,而NIO基于Channel和Buffer(缓冲区)进行操作,数据总是从通道读取到缓冲区中,或者从缓冲区写入到通道中。Selector(选择区)用于监听多个通道的事件(比如:连接打开,数据到达)。因此,单个线程可以监听多个数据通道。

  1. Channel(通道):一个新的原始 I/O 抽象,用于读写 Buffer 类型,通道可以认为是一种连接,可以是到特定设备,程序或者是网络的连接。

    Channel和IO中的Stream(流)是差不多一个等级的。只不过Stream是单向的,譬如:InputStream, OutputStream.而Channel是双向的,既可以用来进行读操作,又可以用来进行写操作。

  2. Buffer(缓冲区):为所有的原始类型提供 (Buffer)缓存支持。

    NIO中的关键Buffer实现有:ByteBuffer, CharBuffer, DoubleBuffer, FloatBuffer, IntBuffer, LongBuffer, ShortBuffer,分别对应基本数据类型: byte, char, double, float, int, long, short。当然NIO中还有的

  3. Selector运行单线程处理多个Channel,如果你的应用打开了多个通道,但每个连接的流量都很低,使用Selector就会很方便。

什么是阻塞 IO?什么是非阻塞 IO?

IO 操作包括:对硬盘的读写、对 socket 的读写以及外设的读写。

当用户线程发起一个 IO 请求操作(本文以读请求操作为例),内核会去查看要读取的数据是否就绪,对于阻塞 IO 来说,如果数据没有就绪,则会一直在那等待,直到数据就绪;对于非阻塞 IO 来说,如果数据没有就绪,则会返回一个标志信息告知用户线程当前要读的数据没有就绪。当数据就绪之后,便将数据拷贝到用户线程,这样才完成了一个完整的 IO 读请求操作,也就是说一个完整的 IO 读请求操作包括两个阶段:

  1. 查看数据是否就绪;

  2. 进行数据拷贝(内核将数据拷贝到用户线程)。

那么阻塞(blocking IO)和非阻塞(non-blocking IO)的区别就在于第一个阶段,如果数据没有就绪,在查看数据是否就绪的过程中是一直等待,还是直接返回一个标志信息。

Java 中传统的 IO 都是阻塞 IO,比如通过 socket 来读数据,调用 read()方法之后,如果数据没有就绪,当前线程就会一直阻塞在 read 方法调用那里,直到有数据才返回;而如果是非阻塞 IO 的话,当数据没有就绪,read()方法应该返回一个标志信息,告知当前线程数据没有就绪,而不是一直在那里等待。

NIO 和传统的 IO 有什么区别?

  1. IO是面向流的,NIO是面向缓冲区的。

    Java IO面向流意味着每次从流中读一个或多个字节,直至读取所有字节,它们没有被缓存在任何地方。此外,它不能前后移动流中的数据。如果需要前后移动从流中读取的数据,需要先将它缓存到一个缓冲区。

    NIO的缓冲导向方法略有不同。数据读取到一个它稍后处理的缓冲区,需要时可在缓冲区中前后移动。这就增加了处理过程中的灵活性。但是,还需要检查是否该缓冲区中包含所有您需要处理的数据。而且,需确保当更多的数据读入缓冲区时,不要覆盖缓冲区里尚未处理的数据。

  2. 传统 io 的管道是单向的,nio 的管道是双向的。

  3. IO的各种流是阻塞的, NIO的非阻塞模式

    IO的各种流是阻塞的。这意味着,当一个线程调用read() 或 write()时,该线程被阻塞,直到有一些数据被读取,或数据完全写入。该线程在此期间不能再干任何事情了。

    NIO的非阻塞模式,使一个线程从某通道发送请求读取数据,但是它仅能得到目前可用的数据,如果目前没有数据可用时,就什么都不会获取。而不是保持线程阻塞,所以直至数据变得可以读取之前,该线程可以继续做其他的事情。 非阻塞写也是如此。所以一个单独的线程现在可以管理多个输入和输出通道(channel)。

  4. 两者都是同步的,也就是 java 程序亲力亲为的去读写数据,不管传统 io 还是 nio 都需要read 和 write 方法,这些都是 java 程序调用的而不是系统帮我们调用的,nio2.0 里这点得到了改观,即使用异步非阻塞 AsynchronousXXX 四个类来处理。

BIO 和 NIO 和 AIO 的区别以及应用场景?

同步:java 自己去处理 io。
异步:java 将 io 交给操作系统去处理,告诉缓存区大小,处理完成回调。
阻塞:使用阻塞 IO 时,Java 调用会一直阻塞到读写完成才返回。
非阻塞:使用非阻塞 IO 时,如果不能立马读写,Java 调用会马上返回,当 IO 事件分发器通知可读写时在进行读写,不断循环直到读写完成。

BIO:同步并阻塞,服务器的实现模式是一个连接一个线程,这样的模式很明显的一个缺陷 是:由于客户端连接数与服务器线程数成正比关系,可能造成不必要的线程开销,严重的还 将导致服务器内存溢出。当然,这种情况可以通过线程池机制改善,但并不能从本质上消除 这个弊端。

NIO:在 JDK1.4 以前,Java 的 IO 模型一直是 BIO,但从 JDK1.4 开始,JDK 引入的新的 IO 模型 NIO,它是同步非阻塞的。而服务器的实现模式是多个请求一个线程,即请求会注册到多路复用器 Selector 上,多路复用器轮询到连接有 IO 请求时才启动一个线程处理。

AIO:JDK1.7 发布了 NIO2.0,这就是真正意义上的异步非阻塞,服务器的实现模式为多个有效请求一个线程,客户端的 IO 请求都是由 OS 先完成再通知服务器应用去启动线程处理(回调)。

应用场景:并发连接数不多时采用 BIO,因为它编程和调试都非常简单,但如果涉及到高并发的情况,应选择 NIO 或 AIO,更好的建议是采用成熟的网络通信框架 Netty。

多线程

什么是内存泄漏和内存溢出?

内存泄漏(memoryleak),是指应用程序在申请内存后,无法释放已经申请的内存空间,一 次内存泄漏危害可以忽略,但如果任其发展最终会导致内存溢出(outofmemory)。如读取 文件后流要进行及时的关闭以及对数据库连接的释放。

**内存溢出(outofmemory)**是指应用程序在申请内存时,没有足够的内存空间供其使用。如我 们在项目中对于大批量数据的导入,采用分批量提交的方式。

什么是线程

线程是操作系统能够进行运算调度的最小单位,它被包含在进程之中,是进程中的实际运作单位。 是进程中的单个顺序控制流,是一条执行路径

  • 单线程:一个进程如果只有一条执行路径,则称为单线程程序

  • 多线程:一个进程如果有多条执行路径,则称为多线程程序

进程和线程的区别

进程是操作系统资源分配的基本单位,而线程是cpu的基本调度单位

线程是进程的子集,一个进程可以有很多线程,每条线程并行执行不同的任务。不同的进程使用不同的内存空间,而所有的线程共享一片相同的内存空间。别把它和栈内存搞混,每个线程都拥有单独的栈内存用来存储本地数据。

一个程序运行后至少有一个进程,一个进程可以包含多个线程,但是至少有一个线程
进程间不能共享数据段地址,但是同进程的线程之间可以
举例说明,ctrl+alt+delete打开任务管理器,运行的每个软件都是一个进程,软件里中的例如360能够同时执行几个任务

如何在Java中实现线程?

在语言层面有两种方式。java.lang.Thread 类的实例就是一个线程,但是它需要调用java.lang.Runnable接口来执行,由于线程类本身就是调用的Runnable接口所以你可以继承 java.lang.Thread 类或者直接调用Runnable接口来重写run()方法实现线程。

当然也可以使用Callable和Future创建线程

用Runnable还是Thread?

这个问题是上题的后续,大家都知道我们可以通过继承Thread类或者调用Runnable接口来实现线程,问题是,那个方法更好呢?什么情况下使 用它?这个问题很容易回答,如果你知道Java不支持类的多重继承,但允许你调用多个接口。所以如果你要继承其他类,当然是调用Runnable接口好 了。

Thread 类中的start() 和 run() 方法有什么区别?

这个问题经常被问到,但还是能从此区分出面试者对Java线程模型的理解程度。start()方法被用来启动新创建的线程,而且start()内部 调用了run()方法,这和直接调用run()方法的效果不一样。当你调用run()方法的时候,只会是在原来的线程中调用,没有新的线程启 动,start()方法才会启动新线程。

反射

什么是反射?

反射就是动态加载对象,并对对象进行剖析。在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意一个方法,这种动态获取信息以及动态调用对象方法的功能成为 Java 反射机制。

反射的作用?

  1. 在运行时判断任意一个对象所属的类

  2. 在运行时构造任意一个类的对象

  3. 在运行时判断任意一个类所具有的成员变量和方法

  4. 在运行时调用任意一个对象的方法

获取 class 的三种方式?

类名.class属性;对象名.getClass()方法;Class.forName(全类名)方法

😔反射中,Class.forName()和 ClassLoader.loadClass()的区别?

Class.forName(className) 方 法 , 内 部 实 际 调 用 的 方 法 是Class.forName(className,true,classloader);第 2 个 boolean 参数表示类是否需要初始化, Class.forName(className)默认是需要初始化, 一旦初始化, 就会触发目标对象的 static 块代码执行, static 参数也也会被再次初始化 ,ClassLoader.loadClass(className) 方 法 , 内 部 实 际 调 用 的 方 法 是ClassLoader.loadClass(className,false);第 2 个 boolean 参数,表示目标对象是否进行链接, false 表示不进行链接,由上面介绍可以,不进行链接意味着不进行包括初始化等一些列步骤,那么静态块和静态对象就不会得到执行

设计模式

说一下你熟悉的设计模式?

单例模式:保证被创建一次,节省系统开销。 工厂模式(简单工厂、抽象工厂):解耦代码。

观察者模式:定义了对象之间的一对多的依赖,这样一来,当一个对象改变时,它的所有的 依赖者都会收到通知并自动更新。

外观模式:提供一个统一的接口,用来访问子系统中的一群接口,外观定义了一个高层的接 口,让子系统更容易使用。

模版方法模式:定义了一个算法的骨架,而将一些步骤延迟到子类中,模版方法使得子类可 以在不改变算法结构的情况下,重新定义算法的步骤。

状态模式:允许对象在内部状态改变时改变它的行为,对象看起来好像修改了它的类。

简单工厂和抽象工厂的区别?

简单工厂:用来生产同一等级结构中的任意产品,对于增加新的产品,无能为力。

工厂方法:用来生产同一等级结构中的固定产品,支持增加任意产品。

抽象工厂:用来生产不同产品族的全部产品,对于增加新的产品,无能为力;支持增加产品 族。

设计模式的优点?

设计模式可在多个项目中重用。

设计模式提供了一个帮助定义系统架构的解决方案。 设计模式吸收了软件工程的经验。

设计模式为应用程序的设计提供了透明性。

设计模式是被实践证明切实有效的,由于它们是建立在专家软件开发人员的知识和经验 之上的。

设计模式的分类?

1、根据目的来分

根据模式是用来完成什么工作来划分,这种方式可分为创建型模式、结构型模式和行为型模 式 3 种。

  1. 创建型模式:用于描述“怎样创建对象”,它的主要特点是“将对象的创建与使用分离”。GoF 中提供了单例、原型、工厂方法、抽象工厂、建造者等 5 种创建型模式。

  2. 结构型模式:用于描述如何将类或对象按某种布局组成更大的结构,GoF 中提供了代理、适配器、桥接、装饰、外观、享元、组合等 7 种结构型模式。

  3. 行为型模式:用于描述类或对象之间怎样相互协作共同完成单个对象都无法单独完成的任务,以及怎样分配职责。GoF 中提供了模板方法、策略、命令、职责链、状态、观察者、中介者、迭代器、访问者、备忘录、解释器等 11 种行为型模式。

2、根据作用范围来分

根据模式是主要用于类上还是主要用于对象上来分,这种方式可分为类模式和对象模式两 种。

  1. 类模式:用于处理类与子类之间的关系,这些关系通过继承来建立,是静态的,在编译 时刻便确定下来了。GoF 中的工厂方法、(类)适配器、模板方法、解释器属于该模式。

  2. 对象模式:用于处理对象之间的关系,这些关系可以通过组合或聚合来实现,在运行时 刻是可以变化的,更具动态性。GoF 中除了以上 4 种,其他的都是对象模式。

设计模式的六大基本原则?

  1. 单一原则(Single Responsibility Principle):一个类只负责一项职责,尽量做到类的只有一个行为原因引起变化;

  2. 里氏替换原则(LSP liskov substitution principle):子类可以扩展父类的功能,但不能改变原有父类的功能;

  1. 依赖倒置原则(dependence inversion principle):面向接口编程;
  2. 接口隔离(interface segregation principle):建立单一接口;
  3. 迪米特原则(law of demeter LOD):最少知道原则,尽量降低类与类之间的耦合;
  4. 开闭原则(open closed principle):用抽象构建架构,用实现扩展原则;

23 种设计模式的具体的每种模式的功能?

单例(Singleton)模式:某个类只能生成一个实例,该类提供了一个全局访问点供外部获取 该实例,其拓展是有限多例模式。

原型(Prototype)模式:将一个对象作为原型,通过对其进行复制而克隆出多个和原型 类似的新实例。

工厂方法(Factory Method)模式:定义一个用于创建产品的接口,由子类决定生产什么产品。

抽象工厂(AbstractFactory)模式:提供一个创建产品族的接口,其每个子类可以生产 一系列相关的产品。

建造者(Builder)模式:将一个复杂对象分解成多个相对简单的部分,然后根据不同需 要分别创建它们,最后构建成该复杂对象。

代理(Proxy)模式:为某对象提供一种代理以控制对该对象的访问。即客户端通过代 理间接地访问该对象,从而限制、增强或修改该对象的一些特性。

适配器(Adapter)模式:将一个类的接口转换成客户希望的另外一个接口,使得原本 由于接口不兼容而不能一起工作的那些类能一起工作。

桥接(Bridge)模式:将抽象与实现分离,使它们可以独立变化。它是用组合关系代替 继承关系来实现,从而降低了抽象和实现这两个可变维度的耦合度。

装饰(Decorator)模式:动态的给对象增加一些职责,即增加其额外的功能。

外观(Facade)模式:为多个复杂的子系统提供一个一致的接口,使这些子系统更加容 易被访问。

享元(Flyweight)模式:运用共享技术来有效地支持大量细粒度对象的复用。

组合(Composite)模式:将对象组合成树状层次结构,使用户对单个对象和组合对象 具有一致的访问性。

模板方法(TemplateMethod)模式:定义一个操作中的算法骨架,而将算法的一些步骤 延迟到子类中,使得子类可以不改变该算法结构的情况下重定义该算法的某些特定步骤。

策略(Strategy)模式:定义了一系列算法,并将每个算法封装起来,使它们可以相互 替换,且算法的改变不会影响使用算法的客户。

命令(Command)模式:将一个请求封装为一个对象,使发出请求的责任和执行请求 的责任分割开。

职责链(Chain of Responsibility)模式:把请求从链中的一个对象传到下一个对象,直到请求被响应为止。通过这种方式去除对象之间的耦合。

状态(State)模式:允许一个对象在其内部状态发生改变时改变其行为能力。

观察者(Observer)模式:多个对象间存在一对多关系,当一个对象发生改变时,把这 种改变通知给其他多个对象,从而影响其他对象的行为。

中介者(Mediator)模式:定义一个中介对象来简化原有对象之间的交互关系,降低系 统中对象间的耦合度,使原有对象之间不必相互了解。

迭代器(Iterator)模式:提供一种方法来顺序访问聚合对象中的一系列数据,而不暴 露聚合对象的内部表示。

访问者(Visitor)模式:在不改变集合元素的前提下,为一个集合中的每个元素提供多 种访问方式,即每个元素有多个访问者对象访问。

备忘录(Memento)模式:在不破坏封装性的前提下,获取并保存一个对象的内部状态, 以便以后恢复它。

解释器(Interpreter)模式:提供如何定义语言的文法,以及对语言句子的解释方法, 即解释器。

UML 是什么?

统一建模语言(Unified Modeling Language,UML)是用来设计软件蓝图的可视化建模语言, 1997 年被国际对象管理组织(OMG)采纳为面向对象的建模语言的国际标准。它的特点是简单、统一、图形化、能表达软件设计中的动态与静态信息。

统一建模语言能为软件开发的所有阶段提供模型化和可视化支持。而且融入了软件工程领域 的新思想、新方法和新技术,使软件设计人员沟通更简明,进一步缩短了设计时间,减少开 发成本。它的应用领域很宽,不仅适合于一般系统的开发,而且适合于并行与分布式系统的 建模。

UML 从目标系统的不同角度出发,定义了用例图、类图、对象图、状态图、活动图、时序图、协作图、构件图、部署图等 9 种图。

桥接模式是什么?

桥接(Bridge)模式的定义如下:将抽象与实现分离,使它们可以独立变化。它是用组合关 系代替继承关系来实现,从而降低了抽象和实现这两个可变维度的耦合度。

优点是:由于抽象与实现分离,所以扩展能力强; 其实现细节对客户透明。

缺点是:由于聚合关系建立在抽象层,要求开发者针对抽象化进行设计与编程,这增加了系 统的理解与设计难度

类适配器:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-MIUiuwpo-1635166712562)(asset/img/java基础面试题 - 副本/wps14CC.tmp.png)]

对象适配器:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-gNmfmefa-1635166712563)(asset/img/java基础面试题 - 副本/wps14E0.tmp.png)]

策略模式是什么?

策略(Strategy)模式的定义:该模式定义了一系列算法,并将每个算法封装起来,使它们 可以相互替换,且算法的变化不会影响使用算法的客户。策略模式属于对象行为模式,它通 过对算法进行封装,把使用算法的责任和算法的实现分割开来,并委派给不同的对象对这些算法进行管理。

策略模式的主要优点如下

  1. 多重条件语句不易维护,而使用策略模式可以避免使用多重条件语句。

  2. 策略模式提供了一系列的可供重用的算法族,恰当使用继承可以把算法族的公共代码转 移到父类里面,从而避免重复的代码。

  3. 策略模式可以提供相同行为的不同实现,客户可以根据不同时间或空间要求选择不同的。

  4. 策略模式提供了对开闭原则的完美支持,可以在不修改原代码的情况下,灵活增加新算法。

  5. 策略模式把算法的使用放到环境类中,而算法的实现移到具体策略类中,实现了二者的分离。

其主要缺点如下

  1. 客户端必须理解所有策略算法的区别,以便适时选择恰当的算法类。

  2. 策略模式造成很多的策略类

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-v1H5HCuz-1635166712564)(asset/img/java基础面试题 - 副本/wps14E4.tmp.png)]

枚举

网络编程

枚举和注解

网络通信

jvm

开源框架

分布式相关

数据库

并发和性能调优

不确定/待看

强引用和软引用和弱引用以及虚引用?

主要是为了更好的进行内存管理而设置的一套机制,粗俗的说就是不同的引用垃圾回收的力度不同。

强引用:最普遍的一种引用方式,如 String s = “abc”,变量 s 就是字符串“abc”的强引用,只要强引用存在,则垃圾回收器就不会回收这个对象。

软引用(SoftReference):用于描述还有用但非必须的对象,如果内存足够,不回收,如果内存不足,则回收。一般用 于实现内存敏感的高速缓存,软引用可以和引用队列 ReferenceQueue 联合使用,如果软引用的对象被垃圾回收,JVM 就会把这个软引用加入到与之关联的引用队列中。

弱引用(WeakReference):弱引用和软引用大致相同,弱引用与软引用的区别在于:只具有弱引用的对象拥有更短暂的 生命周期。在垃圾回收器线程扫描它所管辖的内存区域的过程中,一旦发现了只具有弱引用 的对象,不管当前内存空间足够与否,都会回收它的内存。

虚引用(PhantomReference):就是形同虚设,与其他几种引用都不同,虚引用并不会决定对象的生命周期。如果一个对象 仅持有虚引用,那么它就和没有任何引用一样,在任何时候都可能被垃圾回收器回收。 虚引用主要用来跟踪对象被垃圾回收器回收的活动。

虚引用与软引用和弱引用的一个区别在于:

虚引用必须和引用队列 (ReferenceQueue)联合使用。当垃圾回收器准备回收一个对象时, 如果发现它还有虚引,就会在回收对象的内存之前,把这个虚引用加入到与之关联的引用队列中。

EJB 的生命周期,以及如何管理事务?

SessionBean:Stateless Session Bean 的生命周期是由容器决定的,当客户机发出请求要 建立一个 Bean 的实例时,EJB 容器不一定要创建一个新的 Bean 的实例供客户机调用,而是随便找一个现有的实例提供给客户机。当客户机第一次调用一个 Stateful Session Bean 时,容器必须立即在服务器中创建一个新的 Bean 实例,并关联到客户机上,以后此客户机调用Stateful Session Bean 的方法时容器会把调用分派到与此客户机相关联的Bean 实例。EntityBean:Entity Beans 能存活相对较长的时间,并且状态是持续的。只要数据库中的数据存在,Entity beans 就一直存活。而不是按照应用程序或者服务进程来说的。即使 EJB 容器崩溃了,Entity beans 也是存活的。Entity Beans 生命周期能够被容器或者 Beans 自己管理。EJB 通过以下技术管理实务:对象管理组织(OMG)的对象实务服务(OTS),Sun Microsystems 的 Transaction Service(JTS)、Java Transaction API(JTA),开发组(X/Open)的 XA 接口。

📝前端分割线

html+css+js+jquery+xml

网站性能优化

HTML方面:

  1. 资源文件js css 图片合并压缩
  2. 减少页面dom操作,操作多的话可以考虑使用虚拟dom
  3. 减少http请求
  4. 使用cdn加速
  5. 减少cookie大小

从浏览器地址栏输入url到显示页面的步骤

  1. 浏览器根据请求的URL,交给DNS域名解析,找到真实的ip,交给域名解析。
  2. 服务器交给后端处理完成后返回的数据,浏览器接收文件HTML,CSS,JS图片等。
  3. 浏览器对加载的资源进行语法解析,建立相应的数据内部结构。
  4. 解析html,创建dom树,自上而下的顺序
  5. 解析css,优先级:浏览器默认设置<用户设置<外部样式<内联样式<HTML中的style样式;
  6. 将css与dom合并,构建渲染树
  7. 布局重绘重排,页面完成渲染。

对浏览器内核的理解

主要分为渲染引擎和js引擎

  • 渲染引擎:主要负责取得网页的(html,xml,图片等),整理信息结合css渲染页面,计算网页的显示方式,浏览器内核的不同对网页的语法解释也会有所不同,所以渲染效果也会有所不同,这就存在了兼容性的问题。

  • js引擎:解析和执行js来达到网页的动态交互效果

最开始渲染引擎和js引擎没有太区分,后来越来越独立化,然后内核一般就是指渲染引擎了。

link与@import的区别

  1. link是html 的方式,@import是css的方式
  2. link最大限度支持并行下载,@import过多嵌套导致串行下载
  3. link可以通过rel="alternate stylesheet"指定候选样式
  4. 总体来说:link优于@import

对this的理解

this总是指向函数的直接调用者(而非间接调用者)
如果有new关键字,this指向new出来的那个对象
在事件中,this指向触发这个事件的对象,特殊的是,IE中的attachEvent中的this总是指向全局对象Window

xml和json的区别,请用四个词语来形容

  • JSON相对于XML来讲,数据的体积小,传递的速度更快些
  • JSON与JavaScript的交互更加方便,更容易解析处理,更好的数据交互
  • XML对数据描述性比较好;
  • JSON的速度要远远快于XML

undefined 和 null 区别

null: Null类型,代表“空值”,代表一个空对象指针,使用typeof运算得到 “object”,所以你可以认为它是一个特殊的对象值。
undefined: Undefined类型,当一个声明了一个变量未初始化时,得到的就是undefined。

jQuery 库中的 $() 是什么?

$() 函数是 jQuery() 函数的别称, $() 函数用于将任何对象包裹成 jQuery 对象,接着你就被允许调用定义在 jQuery 对象上的多个不同方法。你甚至可以将一个选择器字符串传入 $() 函数,它会返回一个包含所有匹配的 DOM 元素数组的 jQuery 对象。

$(document).ready() 是个什么函数?为什么要用它?

这段代码其实简写就等价于我们常见的 $(function(){ });
ready() 函数当DOM 完全加载(例如HTML被完全解析DOM树构建完成时)后执行代码,jQuery允许你执行代码。
使用$(document).ready()的最大好处在于它适用于所有浏览器,jQuery帮你解决了跨浏览器的难题。

javaScript window.onload 事件和 jQuery ready 函数有何不同?

JavaScript window.onload 事件除了要等待 DOM 被创建还要等到包括大型图片、音频、视频在内的所有外部资源都完全加载,然后再执行JS代码。

jQuery ready() 函数只需要等待网页中的DOM结构加载完毕,表示文档结构已经加载完成(不包含图片等非文字媒体文件),就能执行JS代码。使用 jQuery $(document).ready() 的另一个优势是你可以在网页里多次使用它,浏览器会按它们在 HTML 页面里出现的顺序执行它们

使用 CDN 加载 jQuery 库的主要优势是什么 ?

CDN的全称是Content Delivery Network,即内容分发网络,使用户就近获取所需内容,降低网络拥塞,提高用户访问响应速度和命中率。

除了报错节省服务器带宽以及更快的下载速度这许多的好处之外, 最重要的是,如果浏览器已经从同一个CDN下载类相同的 jQuery 版本, 那么它就不会再去下载它一次. 因此今时今日,许多公共的网站都将jQuery用于用户交互和动画, 如果浏览器已经有了下载好的jQuery库,网站就能有非常好的展示机会。

cdn的作用:cdn可以处理整个网站 70%-95%的访问量,从而解决网站的并发量,简单的说就是通过在不同地点缓存内容,然后通过负载平衡等技术将用户请求定向到最近的缓存服务器上获取内容,提高用户访问网站的响应速度。

实现:<script src="https://cdn.static.runoob.com/libs/jquery/2.1.1/jquery.min.js"></script>

什么是AJAX,为什么要使用Ajax(请谈一下你对Ajax的认识)

AJAX是“Asynchronous JavaScript and XML”的缩写。他是指一种创建交互式网页应用的网页开发技术。

还有一些很复杂的话术,简单的说就是通过各种技术实现前后端交互

Ajax和javascript的区别。

javascript是一种在浏览器端执行的脚本语言,Ajax是一种创建交互式网页应用的开发技术 ,它是利用了一系列相关的技术其中就包括javascript。

介绍一下XMLHttpRequest对象的常用方法和属性=>以及书写。

<script type="text/javascript">
 //1.创建XMLHttpRequest对象
    var xmlhttp;
    if (window.XMLHttpRequest) {
        // code for IE7+, Firefox, Chrome, Opera, Safari
        xmlhttp = new XMLHttpRequest();
    } else {
        // code for IE6, IE5
        xmlhttp = new ActiveXObject("Microsoft.XMLHTTP");
    }

    /* 2.建立连接
       参数:
          1.请求方式,GET、POST
          2.请求路径,一般写一个服务器资源的地址(Servlet的地址)
          3.同步或异步请求,true(异步)或 false(同步)
    */
    xmlhttp.open("GET", "${pageContext.request.contextPath}/ajaxServlet?name=Zhangsan", true);
    //3.发送请求
    xmlhttp.send();
    
    //如果需要像 HTML 表单那样 POST 数据,请使用 setRequestHeader() 来添加 HTTP 头。
    //然后在 send() 方法中规定您希望发送的数据:
    //xmlhttp.open("POST","${pageContext.request.contextPath}/ajaxServlet",true);
    //xmlhttp.setRequestHeader("Content-type","application/x-www-form-urlencoded");
    //xmlhttp.send("name=Zhangsan");

    //4.接收并处理来自服务器的响应结果
    xmlhttp.onreadystatechange = function () {
        /**
         * readyState:XMLHttpRequest 的状态
         *  0: 请求未初始化
         *  1: 服务器连接已建立
         *  2: 请求已接收
         *  3: 请求处理中
         *  4: 请求已完成,且响应已就绪
         *
         *  status:响应状态码
         */
        if (xmlhttp.readyState == 4 && xmlhttp.status == 200) {
            alert(xmlhttp.responseText);
        }
    }
</script>
open(‘method’,’url’,async);	// 创建一个新的http请求,并指定此请求的方法、URL以及验证信息   
  method:请求的类型;GET 或 POST    
  url:文件在服务器上的位置  
  async:true(异步)或 false(同步)
send()方法,发送具体请求  => 传递null防止sql注入
abort()方法,停止当前请求
readyState属性  请求的状态 有5个可取值  
  0 - (未初始化)还没有调用 send()方法  
  1 - (正在加载)已调用 send()方法,正在发送请求   
  2 - (已加载)send()方法执行完成    
  3 - (交互)正在解析响应内容   
  4 - (完成)响应内容解析完成,可以在客户端调用   
responseText 属性从服务器进程返回数据的字符串形式。
reponseXML 属性 服务器的响应,表示为XML
status  服务器的HTTP状态码,200对应ok  400对应not found

什么是XML

XML是扩展标记语言,能够用一系列简单的标记描述数据

XML的解析方式

常用的用dom解析和sax解析。dom解析是一次性读取xml文件并将其构造为DOM对象供程序使用,优点是操作方便,但是比较耗内存。Sax是按事件驱动的方式解析的,占用内存少,但是编程复杂

你采用的是什么框架(架包)

这题是必问的,一般也是最开始就会问到。

在java中比较流行的有 dojo, Prototype , JQuery, Dwr, extjs 等等

如果熟悉某种ajax框架,他可能会问到怎样在程序中使用这种框架

DWR框架介绍

DWR(DirectWeb Remoting)是一个WEB远程调用框架.利用这个框架可以让AJAX开发变得很简单.利用DWR可以在客户端利用JavaScript直接调用服务端的Java方法并返回值给JavaScript就好像直接本地客户端调用一样(DWR根据Java类来动态生成JavaScrip代码).

DWR的实现原理是通过反射,将java翻译成javascript,然后利用回调机制,从而实现了javascript调用Java代码

介绍一下Prototype的 ( ) 函 数 , ()函数, ()F()函数,$A()函数都是什么作用?

$() 方法是在DOM中使用过于频繁的 document.getElementById() 方法的一个便利的简写,就像这个DOM方法一样,这个方法返回参数传入的id的那个元素。

$F()函数是另一个大收欢迎的“快捷键”,它能用于返回任何表单输入控件的值,比如textbox,drop-down list。这个方法也能用元素id或元素本身做为参数。

$A()函数能把它接收到的单个的参数转换成一个Array对象。

http

BS 与 CS 的联系与区别?

  1. 硬件环境不同:C/S 一般建立在专用的网络上, 小范围里的网络环境, 局域网之间再通过专门服务器提供连接和数据交换服务. B/S 建立在广域网之上的, 不必是专门的网络硬件环境,例与电话上网, 租用设备. 信息自己管理. 有比 C/S 更强的适应范围, 一般只要有操作系统和浏览器就行

  2. 对安全要求不同:C/S 一般面向相对固定的用户群, 对信息安全的控制能力很强. 一般高度机密的信息系统采用 C/S 结构适宜. 可以通过 B/S 发布部分可公开信息.B/S 建立在广域网之上, 对安全的控制能力相对弱, 可能面向不可知的用户。

  3. 对程序架构不同:C/S 程序可以更加注重流程, 可以对权限多层次校验, 对系统运行速度可以较少考虑.B/S 对安全以及访问速度的多重的考虑, 建立在需要更加优化的基础之上. 比 C/S 有更高的要求 B/S 结构的程序架构是发展的趋势, 从 MS 的.Net 系列的 BizTalk 2000 Exchange 2000 等, 全面支持网络的构件搭建的系统. SUN 和IBM 推的JavaBean 构件技术等,使 B/S 更加成熟.

  4. 软件重用不同:C/S 程序可以不可避免的整体性考虑, 构件的重用性不如在 B/S 要求下的构件的重用性好.B/S 对的多重结构,要求构件相对独立的功能. 能够相对较好的重用.就入买来的餐桌可以再利用,而不是做在墙上的石头桌子

  5. 系统维护不同:C/S 程序由于整体性, 必须整体考察, 处理出现的问题以及系统升级. 升级难. 可能是再做一个全新的系统;B/S 构件组成,方面构件个别的更换,实现系统的无缝升级. 系统维护开销减到最小.用户从网上自己下载安装就可以实现升级.

  6. 处理问题不同:C/S 程序可以处理用户面固定, 并且在相同区域, 安全要求高需求, 与操作系统相关. 应该都是相同的系统;B/S 建立在广域网上, 面向不同的用户群, 分散地域, 这是C/S 无法作到的. 与操作系统平台关系最小.

  7. 用户接口不同:C/S 多是建立的 Window 平台上,表现方法有限,对程序员普遍要求较高;B/S 建立在浏览器上, 有更加丰富和生动的表现方式与用户交流. 并且大部分难度减低, 减低开发成本.

  8. 信息流不同:C/S 程序一般是典型的中央集权的机械式处理, 交互性相对低;B/S 信息流向可变化, B-B B-C B-G 等信息、流向的变化, 更像交易中心。

Http 请求的 get 和 post 方法的区别。

  1. Get 是用来从服务器上获得数据,而Post 是用来向服务器上传递数据;

  2. Get 是获取信息,而不是修改信息,类似数据库查询功能一样,数据不会被修改

  3. Get 请求的参数会跟在 url 后进行传递,请求的数据会附在 URL 之后,以?分割 URL 和传输数据,参数之间以&相连,%XX 中的 XX 为该符号以 16 进制表示的 ASCII,如果数据是英文字母/数字,原样发送,如果是空格,转换为+,如果是中文/其他字符,则直接把字符串用BASE64 加密。

  4. Get 传输的数据有大小限制,因为 GET 是通过 URL 提交数据,那么 GET 可提交的数据量就跟 URL 的长度有直接关系了,不同的浏览器对 URL 的长度的限制是不同的。

  5. GET 请求的数据会被浏览器缓存起来,用户名和密码将明文出现在 URL 上,其他人可以查到历史浏览记录,数据不太安全。

    在服务器端,用 Request.QueryString 来获取 Get 方式提交来的数据

    Post 请求则作为 http 消息的实际内容发送给 web 服务器,数据放置在 HTML Header 内提交, Post 没有限制提交的数据。Post 比 Get 安全,当数据是中文或者不敏感的数据,则用 get, 因为使用 get,参数会显示在地址,对于敏感数据和不是中文字符的数据,则用 post。

  6. POST 表示可能修改变服务器上的资源的请求,在服务器端,用 Post 方式提交的数据只能用 Request.Form 来获取。

Http与Https的区别

  1. https协议需要到CA申请证书,一般免费证书较少,因而需要一定费用。(原来网易官网是http,而网易邮箱是https。)
  2. http是超文本传输协议,信息是明文传输,https则是具有安全性的ssl加密传输协议。
  3. http和https使用的是完全不同的连接方式,用的端口也不一样,前者是80,后者是443。
  4. http的连接很简单,是无状态的。Https协议是由SSL+Http协议构建的可进行加密传输、身份认证的网络协议,比http协议安全。(无状态的意思是其数据包的发送、传输和接收都是相互独立的。无连接的意思是指通信双方都不长久的维持对方的任何信息。)

📝javaweb分割线

jdbc

JDBC 访问数据库的基本步骤是什么?

  1. Class.forName()加载数据库连接驱动;

  2. DriverManager.getConnection()获取数据连接对象;

  3. 根据 SQL 获取 sql 会话对象,有 2 种方式 Statement、PreparedStatement ;

  4. 执行 SQL,执行 SQL 前如果有参数值就设置参数值 setXXX();

  5. 处理结果集;

  6. 关闭结果集、关闭会话、关闭连接。

为什么要使用 PreparedStatement?

PreparedStatement 接口继承 Statement,PreparedStatement 实例包含已编译的 SQL 语句,所以其执行速度要快于 Statement 对象。

作为 Statement 的子类, PreparedStatement 继承了 Statement 的所有功能。三种方法execute、 executeQuery 和 executeUpdate 已被更改以使之不再需要参数。在 JDBC 应用中,多数情况下使用 PreparedStatement,原因如下:

  1. 代码的可读性和可维护性。Statement 需要不断地拼接,而 PreparedStatement 不会。PreparedStatement 尽最大可能提高性能。DB 有缓存机制,相同的预编译语句再次被调用不会再次需要编译。

  2. 最重要的一点是极大地提高了安全性。Statement 容易被 SQL 注入,而 PreparedStatement传入的内容不会和 sql 语句发生任何匹配关系。

数据库连接池的原理。为什么要使用连接池?

  1. 数据库连接是一件费时的操作,连接池可以使多个操作共享一个连接。

  2. 数据库连接池的基本思想就是为数据库连接建立一个“缓冲池”。预先在缓冲池中放入一 定数量的连接,当需要建立数据库连接时,只需从“缓冲池”中取出一个,使用完毕之后再放 回去。我们可以通过设定连接池最大连接数来防止系统无尽的与数据库连接。更为重要的是 我们可以通过连接池的管理机制监视数据库的连接的数量、使用情况,为系统开发,测试及 性能调整提供依据。

  3. 使用连接池是为了提高对数据库连接资源的管理

execute,executeQuery,executeUpdate 的区别是什么?

  1. Statement 的 execute(String query)方法用来执行任意的 SQL 查询,如果查询的结果是一个ResultSet,这个方法就返回 true。如果结果不是 ResultSet,比如 insert 或者 update 查询,它就会返回 false 。 我们可以通过它的 getResultSet 方法来获取 ResultSet , 或者通过getUpdateCount()方法来获取更新的记录条数。

  2. Statement 的 executeQuery(String query)接口用来执行 select 查询,并且返回 ResultSet。即使查询不到记录返回的 ResultSet 也不会为 null。我们通常使用 executeQuery 来执行查询语句, 这样的话如果传进来的是 insert 或者 update 语句的话, 它会抛出错误信息为“executeQuery method can not be used for update”的 java.util.SQLException。 ,

  3. Statement 的 executeUpdate(String query)方法用来执行 insert 或者 update/delete(DML) 语句,或者 什么也不返回,对于 DDL 语句,返回值是 int 类型,如果是 DML 语句的话,它就是更新的条数,如果是 DDL 的话,就返回 0。

只有当你不确定是什么语句的时候才应该使用 execute() 方法, 否则应该使用executeQuery 或者 executeUpdate 方法。

JDBC 的 ResultSet 是什么?

在查询数据库后会返回一个 ResultSet,它就像是查询结果集的一张数据表。
ResultSet 对象维护了一个游标,指向当前的数据行。开始的时候这个游标指向的是第一行。如果调用了 ResultSet 的 next()方法游标会下移一行,如果没有更多的数据了,next()方法会返回 false。可以在 for 循环中用它来遍历数据集。
默认的 ResultSet 是不能更新的,游标也只能往下移。也就是说你只能从第一行到最后一行遍历一遍。不过也可以创建可以回滚或者可更新的 ResultSet
当生成 ResultSet 的 Statement 对象要关闭或者重新执行或是获取下一个 ResultSet 的时候,ResultSet 对象也会自动关闭。
可以通过 ResultSet 的 getter 方法,传入列名或者从 1 开始的序号来获取列数据。

servlet

Servlet体系结构图

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Jk8pcU2h-1635166712565)(asset/img/java基础面试题总结/image-20210926143443600.png)]

什么是 Servlet?

Servlet 是使用 Java Servlet 应用程序接口(API)及相关类和方法的 Java 程序,所有的 Servlet 都必须要实现的核心接口是 javax.servlet.servlet。每一个 servlet 都必须要直接或者间接实现这个接口,或者继承 javax.servlet.GenericServlet 或 javax.servlet.HTTPServlet。

Servlet 主要用于接受请求,处理请求,完成响应

servlet 的生命周期?

Servlet 生命周期可以分成四个阶段:加载和实例化(为对象分配空间)、初始化(为对象的属性赋值)、请求处理(服务阶段)、销毁。

  1. 当客户第一次请求时,首先判断是否存在 Servlet 对象,若不存在,则由 Web 容器加载 Servlet 并将其实例化
  2. 调用 init()方法对其初始化(只调用一次。)
  3. 请求到达时运行其 service 方法,service 方法自动派遣运行与请求对应的doXXX 方法(doGet,doPost)等
  4. 当 Web 容器关闭或者 Servlet 对象要从容器中被删除时,会自动调用 destory()方法。

说出 Servlet 和 CGI 的区别?

Servlet 与 cgi 的区别在于 servlet 处于服务器进程中,它通过多线程方式运行其 service 方法,一个实例可以服务于多个请求,并且其实例一般不会销毁,而 CGI 对每个请求都产生新的进程, 服务完成后就销毁,所以效率上低于 servlet。

tomcat 容器是如何创建 servlet 类实例?用到了什么原理?

当容器启动时,会读取在 webapps 目录下所有的 web 应用中的 web.xml 文件,然后对 xml 文件进行解析,并读取 servlet 注册信息。然后,将每个应用中注册的 servlet 类都进行加载, 并通过反射的方式实例化。(有时候也是在第一次请求时实例化)

在 servlet 注册时加上<load-on-startup>1</load-on-startup>如果为正数,则在一开始就实例化,如果不写或为负数,则第一次请求实例化。

doGet 和 doPost 方法有什么区别?

doGet:GET 方法会把名值对追加在请求的 URL 后面。因为 URL 对字符数目有限制,进而限制了用在客户端请求的参数值的数目。并且请求中的参数值是可见的,因此,敏感信息不能 用这种方式传递。
doPOST:POST 方法通过把请求参数值放在请求体中来克服GET 方法的限制,因此,可以发送的参数的数目是没有限制的。最后,通过 POST 请求传递的敏感信息对外部客户端是不可见的。

request 作用?

  1. 获取请求参数 getParameter()

  2. 获取当前 Web 应用的虚拟路径 getContextPath

  3. 转发 getRequestDispatcher(路径).forward(request,response);

  4. 它还是一个域对象

如何防止表单重复提交?

针对于重复提交的整体解决方案:

  1. 用 redirect(重定向)来解决重复提交的问题

  2. 点击一次之后,按钮失效

  3. 通过 loading(Loading 原理是在点击提交时,生成 Loading 样式,在提交完成之后隐藏该样式)

  4. 自定义重复提交过滤器

转发(forward)和重定向(redirect)的区别?

  1. 从地址栏显示来说

    forward 是服务器请求资源,服务器直接访问目标地址的URL,把那个URL 的响应内容读取过来, 然后把这些内容再发给浏览器.浏览器根本不知道服务器发送的内容从哪里来的,所以它的地址栏还是原来的地址.

    redirect 是服务端根据逻辑,发送一个状态码,告诉浏览器重新去请求那个地址.所以地址栏显示的是新的 URL.

  2. 从数据共享来说

    forward:转发页面和转发到的页面可以共享 request 里面的数据.

    redirect:不能共享数据.

  3. 从运用地方来说

    forward:一般用于用户登陆的时候,根据角色转发到相应的模块.

    redirect:一般用于用户注销登陆时返回主页面和跳转到其它的网站等

  4. 从效率来说

    forward:高.

    redirect:低.

request.getAttribute()和 request.getParameter()有何区别?

  1. request.getParameter()取得是通过容器的实现来取得通过类似 post,get 等方式传入的数据。
  2. request.setAttribute()和 getAttribute()只是在 web 容器内部流转,仅仅是请求处理阶段。
  3. getAttribute 是返回对象,getParameter 返回字符串
  4. getAttribute()一向是和 setAttribute()一起使用的,只有先用 setAttribute()设置之后,才能够通过 getAttribute()来获得值,它们传递的是 Object 类型的数据。而且必须在同一个 request 对象中使用才有效。,而 getParameter()是接收表单的 get 或者 post 提交过来的参数

MVC 的各个部分都有哪些技术来实现?如何实现?

MVC 是Model-View-Controller 的简写。“Model” 代表的是应用的业务逻辑(通过 JavaBean, EJB 组件实现), “View” 是应用的表示面(由 JSP 页面产生),“Controller” 是提供应用的处理过程控制(一般是一个 Servlet),通过这种设计模型把应用逻辑,处理过程和显示

逻辑分成不同的组件实现。这些组件可以进行交互和重用。

get 请求中文乱码?

乱码的根本原因:浏览器的编码方式 UTF-8 和 服务器的解码方式 ISO-859-1 不一样

解决方法:

  1. 第一种方式 使用 URLEncoder 和 URLDecoder 两个类 编解码。先以 iso-8895-1 进行编码,然后再以 utf-8 进行解码

  2. 第二种方式 使用 String 类的方法进行编解码

  3. 第三种方式 更改 server.xml 配置文件。

GET 请求是在URL 地址栏中传递请求参数的,它会被 Tomcat 服务器自动解码,而 Tomcat服务器默认的字符集也是 ISO-8859-1,所以我们需要修改 Tomcat 服务器的字符集为 UTF-8。

post 请求中文乱码问题?

  1. post 请求方式乱码的原因是:因为 post 是以二进制流的形式发送到的服务器。服务器收到数据后。默认以 iso-8859-1 进行编码。

  2. post 请求乱码解决,只需要在获取请求参数之前调用 request.setCharacterEncoding(“UTF-8”); 方法设置字符集 即可。

响应乱码?

1、原因: 由服务器编码,默认使用 ISO-8859-1 进行编码由浏览器解码,默认使用 GBK 进行解码

2、解决方案

  1. 设置响应头: response.setHeader(“Content-Type”,“text/html;charset=utf-8”);

  2. 设置响应的内容类型:response.setContentType(“text/html;charset=utf-8”);

通过这种方式可以在响应头中告诉浏览器响应体的编码方式是 UTF-8;同时服务器也会采用该字符集进行编码,但需要注意的是,两种方法一定要在 response.getWriter()之前进行。

cookie和session

😔session 和 cookie 的区别?

session 是存储在服务器端,cookie 是存储在客户端的,所以安全来讲 session 的安全性要比cookie 高,然后我们获取 session 里的信息是通过存放在会话 cookie 里的 sessionid 获取的。
cookie分为两大类分为 会话 cookie 和 持久化 cookie

  • 会话 cookie 存放在客户端浏览器的内存中,所以说他的生命周期和浏览器是一致的,浏览器关了会话cookie 也就消失了
  • 持久化 cookie 存放在客户端硬盘中,而持久化 cookie 的生命周期就是我们在设置 cookie 时候设置的那个保存时间,然后我们考虑一问题当浏览器关闭时session 会不会丢失,

从上面叙述分析 session 的信息是通过会话 cookie 的 sessionid 获取的, 当浏览器关闭的时候会话 cookie 消失所以我们的 sessionid 也就消失了,但是 session 的信息还存在服务器端,这时我们只是查不到所谓的 session 但它并不是不存在。那么,session 在什么情况下丢失,就是在服务器关闭的时候,或者是 session 过期(默认时间是 30 分钟),再 或 者 调 用 了 invalidate() 的 或 者 是 我 们 想 要 session 中 的 某 一 条 数 据 消 失 调 用session.removeAttribute()方法,然后 session 在什么时候被创建呢,确切的说是通过调用getsession()来创建,这就是 session 与 cookie 的区别.

😔Cookie和Session的区别?

  1. session 保存在服务器;cookie 保存在客户端。 所以安全来讲 session 的安全性要比cookie 高,然后我们获取 session 里的信息是通过存放在会话 cookie 里的 sessionid 获取的。
  2. session 中可以保存对象,cookie 中保存的是字符串。
  3. session 不能区分路径,同一个用户在访问一个网站期间,所有的 session 在任何一个地方都可以访问到。而 cookie 中如果设置了路径参数,那么同一个网站中不同路径下的 cookie 互相是访问不到的。
  4. session 需要借助 cookie才能正常使用。如果客户端完全禁止 cookie,session 将失效。

Cookie 对象的缺陷?

  1. Cookie 是明文的,不安全

  2. 不同的浏览器对 Cookie 对象的数量和大小有限制

  3. Cookie 对象携带过多费流量

  4. Cookie 对象中的 value 值只能是字符串,不能放对象网络中传递数据只能是字符串

Session 的运行机制?

  1. 在服务器端创建 Session 对象,该对象有一个全球唯一的 ID

  2. 在创建 Session 对象的同时创建一个特殊的 Cookie 对象, 该 Cookie 对象的名字是JSESSIONID,该 Cookie 对象的 value 值是 Session 对象的那个全球唯一的 ID,并且会将这个特殊的 Cookie 对象携带发送给浏览器

  3. 以后浏览器再发送请求就会携带这个特殊的 Cookie 对象

  4. 服务器根据这个特殊的 Cookie 对象的 value 值在服务器中寻找对应的 Session 对象,以此来区分不同的用户

钝化和活化?

  1. Session 与 session 域中的对象一起从内存中被序列化到硬盘上的过程我们称为钝化。服务器关闭时会发生钝化。

  2. Session 与 session 域中的对象一起从硬盘上反序列化到内存中的过程我们称为活化。服务器再次开启时会发生活化。

  3. 要保证 session 域中的对象能和 Session 一起被钝化和活化,必须保证对象对应的类实现Serializable 接口

jsp

jsp 和 servlet 的区别、共同点、各自应用的范围?

JSP 是 Servlet 技术的扩展,本质上就是 Servlet 的简易方式。JSP 编译后是“类 servlet”。Servlet 和 JSP 最主要的不同点在于,Servlet 的应用逻辑是在 Java 文件中,并且完全从表示层中的HTML 里分离开来。而 JSP 的情况是 Java 和 HTML 可以组合成一个扩展名为.jsp 的文件。JSP 侧重于视图,Servlet 主要用于控制逻辑。在 struts 框架中,JSP 位于 MVC 设计模式的视图层, 而 Servlet 位于控制层.

jsp 有哪些内置对象?作用分别是什么?

JSP 有 9 个内置对象:

  1. request:封装客户端的请求,其中包含来自 GET 或 POST 请求的参数(即HttpServletRequest类的对象);
  2. response:封装服务器对客户端的响应(即HttpServletResponse类的对象);
  3. pageContext:通过该对象可以获取其他对象;
  4. session:封装用户会话的对象;
  5. application:封装服务器运行环境的对象(即ServletContext类的对象);
  6. out:输出服务器响应的输出流对象(等同与response.getWriter());
  7. config:Web 应用的配置对象;
  8. page:JSP 页面本身(相当于 Java 程序中的 this);
  9. exception:封装页面抛出异常的对象。

jsp三大指令,七大动作

三大指令:

  1. page指令 :设定整个JSP网页的静态属性。
    语法:<%@ page 标签元素=“值”%>,比如 <%@ page language=“java”%>标签元素:language、import、contentType、session、errorPage、isErrorPage等等。

  2. include指令 :用来向当前页面插入一个静态文件的内容。这个文件可以是JSP、HTML、文本或是Java程序。
    语法:<%@ include file=“filename” %> 比如 <%@ include file=“111.txt” %>标签元素:file

  3. taglib指令 :使用标签库定义新的自定义标签,在JSP页面中启用定制行为。当页面引用了用户自定义标签时,taglib指令用于引用自定义标签库,并指定标签的前缀。
    语法:<%@ taglib uri=“URIToTagLibrary” prefix=“tagPrefix” %>如<%@ taglib uri=“http://www.jspcentral.com/tags” prefix=“JAXP” %>标签元素:uri、Prefixpage指令元素的属性

jSP 7 个 动作指令如下 :

  1. jsp : forward: 执行页面转向,将请求的处理转发到下一个页面。
  2. jsp : param: 用于传递参数,必须与其他支持参数曲标签一起使用。
  3. jsp : include: 用于动态引入一个 JSP 页面。
  4. jsp : plugin: 用于下载 JavaBean 或 Applet 到客户端执行。
  5. jsp : useBean: 使用 JavaBean。
  6. jsp : setProperty: 修改 JavaBean 实例的属性值。
  7. jsp : getProperty: 获取 JavaBean 实例的属性值。

页面间对象传递的方法?

request、session、application、cookie

jsp 的四种范围?

JSP有4种范围,分别是page、request、session和application,都能用setAttribute("", “”)添加变量,getAttribute("")获取变量,对于page,得用pageContext。作用范围:

  • page 在同一个页面有效;

  • request 在同一次请求(请求页面)间有效,一般请求完毕则失效,但若是通过forward的方式跳转,则forward页面依旧能拿到request的值。但如果是通过redirect的方式,则相当于重新发送一次页面请求,request中的值失效;
    注: <jsp:forward page= “相对路径”/> 作用是将请求转到另一个页面,表现为跳转,实际上也分享了request的值

  • session 在一个会话的生命周期内有效,简单来说就是与服务器连接的时间内,注意的是所有页面共享,如果期间断线,便会失效;

  • application 作用域最大,直到服务器停止才会失效,所有页面共享。但使用时不宜定义太多,不然或造成服务器负担加重;

作用域由大到小:application> session> request> page

值得注意的是一个request可以包含多个page(include, forward, filter)

jsp 静态包含和动态包含的区别?

  1. 两者格式不同,静态包含:<%@ include file="文件.jsp" %>,而动态包含:<jsp :include page = "文件.jsp" />
  2. 包含时间不同,静态包含是先将几个文件合并,然后再被编译,缺点就是如果含有相同的 标签,会出错。动态包含是页面被请求时编译,将结果放在一个页面。
  3. 生成的文件不同,静态包含会生成一个包含页面名字的 servlet 和 class 文件;而动态包含会各自生成对应的 servlet 和 class 文件
  4. 传递参数不同,动态包含能够传递参数,并且它总是会检查所含文件的变化,而静态包含不能传参,不能检测文件变化

介绍在JSP 中如何使用JavaBeans

在JSP 中使用JavaBean 常用的动作有:

  1. < jsp:useBean />:用来创建和查找bean 对象;
  2. < jsp:setProperty />:用来设置bean 的属性,即调用其setXxx()方法;
  3. < jsp:getProperty />:用来获得bean 的属性,即调用其getXxx()方法。

JSP 和Servlet中的请求转发分别如何实现?

JSP 中的请求转发可利用forward 动作实现:<jsp:forward />;

Serlvet 中实现请求转发的方式为:getServletContext().getRequestDispatcher(path).forward(req,res)。

filter

Filter 的工作原理?

Filter 接口中有一个 doFilter 方法,当我们编写好 Filter,并配置对哪个 web 资源进行拦截后,WEB 服务器每次在调用 web 资源的 service 方法之前,都会先调用一下 filter 的 doFilter 方法,因此,在该方法内编写代码可达到如下目的:

  • 调用目标资源之前,让一段代码执行。

  • 是否调用目标资源(即是否让用户访问 web 资源)。

  • 调用目标资源之后,让一段代码执行。

web 服务器在调用 doFilter 方法时,会传递一个 filterChain 对象进来,filterChain 对象是filter 接口中最重要的一个对象,它也提供了一个doFilter 方法,开发人员可以根据需求决定是否调用此方法,调用该方法,则 web 服务器就会调用 web 资源的 service 方法,即 web 资源就会被访问,否则 web 资源不会被访问

Filter 链是什么?

在一个 web 应用中,可以开发编写多个 Filter,这些 Filter 组合起来称之为一个 Filter 链。web 服务器根据 Filter 在 web.xml 文件中的注册顺序,决定先调用哪个 Filter,当第一个 Filter 的 doFilter 方法被调用时,web 服务器会创建一个代表 Filter 链的 FilterChain 对象传递给该方法。在 doFilter方法中,开发人员如果调用了FilterChain 对象的doFilter 方法,则web 服务器会检查FilterChain对象中是否还有 filter,如果有,则调用第 2 个 filter, 如果没有,则调用目标资源。

写出熟悉的 JSTL 标签

< c:if >、< c:choose >、< c: when >、< c: otherwise >、< c:forEach >、< c:set >。

Listener

Servlet Filter Listener 启动顺序?

启动的顺序为 listener->Filter->servlet.

简单记为:理(Listener)发(Filter)师(servlet).

执行的顺序不会因为三个标签在配置文件中的先后顺序而改变。

监听器类型?

按监听的对象划分:servlet2.4 规范定义的事件有三种:

  1. 用于监听应用程序环境对象(ServletContext)的事件监听器

  2. 用于监听用户会话对象(HttpSession)的事件监听器

  3. 用于监听请求消息对象(ServletRequest)的事件监听器按监听的事件类项划分

    1. 用于监听域对象自身的创建和销毁的事件监听器
    2. 用于监听域对象中的属性的增加和删除的事件监听器
    3. 用于监听绑定到 HttpSession 域中的某个对象的状态的事件监听器

在一个 web 应用程序的整个运行周期内, web 容器会创建和销毁三个重要的对象,ServletContext,HttpSession,ServletRequest。

WebService

什么是webservice?

WebService是一种跨编程语言和跨操作系统平台的远程调用技术。

就是说服务端程序采用Java编写,客户端程序则可以采用其他编程语言编写,反之亦然!跨操作系统平台则是指服务端程序和客户端程序可以在不同的操作系统上运行。

所谓远程调用,就是一台计算机a上的一个程序可以调用到另外一台计算机b上的一个对象的方法。

什么是 webservice?

从表面上看,WebService 就是一个应用程序向外界暴露出一个能通过 Web 进行调用的 API, 也就是说能用编程的方法通过 Web 来调用这个应用程序。我们把调用这个 WebService 的应用程序叫做客户端,而把提供这个 WebService 的应用程序叫做服务端。从深层次看, WebService 是建立可互操作的分布式应用程序的新平台,是一个平台,是一套标准。它定义了应用程序如何在 Web 上实现互操作性,你可以用任何你喜欢的语言,在任何你喜欢的平台上写 Web service ,只要我们可以通过 Web service 标准对这些服务进行查询和访问。

webservice 协议

基于 WebService 的远程调用协议。

连接个数:多连接

连接方式:短连接

传输协议:HTTP

传输方式:同步传输

序列化:SOAP 文本序列化

适用场景:系统集成,跨语言调用

1、基于 CXF 的 frontend-simple 和 transports-http 实现。

2、CXF 是 Apache 开源的一个 RPC 框架:http://cxf.apache.org,由 Xfire 和 Celtix合并而来 。

webservice的组成

Webservice由WSDL,SOAP,UDDP组成。

WSDL是web service definition language的缩写,即web service的定义(描述)语言。一个WSDL文档的根元素是definitions元素,WSDL文档包含7个重要的元素:types, import, message, portType, operations, binding和service元素。

SOAP是simple object access protocal的缩写,即简单对象访问协议。 是基于XML和HTTP的一种通信协议。是webservice所使用的一种传输协议,webservice之所以能够做到跨语言和跨平台,主要是因为XML和HTTP都是独立于语言和平台的。

UDDI是Universal Description Discovery and Integration的缩写,即统一描述、发现和整合规范。用来注册和查找服务,把web services收集和存储起来,这样当别人访问这些信息的时候就从UDDI中查找,看有没有这个信息存在。

RESTful Webservice的优点

可以用任何编程语言编写,并且可以在每个框架上执行。语言和框架完全独立。

REST非常紧凑,并且由于带宽和资源消耗较少而可以快速查看。

该系统包括多种技术和数据格式,如明文,XML,JSON等。

这可以通过浏览器进行切实可行的检查,并且具有松散耦合的实现。

REST Webservice和SOAP Webservice之间有什么区别

REST提升了各种格式,如text,JSON和XML,而SOAP只支持XML。

REST仅通过HTTP(S)在传输层上运行,因为SOAP也可以在单独的传输层协议上使用。

REST使用资源进行操作,每个URL都是资源描述,其中SOAP与使用各种工作流创建特定业务逻辑的业务操作一起运行。

面向SOAP的读取无法归档,因为SOAP需要缓存可以归档面向REST的读取的位置。

SOAP提升了SSL和WS的安全性 - 安全性,而REST仅提升SSL安全性。

SOAP促进ACID(原子性,一致性,隔离性,耐久性); REST提升事务,但它不符合ACID,不能提供两个提交阶段。

SOAP1.1版本与SOAP1.2的区别

SOAP1.1存在SOAPAction的请求头。SOAP1.2没有SOAPAction的请求头

在CXF中两种协议请求的方式也不一样。

1.1为content-Type:text/xm;charset=UTF-8

1.2为content-Type:application/soap+xml;charset=UTF-8

Webservice的SEI指什么?

WebService EndPoint Interface(webservice终端[Server端]接口)就是 WebService服务器端用来处理请求的接口。

说说你知道的webservice框架,他们都有什么特点?

Webservice常用框架有JWS、Axis2、XFire以及CXF。

下面分别介绍一个这几种Web Service框架的基本概念

1、JWS是Java语言对WebService服务的一种实现,用来开发和发布服务。而从服务本身的角度来看JWS服务是没有语言界限的。但是Java语言为Java开发者提供便捷发布和调用WebService服务的一种途径。

2、Axis2是Apache下的一个重量级WebService框架,准确说它是一个Web Services / SOAP / WSDL 的引擎,是WebService框架的集大成者,它能不但能制作和发布WebService,而且可以生成Java和其他语言版WebService客户端和服务端代码。这是它的优势所在。但是,这也不可避免的导致了Axis2的复杂性,使用过的开发者都知道,它所依赖的包数量和大小都是很惊人的,打包部署发布都比较麻烦,不能很好的与现有应用整合为一体。但是如果你要开发Java之外别的语言客户端,Axis2提供的丰富工具将是你不二的选择。
3、XFire是一个高性能的WebService框架,在Java6之前,它的知名度甚至超过了Apache的Axis2,XFire的优点是开发方便,与现有的Web整合很好,可以融为一体,并且开发也很方便。但是对Java之外的语言,没有提供相关的代码工具。XFire后来被Apache收购了,原因是它太优秀了,收购后,随着Java6 JWS的兴起,开源的WebService引擎已经不再被看好,渐渐的都败落了。
4、CXF是Apache旗下一个重磅的SOA简易框架,它实现了ESB(企业服务总线)。CXF来自于XFire项目,经过改造后形成的,就像目前的Struts2来自WebWork一样。可以看出XFire的命运会和WebWork的命运一样,最终会淡出人们的视线。CXF不但是一个优秀的Web Services / SOAP / WSDL 引擎,也是一个不错的ESB总线,为SOA的实施提供了一种选择方案,当然他不是最好的,它仅仅实现了SOA架构的一部分。
注:对于Axis2与CXF之间的关系,一个是Axis2出现的时间较早,而CXF的追赶速度快。如何抉择:
1、如果应用程序需要多语言的支持,Axis2应当是首选了;
2、如果应用程序是遵循 spring哲学路线的话,Apache CXF是一种更好的选择,特别对嵌入式的Web Services来说;
3、如果应用程序没有新的特性需要的话,就仍是用原来项目所用的框架,比如 Axis1,XFire,Celtrix或BEA等等厂家自己的Web Services实现,就别劳民伤财了。

你的系统中是否有使用到webservice开发,具体是怎么实现的?

如果你觉得自己掌握的不够好,对自己不够自信的可以回答为“我的系统中没有使用到webservice的开发,但是我掌握webservice开发的概念和流程”,然后可以给他讲讲相关的概念,也就是上面的这些问题的回答,这样可以绕过这个问题,因为并不是所有的系统都会涉及到webservice的开发。

另一种回答即是先给他介绍一种webservice开发框架,比如CXF,然后告诉他你做的是服务端开发还是客户端开发,如果你说你做的事服务端开发,那么你就告诉他怎么定义的webservice,使用了哪些注解,怎么跟spring进行的整合,怎么发布的服务等等;如果你告诉他你做的事客户端的开发,那么你可以告诉他你怎么生成的本地代码,然后又怎么通过本地代码去调用的webservice服务。

Webservice有哪些优势?

Webservice的一些主要好处是:

互操作性:应用程序可以使用Webservice以任何语言与另一个应用程序进行交互。

可重用性:Webservice可能会暴露给其他应用程序。

模块化:我们可以使用Webservice为特定任务(例如税务计算)构建服务。

每个应用程序的标准协议:Webservice使用标准化协议使其可以理解为使用各种语言编译的客户应用程序。这种通常的程序有助于跨平台的实现。

更便宜的通信成本:Webservice确实使用SOAP over HTTP来允许任何人使用已经存在的用于Webservice的Internet。

posted @ 2022-04-02 09:46  coderwcb  阅读(62)  评论(0编辑  收藏  举报