java面试知识总结

C

重载和重写

Java 重写(Override)与重载(Overload)

重写(Override)重写是子类对父类的允许访问的方法的实现过程进行重新编写, 返回值和形参都不能改变。即外壳不变,核心重写!

重写的好处在于子类可以根据需要,定义特定于自己的行为。 也就是说子类能够根据需要实现父类的方法。重写方法不能抛出新的检查异常或者比被重写方法申明更加宽泛的异常。例如: 父类的一个方法申明了一个检查异常 IOException,但是在重写这个方法的时候不能抛出 Exception 异常,因为 Exception 是 IOException 的父类,只能抛出 IOException 的子类异常。 在面向对象原则里,重写意味着可以重写任何现有方法。

重载(overloading) 是在一个类里面,方法名字相同,而参数不同。返回类型可以相同也可以不同。每个重载的方法(或者构造函数)都必须有一个独一无二的参数类型列表。最常用的地方就是构造器的重载。

法的重写(Overriding)和重载(Overloading)是java多态性的不同表现,重写是父类与子类之间多态性的一种表现,重载可以理解成多态的具体表现形式。

(1)方法重载是一个类中定义了多个方法名相同,而他们的参数的数量不同或数量相同而类型和次序不同,则称为方法的重载(Overloading)。

(2)方法重写是在子类存在方法与父类的方法的名字相同,而且参数的个数与类型一样,返回值也一样的方法,就称为重写(Overriding)。

(3)方法重载是一个类的多态性表现,而方法重写是子类与父类的一种多态性表现。

H

Hash

HashMap1.7和1.8的区别

精简版总结

Hashmap1.7和1.8的线程不安全原因总结

ConcurrentHashMap 1.7和1.8的区别

HashMap什么时候扩容?存储的元素的个数(key的个数之和)大于桶数组长度乘以装载因子。

为什么jdk8的HashMap链表的长度超过8会转换成红黑树?

扩展:

ConcurrentHashMap在jdk1.7和jdk1.8中的不同

为什么Hashtable ConcurrentHashmap不支持key或者value为null

hashcode和equal

hashCode与equals的区别与联系

hashcode方法只有在集合中用到

保证集合元素的唯一性是通过对象的hashCode和equals方法来完成对象唯一性的。

hashCode值和对象的内容是存储在hash表中的。

        如果对象的hashCode值不同,那么不用判断equals方法,就直接存储到哈希表中。

        如果对象的hashCode值相同,那么要再次判断对象的equals方法是否为true。

                如果为true,视为相同元素,不存储。

                 如果为false,那么视为不同元素,就进行存储。

hashCode用来做什么

java中的hashCode方法就是根据一定的规则将与对象相关的信息(比如对象的存储地址,对象的字段等)映射成一个数值,这个数值称作为散列值。即在散列集合包括HashSet、HashMap以及HashTable里,对每一个存储的桶元素都有一个唯一的"块编号",即它在集合里面的存储地址;当你调用contains方法的时候,它会根据hashcode找到块的存储地址从而定位到该桶元素。

 hashCode和equals什么时候重写?

一般来说,如果你要把一个类的对象放入容器中,那么通常要为其重写equals()方法,让他们比较内容值而不是地址值。特别地,如果要把你的类的对象放入散列中,那么还要重写hashCode()方法;要放到有序容器中,还要重写compareTo()方法。equals()相等的两个对象,hashcode()一定相等;equals()不相等的两个对象,却并不能证明他们的hashcode()不相等。换句话说,equals()方法不相等的两个对象,hashcode()有可能相等。HashMap中,如果要比较key是否相等,要同时使用这两个函数!因为自定义的类的hashcode()方法继承于Object类,其hashcode码为默认的内存地址,这样即便有相同含义的两个对象,比较也是不相等的。

(对象在不重写的情况下使用的是Object的equals方法和hashcode方法,从Object类的源码我们知道,默认的equals 判断的是两个对象的引用指向的是不是同一个对象;而hashcode也是根据对象地址生成一个整数数值)

I

Integer

Integer、int与new Integer

M

MySQL

参考:原文链接

b.

B+tree比B 树更适合实际应用中操作系统的文件索引和数据库索引?

B+tree的磁盘读写代价更低,B+tree的查询效率更加稳定
B+树只要遍历叶子节点就可以实现整棵树的遍历,而且在数据库中基于范围的查询是非常频繁的,而B树只能中序遍历所有节点,效率太低。

