题目汇总(自己复习用)

session和cookie之间关系

session是基于cookie的,服务器每次创建Session会话的时候,都会为这个session创建一个cookie对象,这个cookie对象的key永远都是JESSIONID,value是新创建出来的session的id值。服务器会把这个cookie发送给客户端,然后浏览器每次进行请求的时候,都会带上这个cookie。这个就是cookie和session的工作机制。
在这里插入图片描述

四个常用的域

  1. pages
    jsp页面被执行,生命周期开始,jsp页面执行完毕,声明周期结束
  2. request
    用户发送一个请求,开始,服务器返回响应,请求结束,生命周期结束。
  3. session
    用户打开浏览器访问,创建session(开始),session超时或被声明失效,该对象生命周期结束。
  4. application
    web应用加载的时候创建。Web应用被移除或服务器关闭,对象销毁。[结束]。
    参考链接

JAVA_WEB三大组件

  1. servlet程序
  2. listene监听器
  3. filter过滤器 拦截请求,过滤响应
    拦截请求: 权限检查,日记操作,事务管理等等
    在这里插入图片描述

执行返回链

在这里插入图片描述

ThreadLocal

dao层有异常一定不能自己捕获,需要往上层去抛,不然没有办法进行回滚
在这里插入图片描述

filter过滤器的生命周期

1:.构造器方法
2.初始化方法
步骤1和2在web工程启动的时候执行,(filter已经创建) 只执行一次
3.doFilter方法
每次拦截到请求都会执行。
4.destroy方法
停止web工程的时候就会执行,也就是销毁filter过滤器。

什么时候用转发什么时候用重定向

转发:就是同一次请求,当用转发时可以共同用同一个请求域中的对象。
重定向:就是两次请求,在浏览器按F5时,就是重复的上一次请求,对于一个添加数据的操作来说,如果用转发,那么按了F5之后就会重复上一次的请求,此时请求域中还有数据,那么就会重复添加数据,所以此时应该采用重定向操作,分发为两次请求。

表单重复提交

情况1提交完表单,服务器使用请求转发来进行页面跳转,这个时候,用户按下功能键F5就会发起最后一次请求,会造成表单重复提交的问题。
解决办法:使用重定向进行跳转。
情况2用户正常提交服务器,但是由于网络延迟等原因,迟迟未收到服务器响应,这个时候用户以为表单未提交,然后重复点了几次提交,也会造成表单重复提交
情况3用户正常提交服务器,服务器也没有延迟,但是提交完后,用户回退浏览器,重新提交也会造成表单重复提交。
情况2和情况3需要使用验证码进行解决。
在这里插入图片描述

浏览器有缓存验证码无法刷新的情况解决办法

在请求参数加上一个时间戳。
在这里插入图片描述
在这里插入图片描述

如何动态修改隐藏域中的值

  1. 可以请求发起时,附带上当前要操作的值,并且注入到隐藏域中。
  2. 可以通过判断当前请求参数中是否包含某个参数。
  3. 可以判断request域中是否包含有某个对象。

Java线程的几种状态

  1. NEW:新建状态,还没有调用 start方法时的线程状态
  2. RUNABLE:可运行的状态,还可以分为ready和running状态
  3. BLOCKED:阻塞的线程的线程状态等待监视器锁。就是说当前线程使用了synchronize关键字,被这个关键字修饰的代码块或者方法,都需要获取相应的锁,在没有拿到锁之前就一直处于阻塞状态。
  4. WATING:等待线程的线程状态不具有超时时间,也就是永久等待的意思,Object.wait(),Thread.join(),LockSupport.park()方法会进入这个状态。
  5. TIMED_WATING:具有指定等到时间的等待线程的线程状态。不是永久等待,达到一定时间之后会自动唤醒,通过以下方法可以使得线程进入该种状态:Thread.sleep、Object.wait、Thread.join、LockSupport.parkNanos、LockSupport.parkUntil
  6. TERMINATED:终止线程的线程状态。线程正常完成执行或者出现异常会进入此种状态。

在这里插入图片描述

DHCP协议工作过程

