Q:面向过程和面向对象的区别?
面向过程是以事件为中心的,首先分析解决问题的步骤,然后用函数实现,并按照步骤顺序调用相关的函数。
面向对象是以对象为中心的,首先根据问题,分析问题中包含的对象以及对象的属性和行为,从而抽象得到类以及数据和方法,然后实现类中的方法细节,最后根据问题描述,实例化对象并调用相应的方法解决问题。
Q:Java的基本特性?
抽象:将一类对象的共同特征总结出来,构造类的过程,包括数据抽象和行为抽象。数据抽象是对该类对象的共同属性特征进行提取,行为抽象是对该类对象的共同行为特性进行提取。
继承:从已有的类中得到继承信息的过程,提供继承信息的类称为父类(基类、超类),得到集成的类称为子类(派生类)。继承为变化中的软件系统提供了延续性。
封装:把数据和操作封装起来,外部对数据的访问只能通过调用已定义的接口,外部对具体的属性以及方法的实现细节不关心,只需要直接调用相关的方法实现相关的功能。类就是一个实现封装的数据结构。
多态:同类对象或不同子类的对象对同一消息做出不同的响应。实现多态的方法包括方法重载和方法重写,其中方法重载属于编译时的多态性,在同一个类中,同名的方法如果有不同的参数类型或参数个数则被视为方法重载;方法重写属于运行时的多态性,子类中重写父类的同名方法,二者方法的参数类型、参数个数、返回值类型都完全相同,在子类对象调用相关方法时,直接调用子类重写后的方法,因此可以实现不同子类对统一消息做出不同的响应。
Q:覆盖Overriding和重载Overloading的区别?
覆盖是在运行是决定的,重载是在编译时决定的。
Q:Static和final的区别?
static修饰的变量是指类变量,需要在类加载时进行初始化,java虚拟机只为其分配一次内存,被同类的所有对象共享;final修饰的变量表示常量,不能被改变,在类加载时进行初始化。static修饰的方法是指类方法,在类加载时就存在,不依赖任何实例,不能用abstract修饰。static修饰的代码块,在类加载时就会执行。
final修饰的变量相当于常量,在类加载时就存在,需要初始化,不能被改变。final修饰的类和方法都不能被继承,final修饰的形参不能改变。
Q:Hash Map和Hash Table的区别?
Q:Java序列化和反序列化?
Java序列化:将数据转换成字节序列的过程。即把内存中的数据对象转换为一连串字节描述的过程。什么情况下需要序列化:(1)把内存中的对象状态保存到文件或数据库中;(2)使用套接字在网络上传送对象时;(3)通过RMI(远程方法调用:能够让在客户端Java虚拟机上的对象像调用本地对象一样调用服务端java 虚拟机中的对象上的方法)传输对象。其好处一是实现了数据的持久化,通过序列化可以把数据永久地保存到硬盘上(通常存放在文件里),二是,利用序列化实现远程通信,即在网络上传送对象的字节序列。
Java反序列化:将字节序列恢复为对象的过程。
序列化的实现方法:实现java.io.Serializable接口,如果不实现ExternalSerializable方法,则调用默认的序列化方法,如果实现ExternalSerializable方法,则可以自主地对序列化的内容进行控制,控制哪些属性可以被序列化,哪些属性不能被序列化。
注意:static属性不能被序列化;方法不会被序列化;反序列化时必须有序列化对象的class文件。
实现序列化的协议:COM主要用于Windows平台;CORBA、XML&SOAP、JSON、Thrift、Protobuf、Avro。
Q:Java实现多线程的方法?
继承Thread类,重写run方法
实现Runnable接口
实现Callable接口
Q:内存泄漏和内存溢出?
内存溢出OutOfMemory:分配的内存不足以放得下数据项序列。如栈满时再进栈必定会产生空间溢出,称为上溢,栈空时元素出栈也会产生空间溢出,称为下溢。
内存溢出的原因:(1)内存中加载的数据量过于庞大,如从数据库中取出的数据太多,内存没有足够的空间存放。(2)代码中存在死循环或者循环产生过多重复的对象实体。(3)java虚拟机的启动参数中内存值设置过小。(4)集合类中有对对象的引用,使用完后未清空,使得JVM不能回收。
内存溢出的解决办法:(1)使用内存查看工具动态查看内存使用情况。(2)对代码进行分析,找出可能发生内存溢出的位置。(3)修改java虚拟机的启动参数,增加内存分配量。
内存泄漏:资源使用时申请了空间,但是用完之后没能释放资源,内存依旧被占用,内存泄漏多次会导致内存溢出(上溢)。一般所说的内存泄漏是指堆内存的泄漏,堆内存用于程序的动态内存申请和使用。C/C++中有free函数可以释放内存,java中有垃圾回收机制自动释放内存。
内存泄漏的分类:(1)常发性内存泄漏:发生内存泄漏的代码会被多次执行,引起多块内存的泄漏。(2)偶发性内存泄漏:发生内存泄漏的代码只有在特定的环境或操作过程中才会发生。(3)一次性内存泄漏:发生内存泄漏的代码只会被执行一次,可能是由于算法上的缺陷。如在类的构造函数中分配了内存但是没有在析构函数中释放内存。(4)隐式内存泄漏:程序在运行过程中不停分配内存,直到程序运行结束后才释放内存,但是如果程序运行时间太久,在程序执行过程中的内存泄漏累积也会导致内存溢出。
Q:sleep和wait的区别?
sleep是线程Thread类的静态方法,调用该方法会让当前线程暂时停止执行,将时间让给其他线程,但是对象的锁依然保持,休眠期结束后自动恢复就绪状态。
wait是对象object类的方法,调用该方法会导致当前线程放弃对象的锁,进入对象的等待池中,只有调用对象的notify()方法才能唤醒对象等待池中的线程,从而进入锁等待池,如果线程获得了对象锁则会进入就绪状态。
Q:响应式Web设计及其实现方法?
响应式Web设计:一套应用程序的Web页面(UI)能自动响应不同设备窗口或屏幕尺寸,并且内容和布局渲染良好。
自适应式Web设计:一套应用程序使用多版本用户界面,根据不同设备窗口或屏幕的尺寸服务器端返回不同版本的用户界面,供用户访问。
响应式设计大致可以分为五类:Mostly fluid(浮动式布局模式是一种多列布局,在大屏幕上设置较大的margin,在移动端会浮动后续列,垂直堆叠排列)、Column drop(断列式布局模式是一种多列布局方式,在移动端垂直堆叠排列,随着屏幕增大,将各列平铺排列)、layout shifter、tiny tweaks(微调式布局模式是单列布局模式,随着视口宽的增加,改变字体大小、padding、margin间距,保证内容可连续性)、off canvas(分屏式布局模式是在大屏幕上可选择性的铺开展示,在小屏幕上优先显示主要内容,将不常用或非主要的内容放在屏幕外左右两侧,点击可以切换显示或隐藏)。选择其中的一种或者多种可以实现响应式UI。
Q:Java Web开发中常用数据库?Redis用过吗?
关系型数据库MySQL、SQL Server、Oracle,面向磁盘的数据库,主页访问量瞬间较大的时候,单一使用数据库来保存数据的系统会因为面向磁盘,磁盘读/写速度比较慢的问题而存在严重的性能弊端,一瞬间成千上万的请求到来,需要系统在极短的时间内完成成千上万次的读/写操作,这个时候往往不是数据库能够承受的,极其容易造成数据库系统瘫痪。
NoSQL技术Redis、MongoDB,是基于内存的数据库,Redis是一种速度很快的非关系数据库,可以支持每秒十几万此的读/写操作,可以存储key和5中不同类型的value之间的映射,可以将存储在内存中的键值对数据持久化到硬盘中。它还支持一定的事务能力,这保证了高并发的场景下数据的安全和一致性。还支持集群、分布式、主从同步等配置,原则上可以无限扩展,让更多的数据存储在内存中。
Redis 在 Java Web 主要有两个应用场景:
- 存储 缓存 用的数据;把数据放在 Redis 中,也就是直接放在内存之中,让服务端直接去读取内存中的数据,那么这样速度明显就会快上不少,并且会极大减小数据库的压力,限于成本的原因,一般我们只是使用 Redis 存储一些常用和主要的数据,比如用户登录的信息等。如果命中率很低,就没有必要写入缓存;如果写操作多,频繁需要写入数据库,也没有必要使用缓存;如果要存储几百兆字节的文件,会给缓存带来很大的压力,这样也没有必要。当第一次读取数据的时候,读取 Redis 的数据就会失败,此时就会触发程序读取数据库,把数据读取出来,并且写入 Redis 中;当第二次以及以后需要读取数据时,就会直接读取 Redis,读到数据后就结束了流程,这样速度就大大提高了。
- 需要高速读/写的场合使用它快速读/写;使用 Redis 来应对高并发需求的场合。当一个请求到达服务器时,只是把业务数据在 Redis 上进行读写,而没有对数据库进行任何的操作,这样就能大大提高读写的速度,从而满足高速响应的需求;但是这些缓存的数据仍然需要持久化,也就是存入数据库之中,所以在一个请求操作完 Redis 的读/写之后,会去判断该高速读/写的业务是否结束,这个判断通常会在秒杀商品为0,红包金额为0时成立,如果不成立,则不会操作数据库;如果成立,则触发事件将 Redis 的缓存的数据以批量的形式一次性写入数据库,从而完成持久化的工作。
Q:数据库索引?
索引的概念:索引是一种数据结构,是为了加速对表中元组的检索而创建的一种分散存储结构(B树、B+树、哈希表),索引是对表建立的,由索引页面组成。由根据索引页面、中间层索引页面、叶级索引页面组成,其中叶级索引页面是指向数据页面的指针。索引的建立可以加快检索速度,但同时也减慢了更新速度。
索引的特点:可以加快数据库的检索速度;减慢了数据库插入、修改、删除等维护的速度;索引只能创建在表上,不能创建在视图上;索引既可以直接创建又可以间接创建;在使用查询处理器执行SQL语句时,一个表上一次只能使用一个索引。
索引的优点:创建唯一性索引保证数据库表中每一行数据的唯一性。大大加快了数据检索的速度,这是创建索引的主要原因;加速数据库之间的连接,特别是在实现数据的参照完整性方面具有特别意义。在使用分组和排序子句进行数据检索时,可以显著减少查询中的分组和排序时间。
索引的缺点:创建索引和维护索引需要耗费时间;索引需要占用物理空间;在对表中数据进行修改时,索引也需要维护,降低了数据维护的速度。
索引分类:(1)直接创建索引和间接创建索引。(2)普通索引和唯一性索引。(3)单个索引和复合索引。(4)聚簇索引和非聚簇索引。建立聚簇索引后,表中元组的物理位置按照聚簇索引的顺序存放;建立非聚簇索引后,表中元组的物理位置顺序和非聚簇索引的顺序无关。一个表只能有一个聚簇索引,可以有多个非聚簇索引。
建立索引的原则:在经常需要搜索的列上,可以加快搜索的速度。在经常使用在WHERE子句中的列上面创建索引,加快条件的判断速度。在经常需要排序的列上创 建索引,因为索引已经排序,这样查询可以利用索引的排序,加快排序查询时间。
索引失效:(1)如果条件中有or,即使其中有条件带索引也不会使用;(2)对于多列索引,不是使用的第一部分,则不会使用索引;(3)like查询是以%开头的;(4)如果列类型是字符串,那一定要在条件中使用引号引起来,否则不会使用索引;(5)如果表内数据较少,mysql估计全表扫描比索引快,则不用索引。
为什么索引会增加检索速度:数据库在执行一条SQL语句对表中的数据进行检索时,会进行全表扫描,从而找出符合条件的元组,表越大,则花费的时间越长。针对表中的某一列或多列构造索引后,查询时就会现在索引列表中进行查询,从而定位到相关的行,减少了遍历和匹配的行数,DB在执行一条Sql语句的时候,默认的方式是根据搜索条件进行全表扫描,遇到匹配条件的就加入搜索结果集合。如果我们对某一字段增加索引,查询时就会先去索引列表中一次定位到特定值的行数,大大减少遍历匹配的行数,所以能明显增加查询的速度。缺点是它减慢了数据录入的速度,同时也增加了数据库的尺寸大小。
为什么索引会减慢数据库更新速度:因为在进行数据库的更新时,索引自身的存储结构也需要维护,因此会增加额外的索引维护时间,以B+树为例,B+树是一颗平衡树,如果对树中的节点进行增删改的话,可能会破坏它的结构,为了维持平衡树,就需要做额外的维护工作。
Q:数据库的基本操作?
create 创建表、drop删除表、alter修改表
insert 插入数据、update更新数据、delete删除数据(delete和truncate的区别在于delete是针对行数据的删除,truncate是清空标表中的所有数据,而且delete支持事务回滚,操作会记录在日志文件中,truncate的速度更快。)
Q:事务的概念、特性?
事务是用户定义的一个操作序列,这些操作要么不做,要么全做。在数据库中事务可以是一条SQL语句、一组SQL语句或整个程序。
事务的ACID特性:原子性——事务是数据库逻辑工作的基本单位,事务中的所有操作要么不做,要么全做。一致性——事务的执行会使数据库从一个一致性状态转换成另一个一致性状态,其中一致性状态是指数据库目前只包含事务成功提交后的结果。隔离性——一个事务不能被其他事务所干扰,即事务内部操作以及使用的数据对其他事务都是隔离的。持久性——事务一旦提交,对数据库的改变是永久性的。
并发事务导致的问题:丢失修改——多个事务同时对数据进行修改,事务提交之后会丢失某个事务对数据的修改。读脏数据——在一个事务处理过程中读取了另一个事务未提交的事务中的数据。不可重复读——一个事务两次读取同一行的数据,结果得到不同状态的结果,中间正好另一个事务更新了该数据。
事务的隔离级别有4种:(1)读未提交——一个事务可以读取另一个事务未提交的数据(造成读脏数据)。(2)读提交——一个事务要等另一个数据提交后才能读取数据(避免读脏数据)。(3)重复读——在开始读取数据时,不再允许修改(可避免读脏数据、不可重复读)。(4)序列化——事务串行化顺序执行(避免读脏数据、不可重复的、丢失修改)
【大部分数据库的默认事务隔离级别为读提交,如SQL Server、Oracle,MySQL的默认隔离级别是重复读。】
Q:数据库主从复制原理?
主从复制是指从数据库服务器主节点复制一个或多个从节点。MySQL 默认采用异步复制方式,这样从节点不用一直访问主服务器来更新自己的数据,数据的更新可以在远程连接上进行,从节点可以复制主数据库中的所有数据库或者特定的数据库,或者特定的表。
主从复制的主要用途:(1)读写分离—主节点的数据库负责写操作,从节点的数据库负责读操作。(2)数据实时备份—可以在节点发生故障时,方便数据库恢复以及数据库之间的切换。(3)架构扩展—随着系统中业务访问量的增大,如果是单机部署数据库,就会导致I/O访问频率过高。有了主从复制,增加多个数据存储节点,将负载分布在多个从节点上,降低单机磁盘I/O访问的频率,提高单个机器的I/O性能。
主从复制的流程:MySQL的主从复制主要涉及三个线程,一个是运行在主节点的log dump thread,其余两个是运行在从节点的I/O thread和SQL thread。当从节点连接主节点时,主节点会创建一个log dump thread用于发送bin-log内容,在读取bin-log中操作时,此线程会对主节点上的bin-log加锁,当读取完成,甚至在发动给从节点之前,锁会被释放。当从节点上执行`start slave`命令之后,从节点会创建一个I/O线程用来连接主节点,请求主库中更新的bin-log。I/O线程接收到主节点binlog dump 进程发来的更新之后,保存在本地relay-log中。SQL线程负责读取relay log中的内容,解析成具体的操作并执行,最终保证主从数据的一致性。对于每一个主从连接,都需要三个进程来完成。当主节点有多个从节点时,主节点会为每一个当前连接的从节点建一个binary log dump 进程,而每个从节点都有自己的I/O进程,SQL进程。从节点用两个线程将从主库拉取更新和执行分成独立的任务,这样在执行同步数据任务的时候,不会降低读操作的性能。
Q:SQL存储结构和函数?