B+树的特点
(1)所有关键字都出现在叶子结点的链表中(稠密索引),且链表中的关键字恰好是有序的;
(2)不可能在非叶子结点命中;
(3)非叶子结点相当于是叶子结点的索引(稀疏索引),叶子结点相当于是存储(关键字)数据的数据层;

f.

分库与分表设计分片

分库与分表的目的:减小数据库的单库单表负担,提高查询性能,缩短查询时间。
通过分表,可以减少数据库的单表负担,将压力分散到不同的表上,不同的表上的数据量少了,起到提高查询性能,缩短查询时间的作用,此外,可以很大的缓解表锁的问题。
分表策略可以归纳为垂直拆分水平拆分
水平分表:取模分表就属于随机分表,而时间维度分表则属于连续分表
如何设计好垂直拆分,我的建议:将不常用的字段单独拆分到另外一张扩展表. 将大文本的字段单独拆分到另外一张扩展表, 将不经常修改的字段放在同一张表中,将经常改变的字段放在另一张表中。
对于海量用户场景,可以考虑取模分表,数据相对比较均匀,不容易出现热点和并发访问的瓶颈。

库内分表,仅仅是解决了单表数据过大的问题,但并没有把单表的数据分散到不同的物理机上,因此并不能减轻 MySQL 服务器的压力,仍然存在同一个物理机上的资源竞争和瓶颈,包括 CPU、内存、磁盘 IO、网络带宽等。

分库与分表带来的分布式困境与应对之策
1.数据迁移与扩容问题:一般做法是通过程序先读出数据,然后按照指定的分表策略再将数据写入到各个分表中。
2.分页与排序问题:需要在不同的分表中将数据进行排序并返回,并将不同分表返回的结果集进行汇总和再次排序,最后再返回给用户。
3.分布式全局唯一ID:UUID、GUID等

m.

MyisAM和innodb的有关索引的疑问

MyISAM( 非聚集)
使用B+Tree作为索引结构,叶节点的data域存放的是数据记录的地址。
MyISAM中索引检索的算法为首先按照B+Tree搜索算法搜索索引,如果指定的Key存在,则取出其data域的值,然后以data域的值为地址,读取相应数据记录。
InnoDB( 聚集索引)
第一个重大区别是InnoDB的数据文件本身就是索引文件, 这棵树的叶节点data域保存了完整的数据记录。
但是辅助索引搜索需要检索两遍索引:首先检索辅助索引获得主键,然后用主键到主索引中检索获得记录。

因为InnoDB的数据文件本身要按主键聚集,所以InnoDB要求表必须有主键(MyISAM可以没有)
1)如果没有显式指定,则MySQL系统会自动选择一个可以唯一标识数据记录的列作为主键
2)如果不存在这种列,则MySQL自动为InnoDB表生成一个隐含字段作为主键,这个字段长度为6个字节,类型为长整形。
简单说:如果我们定义了主键(PRIMARY KEY),那么InnoDB会选择其作为聚集索引;如果没有显式定义主键,则InnoDB会选择第一个不包含有NULL值的唯一索引作为主键索引。innodb不需要myi文件

 

innodb为什么要用自增id作为主键

自增主键,那么每次插入新的记录,记录就会顺序添加到当前索引节点的后续位置,当一页写满,就会自动开辟一个新的页
使用非自增主键(如果身份证号或学号等),由于每次插入主键的值近似于随机,因此每次新纪录都要被插到现有索引页得中间某个位置, 频繁的移动和分页操作造成了大量的碎片,得到了不够紧凑的索引结构,后续不得不通过OPTIMIZE TABLE(optimize table)来重建表并优化填充页面。

 

聚集索引与非聚集索引的区别

非聚集索引和聚集索引的区别在于, 通过聚集索引可以查到需要查找的数据, 而通过非聚集索引可以查到记录对应的主键值 , 再使用主键的值通过聚集索引查找到需要的数据
聚集索引和非聚集索引的根本区别是表记录的排列顺序和与索引的排列顺序是否一致。 聚集索引(innodb)的叶节点就是数据节点,而非聚集索引(myisAM)的叶节点仍然是索引节点,只不过其包含一个指向对应数据块的指针。

 

MySQL常见的存储引擎InnoDB、MyISAM的区别?