传送门
动态主机配置协议

  1. DHCP discover:客户端开始DHCP过程发送的报文,是DHCP协议的开始(此时是广播发送)
  2. DHCP offer:服务器收到DHCP discover之后做出的相应,包括了给客户端的ip,客户端的Mac地址,租约过期时间,服务器的识别符,以及其他信息。(此时也是广播发送)
  3. DHCP request:客户机收到offer后,做出的相应,在租约快到期的时候同样会使用这个报文(还是广播发送)
  4. DHCP ack:服务器确定收到客户机的request请求成功之后发送的确认报文,客户机收到这个报文后,才会确认分配给他的ip和其他信息才可以被使用。(广播)当DHCP Server接收到客户机的DHCP REQUEST之后,会广播返回给客户机一个DHCP ACK消息包,表明已经接受客户机的选择,并将这一IP地址的合法租用以及其他的配置信息都放入该广播包发给客户机。
    客户机在接收到DHCP ACK广播后,会向网络发送三个针对此IP地址的ARP解析请求以执行冲突检测,查询网络上有没有其它机器使用该IP地址;如果发现该IP地址已经被使用,客户机会发出一个DHCP DECLINE数据包给DHCP Server,拒绝此IP地址租约,并重新发送DHCP discover信息。此时,在DHCP服务器管理控制台中,会显示此IP地址为BAD_ADDRESS。

Linux输出文件中某一行或者某几行

比如要输出文件中第3行:
sed -n ‘3p’ test.txt
如果输出第1到3行:
sed -n ‘1,3p’ test.txt

TCP和UDP对比

  1. 面向连接:一个面向连接,一个不是面向连接
  2. 可靠性:TCP通过确认重传机制保证可靠性,UDP不保证数据一定到达
  3. 有序性:TCP可以保证消息顺序交付处理,虽然可能这些不是顺序到达。UDP不具备这个特性
  4. 速度上:TCP速度较慢,UDP速度快,适用于对速度敏感的应用。
  5. 量级上:TCP属于重量级,头部有20个字节,UDP属于轻量级头部有8个直接。

Java基本数据类型各占多少个字节

  1. byte:1个字节,默认值0
  2. short:2个字节,默认值0
  3. int:4个字节,默认值0
  4. long:8个字节,默认值0
  5. float:4个字节,默认值0.0f
  6. double:8个字节,默认值0.0d
  7. char:2个字节,默认值’\u0000’
  8. boolean:1个字节,好像有争议

设计模式的一些原则

  • 单一职责原则
  • 接口隔离原则
  • 依赖倒置原则:高层模块不应该依赖低层的模块,都应该依赖于抽象
  • 里氏替换原则:父类能出现的地方子类应该也能出现,也就是子类尽量不要重写父类的方法,如果必须重写那么就不要采用继承,可以采用组合的方式
  • 开闭原则:对扩展开方,修改关闭
  • 迪米特法则:也就是最少知道原则,一个类对自己依赖的类知道的越少越好,体现封装特性。

我熟悉的设计模式

  • 单例模式:要会手写线程安全的DCL方法
  • 简单工厂模式和抽象工厂模式
  • 适配器模式:对象适配器模式,也就是采用组合的方式,还有一个就是类适配器模式,采用的方式是继承,那么就需要重写方法,一般不推荐,因为违背了原则。主要是为了解决兼容问题
  • 策略模式:定义了算法族,分别分装起来,让他们可以相互替换,次模式的变化基于算法的调用者,,像工具类中的Arrays.sort(arr,A) A就是传入的一个比较器的实现类,也就是这个算法你自己定义实现,该模式也可以解决多层if else语句的繁琐情况。
  • 模板方法模式:定义好了算法框架,只是把一些步骤的实习延迟到子类中去实现,使用的时候直接继承这个框架,然后编写核心需要重写的方法。
  • 代理模式:为一个对象提供一个替身,以控制对这个对象的访问,通过代理对象访问目标对象,扩展被代理对象的功能。分为静态代理和动态代理,静态代理和适配器模式的组合版本有点像,而动态代理是可以有选择的方法或者某个某些方法增强,看你自己在实现InvocationHandler后的重写的invoke方法怎么写的,当调用带对象的方法的时候都会经过invoke方法,然后执行method.invoke()方法
  • 观察者模式:定义了对象之间的多对一的依赖,让各个观察者的接口实例对象同时监听某个主题对象。当主题对象发生变化时,它的所有的依赖着都会收到通知,并且更新。类似订阅了公众号,主题推送的时候,每个订阅者都会收到消息。
  • 享元模式:对一些频繁使用的对象并且不会发生变化的可以提前进行缓存,当使用的时候直接从缓存中获取同一个对象。如果不在缓存当中,再创建对象。
  • 桥接模式:我觉得这个模式和组合适配器模式有点像,这个可以提供set方法最实现类对象进行修改,然后更换行为方式,也就是不同的实现方法。就像数据库连接换驱动一样,可以从MySQL切换到Oracle

垃圾回收算法

  • 标记清除算法:简单,但是容易出现碎片
  • 复制算法:需要双倍空间,高效,解决内存碎片问题,适用于存活率低的场景
  • 标记整理算法 适用于老年代

