1. JDK 和 JRE 有什么区别?
-
JDK:Java Development Kit 的简称,java 开发工具包,提供了 java 的开发环境和运行环境。
-
JRE:Java Runtime Environment 的简称,java 运行环境,为 java 的运行提供了所需环境。
1.1 public private protected default 的作用域
public:具有最大访问权限。 可以被同一项目下的任何类所调用,一般用于对外的情况。
protected:与public不同的是不同包下的类是不能使用的,但是其子孙类除外。所以我认为这是特意为子类设计的。
default:它是针对本包设计的,它所修饰的在本包下的其他类都访问。
private:只为类本身提供。是一种封装的体现。
2. == 和 equals 的区别是什么?
== 对于基本类型来说是值比较,对于引用类型来说是比较的是引用;而 equals 默认情况下是引用比较,只是很多类重新了 equals 方法,比如 String、Integer 等把它变成了值比较,所以一般情况下 equals 比较的是值是否相等。
2.1 两个对象的 hashCode()相同,则 equals()也一定为 true,对吗?
不对,两个对象的 hashCode()相同,equals()不一定 true。
2.2创建对象的4中方法:
1、new 关键字直接创建:
Student s=new Student();
2、class的反射调用(使用class的newInstanse方法可以调用无参构造器创建对象):
class.forName();
3、使用clone()来创建:
try{
Student stu3 = (Student) stu1.clone();
System.out.println(stu3);
}
catch (CloneNotSupportedException e)
{
e.printStackTrace();
}
4、使用序列化(实现Serializable接口)
public class Student implements Serializable{ }
3.1int和Integer的区别
1、Integer是int的包装类,int则是java的一种基本数据类型
2、Integer变量必须实例化后才能使用,而int变量不需要
3、Integer实际是对象的引用,当new一个Integer时,实际上是生成一个指针指向此对象;而int则是直接存储数据值
4、Integer的默认值是null,int的默认值是0
3.2.值传递和引用传递有何区别
值传递:传递对象一个副本值,即使副本改了,源对象是不会改变的
引用传递:传递的不是实际对象,而是对象的引用
4. final 在 java 中有什么作用?
-
final 修饰的类叫最终类,该类不能被继承。
-
final 修饰的方法不能被重写。
-
final 修饰的变量叫常量,常量必须初始化,初始化之后值就不能被修改。
5. java 中的 Math.round(-1.5) 等于多少?
等于 -1,因为在数轴上取值时,中间值(0.5)向右取整,所以正 0.5 是往上取整,负 0.5 是直接舍弃。
6. String 属于基础的数据类型吗?
String 不属于基础类型,基础类型有 8 种:byte、boolean、char、short、int、float、long、double,而 String 属于对象。
7. java 中操作字符串都有哪些类?
操作字符串的类有:String、StringBuffer、StringBuilder。
区别和相同:
StirngBuffer和SringBuilde的对象想要输出时,需要调用toString()方法。因为这个两个SB实例化的类都没法直接输出
用append()给字符串后添加字符串
String适用于少量的字符串操作的情况
StringBuilder适用于单线程下在字符缓冲区进行大量操作的情况
StringBuffer适用多线程下在字符缓冲区进行大量操作的情况
StringBuffer和StringBuilder需要使用toString方法才能输出对象
性能和速度: StringBuilder > StringBuffer > String
线程不安全/安全的类
1、 不安全:
StringBuilder、HashMap、ArrayList、LinkedList
2、安全:
StringBuffer 、HashTable、Vector、stack(栈先进后出)
8. String 类的常用方法都有那些?
-
indexOf():返回指定字符的索引。
-
charAt():返回指定索引处的字符。
-
replace():字符串替换。
-
trim():去除字符串两端空白。
-
split():分割字符串,返回一个分割后的字符串数组。
-
getBytes():返回字符串的 byte 类型数组。
-
length():返回字符串长度。
-
toLowerCase():将字符串转成小写字母。
-
toUpperCase():将字符串转成大写字符。
-
substring():截取字符串。
-
equals():字符串比较。
9. 普通类和抽象类有哪些区别?
-
普通类不能包含抽象方法,抽象类可以包含抽象方法。
-
抽象类不能直接实例化,普通类可以直接实例化。
10. 接口和抽象类有什么区别?
-
实现:抽象类的子类使用 extends 来继承;接口必须使用 implements 来实现接口。
-
构造函数:抽象类可以有构造函数;接口不能有。
-
main 方法:抽象类可以有 main 方法,并且我们能运行它;接口不能有 main 方法。
-
实现数量:类可以实现很多个接口;但是只能继承一个抽象类。
-
访问修饰符:接口中的方法默认使用 public 修饰;抽象类中的方法可以是任意访问修饰符。
11.面向对象的三个基本特征
简单来说:继承是子类获得父类的成员,除protected;
重写是继承后重写实现父类的方法
重载是在一个类中使用一系列名字不同的方法
多态是父类使用子类的方法 父类 对象 = new 子类();
多态:
1、Java中主要指对象变量的多态;
2、在Java语言中有两种形式的多态: 编译时多态、运行时多态;
3、编译时多态通过方法重载(overload)来实现,即同一个类中存在多个方法名称相
同但参数列表(参数个数、类型、顺序)不相同的方法;
4、运行时多态通过方法重写(override)来实现,当子类继承父类后重写父类中的可见
(visible)方法,在运行阶段由父类类型的引用指向了子类类型的对象,此时 父类引用
指向哪个子类类型的对象,就调用哪个子类重写后的方法(就是表现谁的形态)
继承:
1、 是指一个对象直接使用另一对象的属性和方法;
2、 Java语言中通过 extends 实现类与类、接口与接口之间的继承,从而实现代码
复用,也是实现多态的基础。
封装:
1、通常将字段私有化(被隐藏起来)、某些不需要在类外部调用的方法也可以隐藏
起来,尽可能隐藏类的实现细节,
2、 将外部可能调用的方法公开。
11.1 overload和override的区别:
Overload(重载):
1、是同一个类中含有多个方法名称相同但参数列表(参数个数、类型、顺序)不相同的方法,
2、这些方法可能是当前类直接声明的,也可能是从父类中继承过来的可见方法。
Override(重写)
1、重写必须是子类继承父类后,子类重新声明了从父类中继承的可见(visible)方法,
2、此时,如果子类中重新声明的方法与父类中的方法 名称相同、参数列表完全相同、返回类型也一致,就说子类重写了父类中的同名方法。
相同点:都要求方法名称相同;
不同点:
1、 重载要求本类中有同名不同那个参的方法;重写必须发生在子类和父类之间;
2、 重载 要求同名方法的参数列表一定不相同;重写要求子类和父类的同名方法
的参数列表完全相同;
3、 重载对返回类型么有要求;而 重写 ( override ) 要求 被重写后的方法的返回
类型 必须跟 父类中相应方法保持一致 ( 如果是返回基本类型,则要求完全相同 )
4、 重载( overload ) 对方法的 权限修饰符 没有要求,而 重写 ( override ) 要求
被重写后的方法的 权限修饰符 的范围不能缩小
注意:
子类不能重写父类的 静态方法,如果子类重新声明了父类中同名的静态方法,
则说 子类 隐藏 了 父类中的同名静态方法。
11. java 中 IO 流分为几种?
按功能来分:输入流(input)、输出流(output)。
按类型来分:字节流和字符流。
11.请求转发和重定向的区别
a.请求转发是一次请求响应,重定向是2次请求
b.请求转发地址栏变化,重定向不会
c.请求转发路径不带工程名,重定向带project name
d.请求转发只能在网站内部,重定向可以去任意的页面
12. java 容器都有哪些?
常用容器的图录:
13. List、Set、Map 之间的区别是什么?
14. HashMap 和 Hashtable 有什么区别?
二者都是用来处理具有键值对特征的数据
-
- HashMap没有考虑同步,是线程不安全的;Hashtable使用了synchronized关键字,是线程安全的;
- HashMap允许null作为Key;Hashtable不允许null作为Key,Hashtable的value也不可以为null
- HashMap线程不安全主要是考虑到了多线程环境下进行扩容可能会出现HashMap死循环
- Hashtable线程安全是由于其内部实现在put和remove等方法上使用synchronized进行了同步,所以对单个方法的使用是线程安全的。但是对多个方法进行复合操作时,线程安全性无法保证。 比如一个线程在进行get操作,一个线程在进行remove操作,往往会导致下标越界等异常
15. 如何决定使用 HashMap 还是 TreeMap?
对于在Map中插入、删除和定位元素这类操作,HashMap是最好的选择。然而,假如你需要对一个有序的key集合进行遍历,TreeMap是更好的选择。
基于你的collection的大小,也许向HashMap中添加元素会更快,将map换为TreeMap进行有序key的遍历。
16. Array 和 ArrayList 有何区别?
-
常用的ArrayList和LinkedList的区别总结如下。
- ArrayList底层使用了动态数组实现,实质上是一个动态数组
- LinkedList底层使用了双向链表实现,可当作堆栈、队列、双端队列使用
- ArrayList在随机存取方面效率高于LinkedList
- LinkedList在节点的增删方面效率高于ArrayList
- ArrayList必须预留一定的空间,当空间不足的时候,会进行扩容操作
- LinkedList的开销是必须存储节点的信息以及节点的指针信息
ArrayList和LinkedList区别
ArrayList 内部借助于数组实现元素的存储。
ArrayList 是线程不安全的,相对于线程安全的Vector来说可能效率较高。
ArrayList 内部基于数组实现数据存储,因此随机访问效率较高。( 可以使用索引直接访问数组中的元素 )
ArrayList 内部基于数组实现数据存储,因此增删元素速度较慢。( 增删元素可能需要挪动数组中大量元素 )
LinkedList 内部基于链表实现元素的存储。
LinkedList是线程不安全的。
LinkedList内部基于链表实现数据存储,因此随机访问效率较低。( 需要逐个遍历链表中的结点 )
LinkedList内部基于链表实现数据存储,因此增删元素速度较快。( 增删元素只需要修改相邻两个节点的指针 )
16.HashSet和TreeSet有哪些区别?
答: HashSet和TreeSet的区别总结如下。
- HashSet底层使用了Hash表实现。
保证元素唯一性的原理:判断元素的hashCode值是否相同。如果相同,还会继续判断元素的equals方法,是否为true
- TreeSet底层使用了红黑树来实现。
保证元素唯一性是通过Comparable或者Comparator接口实现
17.Treemap的特性
Treemap底层使用红黑树实现,存储的键值对按照键来排序
- 如果Key存入的是字符串等类型,那么会按照字典默认顺序排序
- 如果传入的是自定义引用类型,比如说User,那么该对象必须实现Comparable接口,并且覆盖其compareTo方法;或者在创建TreeMap的时候,我们必须指定使用的比较器。
17.1 并行和并发有什么区别?
-
并行是指两个或者多个事件在同一时刻发生;而并发是指两个或多个事件在同一时间间隔发生。
-
并行是在不同实体上的多个事件,并发是在同一实体上的多个事件。
-
在一台处理器上“同时”处理多个任务,在多台处理器上同时处理多个任务。如hadoop分布式集群。
所以并发编程的目标是充分的利用处理器的每一个核,以达到最高的处理性能。
18. 线程和进程的区别?
- 进程是一个“执行中的程序”,是系统进行资源分配和调度的一个独立单位
- 线程是进程的一个实体,一个进程中一般拥有多个线程。线程之间共享地址空间和其它资源(所以通信和同步等操作,线程比进程更加容易)
- 线程一般不拥有系统资源,但是也有一些必不可少的资源(使用ThreadLocal存储)
19. 创建线程有哪几种方式?
①. 继承Thread类创建线程类
-
定义Thread类的子类,并重写该类的run方法,该run方法的方法体就代表了线程要完成的任务。因此把run()方法称为执行体。
-
创建Thread子类的实例,即创建了线程对象。
-
调用线程对象的start()方法来启动该线程。
②. 通过Runnable接口创建线程类
-
定义runnable接口的实现类,并重写该接口的run()方法,该run()方法的方法体同样是该线程的线程执行体。
-
创建 Runnable实现类的实例,并依此实例作为Thread的target来创建Thread对象,该Thread对象才是真正的线程对象。
-
调用线程对象的start()方法来启动该线程。
③. 通过Callable和Future创建线程
-
创建Callable接口的实现类,并实现call()方法,该call()方法将作为线程执行体,并且有返回值。
-
创建Callable实现类的实例,使用FutureTask类来包装Callable对象,该FutureTask对象封装了该Callable对象的call()方法的返回值。
-
使用FutureTask对象作为Thread对象的target创建并启动新线程。
-
调用FutureTask对象的get()方法来获得子线程执行结束后的返回值。
20. 线程有哪些状态?
线程通常都有五种状态,创建、就绪、运行、阻塞和死亡。
-
创建状态。在生成线程对象,并没有调用该对象的start方法,这是线程处于创建状态。
-
就绪状态。当调用了线程对象的start方法之后,该线程就进入了就绪状态,但是此时线程调度程序还没有把该线程设置为当前线程,此时处于就绪状态。在线程运行之后,从等待或者睡眠中回来之后,也会处于就绪状态。
-
运行状态。线程调度程序将处于就绪状态的线程设置为当前线程,此时线程就进入了运行状态,开始运行run函数当中的代码。
-
阻塞状态。线程正在运行的时候,被暂停,通常是为了等待某个时间的发生(比如说某项资源就绪)之后再继续运行。sleep,suspend,wait等方法都可以导致线程阻塞。
-
死亡状态。如果一个线程的run方法执行结束或者调用stop方法后,该线程就会死亡。对于已经死亡的线程,无法再使用start方法令其进入就绪
21. sleep() 和 wait() 有什么区别?
sleep():方法是线程类(Thread)的静态方法,让调用线程进入睡眠状态,让出执行机会给其他线程,等到休眠时间结束后,线程进入就绪状态和其他线程一起竞争cpu的执行时间。
因为sleep() 是static静态的方法,他不能改变对象的机锁,当一个synchronized块中调用了sleep() 方法,线程虽然进入休眠,但是对象的机锁没有被释放,其他线程依然无法访问这个对象。
wait():wait()是Object类的方法,当一个线程执行到wait方法时,它就进入到一个和该对象相关的等待池,同时释放对象的机锁,使得其他线程能够访问,可以通过notify,notifyAll方法来唤醒等待的线程
21.1 sleep 和 yield 的区别:
sleep让线程休眠在获得CPU控制权,yield是线程让步
1. sleep 不考虑线程优先级 ( 一个线程睡眠后其它线程都有机会获得CPU ),yield 要考虑线程优先级 ( 仅让位给 跟自己同等优先级或优先级比自己高的线程 )
2. sleep 可能抛出 InterruptedException ,而 yield 不会抛出异常
3. sleep 导致运行状态的线程进入到阻塞状态,而 yield 会导致运行状态的线程进入就绪状态
22. notify()和 notifyAll()有什么区别?
-
如果线程调用了对象的 wait()方法,那么线程便会处于该对象的等待池中,等待池中的线程不会去竞争该对象的锁。
-
当有线程调用了对象的 notifyAll()方法(唤醒所有 wait 线程)或 notify()方法(只随机唤醒一个 wait 线程),被唤醒的的线程便会进入该对象的锁池中,锁池中的线程会去竞争该对象锁。也就是说,调用了notify后只要一个线程会由等待池进入锁池,而notifyAll会将该对象等待池内的所有线程移动到锁池中,等待锁竞争。
-
优先级高的线程竞争到对象锁的概率大,假若某线程没有竞争到该对象锁,它还会留在锁池中,唯有线程再次调用 wait()方法,它才会重新回到等待池中。而竞争到对象锁的线程则继续往下执行,直到执行完了 synchronized 代码块,它会释放掉该对象锁,这时锁池中的线程会继续竞争该对象锁。
23. 线程的 run()和 start()有什么区别?
每个线程都是通过某个特定Thread对象所对应的方法run()来完成其操作的,方法run()称为线程体。通过调用Thread类的start()方法来启动一个线程。
start()方法来启动一个线程,真正实现了多线程运行。这时无需等待run方法体代码执行完毕,可以直接继续执行下面的代码; 这时此线程是处于就绪状态, 并没有运行。 然后通过此Thread类调用方法run()来完成其运行状态, 这里方法run()称为线程体,它包含了要执行的这个线程的内容, Run方法运行结束, 此线程终止。然后CPU再调度其它线程。
run()方法是在本线程里的,只是线程里的一个函数,而不是多线程的。 如果直接调用run(),其实就相当于是调用了一个普通函数而已,直接待用run()方法必须等待run()方法执行完毕才能执行下面的代码,所以执行路径还是只有一条,根本就没有线程的特征,所以在多线程执行时要使用start()方法而不是run()方法。
24. 什么是死锁?
死锁是指两个或两个以上的进程在执行过程中,由于竞争资源或者由于彼此通信而造成的一种阻塞的现象,若无外力作用,它们都将无法推进下去。此时称系统处于死锁状态或系统产生了死锁,这些永远在互相等待的进程称为死锁进程。是操作系统层面的一个错误,是进程死锁的简称,最早在 1965 年由 Dijkstra 在研究银行家算法时提出的,它是计算机操作系统乃至整个并发程序设计领域最难处理的问题之一。
排查死锁的方法:
24. 怎么防止死锁?
死锁的四个必要条件,只要打破其中一个即可解除:
-
- 资源互斥:一个资源每次只能被一个线程使用
- 请求与保持条件:一个线程因请求资源而阻塞时,对已获得的资源保持不放
- 不剥夺条件:线程已经获得的资源,在未使用完之前,不能强行剥夺
- 循环等待条件:若干线程之间形成一种头尾相接的循环等待资源关系
这四个条件是死锁的必要条件,只要系统发生死锁,这些条件必然成立,而只要上述条件之 一不满足,就不会发生死锁。
理解了死锁的原因,尤其是产生死锁的四个必要条件,就可以最大可能地避免、预防和 解除死锁。
24.1多线程环境下的线程安全
多线程环境下的线程安全主要体现在原子性,可见性,有序性方面
原子性:其他线程是不会看到某个操作执行的中间部分
可见性:可见性是指一个线程对于共享变量的更新,对于后续访问该变量的线程是否可见的问题。
有序性:有序性是指一个处理器上运行的线程所执行的内存访问操作在另外一个处理器上运行的线程来看是否有序的问题。
24.2对synchronized关键字的理解
synchronized是Java中的一个关键字,是一个内部锁。它可以使用在方法上和方法块上,表示同步方法和同步代码块。
在多线程环境下,同步方法或者同步代码块在同一时刻只允许有一个线程在执行,其余线程都在等待获取锁,也就是实现了整体并发中的局部串行。
保证了内部的原子性,可见性,有序性
24.3谈谈你对volatile关键字的理解。
答:volatile关键字是一个轻量级的锁,可以保证可见性和有序性,但是不保证原子性。
24.4Java中的线程池有了解吗?
答:java.util.concurrent.ThreadPoolExecutor类就是一个线程池。客户端调用ThreadPoolExecutor.submit(Runnable task)提交任务,线程池内部维护的工作者线程的数量就是该线程池的线程池大小,有3种形态:
- 当前线程池大小:表示线程池中实际工作者线程的数量
- 最大线程池大小(maxinumPoolSize):表示线程池中允许存在的工作者线程的数量上限
- 核心线程大小(corePoolSize ):表示一个不大于最大线程池大小的工作者线程数量上限
线程池的优势体现如下:
- 线程池可以重复利用已创建的线程,一次创建可以执行多次任务,有效降低线程创建和销毁所造成的资源消耗;
- 线程池技术使得请求可以快速得到响应,节约了创建线程的时间;
- 线程的创建需要占用系统内存,消耗系统资源,使用线程池可以更好的管理线程,做到统一分配、调优和监控线程,提高系统的稳定性。
25.异常处理机制
编译时的异常和JVM的异常
当程序发生异常时会产生一个代表该异常的对象
同时当前程序会把这个异常对象交给运行时系统
运行时系统根据接受到的异常对象寻找相应代码来处理该异常。
26. jsp 有哪些内置对象?作用分别是什么?
JSP有9个内置对象:
-
request:封装客户端的请求,其中包含来自GET或POST请求的参数;
-
response:封装服务器对客户端的响应;
-
pageContext:通过该对象可以获取其他对象;
-
session:封装用户会话的对象;
-
application:封装服务器运行环境的对象;
-
out:输出服务器响应的输出流对象;
-
config:Web应用的配置对象;
-
page:JSP页面本身(相当于Java程序中的this);
-
exception:封装页面抛出异常的对象。
27. session 和 cookie 有什么区别?
-
由于HTTP协议是无状态的协议,所以服务端需要记录用户的状态时,就需要用某种机制来识具体的用户,这个机制就是Session.典型的场景比如购物车,当你点击下单按钮时,由于HTTP协议无状态,所以并不知道是哪个用户操作的,所以服务端要为特定的用户创建了特定的Session,用用于标识这个用户,并且跟踪用户,这样才知道购物车里面有几本书。这个Session是保存在服务端的,有一个唯一标识。在服务端保存Session的方法很多,内存、数据库、文件都有。集群的时候也要考虑Session的转移,在大型的网站,一般会有专门的Session服务器集群,用来保存用户会话,这个时候 Session 信息都是放在内存的,使用一些缓存服务比如Memcached之类的来放 Session。
-
思考一下服务端如何识别特定的客户?这个时候Cookie就登场了。每次HTTP请求的时候,客户端都会发送相应的Cookie信息到服务端。实际上大多数的应用都是用 Cookie 来实现Session跟踪的,第一次创建Session的时候,服务端会在HTTP协议中告诉客户端,需要在 Cookie 里面记录一个Session ID,以后每次请求把这个会话ID发送到服务器,我就知道你是谁了。有人问,如果客户端的浏览器禁用了 Cookie 怎么办?一般这种情况下,会使用一种叫做URL重写的技术来进行会话跟踪,即每次HTTP交互,URL后面都会被附加上一个诸如 sid=xxxxx 这样的参数,服务端据此来识别用户。
-
Cookie其实还可以用在一些方便用户的场景下,设想你某次登陆过一个网站,下次登录的时候不想再次输入账号了,怎么办?这个信息可以写到Cookie里面,访问网站的时候,网站页面的脚本可以读取这个信息,就自动帮你把用户名给填了,能够方便一下用户。这也是Cookie名称的由来,给用户的一点甜头。所以,总结一下:Session是在服务端保存的一个数据结构,用来跟踪用户的状态,这个数据可以保存在集群、数据库、文件中;Cookie是客户端保存用户信息的一种机制,用来记录用户的一些信息,也是实现Session的一种方式。
28. 说一下 session 的工作原理?
其实session是一个存在服务器上的类似于一个散列表格的文件。里面存有我们需要的信息,在我们需要用的时候可以从里面取出来。
类似于一个大号的map吧,里面的键存储的是用户的sessionid,用户向服务器发送请求的时候会带上这个sessionid。这时就可以从中取出对应的值了。
29. 简述 tcp 和 udp的区别?
-
TCP面向连接(如打电话要先拨号建立连接);UDP是无连接的,即发送数据之前不需要建立连接。
-
TCP提供可靠的服务。也就是说,通过TCP连接传送的数据,无差错,不丢失,不重复,且按序到达;UDP尽最大努力交付,即不保证可靠交付。
-
Tcp通过校验和,重传控制,序号标识,滑动窗口、确认应答实现可靠传输。如丢包时的重发控制,还可以对次序乱掉的分包进行顺序控制。
-
UDP具有较好的实时性,工作效率比TCP高,适用于对高速传输和实时性有较高的通信或广播通信。
-
每一条TCP连接只能是点到点的;UDP支持一对一,一对多,多对一和多对多的交互通信。
-
TCP对系统资源要求较多,UDP对系统资源要求较少。
30. tcp 为什么要三次握手,两次不行吗?为什么?
为了实现可靠数据传输, TCP 协议的通信双方, 都必须维护一个序列号, 以标识发送出去的数据包中, 哪些是已经被对方收到的。 三次握手的过程即是通信双方相互告知序列号起始值, 并确认对方已经收到了序列号起始值的必经步骤。
如果只是两次握手, 至多只有连接发起方的起始序列号能被确认, 另一方选择的序列号则得不到确认。
31. 说一下 tcp 粘包是怎么产生的?
①. 发送方产生粘包
采用TCP协议传输数据的客户端与服务器经常是保持一个长连接的状态(一次连接发一次数据不存在粘包),双方在连接不断开的情况下,可以一直传输数据;但当发送的数据包过于的小时,那么TCP协议默认的会启用Nagle算法,将这些较小的数据包进行合并发送(缓冲区数据发送是一个堆压的过程);这个合并过程就是在发送缓冲区中进行的,也就是说数据发送出来它已经是粘包的状态了。
②. 接收方产生粘包
接收方采用TCP协议接收数据时的过程是这样的:数据到底接收方,从网络模型的下方传递至传输层,传输层的TCP协议处理是将其放置接收缓冲区,然后由应用层来主动获取(C语言用recv、read等函数);这时会出现一个问题,就是我们在程序中调用的读取数据函数不能及时的把缓冲区中的数据拿出来,而下一个数据又到来并有一部分放入的缓冲区末尾,等我们读取数据时就是一个粘包。(放数据的速度 > 应用层拿数据速度)
32. TCP/IP四层模型
-
应用层:网络服务与最终用户的一个接口。
-
传输层:定义传输数据的协议端口号,以及流控和差错校验。
-
网络层:进行逻辑地址寻址,实现不同网络之间的路径选择。
-
数据链路层:建立逻辑连接、进行硬件地址寻址、差错校验等功能
-
最全tcp讲解https://www.cnblogs.com/daijiabao/p/11183265.html
33. get 和 post 请求有哪些区别?
-
GET在浏览器回退时是无害的,而POST会再次提交请求。
-
GET产生的URL地址可以被Bookmark,而POST不可以。
-
GET请求会被浏览器主动cache,而POST不会,除非手动设置。
-
GET请求只能进行url编码,而POST支持多种编码方式。
-
GET请求参数会被完整保留在浏览器历史记录里,而POST中的参数不会被保留。
-
GET请求在URL中传送的参数是有长度限制的,而POST么有。
-
对参数的数据类型,GET只接受ASCII字符,而POST没有限制。
-
GET比POST更不安全,因为参数直接暴露在URL上,所以不能用来传递敏感信息。
-
GET参数通过URL传递,POST放在Request body中。
34.设计模式
单例模式
getInstance是一个函数,在java中,可以使用这种方式使用单例模式创建类的实例,所谓单例模式就是一个类有且只有一个实例,不像object ob=new object();的这种方式去实例化后去使用。
简单点说,就是一个应用程序中,某个类的实例对象只有一个,你没有办法去new,因为构造器是被private修饰的,一般通过getInstance()的方法来获取它们的实例。
getInstance()的返回值是一个对象的引用,并不是一个新的实例,所以不要错误的理解成多个对象。单例模式实现起来也很容易,直接看demo吧
1 public static DBConnect instance; 2 3 public static DBConnect getInstance(){ 4 5 if(instance == null){ 6 7 instance = new DBconnect(); 8 9 } 10 11 return instance; 12 13 }
总的来说:这是单例模式,一般用于比较大,复杂的对象,只初始化一次,应该还有一个private的构造函数,使得不能用new来实例化对象,只能调用getInstance方法来得到对象,而getInstance保证了每次调用都返回相同的对象。
详细解释一下:对象的实例化方法,也是比较多的,最常用的方法是直接使用new,而这是最普通的,如果要考虑到其它的需要,如单实例模式,层次间调用等
观察者模式
对象间一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都得到通知并被自动更新。
装饰者模式
对已有的业务逻辑进一步的封装,使其增加额外的功能,如Java中的IO流就使用了装饰者模式,用户在使用的时候,可以任意组装,达到自己想要的效果。
工厂模式
简单工厂模式:一个抽象的接口,多个抽象接口的实现类,一个工厂类,用来实例化抽象的接口
1 // 抽象产品类 2 abstract class Car { 3 public void run(); 4 5 public void stop(); 6 } 7 8 // 具体实现类 9 class Benz implements Car { 10 public void run() { 11 System.out.println("Benz开始启动了。。。。。"); 12 } 13 14 public void stop() { 15 System.out.println("Benz停车了。。。。。"); 16 } 17 } 18 19 class Ford implements Car { 20 public void run() { 21 System.out.println("Ford开始启动了。。。"); 22 } 23 24 public void stop() { 25 System.out.println("Ford停车了。。。。"); 26 } 27 } 28 29 // 工厂类 30 class Factory { 31 public static Car getCarInstance(String type) { 32 Car c = null; 33 if ("Benz".equals(type)) { 34 c = new Benz(); 35 } 36 if ("Ford".equals(type)) { 37 c = new Ford(); 38 } 39 return c; 40 } 41 } 42 43 public class Test { 44 45 public static void main(String[] args) { 46 Car c = Factory.getCarInstance("Benz"); 47 if (c != null) { 48 c.run(); 49 c.stop(); 50 } else { 51 System.out.println("造不了这种汽车。。。"); 52 } 53 54 } 55 56 }
35. 数据库的三范式是什么?
-
第一范式:强调的是列的原子性,即数据库表的每一列都是不可分割的原子数据项。(确保每列保持原子性)
-
第二范式:要求实体的属性完全依赖于主关键字。所谓完全依赖是指不能存在仅依赖主关键字一部分的属性。(确保表中的每列都和主键相关)
-
第三范式:任何非主属性不依赖于其它非主属性。(确保每列都和主键列直接相关,而不是间接相关)
36.varchar比char的好处在于varchar型是可变长度
37. mysql 的内连接、左连接、右连接有什么区别?
内连接关键字:inner join;左连接:left join;右连接:right join。
内连接是把匹配的关联数据显示出来;左连接是左边的表全部显示出来,右边的表显示出符合条件的数据;右连接正好相反。
38. 数据库建模的流程
使用powerdesigner这个工具
- 确定产品需求
- 构造ER关系图
- 建立概念模型(CDM)
- 建立逻辑模型(LDM)
- 建立物理模型(PDM)
- 优化和确定最终物理模型,并导出sql脚本
39. 说一下乐观锁和悲观锁?
-
乐观锁:每次去拿数据的时候都认为别人不会修改,所以不会上锁,但是在提交更新的时候会判断一下在此期间别人有没有去更新这个数据。
-
悲观锁:每次去拿数据的时候都认为别人会修改,所以每次在拿数据的时候都会上锁,这样别人想拿这个数据就会阻止,直到这个锁被释放。
40. 如何做 mysql 的性能优化?
-
为搜索字段创建索引。
-
避免使用 select *,列出需要查询的字段。
-
垂直分割分表。
-
选择正确的存储引擎。
41. redis 是什么?都有哪些使用场景?
Redis是一个开源的使用ANSI C语言编写、支持网络、可基于内存亦可持久化的日志型、Key-Value数据库,并提供多种语言的API。
nosql
Redis 使用场景:
-
数据高并发的读写
-
海量数据的读写
-
对扩展性要求高的数据
42. redis 有哪些功能?
-
数据缓存功能
-
分布式锁的功能
-
支持数据持久化
-
支持事务
-
支持消息队列
43. 说一下 jvm 的主要组成部分?及其作用?
-
类加载器(ClassLoader)
-
运行时数据区(Runtime Data Area)
-
执行引擎(Execution Engine)
-
本地库接口(Native Interface)
组件的作用: 首先通过类加载器(ClassLoader)会把 Java 代码转换成字节码,运行时数据区(Runtime Data Area)再把字节码加载到内存中,而字节码文件只是 JVM 的一套指令集规范,并不能直接交个底层操作系统去执行,因此需要特定的命令解析器执行引擎(Execution Engine),将字节码翻译成底层系统指令,再交由 CPU 去执行,而这个过程中需要调用其他语言的本地库接口(Native Interface)来实现整个程序的功能。
44. 说一下 jvm 运行时数据区?
-
程序计数器
-
虚拟机栈
-
本地方法栈
-
堆
-
方法区
有的区域随着虚拟机进程的启动而存在,有的区域则依赖用户进程的启动和结束而创建和销毁。
47. 说一下堆栈的区别?
1. 栈内存存储的是局部变量而堆内存存储的是实体;
2. 栈内存的更新速度要快于堆内存,因为局部变量的生命周期很短;
3. 栈内存存放的变量生命周期一旦结束就会被释放,而堆内存存放的实体会被垃圾回收机制不定时的回收。
48. 队列和栈是什么?有什么区别?
-
队列和栈都是被用来预存储数据的。
-
队列允许先进先出检索元素,但也有例外的情况,Deque 接口允许从两端检索元素。
-
栈和队列很相似,但它运行对元素进行后进先出进行检索。
49. 说一下类加载的执行过程?
类加载分为以下 5 个步骤:
-
加载:根据查找路径找到相应的 class 文件然后导入;
-
检查:检查加载的 class 文件的正确性;
-
准备:给类中的静态变量分配内存空间;
-
解析:虚拟机将常量池中的符号引用替换成直接引用的过程。符号引用就理解为一个标示,而在直接引用直接指向内存中的地址;
-
初始化:对静态变量和静态代码块执行初始化工作。
50. 怎么判断对象是否可以被回收?
一般有两种方法来判断:
-
引用计数器:为每个对象创建一个引用计数,有对象引用时计数器 +1,引用被释放时计数 -1,当计数器为 0 时就可以被回收。它有一个缺点不能解决循环引用的问题;
-
可达性分析:从 GC Roots 开始向下搜索,搜索所走过的路径称为引用链。当一个对象到 GC Roots 没有任何引用链相连时,则证明此对象是可以被回收的
51.JVM的垃圾回收机制
GC是JVM的垃圾回收机制,当实例化一个Java对象是时,JVM会对该对象分得一份内存,对象不使用了之后,JVM会自动回收该内存块,降低内存溢出的风险
方式:1.计数:对象创建或被引用时,会增加计数,对象为空时,减少计数;直到计数为0时,便回收内存块
2.从GC的根部队整个对象向下进行搜索,搜索过的路为引用链,当一个对象到GC roots 没有任何引用链相连时,证明该对象是可以被回收的
52. 说一下 jvm 有哪些垃圾回收算法?
-
标记-清除算法
-
标记-整理算法
-
复制算法
-
分代算法
53. 说一下 jvm 有哪些垃圾回收器?
-
Serial:最早的单线程串行垃圾回收器。
-
Serial Old:Serial 垃圾回收器的老年版本,同样也是单线程的,可以作为 CMS 垃圾回收器的备选预案。
-
ParNew:是 Serial 的多线程版本。
-
Parallel 和 ParNew 收集器类似是多线程的,但 Parallel 是吞吐量优先的收集器,可以牺牲等待时间换取系统的吞吐量。
-
Parallel Old 是 Parallel 老生代版本,Parallel 使用的是复制的内存回收算法,Parallel Old 使用的是标记-整理的内存回收算法。
-
CMS:一种以获得最短停顿时间为目标的收集器,非常适用 B/S 系统。
-
G1:一种兼顾吞吐量和停顿时间的 GC 实现,是 JDK 9 以后的默认 GC 选项。
54. 说一下 jvm 调优的工具?
JDK 自带了很多监控工具,都位于 JDK 的 bin 目录下,其中最常用的是 jconsole 和 jvisualvm 这两款视图监控工具。
-
jconsole:用于对 JVM 中的内存、线程和类等进行监控;
-
jvisualvm:JDK 自带的全能分析工具,可以分析:内存快照、线程快照、程序死锁、监控内存的变化、gc 变化等。
55. 常用的 jvm 调优的参数都有哪些?
-
-Xms2g:初始化推大小为 2g;
-
-Xmx2g:堆最大内存为 2g;
-
-XX:NewRatio=4:设置年轻的和老年代的内存比例为 1:4;
-
-XX:SurvivorRatio=8:设置新生代 Eden 和 Survivor 比例为 8:2;
-
–XX:+UseParNewGC:指定使用 ParNew + Serial Old 垃圾回收器组合;
-
-XX:+UseParallelOldGC:指定使用 ParNew + ParNew Old 垃圾回收器组合;
-
-XX:+UseConcMarkSweepGC:指定使用 CMS + Serial Old 垃圾回收器组合;
-
-XX:+PrintGC:开启打印 gc 信息;
-
-XX:+PrintGCDetails:打印 gc 详细信息。
56.Ajax的优缺点
优点:1.不用刷新页面就可更新数据
2.异步与服务器通信,不打断用户
3.前端与后端负载分离,减小服务器负载
缺点:1.Ajax无法回到保存数据的历史页面,因为Back和History功能被干掉了
2.带来安全问题,使得开发者容易暴露数据
3.对搜索引擎支持弱
4.不能很好地支持移动设备
57.Vue的优缺点及其特性
特点: 1.MVVM框架:MVVM(Model+View+ViewModel。)是把MVC里的Controller和MVP里的Presenter改成了ViewModel。属性触发的时候, View的变化会自动更新到ViewModel,ViewModel的变化也会自动同步到View上显示,都能触发对应的操作
2.组件化、轻量的框架(20kb)、高效、双向的数据绑定
3.在进行前端和数据一些操作的时候,只需要修改少部分的需要改动的数据
58.Goto语句
起源于汇编语言的控制:“若条件A成立,则跳到这里;否则跳到那里”
尽管goto仍是Java中的一个保留字,但在语言中并未使用它;Java没有goto语句。
而是采用了break和continue这样的操作来完成跳转
59.MVC开发模式
用于应用程序的分层开发
Model层:存取数据的对象,它接受视图层请求的数据,同时带有一些逻辑,数据变化时实时更新控制器
VIew层:数据的可视化层
Controller层:控制Model和View层,控制数据流向和数据变化实时更新到view层进行显示
优点:MVC模式各层各负其责,互不干扰,能把项目分离化,从而提高效率
打车项目中:
Controller层:与service层打交道,把返回过来的数据,反馈到view层将数据可视,控制数据的流向
Service层:存放运行的逻辑,比如检查一些元素是否存在,判断删除是否完成,直接与dao层相联系
Dao层:dao层福贼连接数据库,对数据库进行曾删改查的操作,sql语句也在这里被使用
60.servlet的运行过程
⒈ 客户端发送请求至服务器端;
⒉服务器端根据web.xml文件中的Servlet相关配置信息,将客户端请求转发到相应的Servlet
⒊ Servlet引擎调用Service()方法,根据request对象中封装的用户请求与数据库进行交互,返回数据之后,Servlet会将返回的数据封装到response对象中;
⒋ Servlet生成响应内容并将其传给服务器。响应内容动态生成,通常取决于客户端的请求
⒌ 服务器将响应返回给客户端
61.Oracle和mysql的区别
1.Oracle是大型数据库,mysql是小型数据库;mysql是开源的,Oracle是收费的
2.Oracle支持高并发,大访问量;mysql在高并发的情况下会容易造成崩溃
3.Oracle的数据持久性要高于mysql,Oracle把提交的sql操作线写入了日志文件,即使重启崩溃也能找回,而mysql没法
4.Oracle有各种性能诊断,mysql没有
62.索引的建立
索引是一种数据结构,这种数据结构是需要额外的写入和存储为代价来提高表上数据检索的速度
建立了索引之后就无需查询每一行了
当使用主键或唯一键创建表时,MySQL会自动创建名为PRIMARY的特殊索引, 该索引称为聚簇索引。
PRIMARY索引是比较特殊的,这个索引本身与数据一起存储在同一个表中。另外除PRIMARY索引之外的其他索引称为二级索引或非聚簇索引。
要为列或一组添加索引,可以使用create index语句
CREATE INDEX index_name ON 表名 (列名)
这样就不用扫描整个表了
之后在Select语句中的头部加入EXPLAIN子句
便可完成搜索了
63.索引和主键的区别
当使用主键的时候,mysql会自动创建名为primary的特殊索引,叫做聚簇索引,别的索引称为二级索引
1:主键是为了标识数据库记录唯一性,不允许记录重复,且键值不能为空,主键也是一个特殊索引.
2:数据表中只允许有一个主键,但是可以有多个索引.
5:除主键索引外的索引的值可以为空.
6:主键也可以由多个字段组成,组成复合主键,同时主键肯定也是唯一索引.
7:唯一索引则表示该索引值唯一,可以由一个或几个字段组成,一个表可以有多个唯一索引.
64.mysql解决自增序列
使用AUTO_INCREMENT来定义列,其id被设为主键,无需指定值,即可实现自增长
65.&和&&有什么区别
& 不管前面的条件是否正确,后面都执行
&& 前面条件正确时,才执行后面,不正确时
66.为什么重写equals还要重写hashcode?
equals()和hashcode()是java.lang.Object中提供的用以对象比较的两个重要方法
- public boolean equals(Object obj) { return (this == obj); }:用以判断变量参数与当前实例是否相等,JDK默认实现是基于对象内存地址是否相同,如果两个对象内存地址相同,则表示两个对象相同。
- public native int hashCode();: 默认情况下,该方法返回一个随机整数,对于每个对象来说该数字唯一,但该数字并非恒定,可能随着程序的执行发生变化。
- 如果两个对象相同,则他们的哈希值(hashcode)一定相同
- 如果两个对象的哈希值相同(hashcode)相同,并不意味着他们是相同的
- 对于使用Hash散列方式存储对象的数据结构:HashSet、HashMap、HashTable等,仅仅重载equals方法可能会导致实际业务逻辑失败
- 在比较两个对象时,仅重载hashCode方法并不能强制Java忽略内存地址
所以HashMap中,如果要比较key是否相等,要同时使用这两个函数!
66.Java中的Exception和Error有什么区别?
答: Exception和Error的主要区别可以概括如下。
- Exception是程序正常运行中预料到可能会出现的错误,并且应该被捕获并进行相应的处理,是一种异常现象
- Error是正常情况下不可能发生的错误,Error会导致JVM处于一种不可恢复的状态,不需要捕获处理,比如说OutOfMemoryError
解析:
Exception又分为了运行时异常和编译时异常。
编译时异常(受检异常)表示当前调用的方法体内部抛出了一个异常,所以编译器检测到这段代码在运行时可能会出异常,所以要求我们必须对异常进行相应的处理,可以捕获异常或者抛给上层调用方。
运行时异常(非受检异常)表示在运行时出现的异常,常见的运行时异常包括:空指针异常,数组越界异常,数字转换异常以及算术异常等。
前边说到了异常Exception应该被捕获,我们可以使用try – catch – finally 来处理异常,并且使得程序恢复正常。
67.SSM框架配置的大致流程
a.在Pom.xml中指定所依赖的jar包
b.JDBC.properties中指定数据库连接的账密,驱动,以及url
c.mybatis-config配置mybatis
spring-dao.xml------->将JDBC.properties中的数据进行加载;创建连接池;确定了mybatis和数据库交互的方式
spring-service.xml------->事务管理;将spring-dao中定义好的datasource注入到事务管理器中transaction manager
spring-web.xml------->定义dispatcher-servlet如何响应URL请求;定义一些controller的行为
web.xml------->将每个servlet进行注册,从而响应前端的请求;把spring-dao,spring-service,spring-web三个连接在一起,可以互相访问
68.SSM框架运作流程
1.在dao层中创建对象,定义方法,在mapper中的xml文件中定义了sql语句
2.service层调用dao层方法
3.把数据返回给controller层
4.再将数据以json字符值的形式返还给前台
最后非常感谢大佬的整理,原文链接一共200题:https://www.zhihu.com/question/27858692/answer/787505434
https://mp.weixin.qq.com/s/MXKACpJKLMxep5bXO3EHhw
项目
我的项目A:这是一个仿照滴滴打车的订单管理系统(个人完成)
1.这是一个基于servlet+jsp的一个项目,把订单项目分为了顾客,司机,站点,订单模块,使用了MVC开发模式,将程序的业务分离
Controller层:放置的servlet与service层打交道,只把返回过来的数据,反馈到view层将数据可视,控制数据的流向
Service层:存放运行的逻辑,比如检查一些元素是否存在,判断删除是否完成,直接与dao层相联系
Dao层:dao层负责连接数据库,对数据库进行曾删改查的操作,sql语句也在这里被使用
封装了JDBC的连接
遇到的难题:1。一开始不知道servlet的整个运行过程,感觉很盲目,不知道前端请求发过来的时候时用request对象来request对象来接收请求,用response对象返回请求
2.sql语句的编写
3。写项目时候会出现类似于404,502的这种问题,404一般是地址有问题或者是某个地方的请求转发的时候大小写有问题,502一般清理浏览器缓存
我的项目B:这是一个基于知识图谱的智能学习网站(团队完成)
我负责完成了数据库的建模和前端代码的编写,使用了echarts来构建树图,在这个项目中使用了KNN算法,所以也了解了KNN算法
数据库建模的流程
使用powerdesigner这个工具
- 确定产品需求
- 构造ER关系图
- 建立概念模型(CDM)
- 建立逻辑模型(LDM)
- 建立物理模型(PDM)
客户浏览信息——>每个职业的tag——>获得推介的职业:主要是分析浏览的行为,最后生成一个距离量度:样本空间中2个点之间的距离表示相似度,距离越短,相似度越大
困难:和队友有过对于想法不同的争吵