1)事务:MyISAM不支持,InnoDB支持
2)锁级别: MyISAM 表级锁,InnoDB 行级锁及外键约束
(MySQL表级锁有两种模式:表共享读锁(Table Read Lock)和表独占写锁(Table Write Lock)。什么意思呢,就是说对MyISAM表进行读操作时,它不会阻塞其他用户对同一表的读请求,但会阻塞对同一表的写操作;而对MyISAM表的写操作,则会阻塞其他用户对同一表的读和写操作。
InnoDB行锁是通过给索引项加锁来实现的,即只有通过索引条件检索数据,InnoDB才使用行级锁,否则将使用表锁!行级锁在每次获取锁和释放锁的操作需要消耗比表锁更多的资源。在InnoDB两个事务发生死锁的时候,会计算出每个事务影响的行数,然后回滚行数少的那个事务。当锁定的场景中不涉及Innodb的时候,InnoDB是检测不到的。只能依靠锁定超时来解决。)
3)MyISAM存储表的总行数;InnoDB不存储总行数;
4)MyISAM采用非聚集索引,B+树叶子存储指向数据文件的指针。InnoDB主键索引采用聚集索引,B+树叶子存储数据


q.

区别

CHAR和VARCHAR的区别?

1)char的长度是不可变的,用空格填充到指定长度大小,而varchar的长度是可变的。
2)char的存取数度还是要比varchar要快得多
3)char的存储方式是:对英文字符(ASCII)占用1个字节,对一个汉字占用两个字节。varchar的存储方式是:对每个英文字符占用2个字节,汉字也占用2个字节。


NOW()和CURRENT_DATE()有什么区别?

NOW()命令用于显示当前年份,月份,日期,小时,分钟和秒。
CURRENT_DATE()仅显示当前年份,月份和日期。

各种索引的概念:索引,主键,唯一索引,联合索引,索引分类

索引分类: Mysql常见索引有:主键索引、唯一索引、普通索引、全文索引、组合索引.{按聚集分类:聚集索引和非聚集索引}
索引( 普通索引):不允许有空值,指字段 唯一、不为空值 的列
唯一索引:唯一索引可以保证数据记录的唯一性,在为这个数据列创建索引的时候就应该用关键字UNIQUE把它定义为一个唯一索引。唯一索引允许空值( 索引列的所有值都只能出现一次,即必须唯一)
主键:是一种特殊的唯一索引,在一张表中只能定义一个主键索引,主键用于唯一标识一条记录,使用关键字 PRIMARY KEY 来创建。
外键:表的外键是另一表的主键,
组合索引:索引可以覆盖多个数据列,如像INDEX(columnA, columnB)索引。
CREATE INDEX index_name ON table_name (column_list)
全文索引: 全文索引的索引类型为FULLTEXT, 可以在VARCHAR或者TEXT类型的列上创建。
单列索引与多列索引

建立索引的使用场景

在最频繁使用的、用以缩小查询范围的字段,需要排序的字段上建立索引。
不宜:
1)对于查询中很少涉及的列或者重复值比较多的列
2)对于一些特殊的数据类型,不宜建立索引,比如文本字段(text)等

s.

索引是什么?MySQL为什么使用B+树,而不是使用其他?B+树的特点

索引是帮助MySQL高效获取数据的数据结构。索引:排好序的快速查找数据结构!索引会影响where后面的查找,和order by 后面的排序

B+Tree索引(平衡多路查找树)是B-Tree的改进版本,同时也是数据库索引索引所采用的存储结构。数据都在叶子节点上,并且增加了顺序访问指针,每个叶子节点都指向相邻的叶子节点的地址。B-Tree需要获取所有节点,相比之下B+Tree效率更高。B+树索引需要从根节点到枝节点,最后才能访问到页节点这样多次的IO访问;

hash:虽然可以快速定位,但是没有顺序,IO复杂度高。
二叉树:树的高度不均匀,不能自平衡,查找效率跟数据有关(树的高度),并且IO代价高。
红黑树:树的高度随着数据量增加而增加,IO代价高。

---------

数据库三范式,根据某个场景设计数据表?优缺点

1)所有字段值都是不可分解的原子值。
2)在一个数据库表中,一个表中只能保存一种数据,不可以把多种数据保存在同一张数据库表中。
3)数据表中的每一列数据都和主键直接相关,而不能间接相关。

第一范式(确保每列保持原子性)
第一范式是最基本的范式。如果数据库表中的所有字段值都是不可分解的原子值,就说明该数据库表满足了第一范式。