Minor GC---->采用复制算法,用于年轻代中
老年代:存放生命周期较长的对象----》采用标记-清理算法 或 标记-整理算法
1、Full GC 和 Major GC(一般的理解是Full GC等于 Major GC,收集整个GC堆。注意:如果有人问你Major GC的时候,一定要问清楚是Full GC 还是仅仅指老年代的GC)
2、Full GC 比 Minor GC 慢,但执行频率低
问题:什么时候触发Full GC?什么条件?
1、老年代空间不足(为了避免Full GC的发生,就避免产生大对象的生成)
2、永久代空间不足(这个只是针对JDK7和以前的版本,这也是为什么用元空间替代永久代的原因,为了降低Full GC的频率!!!!)
3、CMS GC时出现 promotion failed ,concurrent mode failure
4、Minor GC晋升到老年代的平均大小大于老年代的剩余空间
5、调用System.gc()----->注意:这只是码农提醒虚拟机进行Full GC操作,实际上还是在不确定的时上进行Full GC
6、使用RMI 进行RPC或管理的JDK应用,每小时执行1次Full GC
(一般能说出三点就可以,三点以上就更好)

哪些可以作为GCRoots

  1. 虚拟机栈中引用的对象
  2. 方法区中类静态属性引用的对象
  3. 方法区中常量引用的对象
  4. 已经启动的Java线程
  5. Native方法栈引用的对象

计算机网络各个应用的端口

  • FTP:文件传输协议,数据端口20 ,控制端口21 基于TCP
  • SSH:远程登录协议 端口22 基于TCP
  • Telnet:终端仿真协议,端口23 使用TCP
  • SMTP:简单文件传输协议 端口25 基于TCP
  • DNS:域名解析协议 端口53 基于UDP
  • TPTF:小型文件传输协议 端口69 使用TCP
  • HTTP:超文本传输控制协议 端口80 基于TCP
  • POP3: 邮局协议 端口110 基于TCP

OSI七层模型

物理层,数据链路层,网络层,传输层,会话层,表示层,应用层

TCP/IP四层模型

网络接口层,网络层,传输层,应用层

  • 物理层:传输比特流
  • 数据链路层:传输数据帧
  • 网络层:数据包
  • 传输层:数据段
    传送门

spring Bean的生命周期

当spring扫面完所有的类生成bd完成就工厂组件完成 然后beanfactoryPostProcessor 开始工作,执行工程的后置处理。
扫描这个类的时候生成一个BeanDefination对象,也就是一个BD,这个BD里边有全限定类名,class,scop,lazy(是否懒加载),然后根据这个bd在进行实例化对象,然后填充属性。
在这里插入图片描述

在这里插入图片描述
上面这个也是一种创建bean的方式,。也就是能够整合其他框架的重要方式。
其他框架整合主要是用factoryBean的方式.

作用范围

  • singleton: 容器中仅存在一个实例,单例存在,默认值
  • prototype:原型的,也就是每次getBean()都会新建一个bean,相当于new
  • request:每次http请求都会创建一个bean,适用于WebApplicationContext环境
  • session:同一个http session共享一个bean,不同session使用不同的bean,适用于WebApplicationContext环境
  • globalSession:一般用于,表示在一个全局的HTTP Session中,一个bean定义对应一个实例。典型情况下,仅在使用portlet context的时候有效。该作用域仅在基于web的Spring ApplicationContext情形下有效。

线程安全原理

number++的四条字节码指令

在这里插入图片描述

  1. getstatic:读取number的值
  2. iconst_1:准备一个常量1
  3. iadd:做一个相加
  4. putstatic:保存到常量里边去
    所以说步骤就是先读取到值,然后准备一个常量1 ,然后执行相加操作,最后保存回去,总共四步操作。
    加锁个释放锁的对应的就是monitorentermonitorexit

volatile底层实现原理

解决的问题就是一个线程修改了变量值后另一个线程看不见的问题,可以保证可见性。
1.当写一个volatile变量时,JMM会把该线程对应的本地内存中的变量强制刷新到主内存中去;
2.这个写会操作会导致其他线程中的缓存无效。volatile能够保证可见性,那么它是如何实现可见性的呢?以X86处理器为例,在对volatile修饰的变量进行写操作时,通过编译器生成反汇编指令后,会发现会多一条Lock前缀,就是由于这条Lock前缀所实现的可见性。
解决原因

  • 缓存已知性协议:当一个线程修改变量后同步会主内存中后,使其他线程中读到的值全部设置为失效,然后其他线程会重新到主内存中去读取这个值
  • CPU嗅探机制

Java内存模型由Java虚拟机规范定义,用来屏蔽各个平台的硬件差异。简单来说:
1 所有变量储存在主内存。
2 每条线程拥有自己的工作内存,其中保存了主内存中线程使用到的变量的副本。
3 线程不能直接读写主内存中的变量,所有操作均在工作内存中完成。

