金九银十面试真题

第一部分:

1.字符串操作有哪些,有什么区别

1).从类的继承关系上来看的话,String和StringBuffer,StringBuilder是没有任何关系的,但是StringBuffer和StringBuilder的继承关系时一样的.

2).三个类存储的本质都是一个char类型数组.不同的是String类型的数组长度是3,而另外两个数组的长度都是19且默认值为0.

3).String类是不可变的字符串,而另外两个类都是可以对字符串进行追加的,追加扩容的方法都是调用父类的追加方法,但是StringBuffer类中多了一行toStringCache = null;的代码,toStringCache是一个char[];

4).在StringBuffer类中的方法绝大部分都加了synchronized关键字,而StringBuilder类中则没有,所以说StringBuffer类是线程安全的,而StringBuilder则不是线程安全的

2.方法重载和方法重写

1).重载(overload):

同一个类中;

方法名必须相同;

形参列表必须不同;

与修饰符无关;

与返回类型无关

2).重写override:

必须在子类与父类之间;

方法名必须相同;

形参列表必须相同;

修饰符:父类权限修饰符<=子类权限修饰符

返回值类型:父类>=子类

重写方法抛出的异常必须小于等于被重写方法抛出的异常

3.接口和抽象类

抽象类

抽象类必须用 abstract 修饰,子类必须实现抽象类中的抽象方法,如果有未实现的,那么子类也必须用 abstract 修饰。抽象类默认的权限修饰符为 public,可以定义为 public 或 procted,如果定义为 private,那么子类则无法继承。抽象类不能创建对象

抽象类和普通类的区别

  1. 抽象类必须用public、procted 修饰(如果为private修饰,那么子类则无法继承,也就无法实现其抽象方法)。默认缺省为 public
  2. 抽象类无法创建对象
  3. 如果一个子类继承抽象类,那么必须实现其所有的抽象方法。如果有未实现的抽象方法,那么必须定义为 abstract

接口

接口中的变量隐式的使用 public static final 修饰,并且需要给出初始值。方法隐式的使用 public abstract 修饰

接口和抽象类的区别

  1. 抽象类只能继承一次,但是可以实现多个接口
  2. 接口和抽象类必须实现其中所有的方法,抽象类中如果有未实现的抽象方法,那么子类也需要定义为抽象类。抽象类中可以有非抽象的方法
  3. 接口中的变量必须用 public static final 修饰,并且需要给出初始值。所以实现类不能重新定义,也不能改变其值。
  4. 接口中的方法默认是 public abstract,也只能是这个类型。不能是 static,接口中的方法也不允许子类覆写,抽象类中允许有static 的方法

4.那些集合是线程安全的

[vector]:就比arraylist多了个同步化机制(线程安全)

[hashtable]:就比hashmap多了个线程安全

hashtable跟hashmap的区别

hashtable是线程安全的,即hashtable的方法都提供了同步机制;hashmap不是线程安全的,即不提供同步机制 ;hashtable不允许插入空值,hashmap允许!

5.多线程的创建方式,乐观锁和悲观锁等、线程池

多线程创建:

1、继承Thread类创建线程

启动线程的唯一方法就是通过Thread类的start()实例方法

2、实现Runnable接口创建线程
如果自己的类已经extends另一个类,就无法直接extends Thread,此时,可以实现一个Runnable接口

3、实现Callable接口通过FutureTask包装器来创建Thread线程

4、使用ExecutorService、Callable、Future实现有返回结果的线程

ExecutoreService提供了submit()方法,传递一个Callable,或Runnable,返回Future。如果Executor后台线程池还没有完成Callable的计算,这调用返回Future对象的get()方法,会阻塞直到计算完成。

5、使用定时器的方式

Timer,TimerTask,执行定时任务

6、使用线程池的方式

通过Executors创建不同的线程池进行任务执行

7、Lambda表达式(函数式编程)JDK1.8提供的新特

lambda表达式代码简洁,实现方便,对并发支持好,性能高

悲观锁和乐观锁

