Java开发面试题
-
- Java基础篇
-
- Java8大基本数据类型
- Java的三大特性
- 面向对象
- 如果让你推销一款Java产品,你会怎么推销呢?(java的特点)
- JVM与字节码
- JDK与JRE
- << 位运算符
- StringBuilder和StringBuffer的区别
- 简单介绍下多态、重载、重写
- 自动装箱和拆箱
- String能被继承吗?
- 简单介绍一下static关键字
- super()和this()
- equals和==
- 关于常量池
- 抽象类与接口
- Java中的比较器(Comparable、Comparator)
- Java中的栈与堆
- final、finally、finalize
- 数组和链表的区别
- 为什么提出集合框架
- 集合的概述以及底层数据结构
- 并发与并行
- sleep和wait的区别
- 线程的生命周期
- 什么是线程、进程
- 线程和进程的区别
- 图解进程线程
- 什么是线程安全、为什么提出线程安全、如何实现?
- Thread 类中的start() 和 run() 方法有什么区别?
- Java中notify 和 notifyAll有什么区别?
- 泛型是什么?为什么使用?
- 概述反射和序列化
- 序列化的好处
- 使用JDBC的过程
- 数据库篇
- 数据结构篇
- 计算机网络篇
- web篇
- 框架篇(这里只涉及SSM)
- 声明
Java基础篇
Java8大基本数据类型
byte | short | int | long | float | double | char | boolean | |
---|---|---|---|---|---|---|---|---|
占用空间 | 1字节(B) | 2字节 | 4字节 | 8字节 | 4字节 | 8字节 | 不定 默认2字节 | JVM未定义 |
初始值 | 0 | 0 | 0 | 0 | 0.0 | 0.0 | 空格 | false |
Java的三大特性
- 封装:隐藏内部功能的具体实现,只保留和外部交流数据的接口。例:汽车与发动机,不必知道发动机的实现原理,只需使用汽车给予的接口,插入钥匙。
- 继承:一个对象可以从它的父类继承所有的通用的属性和方法,并在无需重新编写原来的类的情况下对这些功能进行扩展;最大的好处是实现代码的高效重用。
- 多态:同一个动作作用于不同的对象 所产生不同的行为。例:人会吃饭,中国人用筷子,美国人用叉子。
面向对象
- 面向对象的核心,就是类和对象。Java中的面向对象的思想:万物皆对象。
- 类:是对一类事物的描述,是抽象的,看不见,摸不着。
- 对象:是实际存在的该类事物的每个个体 也称为实例 是具象的。
- 所以面向对象程序设计的重点是类的设计,而不是对象的设计。
- 类是对象的描述
对象叫做类的实例化(Instance)- 类不占内存,对象才占内存。
如果让你推销一款Java产品,你会怎么推销呢?(java的特点)
1.Java是面向对象的
2.Java是跨平台的;一次编译,到处运行
3.Java是多线程的
4.Java有GC,简化了开发
5.Java是分布式的
6.Java现在运用最广泛(有待商榷,python太猛了)
7.支持多线程( C++ 语言没有内置的多线程机制,因此必须调用操作系统的多线程功能来进行多线程程序设计,而 Java 语言却提供了多线程支持);
8.支持网络编程并且很方便( Java 语言诞生本身就是为简化网络编程设计的,因此 Java 语言不仅支持网络编程而且很方便);
9.编译与解释并存;
JVM与字节码
JVM:Java虚拟机(JVM)是运行 Java 字节码的虚拟机。
JVM有针对不同系统的特定实现,目的是使用相同的字节码,它们都会给出相同的结果(一次编译,到处运行)。
字节码:在 Java 中,JVM可以理解的代码就叫做字节码(即扩展名为 .class 的文件),它不面向任何特定的处理器,只面向虚拟机。Java 语言通过字节码的方式,一定程度上解决了传统解释型语言执行效率低的问题,同时又保留了解释型语言可移植的特点。所以 Java 程序运行时比较高效,而且,由于字节码并不针对一种特定的机器,因此,Java程序无须重新编译便可在多种不同操作系统的计算机上运行。
JDK与JRE
JDK是Java Development Kit,它是功能齐全的Java SDK。它拥有JRE所拥有的一切,还有编译器(javac)和工具(如javadoc和jdb)。它能够创建和编译程序。
JRE 是 Java运行时环境。它是运行已编译 Java 程序所需的所有内容的集合,包括 Java虚拟机(JVM),Java类库,java命令和其他的一些基础构件。但是,它不能用于创建新程序。
<< 位运算符
// 在hashmap源码中 默认的容量和最大容量 它采用了位运算符
static final int DEFAULT_INITIAL_CAPACITY = 1 << 4; // 其实就是16
static final int MAXIMUM_CAPACITY = 1 << 30;
static final float DEFAULT_LOAD_FACTOR = 0.75f;
// 位运算符 相当于二进制中 数值左移4位 00001 --> 10000
StringBuilder和StringBuffer的区别
1. 他们都是可变长度的字符串
2. StringBuffer 线程安全 效率低
3. StringBuilder 线程不安全 效率高
简单介绍下多态、重载、重写
多态:同一种事物的多种形态。
作用:1.不必为每一个派生类编写功能调用,只需要对抽象基类进行处理即可,提高可复用性;
2.派生类的功能可以被基类的方法或引用变量所调用,提高可扩展性。
1. 编译时多态 方法重载overload
- 方法名必须相同
- 形参列表必须不同(形参的数据类型和形参的个数不同)
- 与返回值类型无关
2. 运行时多态 方法重写overwrite
- 必须存在继承关系
- 重写的方法、返回值类型、参数列表必须和父类的方法保持一致
- 子类的访问修饰符不能低于父类方法的访问修饰符 public
自动装箱和拆箱
装箱:将基本类型用它们对应的引用类型包装起来;
拆箱:将包装类型转换为基本数据类型;
String能被继承吗?
public final class String implements java.io.Serializable, Comparable<String>, CharSequence
不能,他是被final修饰的。
底层是由数组实现,数组长度不可变
简单介绍一下static关键字
static标记的变量或方法由整个类(所有实例)共享,可不必创建该类对象而直接使用;
static成员也称类成员或静态成员;
随着类的加载而加载;
Java中无静态类。
1. 修饰属性
无论创建多少次对象,都会去共享一个静态属性,存在静态域中和类同一级别
2. 修饰方法
也是存在静态域中,可以使用类名.方法名去访问。
静态方法只能访问静态成员,如果是非静态的,应该通过实例化对象的方式
静态方法不能以任何方式引用this关键字
super()和this()
this:1.当成员变量和局部变量重名,用关键字this来区分
2.this代表当前对象,this就是所存函数所属对象的引用(哪个对象调用了this所在的函数,this就代表谁)
3.this(参数列表),调用本类中重载的构造方法,必须放在第一行。
super:1.使用super调用父类的成员方法和属性
2.可以从子类构造方法中调用父类的构造方法,必须放在第一行。
equals和==
==:基本类型比较的是值的大小
引用类型比较的是内存地址
equals:默认比较是否是同一个对象
例如String、Date等类对equals方法进行了重写的话,比较的是所指向的对象的内容
注意:equals方法不能作用于基本数据类型的变量
// 举例如下
public class test1 {
public static void main(String[] args) {
String a = new String("ab"); // a 为一个引用
String b = new String("ab"); // b为另一个引用,对象的内容一样
String aa = "ab"; // 放在常量池中
String bb = "ab"; // 从常量池中查找
if (aa == bb) // true
System.out.println("aa==bb");
if (a == b) // false,非同一对象
System.out.println("a==b");
if (a.equals(b)) // true
System.out.println("aEQb");
if (42 == 42.0) {
// true
System.out.println("true");
}
}
}
关于常量池
当创建 String 类型的对象时,JVM先会在常量池中查找是否已经存在,如果已存在,就把它赋给当前引用。如果没有,就在常量池中重新创建一个 String 对象。
String a = "xx"; String b ="xx"; String c = "xxx"; System.out.println(a==b); //true jvm现在常量池中创建了"xx",a指向"xx", 创建b时,先会看常量池中是否有"xx",如果有 让b 指向"xx";如果没有 则新建一个。 System.out.println(a==c); // false
抽象类与接口
抽象类:1.首先有构造方法
2.含有抽象方法的类必须被声明为抽象类
3.抽象类不能被实例化,子类必须重写父类的抽象方法
4.abstract不能修饰属性、构造器、private、static、final
5.一般类中不能定义抽象方法;抽象类中可以有抽象方法,也可以有非抽象方法;
6.抽象方法只有方法声明,没有方法实现。
接口:1.特殊的抽象类;
2.接口中包含的方法都是抽象方法,没有方法体;
3.实现接口的类必须实现接口的全部方法。
4.属性:private static final ; 方法:public abstract
区别:1.抽象类有构造器;接口没有
2.关键字不同
3.抽象类可以有非抽象方法;接口只能由抽象方法;
4.抽象类可以定义static方法;接口不行
Java中的比较器(Comparable、Comparator)
- 这两个都是接口。
内部比较器:Comparable
外部比较器:Comparator- 排序规则实现的方法不同
Comparable接口的方法:compareTo(Object o)
Comparator接口的方法:compare(T o1, To2)- Comparable接口用于在类的设计中使用;设计初期,就实现这个借口,指定排序方式。
Comparator接口用于类设计已经完成,根据需求新建排序类实现排序。
// 代码演示
public class Stu implements Comparable{
// 实体类实现内比较器接口
private String name;
private int age;
public Stu(String name, int age) {
super();
this.name = name;
this.age = age;
}
// get set方法已经省略
@Override
public String toString() {
return "Stu [name=" + name + ", age=" + age + "]";
}
@Override
public int compareTo(Object o) {
if (o instanceof Stu) {
Stu s = (Stu) o;
if (this.age > s.age) {
return 1;
} else if (this.age == s.age) {
return 0;
} else {
return -1;
}
}
return 0;
}
}
// 外比较器:重新定义排序类实现外比较器
public class CompareClass implements Comparator<Stu>{
@Override
public int compare(Stu s1, Stu s2) {
return s1.getAge() - s2.getAge();
}
}
// main
public class TestMain {
public static void main(String[] args) {
Stu s1 = new Stu("xzy", 23);
Stu s2 = new Stu("jay", 40);
Stu[] list = new Stu[2];
list[0]=s1;
list[1]=s2;
Arrays.sort(list);// 通过内比较器排序
Arrays.sort(list, new CompareClass());// 通过外比较器 自定义的排序类 CompareClass 排序
System.out.println(Arrays.toString(list));
}
}
Java中的栈与堆
一、Java中的变量在内存中的分配
1.类变量(static):在程序加载时系统就为他在堆中开辟了内存,堆中的内存地址存放在栈中,以便于高速访问
静态变量的周期持续到系统关闭(静态域)。
2.实例变量:当使用new时,使在堆中开辟相应的内存空间。当实例变量的引用丢失后,将被GC列入可回收名单。
3.局部变量:当执行到他的时候,在栈中开辟内存,当局部变量一旦脱离作用域,内存立即释放。
二、堆内存用来存放由new创建的对象和数组,由GC来管理,然后在栈中定义一个特殊的变量,让栈中的这个变量的取值等于数组或对象在堆内存中的首地址,
栈中这个变量就成了数组或对象的引用变量。
三、总结:基本数据类型,局部变量都是存放在栈内存中,用完就消失,没有默认初始化值。
new 创建的实例化对象及数组,是放在堆内存中的,用完之后靠GC不定期自动消除;
堆内存中所有实体都有内存地址值,有默认初始化值;实体不再被指向时,GC自动清除。
局部变量:存储在栈中,必须显示的赋值;
成员变量:存储在堆中,有默认初始值。
final、finally、finalize
final:
1.修饰变量:被声明为final的变量必须在声明时给出变量的初始值,而在以后的引用中只能读取。
2.final声明方法:方法不能被重写
3.修饰类:不能被继承
finally:在异常处理中作为一个必定会执行的语句块。
finalize:java技术允许使用finalize方法在垃圾收集器将对象从内存中清除出去之前做必要的清理工作
数组和链表的区别
1.存储位置上:
数组逻辑上相邻的元素在物理存储位置上也相邻,而链表不一定;
2.存储空间上:
数组是连续的一段内存空间;链表存放的内存空间可以是连续的,也可以不连续的
3.长度可变性:
数组长度一旦声明不可变,链表的长度是按照实际需求进行分配的
数组的优点:随机访问性强;查找速度快;
为什么提出集合框架
数组的优点:1.长度不可变;2.存放对象的个数不确定
数组的缺陷:1.插入和删除效率低;2.可能浪费内存;3.必须有足够的内存空间;4.数组大小固定
链表的优点:1.插入删除速度快;2.内存利用率高;3.可扩展
链表的缺点:1.不能随机查找,必须从第一个开始遍历,查找效率低
集合的概述以及底层数据结构
- Collection接口
- List 有序的 可重复的
- ArrayList:Object数组
- LinkedList:双向链表(JDK1.6之前为循环链表,JDK1.7取消了循环)
- Vector:Object数组
- Set 存储无序的 不可重复的
- HashSet: 基于 HashMap 实现的,底层采用 HashMap 来保存元素
- LinkedHashSet:基于LinkedHashMap 实现
- TreeSet: 红黑树(自平衡的排序二叉树)
- List 有序的 可重复的
- Map 接口 key-value键值对
- HashMap:JDK8之前HashMap由数组+链表组成的,数组是HashMap的主体,链表则是主要为了解决哈希冲突而存在的(“拉链法”解决冲突)。JDK8以后在解决哈希冲突时有了较大的变化,当链表长度大于阈值(默认为8)时,将链表转化为红黑树,以减少搜索时间
- LinkedHashMap: 继承自 HashMap,所以它的底层仍然是基于拉链式散列结构即由数组和链表或红黑树组成。另外,LinkedHashMap 在上面结构的基础上,增加了一条双向链表,使得上面的结构可以保持键值对的插入顺序。同时通过对链表进行相应的操作,实现了访问顺序相关逻辑
- TreeMap:红黑树(自平衡的排序二叉树)
- Hashtable: 数组+链表组成的,数组是 HashMap 的主体,链表则是主要为了解决哈希冲突而存在的
并发与并行
并发:是指同一个时间段内多个任务同时都在执行,并且都没有执行结束。并发任务强调在一个时间段内同时执行,而一个时间段由多个单位时间累积而成,所以说并发的多个任务在单位时间内不一定同时在执行 。
并行:是说在单位时间内多个任务同时在执行 。
在多线程编程实践中,线程的个数往往多于CPU的个数,所以一般都称多线程并发编程而不是多线程并行编程。
sleep和wait的区别
sleep() 方法是线程类(Thread)的静态方法,让调用线程进入睡眠状态,让出执行机会给其他线程,
等到休眠时间结束后,线程进入就绪状态和其他线程一起竞争cpu的执行时间。
因为sleep() 是static静态的方法,他不能改变对象的机锁,当一个synchronized块中调用了sleep() 方法,
线程虽然进入休眠,但是对象的机锁没有被释放,其他线程依然无法访问这个对象。
wait()是Object类的方法,当一个线程执行到wait方法时,它就进入到一个和该对象相关的等待池,同时释放对象的机锁,
使得其他线程能够访问,可以通过notify,notifyAll方法来唤醒等待的线程
线程的生命周期
新建
就绪
运行
阻塞
死亡
什么是线程、进程
进程:是程序的一次执行,是具有一定独立功能的程序关于某个数据集合上的一次运动活动,是操作系统资源分配和调度的最小单位。
线程:是操作系统能够进行运算调度的最小单位,它包含在进程之中,是进程中实际运作单位。
两者关系:进程是指程序执行时的一个实例,线程是进程的一个实体;
线程必定也只数据一个进程,而进程可以拥有多个线程而且至少拥有一个线程。
线程和进程的区别
进程:
- 拥有独立的堆栈空间和数据段,系统开销大
- 由于进程之间是独立的特点 使得进程的安全性比较高 有独立的地址空间 一个进程崩溃 不影响其他进程
- 进程的通信机制相对复杂 譬如管道、信号、消息队列、套接字等
线程:
- 线程拥有独立的堆栈空间 但是共享数据段,它们彼此之间使用相同的地址空间,比进程开销小
- 线程是一个进程中不同的执行路径 一个线程的死亡就等于整个进程的死亡。
- 通信相对方便
图解进程线程
图解进程线程
从上图可以看出:一个进程中可以有多个线程,多个线程共享进程的堆和方法区 (JDK1.8 之后的元空间)资源,但是每个线程有自己的程序计数器、虚拟机栈 和 本地方法栈。
什么是线程安全、为什么提出线程安全、如何实现?
当一个线程在操作共享资源时,未执行完毕的情况下,其他线程参与进来,导致共享资源出现安全问题。
方式一:同步代码块
synchronized(同步监视器){
同步的代码
}
同步监视器:可以由任何对象来承担,针对于实现的方式可以用对象,也可以采用this关键字。对于继承方式 只能采用静态的对象。
方式二:同步方法
确保当中一个线程执行此方法时 其他线程等待知道当前线程执行完。
Thread 类中的start() 和 run() 方法有什么区别?
start()方法被用来启动新创建的线程,而且start()内部调用了run()方法,这和直接调用run()方法的效果不一样。
当你调用run()方法的时候,只会是在原来的线程中调用,没有新的线程启动;start()方法才会启动新线程。
Java中notify 和 notifyAll有什么区别?
notify()方法不能唤醒某个具体的线程,所以只有一个线程在等待的时候它才有用武之地。
而notifyAll()唤醒所有线程并允许他们争夺锁确保了至少有一个线程能继续运行。
泛型是什么?为什么使用?
简单的说一种标签,不确定的类型,用户使用的时候确定类型,是JDK1.5出现的新特性,用于解决安全问题,是一种类型安全机制。
好处:
-将运行时期会可能出现的异常转移到编译期
-提高了安全性
-避免了强制类型转换的麻烦。
概述反射和序列化
反射:
JAVA反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;
对于任意一个对象,都能够调用它的任意方法和属性;这种动态获取信息以及动态调用对象方法的功能称为java语言的反射机制。
序列化:
序列化可以理解成把对象转换为容易传输的格式的过程。
序列化的好处
方便保存对象。因为对象不能保存,所以可以序列化,将其保存。
使用JDBC的过程
1.加载JDBC驱动程序
Class.forName("com.mysql.jdbc.Driver") ;
2.提供JDBC连接的URL
jdbc:mysql: //localhost:3306/test?useUnicode=true&characterEncoding=utf-8 ;
3.创建数据库的连接
Connection con = DriverManager.getConnection(url , username , password )
4.实现PreparedStatement
PreparedStatement pstmt = con.prepareStatement(sql) ;
5.执行SQL语句
6.处理结果
-返回结果集
-影响的记录数
7.关闭JDBC对象
数据库篇
数据库的基本操作
可以参考我的另一篇博客 常用的SQL语句及进阶
MySql底层采用什么数据结构来存储数据?
B-树、平衡树
分页所用的关键字
MySQL:
MySQL中使用 LIMIT
select * from students limit 0, 10 从第0条开始查,一共查询10条记录。
Oracle:
Oracle中使用 ROWNUM
select * from students where rownum >= 1 and rownum <= 10
SQL实现数据表的复制
select into from 和 insert into select都是用来复制表.
两者的主要区别为:
select into from 要求目标表不存在,因为在插入时会自动创建
insert into select from 要求目标表存在
两者的语法:
SELECT vale1, value2 into Table2 from Table1
Insert into Table2(field1,field2,...) select value1,value2,... from Table1
什么是事务
事务(Transaction)是并发控制的基本单位。所谓事务,它是一个操作序列,这些操作要么都执行,要么都不执行,它是一个不可分割的工作单位。
事务的四大特性
-原子性(Atomicity):事务作为一个整体被执行,包含在其中的对数据库的操作要么全部被执行,要么都不执行
-一致性(Consistency):事务应确保数据库的状态从一个一致状态转变为另一个一致状态。
-隔离性(Isolation):多个事务并发执行时,一个事务的执行不应影响其他事务的执行
-持久性(Durability):已被提交的事务对数据库的修改应该永久保存在数据库中
什么是存储过程
存储过程可以说是一个记录集吧,也可以认为是一个方法,它是由一些SQL语句组成的代码块,
这些SQL语句代码像一个方法一样实现一些功能(对单表或多表的增删改查),然后再给这个代码块取一个名字,在用到这个功能的时候调用他就行了。
简单介绍一下触发器
触发器是由 INSERT、UPDATE 和 DELETE 等事件来触发某种特定操作。
满足触发器的触发条件时,数据库系统就会执行触发器中定义的程序语句。这样做可以保证某些操作之间的一致性。
例如,在执行完一句插入语句时,触发查询所有,保证信息的完整性。
什么是E-R图
ER图中包含了实体(即数据对象)、关系和属性3种基本成分;
通常用矩形框代表实体,用连接相关实体的菱形框表示关系,用椭圆形或圆角矩形表示实体(或关系)的属性,并用直线把实体(或关系)与其属性连接起来。
三种联系:
- 1:1 例如,一个部门有一个经理,而每个经理只在一个部门任职,则部门与经理的联系是一对一的
- 1:N 例如,某校教师与课程之间存在一对多的联系“教”,即每位教师可以教多门课程,但是每门课程只能由一位教师来教。
- M:N 例如,学生与课程间的联系(“学”)是多对多的,即一个学生可以学多门课程,而每门课程可以有多个学生来学。
什么是外连接、内连接?
内连接:根据连接条件只保留两个表中有对应数据的记录;
外连接:当一个表中记录在另一个表中没有对应记录时,会生成一条与 NULL 值对应的记录
什么是索引?有什么用?
索引相当于目录,可以更加方便的用于查询。
范式
- 第一范式
- 第一范式(1NF)要求数据库表的每一列都是不可分割的基本数据项,同一列中不能有多个值。
- 若某一列有多个值,可以将该列单独拆分成一个实体,新实体和原实体间是一对多的关系。
- 在任何一个关系数据库中,第一范式(1NF)是对关系模式的基本要求,不满足第一范式(1NF)的数据库就不是关系数据库。
- 第二范式
- 满足第二范式(2NF)必须先满足第一范式(1NF)
- 第二范式要求实体中没一行的所有非主属性都必须完全依赖于主键;即:非主属性必须完全依赖于主键。
- 完全依赖:主键可能由多个属性构成,完全依赖要求不允许存在非主属性依赖于主键中的某一部分属性。若存在哪个非主属性依赖于主键中的一部分属性,那么要将发生部分依赖的这一组属性单独新建一个实体,并且在旧实体中用外键与新实体关联,并且新实体与旧实体间是一对多的关系。
- 第三范式
- 满足第三范式(3NF)必须先满足第二范式。
- 第三范式要求:实体中的属性不能是其他实体中的非主属性。因为这样会出现冗余。即:属性不依赖于其他非主属性。
- 如果一个实体中出现其他实体的非主属性,可以将这两个实体用外键关联,而不是将另一张表的非主属性直接写在当前表中。
数据结构篇
快速排序
冒泡排序
假设有一些数字: 10, 20 ,90 , 5, 18, 33, 46, 66
冒泡排序的规则:依次拿取每个数字进行比较,小的放前面,大的放后面(看需求)。
第一次: 10 , 20 拿前两个数字进行比较 小的放前面。
第二次: 10 , 20 , 90 拿 90 依次与 10 ,20 比较,大就放后面。
第三次: 5, 10 , 20 , 90 5 比 10小 所以放最前。
第四次: 5, 10 , 18 , 20 , 90
...
最终结果: 5 , 10 , 18 , 20, 33 ,46 ,66 ,90
//冒泡排序 外层循环 N-1 内层循环 N-1-i
for(int i=0; i<arr.length-1;i++){
for(int j=0; j<arr.length-1-i;j++){
if(arr[j] > arr[j+1]){
int t=arg[j];
arr[j]=arr[j+1];
arr[j+1]=t;
}
}
}
二分查找
二叉树的遍历
有三种遍历方式:前序、中序、后序
具体遍历过程可以参考博客
什么是红黑树
计算机网络篇
TCP和UDP
TCP:面向有连接的,三次握手机制;传输的数据大小无限制;安全可靠协议;效率低,区分客户端和服务器
UDP:是面向无连接的,发送的数据是通过数据报包的形式,不超过64k;不安全(可靠)协议,效率高;不区分客户端和服务器。(叫发送端和接收端)
三次握手 四次挥手
三次握手
1.进行三次握手,首先向服务器发送一个syn报文,其中syn=1,seq number=1022(随机);
2.服务器接收到syn报文,根据syn=1判断客户端请求建立连接,并返回一个syn报文,为第一次握手,
其中ack number=1023(客户端seq number+1),seq number=2032(随机),syn=1,ack=1;
3.客户端根据服务器的syn报文,确认其ack number是否与上一次发送的seq number+1相等,且ack=1,确认正确,则回应一个ack报文,为第二次握手,
即ack number=2033(服务器seq number+1),ack=1;
4.服务器根据接收到的ack报文,确认ack number是否与上一次发送的seq number+1相等,并且ack=1,确认正确,则建立连接,
进入Established状态,为第三次握手。
网络的七层协议
OSI中的层 | 功能 | TCP/IP协议族 |
---|---|---|
应用层 | 文件传输、电子邮件、文件服务等 | TFTP、HTTP、FTP、SMTP、DNS、Telnet、SNMP |
表示层 | 数据格式化、代码转换、数据加密 | 无 |
会话层 | 解除或建立与别的结点的联系 | 无 |
传输层 | 提供端对端的接口 | TCP、UDP |
网络层 | 为数据包选择路由 | IP、ICMP、OSPF、BGP、ARP、RARP |
数据链路层 | 传输有地址的帧以及错误检测功能 | SLIP、CSLIP、PPP、MTU、ARP、RARP |
物理层 | 以二进制数据形式在屋里媒体上传输数据 | ISO2110、IEEE802、IEEE802.2 |
当在浏览器输入栏按下回车会发生什么
1.回车键按下后,浏览器会对输入的地址数据进行解析
2.进行DNS(域名服务器 UDP的)递归查询
3.使用套接字进行数据访问
4.建立TCP连接(三次握手)
5.浏览器处理数据
邮件服务器之间传送邮件通常使用什么协议,它们分别使用哪个端口,简述其功能。
邮件服务器之间常用邮件协议 SMTP POP3 IMAP。
> SMTP:的一个重要特点是它能够在传送中接力传送邮件,即邮件可以通过不同网络上的主机接力式传送。工作在两种情况下:一是电子邮件从客户机传输到服务器;二是从某一个服务器传输到另一个服务器。SMTP是个请求/响应协议,它监听25号端口,用于接收用户的Mail请求,并与远端Mail服务器建立SMTP连接。
> POP3:仍采用Client/Server工作模式,当客户机需要服务时,客户端的软件将与POP3服务器建立TCP连接,此后要经过POP3协议的三种工作状态,首先是认证过程,确认客户机提供的用户名和密码,在认证通过后便转入处理状态,在此状态下用户可收取自己的邮件或做邮件的删除,在完成响应的操作后客户机便发出quit命令,此后便进入更新状态,将做删除标记的邮件从服务器端删除掉,到此为止整个POP过程完成。
> IMAP:主要提供的是通过Internet获取信息的一种协议。IMAP像POP那样提供了方便的邮件下载服务,让用户能进行离线阅读,但IMAP能完成的却远远不只这些。IMAP提供的摘要浏览功能可以让你在阅读完所有的邮件到达时间、主题、发件人、大小等信息后才作出是否下载的决定
web篇
表单中get和post区别
get:
1.不能传递敏感数据
2.不能传递大量的数据,每次只能传递1024B
3.不能上传附件
post:
1.相对安全
2.可以上传海量数据
3.可以上传附件
什么是Ajax,好处是什么
通过在后台与服务器进行少量数据交换,AJAX 可以使网页实现异步更新。
这意味着可以在不重新加载整个网页的情况下,对网页的某部分进行更新。
九大内置对象
PrintWriter out 输出服务器响应的输出流对象;
Object page JSP页面本身;
PageContext pageContext 通过该对象可以获取其他对象;
HttpServletRequest request 封装客户端的请求,其中包含来自GET或POST请求的参数;
HttpServletResponse response 封装服务器对客户端的响应;
HttpSession session 封装用户会话的对象;
ServletContext application 封装服务器运行环境的对象--全局变量;
Exception exception 封装页面抛出异常的对象;
ServletConfig config Web应用的配置对象。
转发(Forward)和重定向(Redirect)的区别
转发是服务器行为,重定向是客户端行为。
转发(Forward) 通过RequestDispatcher对象的forward(HttpServletRequest request,HttpServletResponse response)方法实现的。RequestDispatcher可以通过HttpServletRequest 的getRequestDispatcher()方法获得。例如下面的代码就是跳转到success.jsp页面。request.getRequestDispatcher("success.jsp").forward(request, response);
重定向(Redirect) 是利用服务器返回的状态码来实现的。客户端浏览器请求服务器的时候,服务器会返回一个状态码。服务器通过 HttpServletResponse 的 setStatus(int status) 方法设置状态码。如果服务器返回301或者302,则浏览器会到新的网址重新请求该资源。
从地址栏显示来说
forward是服务器请求资源,服务器直接访问目标地址的URL,把URL的响应内容读取过来,然后把这些内容再发给浏览器.浏览器不知道服务器发送的内容从哪里来的,所以地址栏还是原来的地址.
redirect是服务端根据逻辑,发送一个状态码,告诉浏览器重新去请求那个地址.所以地址栏显示的是新的URL.
从数据共享来说
forward:转发页面和转发到的页面可以共享request里面的数据.
redirect:不能共享数据.
从运用地方来说
forward:一般用于用户登陆的时候,根据角色转发到相应的模块.
redirect:一般用于用户注销登陆时返回主页面和跳转到其它的网站等
从效率来说
forward:高.
redirect:低.
cookie和session
cookie:浏览器A访问服务器的时候,服务器就给这个A一个id,浏览器会将这个id 保存到本地 cookie中;由web服务器在http响应头中附带给浏览器;一旦浏览器保存了cookie 每次访问web服务器时,都会在http请求头中将cookie 回传给web服务器
session:采用的是在服务端保持Http状态信息的方案(保存在服务端);当服务端需要为某个客户端的请求创建一个session时,服务器首先检查这个客户端的请求里是否包含了一个session标识(即JSESSIONID);在服务端的session对象的内容,可以访问到,这些变量信息是存在服务器的中的。
你了解监听器吗?
监听器是一个专门用于对其他对象身上发生的事件或状态改变进行监听和相应处理的对象,当被监视的对象发生情况时,立即采取相应的行动。
java的事件监听机制
1、事件监听涉及到三个组件:事件源、事件对象、事件监听器。
2、当事件源上发生某一个动作时,它会调用事件监听器的一个方法,并在调用该方法时把事件对象传递进去,
开发人员在监听器中通过事件对象,就可以拿到事件源,从而对事件源进行操作。
框架篇(这里只涉及SSM)
什么是ORM
对象关系映射(Object Relational Mapping)模式是一种为了解决面向对象与关系数据库存在的互不匹配的技术 ;
简单的说, ORM是通过使用描述对象和数据库之间的映射的元数据,将程序中的对象自动持久化到关系数据库中
MyBatis默认用什么做日志管理
log4j
MyBatis动态代理
开发者只需声明mapper接口(类似dao接口),无需声明实现类 而由mybatis框架通过创建接口的代理对象,就和实现类类似。需要按照一定的规范来开发接口和映射文件。
动态代理规则:
1.映射文件mapper.xml的名称要和接口的名称一致
2.映射文件的namespace是 接口的全路径
3.映射文件的sql statement的id是 接口的方法名称
4.映射文件的输入参数类型(parameterType)和接口方法的参数类型一致
5.映射文件的输出结果类型(resultType)和接口方法的返回类型一致
MyBatis输入输出类型
输入输出支持类型:
输入:parameterType 支持的类型: java简单类型 、 hashmap 、 自定义pojo对象
输出1:resultType: 支持的类型: java简单类型 、 hashmap 、 自定义pojo对象
注意:封装到自定义pojo对象的要求:对象的属性名和数据库表的字段名一一对应的!!!
输出2: resultMap:
1.可以解决对象属性名和数据库字段名不一致的问题
2.还可以做一对一 和 一对多
resultMap的使用
<resultMap type="order" id="orderResultMap">
<!-- 定义主键 ,非常重要。如果是多个字段,则定义多个id -->
<!-- property:主键在pojo中的属性名 -->
<!-- column:主键在数据库中的列名 -->
<id property="id" column="id" />
<!-- 定义普通属性 -->
<result property="userId" column="user_id" />
<result property="number" column="number" />
</resultMap>
为什么使用Druid(德鲁伊),不使用c3p0
史上最好的data source,有一个监控面板
- 可以监控每条sql语句的使用次数、运行效率,
- url的监控,请求时间、并发等,
- 也能监控session
简单介绍Spring
spring是一个轻量级的控制反转和面向切面编程的容器框架
1.轻量级:spring大小和开销都是轻量级的
2.非入侵:一般在程序开发中,不需要引入spring包
3.控制反转(IOC):把对象的创建权力交给容器
4.面向切面编程(AOP):基于代理的 可以将核心业务和系统服务分开
Spring的两大特性
1.控制反转 : 把对象的创建、销毁的权利交给容器框架,由容器来管理对象的生命周期;
ioc不是新的技术 只是一种思想或理念。可以实现松耦合!
ioc包括依赖注入(DI,核心) 和 依赖查找;
DI:依赖注入 就是在spring实例化对象的时候,由容器来设置这些对象的属性值。
2.面向切面编程:采用横向抽取机制,把分散在各个方法中的相同的代码抽取出来,
然后再编译期或者是运行时再把这些代码应用到所需要执行的地方。
通知(Advice):aop在切点上执行的增强处理。
切点(Pointcut):就是带有通知的连接点。
切面(Aspect):通常上就是一个类,里面定义了 通知和切点。
AOP=通知+切点
什么是MVC
MVC全名是Model View Controller,是模型(model)-视图(view)-控制器(controller)的缩写.
Model(模型)是应用程序中用于处理应用程序数据逻辑的部分。通常模型对象负责在数据库中存取数据。
View(视图)是应用程序中处理数据显示的部分。通常视图是依据模型数据创建的。
Controller(控制器)是应用程序中处理用户交互的部分。通常控制器负责从视图读取数据,控制用户输入,并向模型发送数据。
SpringMVC的工作流程
客户端发送url到 前端控制器 DispatcherServlet
前端控制器把请求url发送给 处理器映射器 HandlerMapping
处理器映射器 根据请求的url来查找 处理器 Handler,并返回给 前端控制器
前端控制器 调用 处理器适配器 去执行 处理器,传递需要执行的处理器信息
处理器适配器 执行 处理器
处理器 返回一个 ModelAndView 对象
适配器返回ModelAndView给 前端控制器
前端控制器 调用 视图解析器 去解析视图
视图解析器 把逻辑视图解析为真正的视图并且返回给 前端控制器
前端控制器 对视图进行数据渲染、构建DOM树
把页面返回给客户端。
声明
以上试题均为原题或改编,来自各个企业校招笔试面试(不包含BATJ等大厂),仅供参考学习,落笔不易,多多点赞。
不知不觉 也已经写了一年了,再次感谢大家的阅读 THANKS XD?
欢迎大家关注我的公众号【再喝最后一杯珍珠奶茶】,了解更多资讯。
转载:https://blog.csdn.net/qq_37162090/article/details/83066903