一是保证共享变量对所有线程的可见性
二是禁止指令重排序优化
三是volatile对于单个的共享变量的读/写具有原子性,无法保证类似num++的原子性,需要通过循环CAS的方式来保证num++操作的原子性。

synchronize

synchronize执行时,会对应lock原子操作和unlock操作,会刷新工作内存中共享变量的值。
打印函数也可以,因为打印函数里边的方法加了synchronize
指令重拍序 是指重排序后并不会在单线程情况下执行的结果才会重排序,不然也不会进行重排序
而synchronized的作用是加锁,可以保证串行执行,即可以让并发环境 转为单线程环境。因此加了synchronized就已经是单线程环境了。既然是单线程,那么无论是否进行了重排序,最终的结果都不会有影响,即都可以保证线程安全。所以说,在使用synchronized时根本不用关心“重排序”这个问题,无论它支持或不支持,都已经不重要了。

支持可重入:原理,锁对象中会维护一个计数器recursions会记录线程获得几次锁了
可重入的好处:可以避免程序死锁,可以让我们更好地封装代码,也就是调用方法需要获取的锁对象是一样的也是可以的,,那么就可以封装方法

什么是不可中断 :一个线程获得锁后,另一个线程想要获得锁,必须处于阻塞或者等待状态,如果第一个线程不释放锁,第二个线程会一直等待或者阻塞,等待过程中是不可中断的,会一直等待

synchronize使用了编程monitorenter和monitorexit两个指令,每个锁对象都会关联一个monitor(它才是真正的锁对象)它的内部又两个重要的变量,owner会保存获得锁的线程,recursions会保存线程获得锁的次数,当执行monitorenter的时候这个计算器+1,当执行到monitorexit的时候计数器-1,这也是为甚么synchronize支持可重入的原因

synchronize和Lock的区别

  1. synchronize是关键字,而Lock是一个接口。
  2. synchronize会自动释放锁,而Lock需要手动释放锁
  3. synchronize是不可中断的,Lock是可中断或者不可中断都可以(调用lock方法就是不可中断,调用挺容易tryLock指定获取锁等待的时间方法时 ,是可中断的,返回值是一个布尔类型的值,返回true就是获取到了,返回false就是没获取到)
  4. 通过Lock可以知道线程有没有拿到锁,而synchronize不能
  5. synchronize能锁住方法和代码块,而Lock只能锁代码块
  6. synchronize是非公平锁,而Lock支持非公平和公平两种方式

平时写代码如何对synchronize进行优化

  1. 减少同步代码块的范围
  2. 降低synchronize锁的粒度,可以联想之前ConcurrentHashMap的分段锁的思想,就是降低了锁的粒度。像HashTable就是一种不好的方式,一个线程在进行读或者写的时候,其他线程就没办法读取获取更新,因为他锁的就是整个对象,所以并发特性不太好。
  3. 读写分离。LinkedBlockingQueue入队和出队使用的就是不同的锁,相对于读写只有一个锁的效率高。
    在这里插入图片描述

CAS原理

AtomicInteger源码中会维护三个变量,指针偏移,value值等,还有一个就是Unsafe类,这个类提供了原子操作
通过内存偏移地址拿到最新值V,预期的旧值A,需要修改的新值B

// setup to use Unsafe.compareAndSwapInt for updates
    private static final Unsafe unsafe = Unsafe.getUnsafe();
    private static final long valueOffset;  // 实际内存地址偏移
private volatile int value;  // 保证可见性

    /**
     * Creates a new AtomicInteger with the given initial value.
     *
     * @param initialValue the initial value
     */
    public AtomicInteger(int initialValue) {
        value = initialValue;
    }

把自增操作变成原子的主要是用了Unsafe中的getAndAddInt方法
更新过程中会需要三个值, 一个预估值,一个内存中的最新值,还有一个就是需要加的 1

public final int getAndAddInt(Object var1, long var2, int var4) {
        int var5;
        do {
        // 通过Unsafe类直接操作内存,获取最新值
            var5 = this.getIntVolatile(var1, var2);
        } while(!this.compareAndSwapInt(var1, var2, var5, var5 + var4));
        return var5;
    }

悲观锁

假设每次都是最坏的情况,每次取拿数据的时候都会认为比人会修改,所以每次拿数据的时候都会上锁,这样别的线程想拿这个数据就会阻塞,synchronize也是一种悲观锁,JDK中ReetrantLock也是一种悲观锁。

乐观锁