悲观锁:总是假设最坏的情况,认为竞争总是存在,每次拿数据的时候都认为会被修改,因此每次都会先上锁。其他线程阻塞等待释放锁。
乐观锁:总是假设最好的情况,认为竞争总是不存在,每次拿数据的时候都认为不会被修改,因此不会先上锁,在最后更新的时候比较数据有无更新,可通过版本号或CAS实现。

悲观锁:用于写比较多的情况,避免了乐观锁不断重试从而降低性能
乐观锁:用于读比较多的情况,避免了不必要的加锁的开销

6.深克隆和浅克隆的区别

浅克隆:创建一个新对象,新对象的属性和原来对象完全相同,对于非基本类型属性,仍指向原有属性所指向的对象的内存地址。

深克隆:创建一个新对象,属性中引用的其他对象也会被克隆,不再指向原有对象地址

第二部分数据库:

1.MySQL的索引

普通索引、唯一索引(索引列的值必须唯一,但允许有空值)、主键索引

2.怎么查看MySQL的索引是否满足需求

explain select * from table

主要关注的是,type 和 key:

type = ALL :表示全表扫描

type = const :表示通过索引一次就找到了

key = NULL:表示没有使用索引

key = primary :表示使用了主键

key一般=使用了主键/索引的名字

3.mysql的引擎以及区别

1、MyISAM:

①不支持事务,但是整个操作是原子性的(事务具备四种特性:原子性、一致性、隔离性、持久性)

②不支持外键,支持表锁,每次所住的是整张表

MyISAM的表锁有读锁和写锁(两个锁都是表级别)

​ ③一个MyISAM表有三个文件:索引文件,表结构文件,数据文件

④存储表的总行数,执行select count(*) from table时只要简单的读出保存好的行数即可

​ ⑤采用非聚集索引,索引文件的数据域存储指向数据文件的指针。辅索引与主索引基本一致,但是辅索引不用保证唯一性。

⑥支持全文索引和空间索引

⑦对于AUTO_INCREMENT类型的字段,在MyISAM表中,可以和其他字段一起建立联合索引。

2、Innodb:

①支持事务,支持事务的四种隔离级别;是一种具有事务(commit)、回滚(rollback)和崩溃修复能力(crash recovery capabilities)的事务安全(transaction-safe (ACID compliant))型表。

②支持行锁和外键约束,因此可以支持写并发

③不存储总行数;也就是说,执行select count() from table时,InnoDB要扫描一遍整个表来计算有多少行。注意的是,当count()语句包含 where条件时,两种表的操作是一样的。

④对于AUTO_INCREMENT类型的字段,InnoDB中必须包含只有该字段的索引

⑤DELETE FROM table时,InnoDB不会重新建立表,而是一行一行的删除

⑥一个Innodb表存储在一个文件内(共享表空间,表大小不受操作系统的限制),也可能为多个(设置为独立表空间,表大小受操作系统限制,大小为2G),受操作系统文件大小的限制

⑦主键索引采用聚集索引(索引的数据域存储数据文件本身),辅索引的数据域存储主键的值;因此从辅索引查找数据,需要先通过辅索引找到主键值,再访问主键索引;最好使用自增主键,防止插入数据时,为维持B+树结构,文件的大调整。

https://www.cnblogs.com/rgever/p/9736374.html

4.MySQL中char和varchar有什么区别

CHAR列的长度固定为创建表时声明的长度。长度可以为从0到255的任何值。当保存CHAR值时,在它们的右边填充空格以达到指定的长度。当检索到CHAR值时,尾部的空格被删除掉。在存储或检索过程中不进行大小写转换。
VARCHAR列中的值为可变长字符串。长度可以指定为0到65,535之间的值

CHAR的处理速度比varchar快很多。但是缺点是浪费存储空间

5.redis缓存和mysql数据库同步

1>采用延时双删策略

在写库前后都进行redis.del(key)操作,并且设定合理的超时时间。

1)先删除缓存2)再写数据库3)休眠500毫秒4)再次删除缓存