第一范式的合理遵循需要根据系统的实际需求来定。比如某些数据库系统中需要用到“地址”这个属性,本来直接将“地址”属性设计成一个数据库表的字段就行。但是如果系统经常会访问“地址”属性中的“城市”部分,那么就非要将“地址”这个属性重新拆分为省份、城市、详细地址等多个部分进行存储,这样在对地址中某一部分操作的时候将非常方便。这样设计才算满足了数据库的第一范式,如下表所示。

上表所示的用户信息遵循了第一范式的要求,这样在对用户使用城市进行分类的时候就非常方便,也提高了数据库的性能。

第二范式(确保表中的每列都和主键相关)

第二范式在第一范式的基础之上更进一层。第二范式需要确保数据库表中的每一列都和主键相关,而不能只与主键的某一部分相关(主要针对联合主键而言)。也就是说
在一个数据库表中,一个表中只能保存一种数据,不可以把多种数据保存在同一张数据库表中。

比如要设计一个订单信息表,因为订单中可能会有多种商品,所以要将订单编号和商品编号作为数据库表的联合主键。

第三范式(确保每列都和主键列直接相关,而不是间接相关)
第三范式需要确保数据表中的每一列数据都和主键直接相关,而不能间接相关。

比如在设计一个订单数据表的时候,可以将客户编号作为一个外键和订单表建立相应的关系。而不可以在订单表中添加关于客户其它信息(比如姓名、所属公司等)的字段。

优点:可以尽量得减少数据冗余 缺点:对于查询需要多个表进行关联,更难进行索引优化
反范式化: 优点:可以减少表得关联 缺点:数据冗余以及数据异常
-----------------------------------

数据库悲观锁和乐观锁的原理和应用场景?

悲观锁,先获取锁,再进行业务操作,一般就是利用类似 SELECT … FOR UPDATE 这样的语句,对数据加锁,避免其他事务意外修改数据。
当数据库执行select … for update时会获取被select中的数据行的行锁,select for update获取的行锁会在当前事务结束时自动释放,因此必须在事务中使用。

乐观锁则与,先进行业务操作,只在最后实际更新数据时进行检查数据是否被更新过。Java 并发包中的 AtomicFieldUpdater 类似,也是利用 CAS 机制,并不会对数据加锁,而是通过对比数据的时间戳或者版本号,来实现乐观锁需要的版本判断。

--------------------------------------

SQL怎么优化

SQL优化是一个分析,优化,再分析,再优化的过程。站在执行计划的角度来说,我们这个过程,就是在不断的减少rows的数量。

1.建索引
2.减少表之间的关联
3.优化 sql,尽量让 sql 很快定位数据,不要让sql 做全表查询,应该走索引,把数据 量大的表排在前面
4.简化查询字段,没用的字段不要,已经对返回结果的控制,尽量返回少量数据
5.尽量用PreparedStatement 来查询,不要用 Statement

(索引相关)
不要在列上使用函数,这将导致索引失效而进行全表扫描。
尽量避免使用 != 或 not in或 <> 等否定操作符
尽量避免使用 or 来连接条件
多个单列索引并不是最佳选择,复合索引的最左前缀原则(MySQL 只能使用一个索引,会从多个索引中选择一个限制最为严格的索引,因此,为多个列创建单列索引,并不能提高 MySQL 的查询性能。) 联合索引遵从最左前缀原则
查询中的某个列有范围查询,则其右边所有列都无法使用索引优化查找。
索引不会包含有NULL值的列
当查询条件左右两侧类型不匹配的时候会发生隐式转换,隐式转换带来的影响就是可能导致索引失效而进行全表扫描。
like 语句的索引失效问题

0.先运行看看是否真的很慢,注意设置SQL_NO_CACHE
1.where条件单表查,锁定最小返回记录表。这句话的意思是把查询语句的where都应用到表中返回的记录数最小的表开始查起,单表每个字段分别查询,看哪个字段的区分度最高
2.explain查看执行计划,是否与1预期一致(从锁定记录较少的表开始查询)
3.order by limit 形式的sql语句让排序的表优先查
4.了解业务方使用场景
5.加索引时参照建索引的几大原则
6.观察结果,不符合预期继续从0分析

--------------------------------

创建索引时需要注意什么?

非空字段:应该指定列为NOT NULL,除非你想存储NULL。在mysql中,含有空值的列很难进行查询优化,因为它们使得索引、索引的统计信息以及比较运算更加复杂。你应该用0、一个特殊的值或者一个空串代替空值;