总是假设最好的情况,每次去拿数据的时候都不会认为比人会修改,就算改了也没关系,也会不断重试,但是在更新的时候会判断在此期间有没有线程修改过这个数据,如果没有那么就修改成功,如果有的话,就进行循环重试。

进程和线程的区别

传送门

进程

  • 进程是一个程序在一个数据集中的一次动态执行过程,可以简单理解为“正在执行的程序”,它是CPU资源分配和调度的独立单位。
  • 进程一般由程序、数据集、进程控制块三部分组成。我们编写的程序用来描述进程要完成哪些功能以及如何完成;数据集则是程序在执行过程中所需要使用的资源;进程控制块用来记录进程的外部特征,描述进程的执行变化过程,系统可以利用它来控制和管理进程,它是系统感知进程存在的唯一标志。
  • 进程的局限是创建、撤销和切换的开销比较大。

线程

  • 线程是在进程之后发展出来的概念。 线程也叫轻量级进程,它是一个基本的CPU执行单元,是资源调度的基本单位,也是程序执行过程中的最小单元,由线程ID、程序计数器、寄存器集合和堆栈共同组成。一个进程可以包含多个线程。
  • 线程的优点是减小了程序并发执行时的开销,提高了操作系统的并发性能,缺点是线程没有自己的系统资源,只拥有在运行时必不可少的资源,但同一进程的各线程可以共享进程所拥有的系统资源,如果把进程比作一个车间,那么线程就好比是车间里面的工人。不过对于某些独占性资源存在锁机制,处理不当可能会产生“死锁”。

进程通信方式

  1. 管道:面向字节流
  2. 信号量:临界资源,同一个时刻只能有一个进程进行访问,原子操作,它是一个计数器,记录资源能被多少个进程同时访问。用于控制多进程对临界资源的访问(同步)),并且是非负值。主要作为进程间以及同一进程的不同线程间的同步手段。
  3. 消息队列:消息队列是消息的链表,是存放在内核中并由消息队列标识符标识。因此是随内核持续的,只有在内核重起或者显示删除一个消息队列时,该消息队列才会真正被删除。
  4. 共享内存:共享内存就是映射一段能被其他进程所访问的内存,这段共享内存由一个进程创建,但多个进程都可以访问。
  5. socket通信:适合同一主机的不同进程间和不同主机的进程间进行全双工网络通信。但并不只是Linux有,在所有提供了TCP/IP协议栈的操作系统中几乎都提供了socket,而所有这样操作系统,对套接字的编程方法几乎是完全一样的,即“网络编程”。

HTTP请求包含哪些

传送门

请求体

三部分组成,请求行,请求头,请求体

响应体

三部分组成,响应行,响应头,响应体

  1. 1xx 消息,一般是告诉客户端,请求已经收到了,正在处理,别急…
  2. 2xx 处理成功,一般表示:请求收悉、我明白你要的、请求已受理、已经处理完成等信息.
  3. 3xx 重定向到其它地方。它让客户端再发起一个请求以完成整个处理。
  4. 4xx 处理发生错误,责任在客户端,如客户端的请求一个不存在的资源,客户端未被授权,禁止访问等。
  5. 5xx 处理发生错误,责任在服务端,如服务端抛出异常,路由出错,HTTP版本不支持等。

重定向和转发的区别

传送门
重定向是发生在客户端的两次请求,转发是服务端内部转发

Cookie和Session的区别

传送门

1、cookie数据存放在客户的浏览器上,session数据放在服务器上。
2、cookie不是很安全,别人可以分析存放在本地的COOKIE并进行COOKIE欺骗,考虑到安全应当使用session。
3、session会在一定时间内保存在服务器上。当访问增多,会比较占用你服务器的性能
考虑到减轻服务器性能方面,应当使用COOKIE。
4、单个cookie保存的数据不能超过4K,很多浏览器都限制一个站点最多保存20个cookie。
5、所以个人建议:
将登陆信息等重要信息存放为SESSION
其他信息如果需要保留,可以放在COOKIE中

TCP 保证可靠性的机制

  • 确认和重传:就收方收到报文就会确认,发送方隔一段时间后没有收到确认就重传
  • 数据校验
  • 数据合理分片和排序:
    UDP:IP数据报大于1500字节,大于MTU.这个时候发送方IP层就需要分片(fragmentation).把数据报分成若干片,使每一片都小于MTU.而接收方IP层则需要进行数据报的重组.这样就会多做许多事情,而更严重的是,由于UDP的特性,当某一片数据传送中丢失时,接收方便无法重组数据报.将导致丢弃整个UDP数据报.
    TCP会按MTU合理分片,接收方会缓存未按序到达的数据,重新排序后再交给应用层。
  • 流量控制:当就收方来不及处理发送方发送的数据,能提示发送方降低发送速率,防止包丢失
  • 拥塞控制:当网络拥塞时,减少数据的发送。
  • 滑动窗口

