第一篇
Posted kanhin
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了第一篇相关的知识,希望对你有一定的参考价值。
JAVA知识
1.java的四个基本特性,对多态的理解
- java的四个基本特性
- 继承:继承是从已有的类得到继承信息创建新类的过程,提供继承信息的类被称为父类
- 抽象:抽象时间一类对象的共同特征总结出来构造类的过程,包括数据抽象和行为抽象
- 封装:通常认为封装是吧数据和操作数据的方法绑定起来,对数据的访问只能通过一定义的接口
- 多态:允许不同子类型的对象对同一消息作出不同的响应
- 多态的理解
- 方法的重载:实现的是编译时的多态(前绑定)
- 方法的重写:实现的是运行时的多态(后绑定)
- 实现的多态需要做的两件事:1.方法重写(子类继承父类并重写父类中已有的或抽象方法)2.对象造型(用父类型应用一用自类型的引用)
- 项目中多态的应用
- 简单例子:在物流信息管理系统中,有两种用户:订购客户和卖房客户,登录系统都用Login,但是Login里面的东西不同
深层次的挖掘-> https://www.cnblogs.com/chenssy/p/3372798.html 多态的面试题解析(一定要记住)
https://blog.csdn.net/clqyhy/article/details/78978785 同上
2.面向对象和面向过程的区别
- 面向对象和面向过程的区别
- 面向过程就像一个细心的管家,事无巨细都要考虑到,二面向对象就像是个家用电器。只要知道功能,不需要知道他的工作原理
- 面向过程是时间为中心的编程思想,就是分析出解决问题所需要的步骤,然后用函数将这些步骤实现,并按照顺序调用,面向对象是一对象为中心的编程思想
3.重载和重写
- 重载:重载放生在同一个类中,同名的方法如果有不同的参数列表(参数类型不同,参数个数不通过,或者二者都不同),则视为重载
- 重写:重写发生在子类和父类之间,重写要求子类被重写方法与父类被重写的方法有相同的返回类型,,比父类被重写方法更更好访问,不能比父类被重写方法声明更多的异常(历史替换原则),根据不同的子类对象确定调用哪个方法。
4.面对对象开发的六个基本原则(面试中问过)
- 六个基本原则
- 单一职责:一个类只做他该做的事情(高内聚:面向对象中,如果只让一个类完成它该做的事,而不设计与他无关的领域就是践行了高内聚)
- 开放封闭:软件尸体应当对扩展开放,对修改封闭。要做到开闭有两个要点:1.抽象是关键,一个系统中如果没有抽象类或接口系统就没有扩展点2.封装可变性,将系统中的各种可变因素封装到一个继承结构中,如果多个可变因素混杂在一起,系统就变的复杂而混乱
- 里氏替换原则:任何时候都可用子类型替换掉父类型,子类一定是增加父类的能力而不是减少父类的能力,因此子类比父类的能力更多,把能力多的对象换能力少的对象当然没有任何问题
- 依赖倒置:面向接口编程(该原则说的直白和具体一些就是生命方法的参数类型,方法返回类型,变量的引用类型事,尽可能用抽象类型而不用具体类型,因为抽象类型可以被他的任何子类所代替)
- 合成聚合复用:优先使用聚合或合成关系复用代码(不要直接使用继承-容易破坏开闭原则)
- 接口隔离:接口小而专,绝不能大而全,一个接口应该只描述一种能力,接口也应该是高内聚的。
- 迪米特法则:又称最少知识原则,一个对象应该对其他对象有尽可能少的了解
- 项目中用到的原则:单一职责,开放封闭,合成聚合复用(String?),接口隔离
5.static,final的区别和用途
- static
- 修饰变量:静态变量随着类加载时被完成初始化,内存中只有一个,但jvm也只会为它分配一次内存,所有类共享静态变量
- 修饰方法:类加载的时候就存在,不依赖任何的实例,static方法必须实现,不能用abstract
- 修饰代码块:在类加载完之后就会执行代码块中的内容
- 父类静态代码块->子类静态代码块->父类非静态代码块->父类构造方法->子类非静态代码块->子类构造方法
- final
- 修饰变量
- 编译期常量:类加载的过程完成初始化,编译后带入到任何计算式中也能是基本类型
- 运行时常量:基本数据类型饮用数据类型,引用不可变,但是引用的对象内容可变
- 修饰方法:不能被继承,不能被子类修改
- 修饰类:不能继承
- 修饰形参:final形参不可变
- 修饰变量
6.HashMap和Hashtable的区别,HashMap中的key可以是任何对象或数据类型么?Hashtable是线程安全的么?
- HashMap和Hashtable的区别
- Hashtable的方法是同步的,HashMap未经同步,所以多线程的时候要手动同步
- Hashtable不允许NULL值(key和value都不可以),HashMap允许NULL值(key和value都可以)
- 两者的遍历方式大同小异,Hashtable比HashMap多了elements方法,Hashtable和HashMap都能通过values返回Collection,然后遍历,两者都可以返回entrySet,然后遍历处理
- Hashtable使用Enumeration,HashMap使用Iterator
- 哈希值的使用不同,Hashtable直接使用对象的hashcode,而HashMap重新计算hash值,而且用&代替求模运算
- Hashtable的hash数组默认大小是11,增加方式是old*2+1 ,HashMap的hash数组默认大小是16,而且必须是2的指数
- Hashtable给予Dictionary类,而HashMap给予AbstractMap类
- HashMap中的key可以是任何对象或数据类型么
- 可以为NULL,但不能是可变对象,如果是可变对象的话,对象中的属性改变,则对象hashcode也进行相应的改变,d无法查找到map中的数据
- 如果可变对象在HashMap中作为键,那就要小心在改变对象状态的时候不要改变他的哈希值了,需要保证Hash值不变即可
- Hashtable是线程安全的么
- Hashtable是线程安全的,其实是在对应的方法上添加了synchronized关键字进行修饰,优于执行侧方法的时候需要获取到对象的锁,但是运行起来非常的慢为了实现线程安全,使用ConcurrentHashMap
7.HashMap和ConcurrentHashMap的区别,ConcurrentHashMap是线程安全的么?ConcurrentHashMap如何保证线程安全?(面试问过,一定要多看几遍,这个是重点)
- HashMap和ConcurrentHashMap的区别
- HashMap非线程安全,ConcurrentHashMap线程安全
- ConcurrentHashMap将整个Hash桶进行了分段Segment,也就是将这个大的数组分成了集合小的片段segment,而且每个小的片段segment上都有锁的存在,那么在插入元素的时候就需要小找到应该插入的那一个片段segment,然后在这个片段进行插入,畏怯这里还要获取segment锁 (JDK7)
- ConcurrentHashMap让所得力度更精细一些,并发性能更好
- ConcurrentHashMap线程安全么,ConcurrentHashMap如何保证线程的安全
- Hashtable在竞争激烈的并发环境下变现出效率低下是因为都必须竞争一把锁,假如容器里又多把锁,每一把锁用于所容器的一部分数据,那么当多线程发昂问容器里的不同数据时,线程就不会有锁的竞争,从而提高兵法访问效率,这就是ConcurrentHashMap锁使用的锁分段技术,首先将数据分成一段一段的存储,然后给每一段配一把锁,当一个线程占用锁访问其中一个段数据的时候,其他段数据也能被其他线程访问
- get操作的搞笑指出在于整个get过程不需要加锁,除非是读到空值才会加锁重读,get方法里将使用的共享变量都定义成volatile,如用于统计当前Segemnt大小的count 字段,用于存储值的HashEntry的value,定义成volatile的变量能够在线程之间保持可见性,能够被多线程同时读,并且保证不会读到过期的值,但是只能被单线程写(写入不依赖原值除外)
- put方法首先定位带segment然后在segment里进行插入操作,插入操作需要经历两个步骤,第一步判断segment里的HashEntry是否需要扩容,第二部定位到HashEntry然后插入数据(JDK7)
todo 拓展HashMap源码
8.因为别人知道远吗怎么实现,故意构造相同的hash的字符串进行攻击怎么处理?那jdk7怎么办?
- 怎么处理构造相同的hash字符串进行攻击
- 当客户端提交一个请求并附带参数的时候,web应用服务器会把我们的参数化成一个HashMap存储,这个HashMap的逻辑结构如下:key->value
- 但是物理存储结构是不同的,key值会化成hashcode,这个hashcode会被转成数组下标:0->value1
- 不同的String会产生相同的hashcode而导致碰撞,结构0->value1->value2
- 限制post和get的参数个数,越少越好
- 限制post数据包的大小
- WAF
- jdk7如何处理hashcode字符串攻击
- HashMap会动态的使用一个专门的treemap实现来替换掉它
9.String,StringBuffer,StringBuilder以及对 String 不可变的理解(面试问过,当时没回答出来String不可变的设计)
- 都是final类型,都不允许被继承
- String的长度是不可变的,StringBuffer,StringBuilder的长度是可变的
- StringBuffer是线程安全的,StringBuilder不是线程安全,他们的方法都是一样的,StringBuffer的所有方法都添加了synchronized修饰,保证线程安全
- StringBuilder比StringBuffer有更好的性能
- 如果一个String类型的字符串,在编译时就可以确定是一个字符串常量,到编译完成之后,字符床会自动拼接成一个常量,此时string的速度比StringBuffer,StringBuilder要快
- String不变性的理解
- String类是被final进行修饰的,不能被继承
- 用+连接字符串的时候会创建新的字符串
- String s = new String("hello") 可能会创建两个对象也可能创建一个对象,如果静态区中有“hello”字符常量对象的话,则仅仅在堆中会创建一个对象,如果静态区中没有的话就需要创建两个对象,也就是字符串池的优化需要,多次创建字符串只会返回同一个对象
- 在java中通过使用“+”拼接字符的话,底层会转成通过StringBuilder实力的append方法来实现
- 保证配置环境的安全性
10.String有重写Object的hashcode和toString么?如果重写equals不重写hashcode会出现什么问题?
- String有重写Object的hashcode和toString方法么
- String重写了hashcode和toString方法
- 当equals方法被重写时,通常有必要重写hashcode方法,以维护hashcode方法的常规协定,该协定声明相等的两个对象必须有相同的hashcode
- object1.equals(object2)为true,object1.hashcode()==object2.hashcode()为true
- object1.hashcode()==object2.hashcode()为false,bject1.equals(object2)为false
- object1.hashcode()==object2.hashcode()为true,bject1.equals(object2)为不一定为true
很容易举出的例子就是HashMap的key的hashcode
11.Java序列化,如何实现序列化和反序列化,常见的序列化协议有哪些?
12.java实现多线程的方式及各自的区别?
- 实现多线程的三种方式
- 继承Thread类,重写run函数
- 实现Runnable接口
- 实现Callable接口
- 三种方式的区别
- 实现Runnable可以避免java单继承所带来的局限,增强健壮性,代码数据相互独立
- 继承Thread类和实现Runnable方法启动线程都是使用start方法,然后jvm虚拟机将此线程放到就绪队列中,有处理机可用,则执行run方法
- 实现Callable接口要实现call方法,并且线程执行完会有返回值,其他两种没有返回值
13.线程安全
- 定义
- 某个类的行为与其规范一致
- 不管多个线程是怎样执行顺序和优先级,或是wait,sleep,join等控制方式,如果一个类在多线程访问下运转一切正常,并且访问不需要额外同步处理或者协调,那么我们就认为他是线程安全的
- 如何保证线程安全的
- 对变量使用volatile
- 对程序段进行加锁synchronized
- 注意
- 非线程安全的集合在多线程环境下可以使用,但不能作为多线程共享的属性,可以作为莫线程独享的属性
- 例如Vector是线程安全的,ArrayList不是线程安全的,如果每一个线程中new一个ArrayList,而这个ArrayList只是在这个线程中使用,肯定没有问题
14.多线程如何进行信息交互(面试问过,当时回答的不全)
- object中的方法,wait(),notify(),notifyAll()
- 通过共享内存的方式,定义一个volatile变量,两个线程轮训处理这个变量
15.多线程共用一个数据变量需要注意什么?
- 当我们在线程对象(Runnable)中定义了全局变量,run方法会修改该变量时,如果有多个线程同时使用该线程对象,那么就会在城全局变量的值被同时修改,造成错误
- ThreadLocal是jdk引入的一种机制,它解决了线程间共享变量,使用ThreadLocal声明的变量,即时在线程中属于全局变量,针对于某个线程来讲,这个变量也是独立的
- volatile变量每次被线程访问的同时,都强迫线程从驻内存中重新读区该变量的最新值,而当该变量发生修改变化的时候,会强迫当前线程将当前的最新值刷新到贮存,这样一来不同线程都能及时的看到该变量的最新值
16.什么是线程池?如何让你设计一个动态大小的线程池,如何设计,应该用哪些方法?
- 什么是线程池
- 线程池顾名思义就是实现创建若干个可执行的线程放入到池中,需要的时候从池中获取线程不用自省创建,使用完毕不需要销毁线程而是放回池中,从而减少创建和销毁对象的开销
- 设计一个动态大小的线程池,如何设计,应该有哪些方法
- 一个线程池包含以下四个基本组成部分
- 线程管理器(ThreadPool):用于创建并管理线程池的,包括创建线程池,销毁线程池,添加新任务
- 工作线程(PoolWork):线程池中的线程,在没有任务时处于等待状态,可以循环的执行任务
- 任务接口(Task):每个任务必须实现的接口,一共工作线程调度任务的执行,它主要规定了任务的入口,任务执行完后的收尾工作,任务的执行状态等
- 任务队列(TaskQueue):用于存放没有处理的任务,提供一种缓冲机制
- 所包含的方法
- ThreadPool()创建线程池
- getThreadPool()获得一个默认线程个数的线程池
- execute(Runnable task)执行任务,其实只是把任务加入到任务队列,什么时候执行由线程池管理规定
- execute(Runnable[] task)批量执行任务,同上
- destroy()销毁线程池,该方法保证所有任务都完成的情况下才销毁所有线程,否则等待任务完成才销毁
- 一个线程池包含以下四个基本组成部分
todo 这里需要对线程池的源码进行一下解析
17.java是否有内存泄漏和内存溢出?
- 静态集合类:使用Set,Vector,HashMap等集合类的时候规定,当哲学类被定义成静态的时候,由于他们的生命周期跟应用程序一样长,这个时候有可能发生内存泄漏
-
class StaticTest{ private static Vector v = new Vector(10); public void init(){ for(int I = 0 ; I < 100;i++){ Object object = new Object(); v.add(object); object = null; } } }
上面代码中,循环创建了Object对象,并添加到Vector中,然后设置为null,可是这些对象被Vector饮用者,因此不能被GC回收,因此造成了内存泄漏,因此要释放这些对象,还需要将他们从vector中删除,最简单的方法就是将Vector设置为null
-
- 监听器:在Java编程中,我们都需要和监听器打交道,通常一个程序中会用到很多监听器,但是在释放的时候没有去删除这些监听器,从而增加了内存泄漏的机会
- 物理连接:一些物理连接,比如数据库连接和网络连接,除非是显示的关闭了连接,否则是不会自动被GC回收的,java数据库谅解一般用datasource.getConnection()来创建,当不再适应必须用close()方法释放,因为这些连接时独立于JVM的,所以需要在try-catch-finally中释放连接
- 单例模式:因为单例对象初始化后在jvm的整个生命周期内存在,如果他持有一个外部对象的引用(生命周期比较短),那么这个外部对象就不能回首,从而导致内存泄漏,如果这个外部对象还持有其他对象的引用,那么内存泄漏更严重
18.concurrent包下面都用过什么(面试问过)
- concurrent下面的包
- Executor用来创建线程池,实现Callable接口,添加线程
- FutureTask此FutureTask的get方法所返回的结果类型
- TimeUnit
- Semaphore
- LinkedBlockingQueue
- 所用过的类
- Executor
19.volatile关键字如何保证内存可见性(面试问过)
- volatile关键字的作用
- 保证内存的可见性
- 防止指令重拍
- 注意:volatile不保证原子性
内存可见性
- volatile保证可见性的原理是在每次访问变量时都会进行一次刷新,因此每次访问都是主内存中最新的版本,索引volatile关键字的作用之一就是保证变量秀高的实时可见性
- 对变量的写入不依赖变量的当前值,或者你能确保只有当个线程更新变量的值
- 该变量没有包含在具有其他变量的不变式中
- 在两个或者更多的线程需要访问的成员变量上使用volatile,当要访问的变量已在synchronized代码扩种或者卫敞亮,没必要使用volatile
- 优于使用volatile屏蔽掉了jvm的必要的的代码优化,所以在效率上比较低,因此一定在必要时才使用此关键字
- volatile不会进行加锁操作,volatile是一种稍弱的同步机制在访问colatile变量是不会进行加锁操作,因此就不会执行线程阻塞,因此volatile变量是一种比synchronized更轻量级的同步机制
- volatile变量的作用类似于同步变量的读写操作:从内存可见性角度来看,写入volatile变量相当于推出同步代码块,而读取volatile变量相当于进入同步代码块
- volatile不如synchronized安全,在代码中如果过度依赖volatile变量来控制状态的可见性,通常会比使用锁的代码更加脆弱,也更难以理解,仅当volatile变量能简化代码的实现一机对同步策略的验证时,才应该适应它,一般来说,使用同步机制会更加安全一些
- volatile无法保证内存可见性和原子性,加锁机制(同步机制)既可以保证可见性又可以保证原子性,而volatile变量只能保证可见性,原因是生命为volatile的简单变量如果当前值与该变量以前的值相关,那么volatile关键字不起作用,也就是说如下的表达式都不是原子操作 count++,count = count+1
20.sleep和wait分别是哪个类的方法
- sleep和wait
- sleep是thread类的方法
- wait是object的方法
- 有什么区别
- sleep方法(休眠)是线程类的静态方法,调用此方法会让当前线程暂停执行指定的时间,将执行机会让给其他线程,但是对象的锁依然保持,因此休眠时间结束后会自定恢复(线程回到就绪状态)
- wait()是object的方法,调用对象的wait方法导致当前线程放弃对象的锁(线程暂停执行),进入到对象的等待池中,只有调用对象的notify方法才能唤醒等待池中的线程到对象等锁池中,如果线程重新获得对象的锁就可以进入就绪状态
21.synchronized和lock的区别(面试问过)
- synchronized与lock的区别
- synchronized(隐式锁):在需要同步的对象中架次控制,synchronized科技加载方法上也可以加载代码块中,括号中表示需要的锁的对象
- lock(显示锁):需要制定起始的位置和中止的位置,一般使用ReentrantLock类作为锁,多个线程必须使用一个ReentrantLock类作为锁,且加锁和解锁必须指出lock()和unlock(),一般会在finally中些unlock防止死锁
- 性能上synchronized是托管给jvm的,lock是java写的控制锁的代码,在1.5中synchronized性能低消,1.6以后做了优化,有适应性自旋,缩小出,锁粗话,轻量级锁,偏向锁等,并不比lock差
- 机制上synchronized原始采用的是CPU悲观锁,即线程独占锁,独占锁一位置其他线程只能依靠阻塞来等待线程释放锁,Lock用的是乐观锁方式,如果冲突就重试,直到成功,乐观锁的实现机制就是CAS操作。
22.synchronized的底层是如何实现的(面试问过)
- 底层实现:https://blog.csdn.net/javazejian/article/details/72828483 java虚拟机中的同步给予进入和退出管程(Monitor)对象实现,无论是显示同步有明确的monitorenter和monitorexit指令,即同步代码块,还是隐形的同步,同步方法并不是有指令实现的而是由方法的ACC_SYNCHRONIZED实现的,注意1.6以后的synchronized的优化-偏向锁,轻量级锁,自旋,锁清除等
- 用在代码块和方法上有什么区别
- synchronized用在代码块锁调用的是该方法的对象,也可以选择锁住任何一个对象
- synchronized用在方法上锁的是调用该方法的对象
- synchronized用在代码块可以减小锁的力度,从而提高兵法性能
- 无论用在代码块上还是用在方法上,都是获取对象的锁,每一个对象只有一个锁与之冠良,实现同步需要很大的系统开销作为代价,甚至可能造成死锁,所以尽量避免无所谓的同步控制
23.常见的异常分那两种?常见异常的积累以及常见的异常(概念模糊)
- Throwable是java语言中所有错误和异常的超类,他有两个子类:Error,Exception
- 异常种类
- Error:程序无法处理比如OutOfMemory,ThreadDeath等,出现这种情况只能由jvm处理,jvm大多数情况袭会选择终止线程
- Exception:Exception是程序可以处理的异常,他又分为受检查异常和不受检查异常
- 不受检查异常:发生在运行时期,具有不确定性,由程序逻辑引起的比如NullPorinterException
- 受检查异常:发生在编译阶段,必须使用try-catch(或者throws),否则编译不通过
24.java的NIO,BIO,AIO分别是什么(很重要的概念,一定要了解)
- BIO
- 同步并阻塞,服务器实现为一个连接一个线程,即客户端有连接请求时服务器端就需要启动一个线程进行处理,如果这个连接不做任何事情会造成不必要的线程开销,当然可以通过线程池机制改善。
- BIO方式适用于连接数小而且固定的架构,这种方式对服务器资源要求比较高,兵法句小雨应用中,jdk1.4的唯一选择,程序简单理解
- NIO
- 同步非阻塞,服务器实现模式为一个请求一个线程,即客户端发送的连接请求都归注册到多路复用器上,多路复用器轮训到连接有I/IO请求,才请求一个线程处理
- NIO方式适用于连接数目多且连接比较短(轻操作),比如聊天服务器,兵法局限于应用中,编程比较负载,jdk1.4开始支持
- AIO
- 异步非阻塞,服务器实现模式为一个有效的请求一个线程,客户端的I/O请求都是由OS先完成了再通知服务器应用去启动线程处理
- AIO方式适用于连接数目过多且连接比较长(重操作),比如相册服务器,充分利用OS参与兵法操作,编程比较复杂7以后才支持
25.所了解的设计模式,单例模式的注意事项,jdk源码用到了哪些设计模式(个人觉得也是非常重要的概念)
- 所了解的设计模式
- 工厂模式:定义一个用于创建对象的接口,让子类决定是梨花哪一个类,factory method是一个类的是梨花延迟到子类
- 单例模式:保证一个类只有一个示例,并提供一个访问他的全局访问点
- 适配器模式:将一类的接口转换成客户希望的另一个接口,adapter模式是的原本不兼容而不能一起工作的那些类可以一起工作
- 装饰者模式:动态地给一个对象增加一些额外的职责,就增加功能来说,Decorator模式相比于孜勒更加的灵活
- 代理模式:为其他对象提供一种代理一控制这个对象的访问
- 迭代器模式:提供一个方法顺序访问一个聚合对象的哥哥元素,而又不暴露该对象的内部表示
- 单例模式的注意事项
- 尽量使用懒加载
- 重重检索实现线程安全(double-check)
- 构造方法为private
- 定义静态的singleton instance对象和getInstance方法
- jdk源码中用到的设计模式
- 装饰者模式:I/O流
- 迭代器模式:Iterator
- 单例模式:Runtime
- 代理模式:RMI
todo 设计模式一定要多了解
26.匿名内部类是什么?如何访问在其外面定义的变量
- 匿名内部类是什么
- 您名内部类是是没有访问修饰符的
- 所以当所在方法的形参需要被匿名使用,那么这个形参就必须为final
- 匿名内部类没有构造方法,因为他连名字都没有
- 如何访问在外面定义变量
- 必须定义为final
27.如果你定义一个类,包括学好,姓名,分数没如何把这个对象作为key?要重写equals和hashcode么?
- 需要重写equals和hashcode方法,必须保证对象的属性改变时hashcode不变
28.为什么要实现内存模型(不是JVM,是JMM很重要,面试可能会问)
- 内存模型就是为了在现代计算机平台中保证程序可以正确性的整形,但是不同平台的实现时不同的
- 编译器中生成的指令顺序可以与源代码中的顺序不同
- 编译器可以吧变量保存在寄存器中而不是内存中
- 处理器可以采用乱序或并行等方式来执行指令
- 缓存可能会改变将写入变量提交到主内存的次序
- 保存在处理器本地缓存中的值对其他处理器是不可见的
数据库知识
1.常用的数据库有哪些?redis用过么?
- 常用的数据库
- mysql,sqlServer
- redis
- redis是一个速度非常快的非关系性数据库,他可以存储建雨5中不同类型的值,可以讲存储在内存中的简直数据持久化到磁盘中
- 与memcached相比
- 两者都可用于存储键值映射,彼此性能也相差无几
- redis能够自动以两种不同的方式将数据写入硬盘
- reids除了能存储普通的字符串之外,还可以存储其他四种结构,memcached只能存储字符串
- redis既能用做主数据库,又可以作为其他存储系统的辅助数据库
2.数据库索引的优缺点以及是么时候数据库索引失效(面试问过)
- 索引的特点
- 可以加快数据库检索的速度
- 降低数据库插入,修改,删除等维护的速度
- 只能创建在表上,不能创建在视图上
- 既可以直接创建又可以间接创建
- 可以在优化隐藏中使用索引
- 使用查询处理器执行sql语句,在一个表上,一次只能使用一个索引
- 索引的优点
- 创建唯一性索引,保证数据库中每一行数据的唯一性
- 大大加快数据检索速度,这是创建索引的主要原因
- 加快数据表之间的连接,特别是在实现数据的参考完整性方面有特别的意义
- 在使用分组和排序子句进行数据检索是,同样可以显著减少查询中分组和排序的时间
- 通过使用索引,可以在查询中使用优化隐藏起,提高系统的性能
- 索引的缺点
- 创建索引和维护索引要耗费时间,这种时间随着数据量的增加而增加
- 索引需要占用物理空间,除了数据表占用数据空间之外,每一个索引还要占一定的物理空间,如果简历聚簇索引需要的空间就会更大
- 当对应的表数据进行增加,删除和修改的时候,索引也需要维护,降低数据维护的速度
- 索引的分类
- 直接创建索引和间接创建索引
- 普通索引和唯一性索引
- 单个索引和复合索引
- 聚簇索引和非聚簇索引
- 索引失效
- 如果条件中有or,即时其中有条件带来索引也不会使用
- 对于多列索引,不是使用的第一部分,则不会使用索引
- like查询是一%开头的
- 如果列类型是字符串,那一定要在条件中用引号引起来,否则不会使用索引
- 如果mysql估计使用全表嫂面壁使用索引快,则不使用索引
- 各引擎支持的索引
- 略过了
3.事务的隔离级别(这个概念很重要)
- 读未提交
- 最低的隔离级别,允许其他食物看到没有提交的数据,会导致脏读
- 读已提交
- 被读取的数据可能被其他事物修改了,这样可能导致不可重复读,也就是说,是武都区的时候获取锁,但是再度娃之后立刻释放(不需要等待十五结束),而写锁则是事务提交之后才释放,释放毒素哦之后就可能被其他事务修改数据,该等级也是sqlServer默认的隔离等里
- 可重复读
- 所有被select修改过的数据都不能被修改,这样可以避免一个事物前后读不一致的情况,但是没办法控制幻读,因为这个时候其他事务不能更改所选的数据,但是可以新增数据,因为该事务没有范围锁
- 串行化
- 所有事物一个接着一个的被执行,这样就可以避免幻读,对于给予锁来实现兵法控制的数据库来说,串行化要求在执行范围查询的时候,需要获取范围锁,如果不是给予锁实现并发控制的数据库,则检查有违反串行操作的食物,则需要回滚事务
隔离界别 | 脏读 | 不可重复度 | 幻读 | |
读未提交 | 可能 | 可能 | 可能 | |
读已提交 | 不可能 | 可能 | 可能 | |
可重复读 | 不可能 | 不可能 | 可能 | |
串行化 | 不可能 | 不可能 | 不可能 |
4.数据库中的范式(概念薄弱,需要注意)
- 目前关系型数据库有六种范式:第一范式,第二范式,第三范式,巴斯克等范式,第四范式,第五范式,一般来说满足第三范式就足够了
- 范式
- 1NF:每个属性都不可再分
- 2NF:属性完全依赖与主键(消除部分子函数依赖)
- 3NF:属性不依赖于其他非主属性
- BCNF:任何非主属性不能对主键子集依赖
- 4NF:要求同一表内的多对多关系删除
- 5NF:从最终结构重新建立原始结构
5.数据库中的索引结构?什么情况下适合建索引
- 数据库中的索引结构
- 因为在使用二叉树的时候由于二叉树的深度过大而造成I/O读写过于频繁,进而导致查询效率低下,因此采用多茶树结构,B树的各种操作能是B树保持较低的高度
- B树又叫平衡多路查找树,一个m阶的B树特性如下:
- 树中的每个节点最多含有m个孩子(m>=2)
- 除了根节点和叶子节点外,其他每个节点至少有[ceil(m/2)]个孩子(其中ceil(x)是取上限的函数)
- 根节点至少有两个孩子
- 所有叶子节点都出现在同一层,叶子节点不包含任何关键字信息
- B+树
- 在什么情况下适合建立索引
- 为经常出现在关键字order by,group by,distinct后面的字段,建立索引
- 在union等集合操作的结果,建立索引,其建立索引的目的同上
- 为经常用做查询选择字段,建立索引
- 为经常用做表连接的属性上建立索引
- 考虑使用索引覆盖,对数据很少被更新的表,如果用户进场只查询其中几个字段,可以考虑在这几个字段上建立索引,从而将表的扫面变为索引的扫描
6.redis的存储结构,或者说如何工作,与mysql的区别,有哪些数据类型(面试问过)
- redis的数据结构
- string:可以是整数,字符串,浮点数
- list:一个链表,链表上的每个节点都包含了一个字符串
- set:包含了字符串的无需收集器,并且被包含的字符串都是独一无二,各不相同的
- hash:包含键值对的无序散列表
- zset:字符串成员于浮点数之间的有序映射,元素的排列顺序有分值的大小决定
7.数据库中分页查询语句怎么写
- mysql的limit用法
- select from table limit offset ,size
8.数据库ACID(基本概念)
- 原子性:保证事务中的所有操作全部执行或者全不执行
- 一致性:保证数据库始终保持数据的一致性-事务操作之前和之后是一致的
- 持久性:事务操作完成之后对数据库的影响是持久的,即便是市局哭因故障而受到破坏,数据库也能恢复
- 隔离性:多个事务并发的时候结果应该是互不影响的,也就是结果应该与多个事务穿行执行结果一样的
9.脏读,不可重复读和幻读(也是基本概念)
- 脏读:事务T1更新了一行记录,但是没有提交所做的修改,T2读取更新后的行,然后T1执行了回滚操作,取消了刚才所做的修改,现在T2读取的行就无效了
- 不可重复读:事务T1读取一行记录,紧接着T2修改了T1刚才读取的一行记录,T1又再次读取这行记录,发现与刚才读取的结果不同
- 幻读:事务T1读取一条指定的where子句所返回的结果,然后T2事务新插入一行记录,这行记录刚好可以满足T1所使用的查询条件,然后T1再次查询,发现多了一行
10.MyISAM和InnoDB引擎的区别(基本概念)
- 主要区别
- MyISAM是非事务安全性,而InnoDB是事务安全性
- MyISAM锁的粒度是表级的,而InnoDB支持行级锁
- MyISAM支持全文索引,InnoDB不支持
- MyISAM相对简单,效率相对优于InnoDB
- MyISAM表是保存成文件的形式,在跨平台的数据转移中使用MyISAM存储会省去不少的麻烦
- InnoDb表比ISAM表更安全,可以保证数据不会丢失的情况,切换非事务表到事务表
- 应用场景
- MyISAM管理非事务表,它提供高速存储和检索,如果应用中需要执行大量的select查询,那么MyISAM是更好的选择
- InnoDB用于事务处理应用程序,具有众多特性,包括ACID事务的支持,如果应用中需要执行大量的insert,update,则应该使用Inn oDB
JAVA虚拟机
1.JVM垃圾处理方法
- 标记-清除算法
- 标记阶段:先通过根节点,标记所有从根节点开始的对象,未被标记的为垃圾对象
- 清除阶段:清除所有未被标记的对象
- 复制算法
- 将原有的内存空间分为两块,每次只使用一块,在垃圾回收时,将正在使用的内存中的存活对象复制到未使用的呢村块中,然后清除正在使用的内存块中的所有对象
- 标记-整理算法
- 标记阶段:先通过根节点,标记所有从根节点开始的对象,未被标记的为垃圾对象
- 整理阶段:将所有存活对象压缩到内存的一端,之后清理边界的所有空间
- 三种算法的比较
- 效率:复制算法=标记整理>标记清除
- 内存整齐度:复制算法=标记整理>标记清除
- 内存利用率:标记整理>标记清除>复制算法
2.JVM如何GC,新生代,老年代,持久代都存储哪些东西,以及各个区的作用
- 新生代
- 在方法中去new一个对象,那这方法调用完毕后,对象就会被回收,这就是一个典型的新生代对象
- 老年代
- 在新生代中经历了N次来几回收后仍然存活的对象就会被放到老年代中,而且大对象直接进入到老年代
- 当survivor空间不够用时,需要依赖于老年代进行分配担保,所以大对象直接进入老年代
- 永久代
- 即方法区
担保机制需要深入了解一下
3.GC用的引用可达性分析算法中,哪些对象可作为GC ROOTS的对象(重要概念)
- java虚拟机栈中的对象
- 方法区中的静态对象
- 方法区中的常量引用对象
- 本地方法区中JNI(Native方法)引用对象
4.什么时候进行MinGC,FullGC
- MinGC:
- 新生代中的垃圾收集动作,采用的是复制算法
- 对于较大的对象,在MinorGC的时候可以直接进入到老年代
- FullGC:
- FullGC是发生在老年代的垃圾收集动作,采用的是标记清除/整理算法
- 由于老年代的对象几乎都是Survivor区煎熬过老的不会那么容易死掉,因此FullGC触发的不是那么的频繁
这里感觉FullGC理解有误区,要重新学习
什么时候触发FullGC请看这里
5.各个垃圾收集器是怎么工作的
- Serial收集器
- 是一个单线程收集器,不是只能使用一个CPU,在进行垃圾收集时,必须暂行其他所有的工作线程,知道收集结束
- 新生代采用复制算法,stop-the-world
- 老年代采用标记整理算法,stop-the-world
- 简单高效,client模式下默认的新生代收集器
- ParNew收集器
- ParNew收集器时Serial收集器的多线程版本
- 新生代采用复制算法,stop-the-world
- 老年代采用标记整理算法,stop-the-world
- 它是运行在server模式下的首选的新生代收集器
- 除了serial收集器之外,只有他能和CMS收集器配合工作
- ParNew Scanvenge收集器
- 类似ParNew收集器,但更加关注吞吐量,目标是:达到一个可控制吞吐量的收集器
- 停顿时间和吞吐量不可能同时调优,我们一方面希望停顿时间减少,另一方面希望吞吐量高,这是矛盾的,因为在GC的时候,来及回收工作总总量不变,如果停顿时间减少,那频率就会提高,既然频率提高了,说明就会进行GC吞吐量就会减少,性能会降低
- G1收集器
- 是当今收集器发展的最前沿成果之一,对垃圾回收进行了划分优先级的操作,这种优先级的区域回收方式保证了他的高效率
- 最大的优点就是结合了空间整合,不会产生大量的碎片,也降低了进行gc的频率
- 让使用者明确指定停顿时间
- CMS收集器(兵法标记清除老年代收集器)
- 一种以获得最短回收停顿时间为目标的收集器,适用于互联网站或者B/S系统的服务器
- 初始标记(stop-the-world):跟可以直接关联到的对象
- 并发标记(和用户线程一起):主要标记过程,标记全部对象
- 重新标记(stop-the-world):由于并发标记,用户线程依然运行,因此在正式清理钱,在做修正
- 并发清除(和用户线程一起):基于标记结果,直接清理对象
- 并发收集,低停顿
6.Java虚拟机内存的划分,每个区域的功能
- 程序计数器(线程私有)
- 虚拟机栈(线程私有)
- 本地方法栈(线程私有)
- java堆
- 方法区
- 运行时常量池
7.用什么工具可以查出内存泄漏
- MemoryAnalyzer
- EclipseMAT
- JProbe
8.JVM如何加载一个类的过程,双亲委派模型中,哪些方法有没有可能父类加载器和子类加载器同一个类,该使用哪一个类
- 双亲委派概念
- 加载器
- 结果加载同一个类,该使用哪一个类
9.JVM线程死锁,你该如何判断是因为什么?如果用VisualVM,dump线程信息出来,会有哪些信息
- 常常需要在个两分钟后在收集一次thread dump,如果得到输出结果相同,仍然是大量thread都在等待给同一个地址上上锁,那么肯定死锁了
10.java是如何进行对象实例话的
11.Student s = new Student(),在内存中做了哪些事情?(流程了解一下)
- 加载Student.class文件进内存
- 在栈内为s开辟空间
- 在堆内存为学生对象开辟空间
- 为学生对象的成员变量进行默认初始化
- 为学生对象的成员变量进行显示初始化
- 通过构造方法为学生对象的成员变量赋值
- 学生对象初始化完毕,把对象地址复制给s变量
12.了解JVM调优没,基本思路是什么(面试应该会问)
JSP和Servlet(这里有很多知识点要学一下)
1.保持会话状态,有哪些方式,区别如何?(这里也是重点)
- 由于http协议本身是无状态的,服务器为了区分不同的用户,就需要对用户绘画进行跟踪,简单的说就是为了用户进行登记,为用户分配一个id,下次用户在请求中包含此id,服务器就会判断到底是哪一个用户
- url重写:在url中添加用户绘画的信息作为请求的参数,或者将唯一会话的id添加到url结尾一标识一个绘画
- 设置表单以藏于:将会话跟踪相关字段添加到隐式表单中,这些信息不会再浏览器中显示但是提交表单时会提交给服务器
- 这两种方式很难处理跨越多个页面的信息传递,因为如果每次都要修改url活在页面中添加隐式表单来存储用户绘画相关信息,事情将会变的非常满帆
2.cookie和session的区别(面试问过)
- session存储在服务器端,cookie存储在客户端
- session运行依赖sessionid,而sessionid存在cookie中,也就是说如果cookie禁用了,同时session也会失效
- session可以放在文件,数据库,或者内存中
- 用户验证这种场合一般会用session
- cookie不是很安全,别人可以分析存放在本地的cookie并且进行cookie欺骗,考虑到安全应该使用session
- session会在一定时间呗保存在服务器上,当访问增多,会比较占用服务器的性能考虑到减轻服务器的压力应当使用cookoe
- 单个cookie不能超过4k,很多浏览器都会限制一个站点最多保存20个cookie
3.servlet的生命周期
4.JSP和Servlet的区别
计算机网络
1.http和https的区别
- http是http协议运行在tcp之上,所有传输的内容都是明文,客户端和服务器都无法验证对方的身份
- https是http运行在ssl/tls智商,ssl/tls运行在tcp之上,所有传输的内容都经过加密,加密采用对称加密,但对成加密的秘钥用服务器房的整数进行了肺对成加密,此外客户端可以验证服务器的身份,如果配置了客户端验证,服务方也可以验证客户端的身份
- https协议需要用到ca申请证书,一般免费的证书很少,需要交费
- http是超文本传输协议,信息是铭文传输,https则是具有安全性的加密传输协议
- http和https使用完全不同的连接方式,用的端口也不一样,前者是80,后者是443
2.tcp如何保证可靠性传输?三次握手过程
- tcp如何保证可靠传输
- 数据包校验
- 超时重传机制
- 应答机制
- 对失序数据包进行重排序
- TCP还能提供流量控制
- 三次握手以及四次挥手
3.为什么tcp连接需要三次握手,两次不可以么?
- 为了防止已失效的连接请求突然又传送到了服务端,而产生错误
- 例子
- 已失效的连接请求报文的产生在这样一种情况下,client发出的第一个连接请求报文段并没有丢失,而是在某个网络节点长时间的滞留了,一直延误到了连接释放以后的某个时间才到server,本来这是一个早已失效的报文段,但是server收到次失效的连接请求报文段后,误认为是client再次发出的心的连接的请求,于是就想client发出确认报文段,同意建立连接,假设不采用三次握手,那么只要server发出确认新的连接就建立了,,由于现在client并没有发出连接请求,因此不会理会server的确认,也不会向server发送数据,但server却以为新的运输连接已经建立,并一直等待client发来数据,这样server许多资源就浪费了,利用三次握手可防止以上事情发生
4.如果客户端不断的发送请求连接会怎么样
5.get和post的区别
- GET被强制服务器支持
- 浏览器对URL的长度有限制,所以GET请求不能代替POST请求发送大量数据
- GET请求发送数据更小
- GET请求是不安全的
- GET请求是幂等的
- POST请求不能被缓存
- POST请求相对GET请求是安全的
- 以下情况,请使用POST请求
- 无法使用缓存文件
- 向服务器发送大量数据(POST没有数据量限制)
- 发送包含未知字符的用户输入,POST比GET更稳定也更可靠
- POST比GET安全性更高
6.tcp和udp的区别
- TCP和UDP的区别
- udp是无连接的,即发送数据之前不需要建立连接
- udp使用尽量最大努力教父,即不保证可靠教父,同时也不使用拥塞控制
- udp是面向报文的,udp没有拥塞控制,很适合多媒体通信要求
- udp支持一对一,一对多,多对一,多对多的交互通信
- udp的首部开销少,只有8个字节
- tcp是面向连接的运输层协议
- 每一条tcp连接只能有两个端点,每一个tcp连接只能是点对点的
- tcp提供可靠交付的服务
- tcp提供全双工通信
- tcp是面向字节流的
- 首部最低20个字节
- tcp加快传输效率的方法
- 采用一块确认的机制
7.滑动窗口算法
8.tcp的阻塞处理
- 慢启动
- 拥塞避免
- 拥塞发生
- 快速恢复
9.从输入网址到获取页面的过程
- 查询DNS获取域名对应的IP地址
- 浏览器自身的DNS缓存
- 搜索操作系统的DNS缓存
- 发起一个DNS的系统调用
- 宽带运营服务器查看本身缓存
- 运营商服务器发起一个迭代DNS解析请求
- 浏览器获得域名对应的ip地址后,发起http三次握手
- tcp/ip建立起来后,浏览器就可以向服务器发送http请求了
- 服务器接收到这个请求,根据参数,经过后端处理生成html页面代码返回给浏览器
- 浏览器拿到代码开始解析渲染,如果引用外部JS,CSS等,他们同样也是一个个的http请求,都要经过上面的步骤的
- 渲染后把一个完整的页面呈现给用户
10.说一下http请求(面试问过)
常用算法
1.如何判断一个单链表是否有环
public static boolean hasCycle(ListNode head) { ListNode quick = head; ListNode slow = head; //循环判断一下当前的slow是不是为空 ,quick是不是为空 quick.next是不是空 while(slow != null && quick != null && quick.next != null ){ slow = slow.next; quick = quick.next.next; if(slow == quick){ return true; } } return false; }
2.快速排序,过程,复杂度?什么情况下适用,不适用
3.什么是二叉平衡树,如何插入节点,删除节点
4.二分搜索的过程
5.归并排序的过程,时间复杂度,空间复杂度
6.给你一万个数,如何找出里面的所有的重复的数,用你能想到的方法,时间和空间复杂度分别是多少
7.给你一个数组,如何找到和为K的两个数
8.100000个数找出最小或最大的10个
操作系统
以上是关于第一篇的主要内容,如果未能解决你的问题,请参考以下文章