取值离散大的字段:(变量各个取值之间的差异程度)的列放到联合索引的前面,可以通过count()函数查看字段的差异值,返回值越大说明字段的唯一值越多字段的离散程度高;

索引字段越小越好:数据库的数据存储以页为单位一页存储的数据越多一次IO操作获取的数据越大效率越高。唯一、不为空、经常被查询的字段 的字段适合建索引

---------------------------------

数据库中乐观锁和悲观锁的实现方式

乐观锁:获取数据时不会考虑并发情况造成的数据冲突,然后数据更新提交时正式对数据的冲入与否进行检测;

悲观所:总是做最坏的打算,每次读取数据时都认为数据会被别的线程修改,所以会进行加锁,当别的线程要访问数据时都要被阻塞挂起。

乐观锁的实现方式:

version方式:在数据表中加一个version版本字段,(这个字段表示数据被修改的),数据被修改时,version会加一。线程读取数据时同时也需要读version值,提交数据是,刚才读取到的version值和当前数据库里面存储的version一样时才可以更新,否则将重新操作,直到更新成功。

时间戳方式

悲观锁的实现方式:

for update 方式:一般使用 select ...for update 对选择的数据进行加锁,例如 select * from t_goods where id = 1 for update,这条sql语言就锁定了t_goods表中符合id=1的这条记录,本次事务提交之前,外界无法修改这些记录。

表级锁定、行级锁定、页级锁定

表级锁定

MySQL各存储引擎中最大粒度的锁定机制。表级所实现逻辑简单,带来的系统负面影响小。获取锁和释放锁的速度都很快,可以避免死锁问题。

最大的负面影响就是出现锁资源争用的概率也会最高,并发度会大打折扣。

行级锁定

锁定对象的粒度很小,是目前各大数据库管理软件所实现的所颗粒粒度最小的。发生锁资源争夺的概率比较小,可以给予应用程序尽可能的大的并发处理能力,提高系统性能

粒度小那获取锁和释放锁需要做的事情也更多,带来的消耗自然较大,容易发生死锁

页级锁定

(MySQL中比较特别的一种锁定级别,在其他的数据库管理软件中也不是很常见)

介于行级锁和表级所之间,获取锁所需要的资源开销和能够提供的并发能力也是在二者之间,也会发生死锁。使用页级锁定的主要是BerkeleyDB存储引擎

MyISAM存储引擎使用的锁定机制完全是由MySQL提供的表级锁定提供的。表级锁的两种模式:表共享所和表独占写锁。MyISAM表的读操作和写操作之间,以及写操作之间是串行的。(可以进行并行插入,通过设置ConcurrentInsert值来进行控制是否使用并行插入)

MyISAM表锁优化建议

1.查询表级锁的争用情况(Table_locks_immedia和Table_locks_waited)

2.缩短锁定时间

3.分离能并行的操作

4.合理利用读写优先级

S

String

String 为什么设计为final?

被final修饰的类不能被继承,也就是不能有子类。那么为什么要把String设计为不能被继承呢?简单来说有两点:安全和效率。

安全

  1. 于Java的多态特性,当我们把MyString的实例作为参数传入method()方法时,编译器是不会报错的。但是我们的运行结果则完全错误,这会造成非常严重的后果。整个类声明为final之后,如果有一个String的引用,则它引用的一定是String对象,而不会是其他类的对象(泛型允许引用子类)
  2. 引用类型本身的问题。因为Java对象参数传的是引用,所以可变的的StringBuffer参数就被改变了。可以看到变量sb在Test.appendSb(sb)操作之后,就变成了"aaabbb"。有的时候这可能不是程序员的本意。所以String不可变的安全性就体现在这里。
  3. 不可变的字符串还可以保证多线程时的线程安全问题。多线程时,只有读操作一般不会引发线程安全问题,当读写同时存在时便容易引发安全问题。当字符串不可变时也就不能写,当然不会引发线程问题。

效率

     基于字符串的不可变,才能有字符串常量池这一特性。字符串常量池的诞生是为了提升效率和减少内存分配。可以说我们编程有百分之八十的时间在处理字符串,而处理的字符串中有很大概率会出现重复的情况。正因为String的不可变性,常量池很容易被管理和优化。

String s1 = "abc" 与 String s2 = new String("abc")的区别

 

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值