CAP的一些概念

一致性Consistency
高可用性 Availability
分区容错性Partition tolerance
传送门

Redis数据类型有哪几种

传送门

  • String(字符串)
    string 是 redis 最基本的类型,你可以理解成与 Memcached 一模一样的类型,一个 key 对应一个 value。
    string 类型是二进制安全的。意思是 redis 的 string 可以包含任何数据。比如jpg图片或者序列化的对象。
    string 类型是 Redis 最基本的数据类型,string 类型的值最大能存储 512MB。
    常用命令:set、get、decr、incr、mget等。注意:一个键最大能存储512MB。

  • Hash(哈希)
    Redis hash 是一个键值(key=>value)对集合;是一个 string 类型的 field 和 value 的映射表,hash 特别适合用于存储对象。
    每个 hash 可以存储 232 -1 键值对(40多亿)。
    常用命令:hget、hset、hgetall等。
    应用场景:存储一些结构化的数据,比如用户的昵称、年龄、性别、积分等,存储一个用户信息对象数据。

  • List(列表)
    Redis 列表是简单的字符串列表,按照插入顺序排序。你可以添加一个元素到列表的头部(左边)或者尾部(右边)。
    list类型经常会被用于消息队列的服务,以完成多程序之间的消息交换。
    常用命令:lpush、rpush、lpop、rpop、lrange等。
    列表最多可存储 232 - 1 元素 (4294967295, 每个列表可存储40多亿)。

  • Set(集合)
    Redis的Set是string类型的无序集合。和列表一样,在执行插入和删除和判断是否存在某元素时,效率是很高的。集合最大的优势在于可以进行交集并集差集操作。Set可包含的最大元素数量是4294967295。
    集合是通过哈希表实现的,所以添加,删除,查找的复杂度都是O(1)。
    应用场景:
    1、利用交集求共同好友。
    2、利用唯一性,可以统计访问网站的所有独立IP。
    3、好友推荐的时候根据tag求交集,大于某个threshold(临界值的)就可以推荐。
    常用命令:sadd、spop、smembers、sunion等。
    集合中最大的成员数为 232 - 1(4294967295, 每个集合可存储40多亿个成员)。

  • Zset(sorted set:有序集合)
    Redis zset 和 set 一样也是string类型元素的集合,且不允许重复的成员。
    不同的是每个元素都会关联一个double类型的分数。redis正是通过分数来为集合中的成员进行从小到大的排序。
    zset的成员是唯一的,但分数(score)却可以重复。
    sorted set是插入有序的,即自动排序。
    常用命令:zadd、zrange、zrem、zcard等。
    当你需要一个有序的并且不重复的集合列表时,那么可以选择sorted set数据结构。
    应用举例:
    (1)例如存储全班同学的成绩,其集合value可以是同学的学号,而score就可以是成绩。
    (2)排行榜应用,根据得分列出topN的用户等。

枚举类型可以被继承吗

传送门
不能被继承,也不能继承其他类,对象默认都是public static final的 ,并且声明的枚举类都默认继承java.lang.Enum

Java子父类加载顺序初始化顺序

传送门

  1. 父类静态成员变量
  2. 父类静态代码块
  3. 子类静态成员变量
  4. 子类静态代码块
  5. 父类成员变量
  6. 父类非静态代码块
  7. 父类构造器
  8. 子类成员变量
  9. 子类非静态代码块
    10.子类构造器

特点:

  • 先父类,后子类
  • 先静态,后非静态
  • 先成员变量、后代码块、最后构造器

Java类加载过程

双亲委派模型加载顺序

加载

主要负责查找并且加载类的二进制数据文件,其实就是class文件

连接

1.验证

主要确保类文件的正确性,比如class的版本,class文件的魔术因子是否正

2.准备

为类的静态变量分配内存,并且为其初始化默认值。

3.解析

把类中的符号引用转换为直接引用。

初始化

为类的静态变量赋予正确的初始值(代码编写阶段给定的值)

Java内存模型

传送门
传送门2

程序计数器

计数器记录的是正在执行的虚拟机字节码指令的地址;如果正在执行的是Natvie 方法,这个计数器值则为空(Undefined)。此内存区域是唯一一个在Java 虚拟机规范中没有规定任何OutOfMemoryError 情况的区域。

java虚拟接栈