弊端:

结合双删策略+缓存超时设置,这样最差的情况就是在超时时间内数据存在不一致,而且又增加了写请求的耗时。

2>异步更新缓存(基于订阅binlog的同步机制)

MySQL binlog增量订阅消费+消息队列+增量数据更新到redis

1)读Redis:热数据基本都在Redis

2)写MySQL:增删改都是操作MySQL

3)更新Redis数据:MySQ的数据操作binlog,来更新到Redis

redis更新

1)数据操作主要分为两大块:

  • 一个是全量(将全部数据一次写入到redis)
  • 一个是增量(实时更新)

这里说的是增量,指的是mysql的update、insert、delate变更数据。

2)读取binlog后分析 ,利用消息队列,推送更新各台的redis缓存数据。

6.MySQL的行锁,表锁,页锁

  • 表锁:开销小,加锁快;不会出现死锁;锁定力度大,发生锁冲突概率高,并发度最低

  • 行锁:开销大,加锁慢;会出现死锁;锁定粒度小,发生锁冲突的概率低,并发度高

  • 页锁:开销和加锁速度介于表锁和行锁之间;会出现死锁;锁定粒度介于表锁和行锁之间,并发度一般

    https://www.cnblogs.com/jpfss/p/8890250.html

第三部分框架:

1.spring注入,spring常用注解以及作用

注入

1.@Autowired:自动装配

**构造器注入:**通过将@Autowired注解放在构造器上来完成构造器注入,默认构造器参数通过类型自动装配;

**字段注入:**通过将@Autowired注解放在构造器上来完成字段注入

**方法参数注入:**通过将@Autowired注解放在方法上来完成方法参数注入

2.setter 方法注入

3.构造器注入

4.静态工厂的方法注入:通过调用静态工厂的方法来获取自己需要的对象

5.实例工厂的方法注入:首先new工厂类,再调用普通的实例方法

注解:

@Controller:用来注解这个bean(类)是MVC模型中的一个控制层,使分发处理器识别到该类,该类会被spring的auto-scan扫到纳入管理

@RequestMaping

​ value:指定浏览器请求的地址;
   method:指定请求的method类型, GET、POST、PUT、DELETE等;
   consumes:指定处理请求的提交内容类型(Content-Type),例如application/json, text/html;
   produces:指定返回的内容类型,仅当request请求头中的(Accept)类型中包含该指定类型才返回;
   params:指定request中必须包含某些参数值是,才让该方法处理;
   headers:指定request中必须包含某些指定的header值,才能让该方法处理请求;
@Service:用于标注业务层组件(Service层)上

@Resource:默认按ByName进行自动装配

@Autowired:@Autowired是根据类型(ByType)进行自动装配的,没有name属性,如果要按名称进行装配,需要配合@Qualifier使用

@Repository:用户标注数据访问层组件(Dao层)

@Component:泛指组件

2.spring扫描是怎么实现

ClassPathScanningCandidateComponentProvider:是Spring中包扫描机制最底层的类,用于扫描指定包下面的类文件,并且会根据用户提供的includeFilters以及excludeFilters来过滤掉不想注册的类,最后生成一个基本的BeanDefinition

https://www.cnblogs.com/wt20/p/10990697.html

3.redis的数据类型,缓存穿透怎么处理

Redis有序集合Zset(sorted set)
在set基础上,加一个score值。
Redis哈希(Hash)
Redis集合(Set)
Redis列表(List)
Redis字符串(String)

缓存穿透是指查询一个根本不存在的数据,缓存层和存储层都不会命中,通常出于容错的考虑,如果从存储层查不到数据则不写入缓存层

缓存空对象:存在漏洞,不经过判断就直接将Null对象存入到缓存中,针对这类数据设置一个较短的过期时间,让其自动剔除。

布隆过滤器拦截:设置过期时间,让其自动过期失效

优点是空间效率和查询时间都远远超过一般的算法,缺点是有一定的误识别率和删除困难

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值