生命周期与线程相同,虚拟机栈描述的是Java 方法执行的内存模型:每个方法被执行的时候都会同时创建一个栈帧(Stack Frame ①)用于存储局部变量表操作栈动态链接方法出口等信息。每一个方法被调用直至执行完成的过程,就对应着一个栈帧在虚拟机栈中从入栈到出栈的过程。
如果线程请求的栈深度大于虚拟机所允许的深度,将抛出StackOverflowError 异常;如果虚拟机栈可以动态扩展(当前大部分的Java 虚拟机都可动态扩展,只不过Java 虚拟机规范中也允许固定长度的虚拟机栈),当扩展时无法申请到足够的内存时会抛出OutOfMemoryError 异常。

本地方法栈

虚拟机栈为虚拟机执行Java 方法(也就是字节码)服务,而本地方法栈是为虚拟机使用到的Native 方法服务。
与虚拟机栈一样,本地方法栈区域也会抛出StackOverflowError 和OutOfMemoryError异常。

Java堆

Java 堆是被所有线程共享的一块内存区域,在虚拟机启动时创建。
此内存区域的唯一目的就是存放对象实例,几乎所有的对象实例都在这里分配内存。这一点在Java 虚拟机规范中的描述是:所有的对象实例以及数组都要在堆上分配,但是随着JIT 编译器的发展与逃逸分析技术的逐渐成熟,栈上分配、标量替换优化技术将会导致一些微妙的变化发生,所有的对象都分配在堆上也渐渐变得不是那么“绝对”了。
Java 堆中还可以细分为:新生代和老年代;再细致一点的有Eden 空间、From Survivor 空间、To Survivor 空间等。如果从内存分配的角度看,线程共享的Java 堆中可能划分出多个线程私有的分配缓冲区(Thread Local Allocation Buffer,TLAB)。不过,无论如何划分,都与存放内容无关,无论哪个区域,存储的都仍然是对象实例,进一步划分的目的是为了更好地回收内存,或者更快地分配内存。

方法区

方法区(Method Area)与Java 堆一样,是各个线程共享的内存区域,它用于存储已被虚拟机加载的类信息、常量、静态变量、即时编译器编译后的代码等数据。虽然Java 虚拟机规范把方法区描述为堆的一个逻辑部分,但是它却有一个别名叫做Non-Heap(非堆),目的应该是与Java 堆区分开来。
运行时常量池
运行时常量池(Runtime Constant Pool)是方法区的一部分。Class 文件中除了有类的版本、字段、方法、接口等描述等信息外,还有一项信息是常量池(Constant Pool Table),用于存放编译期生成的各种字面量和符号引用,这部分内容将在类加载后存放到方法区的运行时常量池中。

线程池核心参数

传送门
总共7个核心参数

  1. corePoolSize核心线程数:线程池中维护的一个最小的线程数量,即使这些线程处于空闲状态,他们也不会被销毁,除非设置了allowCoreThreadTimeOut。这里的最小线程数量即是corePoolSize。
  2. maximumPoolSize线程池中最大线程数量。
  3. keepAliveTime 空闲线程存活时间 一般为long型
  4. TimeUnit unit keepAlive的计量单位
  5. BlockingQueue workQueue工作队列
  6. ThreadFactory factory 线程工厂
  7. RejectedExecutionHandler handler拒绝策略

execute和submit的区别

传送门

事务的特性

传送门

  • 原子性
  • 一致性
  • 隔离性
  • 持久性

事务隔离级别

  • 读未提交(Read Uncommitted):一个事务可以读取到,另外一个事务尚未提交的变更。
  • 提交已提交(Read committed):一个事务提交后,其变更才会被另一个事务读取到。
  • 可重复读(Repeatable Read):在一个事务执行的过程中所读取到的数据,和事务启动时所看到的一致。
  • 可串行化(Serializable):当操作一行数据时,读写分别都会加锁。当出现读写锁互斥时,会排队串行执行。

对于MySQL 默认的隔离级别–可重复读

隔离级别脏读不可重复读幻读
读未提交
读已提交×
可重复读××
可串行化×××

√代表会发生,×代表不会发生。

数据库设计三大范式

  1. 第一范式:确保每一列的原子性,如果表中的所有字段的值都是不可以再分解的原子,就说明数据库表满足了第一范式。就好比地址,写湖南长沙,但是这个地址还可以切分为省份和城市两个字段
  2. 第二范式:在第一范式的基础上更进一层。确保表中的每列都和主键相关,而不能只与主键的一部分相关(主要说的是联合主键)。也就是说在一个数据库表中,一个表只能保存一种数据,不可以把多种数据保存在同一张表中。就说不相关的数据不要保存在一起。
  3. 第三范式:确保每列都和主键列直接相关,而不是间接相关。

Mybatis一级缓存二级缓存

传送门
传送门

时间格式器SimpleDataFormat是线程安全的吗?

不是线程安全的,可以使用ThreadLocal来解决线程安全问题。

Java的几种引用类型?

强引用StrongReference :最常见的引用方式,JVM绝对不会回收它,宁愿牺牲自己抛出OutOfMemoryError挂掉程序,也不会回收它。
软引用SoftReference:如果虚拟机内存充足,无论发生多少次GC,软引用指向的对象都不会回收,如果内存满了就会被回收。可以用于缓存,一般来说当内存不够了,缓存自然会被清空。

SoftReference<String> soft = new SoftReference<>(new String("softReference"));

弱引用WeakReference:和软引用的区别就是一旦发生了GC,弱引用指向的对象就会被回收,这个和虚拟机内存满不满没有关系。它们的生命周期就是两次GC的间隔时间。

WeakReference<String> weakReference = new WeakReference<>(new String("weakReference"));

虚引用,幻引用PhantomReference:虚引用多了一个依赖队列,虚引用并不会决定对象的生命周期,有他没他一样,无法通过虚引用获取对象。

数据库Delete和Trancate

  • delete是DML语言,trancate是DDL语言需要drop权限性能比delete性能高,delete只能一行行删除数据。
  • 事务方面:delete出现错误可以进行回滚,trancate不会回滚(小心使用)
  • trancete语句 是清空表中所有数据,没有其他选择说某些东西不删,某些东西删了
  • 当表中的主键是自动增长(auto_increment)时,用delete删除完数据之后,再往表中插入数据,当数据的主键为空,其自动增长时,并不是从1开始,也就是说,delete虽然删除了数据,但是,他并没有将主键自增(auto_increment)重新设为1。而truncate则做了这件事,它不仅将数据全部清空,还将主键自增的值初始为1。
  • 总之delete只删数据,不清痕迹;trancate既删数据,又清痕迹。

HashMap解决冲突的神奇算法

首先保证table数组的长度始终是2的整数次幂,然后在计算哈希值时,为了防止高位参与不了计算从而导致取余的时候出现比较高的概率的哈希冲突。他在内部又进行了这样一步操作。

static final int hash(Object key) {
        int h;
        return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16);
    }

因为就算这个 (n - 1) & hash操作能够提高计算效率,但是它始终用的是低位的hash值进行计算,所以在内部又求了哈希值之后右移16为进行或运算,尽量让32的哈希值全部参与运算,更好地防止hash冲突。(更加散列或者扰动

解决hash冲突的方法有哪些

  1. 开方地址法
  2. 再哈希
  3. 链地址法(java采用的这种方式)
  4. 建立一个公共溢出区

各种排序算法的稳定性及最好最坏及平均情况下的时间复杂度

传送门

  • 冒泡:稳定,平均和最坏情况下时间复杂度都是n^2,最好的情况下时间复杂度为n
  • 直接选择:不稳定,平均和最坏情况下时间复杂度都是n^2,最好的情况下时间复杂度为n
  • 直接插入排序:稳定,平均和最坏情况下时间复杂度都是n^2,最好的情况下时间复杂度为n
  • 希尔排序:不稳定,平均n^1.3 最好n,最坏情况下 n ^2
  • 快速排序:不稳定,平均和最好的情况下时间复杂度都为nlog(n),最坏情况下n^2
  • 归并排序:稳定,时间复杂度都是nlog(n)
  • 堆排序:不稳定时间复杂度都是nlog(n)
    其中log都是以2为底的对数
    直接选择排序和堆排序属于选择排序
    冒泡排序和快速排序属于交换排序
    直接插入和希尔排序属于插入类排序

JDK和JRE的区别和联系

传送门

  • JDK: jdk是java语言开发工具包,包含了java运行时环境(JRE),和一堆java调试工具(javac / java / jdb / jconsole / jvisualvm)等。
  • JRE:包含JVM标准实现及Java核心类库。JRE是Java运行环境,并不是一个开发环境,所以没有包含任何开发工具(如编译器和调试器)
    JRE是指java运行环境。光有JVM还不能成class的 执行,因为在解释class的时候JVM需要调用解释所需要的类库lib。 (jre里有运行.class的java.exe)
  • JVM:JVM(Java Virtual Machine),即java虚拟机, java运行时的环境,JVM是一种用于计算设备的规范,它是一个虚构出来的计算机,是通过在实际的计算机上仿真模拟各种计算机功能来实现的。针对java用户,也就是拥有可运行的.class文件包(jar或者war)的用户。里面主要包含了jvm和java运行时基本类库(rt.jar)。rt.jar可以简单粗暴地理解为:它就是java源码编译成的jar包。Java虚拟机在执行字节码时,把字节码解释成具体平台上的机器指令执行。这就是Java的能够“一次编译,到处运行”的原因。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值