面试--基础+集合相关
基础
https://blog.csdn.net/fangchao2011/article/details/89203535
继承,封装,多态?
封装:是对象和类概念的主要特性,把客观事物封装成抽象的类,并且类可以把自己的数据和方法只让可信的类或者对象操作,对不可信的进行信息隐藏。
继承:子类继承父类,它就可以使用父类的所有功能,并在无需编写父类的情况下对这些功能进行扩展。
多态:多态性是允许你将父对象设置成为一个或更多的他的子对象相等的技术,赋值之后,父对象就可以根据当前赋值给它的子对象的特性以不同的方式运作。
简单的说,就是一句话:允许将子类类型的指针赋值给父类类型的指针。Fu f=new Zi(); 多态的三个条件:一、要有继承;二、要有重写;三、父类引用指向子类对象
抽象类和接口的区别?
抽象类可以有构造方法,接口中不能有构造方法
定义的关键字不同。 abstract interface
子类继承关键字不同。extends implements
一个普通类只能继承一个抽象类,可以实现多个接口
抽象类中的普通方法无限制,抽象方法不能被 private 修饰;接口中的方法定义默认为public abstract类型,并且不能定义为其他控制符
抽象类中的属性访问控制符无限制,而接口有限制,接口中定义的变量默认为 public static final 类型,
抽象类中未被abstract修饰的普通方法必须有实现,抽象方法必须没有实现;而接口中方法默认被abstract修饰所以不能有实现,但在 JDK 8 中的 static 和 defualt 方法必须有实现。
静态代码块的使用不同:抽象类可以有静态代码块,而接口不能有。
https://zhuanlan.zhihu.com/p/448805970
pojo, entity ,vo , dto的区别?
1、pojo 即无规则简单Java对象,即不与数据库打交道的简单对象。
2、entity 里的每一个字段,与数据库相对应,
2、vo 视图对象 对应页面显示的数据对象,可以和表对应,也可以不对应。一般在Controller层使用
3、dto 数据传输对象 这是用来转换从 entity 到 vo,或者从 vo 到 entity 的中间的东西 。一般在Service层使用
java中io流分为几种?
按照功能分为:输入流和输出流
按照类型分为:字节流和字符流
字节流和字符流的区别,字节流按8位传输以字节为单位输入输出数据,字符流按16位传输以字符为单位输入输出数据。
BIO、NIO、AIO 有什么区别?
BIO:Block IO 同步阻塞式 IO,就是我们平常使用的传统 IO,它的特点是模式简单使用方便,并发处理能力低。
NIO:New IO 同步非阻塞 IO,是传统 IO 的升级,客户端和服务器端通过 Channel(通道)通讯,实现了多路复用。
AIO:Asynchronous IO 是 NIO 的升级,也叫 NIO2,实现了异步非堵塞 IO ,异步 IO 的操作基于事件和回调机制。
Files的常用方法都有哪些?
Files.exists():检测文件路径是否存在。Files.createFile():创建文件。
Files.createDirectory():创建文件夹。
Files.delete():删除一个文件或目录。
Files.copy():复制文件。
Files.move():移动文件。
Files.size():查看文件个数。
Files.read():读取文件。
Files.write():写入文件。
反射的三种方式
1.调用某个对象的getClass方法以获取该类的Class对象:
Person p = new Person();
Class clazz = p.getClass();
2.调用某个类的Class属性以获取该类对应的Class对象:
Class clazz = Person.class;
3.调用Class类中的forName静态方法获取该类对象,这是最安全也是性能最好的方法:
Class three = Class.forName("com.nasi.demo.entity.User");//类的全路径包括包名
3.1//获取全部方法 Method[] declaredMethods = three.getDeclaredMethods();
3.2//获取全部构造方法 Constructor[] declaredConstructors = three.getDeclaredConstructors();
3.3//获取全部属性 Field[] declaredFields = two.getDeclaredFields();
&和&&的区别?
&和&&都可以用作逻辑与的运算符,当运算符两边的表达式的结果都为true时,整个运算结果才为true
&&还具有短路的功能,即如果第一个表达式为false,则不再计算第二个表达式,
&还可以用作位运算符,当&操作符两边的表达式不是boolean类型时, &表示按位与操作(只有两个数的二进制同时为1,结果才为1,否则为0)
重载和重写的区别?
重载实质就是在一个类中有多个具有不同参数个数或者参数类型或者参数顺序的同名方法(返回类型可以随意,不能以返回类型作为重载函数的区分标准),是一个类中多态性的一种表现。
重写是父类与子类之间的多态性,子类重写父类的方法,子类函数的访问权限修饰符不能小于父类的。如需父类中原有的方法使用super关键字。
构造方法名必须和类名一致,所以构造方法不能被重写,但是可以被重载。
String类的常用方法?
length():返回字符串长度;split():分割字符串,返回一个分割后的字符数组。indexOf("abc"):返回指定字符的索引;charAt(i):根据下标获取对应的字符;
equals():字符串比较;replace():字符串替换,然后返回一个新的字符串,注意:原本的字符串不变;trim():去掉字符串前面和后面的空格;
concat():拼接字符串 ;substring(i):从下标为i往后截取字符串(包括下标为i)。substring(begin,end):截取的字符串包含begin不含end
getBytes():返回字符串的 byte 类型数组;toUpperCase():将字符串转成大写字符;toLowerCase():将字符串转成小写字母;
String为什么是不可变的?Stringbuffer和StringBuilder
源码中String类中有一个char数组,并且这个char数组是被final修饰的。因为数组一旦创建长度不可变。
并且被final修饰的引用一旦指向某个对象之后,不可在指向其它对象,所以String是不可变的!
StringBuffer/StringBuilder都继承AbstractStringBuilder类,内部实际上是一个没有被final修饰char[ ]数组,
StringBuffer和StringBulider的初始化容量应该为16,当存满之后会进行扩容,底层调用了数组拷贝的方法:System.arraycopy()…扩容的,
所以StringBuffer/StringBuilder适用于字符串的频繁拼接操作,并且StringBuffer是线程安全的,StringBuilder是非线程安全的。
==和equals的区别?
==:如果比较的对象是基本数据类型,则比较的是数值是否一致;如果比较的是引用数据类型,则比较的是对象的地址值是否一致。
equals()方法不能用于基本数据类型的比较,用于比较对象的时候返回值取决于重写实现。
对于String类 Date类 File类等 可重写equals() 方法用于比较对象的属性内容是否一致。
final,finally,finalize的区别?
final用于声明属性,方法,类,分别表示属性不可变,方法不可覆盖(重写),类不可继承。
finally是异常处理结构语句的一部分,表示总是执行。
finalize是Object类的一个方法,在垃圾收集器执行的时候会调用被回收对象的此方法,可以覆盖此方法提供垃圾收集时的其他资源回收,例如关闭文件等.JVM不保证此方法总被调用。
补充:try -catch语句块中存在return语句,finally会不会执行。
不管有没有出现异常,或者try-catch中有return时,finally仍然会执行,先执行try-catch里面return之前(包括return 语句中的表达式计算),再执行finally块,
finally中最好不要有return,否则会提前退出,返回值不是try或catch中保存的返回值。
int 和integer有什么区别?
int是java提供的8种原始数据类型之一。java为每个原始数据类型提供了封装类,Integer就是java为int提供的封装类。
int的默认值为0,Integer的默认值为null,是引用类型,即Integer可以区分出未赋值和值为0的区别,int则无法表达出未赋值的情况,
①、无论如何,Integer与new Integer不会相等。不会经历拆箱过程,因为它们存放内存的位置不一样。
②、两个都是非new出来的Integer,如果数在-128到127之间,则是true,否则为false。
③、两个都是new出来的,则为false。
④、int和integer(new或非new)比较,都为true,因为会把Integer自动拆箱为int,其实就是相当于两个int类型比较。
@Autowired 和 @Resource 有什么不同
来源不同:@Autowired 来自 Spring 框架,而@Resource 注解来源于 jdk 中的 rt.jar
依赖查找的顺序不同:@Autowired 先根据类型再根据名称查询,而 @Resource 先根据名称再根据类型查询;
支持的参数不同:@Autowired 只支持设置 1 个参数,而 @Resource 支持设置 7 个参数;
依赖注入的用法支持不同:@Autowired 既支持构造方法注入,又支持属性注入和 Setter 注入,而 @Resource 只支持属性注入和 Setter 注入;
编译器 IDEA 的提示不同:当注入 Mapper 对象时,使用 @Autowired 注解编译器会提示错误,而使用 @Resource 注解则不会提示错误。
容器
java 容器都有哪些?
Collection 和 Collections 有什么区别?
java.util.Collection 是一个集合接口(集合类的一个顶级接口)。它提供了对集合对象进行基本操作的通用接口方法。Collection接口在Java 类库中有很多具体的实现。Collection接口的意义是为各种具体的集合提供了最大化的统一操作方式,其直接继承接口有List与Set。
Collections则是集合类的一个工具类/帮助类,其中提供了一系列静态方法,用于对集合中元素进行排序、搜索以及线程安全等各种操作。
list和set和map的区别?
list和set都继承collection接口,collection继承 Iterable 接口;map是一个单独的接口。
list: 是一个有序的容器,允许重复的对象,可以插入多个null元素
set: 是一个无序的容器,不允许重复的对象,只能插入一个null元素
list的常用实现类有ArrayList,LinkedList和Vector.ArrayList最流行,查询速度快支持随机访问。LinkedList更适用于经常从list中增加删除元素的场合。Vector表示底层数组,线程安全。
set的常用实现类有 HashSet、LinkedHashSet 以及 TreeSet。最流行的是基于 HashMap实现的 HashSet;
LinkedHashset : 保证元素添加的自然顺序 ;TreeSet : 保证元素的自然顺序a-z排列 ;HashSet无序。
map里可以有任意的null值但是只能有一个null键,map可能有相同的值但是键对象必须是唯一的。map的常用实现类是CurrentHashMap,HashMap,LinkedHashMap,HashTable,TreeTable.
ArrayList和LinkedList的区别?
ArrrayList底层的数据结构是数组,ArrayList查询快,因为它数据的存储形式是连续的 ,可以通过下标可以直接获取;由于数据是连续存储的,那么插入和删除势必导致部分或整体数据的位置偏移,仅仅插入一个数据,却需要操作其他元素的位置的变动。
LinkedList 的底层数据结构是双向循环链表,不支持随机访问。元素之间直接通过指针相互关联,查询需要遍历链表,效率较低;插入和删除只需要改变指针指向,不必修改列表中剩余的元素,插入和删除效率高。
ArrayList 的时间复杂度是 O(1),而 LinkedList 是 O(n) 注:这里的n为元素个数的一半, 时间复杂度中的n仅和操作的数据量有关, 这里LinkedList的查询仅对一半的数据查找。
Array和ArrayList的区别?
Array可以包含基本类型和对象类型,ArrayList只能包含对象类型
Array的大小是固定的,ArrayList的大小是动态的
Array数组只能通过数组下标来对指定位置的元素进行变更。
ArrayList在Array的基础上增加了很多的方法。比如add,addAll,remove,removeAll,contains,以及iterator等等多种丰富的功能方法。
使用场景:如果我们需要保存一些在整个程序运行期间都会存在而且不变的数据,我们可以使用Array。但是我们如果只是单纯想要以数组的形式保存数据,而不是对数组进行增加等操作,只是方便我们查找的话,那么选择ArrayList
如何实现List和数组之间的转换?
List转换成为数组:调用ArrayList的toArray方法。
数组转换成为List:调用Arrays的asList方法。
在 Queue 中 poll()和 remove()有什么区别?
poll() 和 remove() 都是返回队列头部的元素,如果队列没有数据, poll() 获取元素失败会返回null, remove() 失败的时候会抛出NoSuchElementException异常。
线程安全的集合?
vector:比arraylist多了个同步化机制,不过效率较低。
statck:堆栈类,先进后出。
hashtable:就比HashMap多了个线程安全。
ConcurrentHashMap:是一种高效但是线程安全的集合。
ConcurrentHashMap为什么是线程安全的?
迭代器 Iterator 是什么?
迭代器是一种设计模式,不是一个集合,它是一种用于访问集合的方法,可用于迭代 ArrayList 和 HashSet 等集合
Iterator 怎么使用?有什么特点?
Java中的Iterator功能比较简单,并且只能单向移动:
(1) l集合调用iterator()方法返回一个Iterator。第一次调用Iterator的next()方法时,它返回序列的第一个元素。
(2) 使用next()获得序列中的下一个元素。
(3) 使用hasNext()检查序列中是否还有元素。
(4) 使用remove()将迭代器新返回的元素删除。
Iterator是Java迭代器最简单的实现,为List设计的ListIterator具有更多的功能,它可以从两个方向遍历List,也可以从List中插入和删除元素。
Iterator 和 ListIterator 有什么区别?
Iterator可用来遍历Set和List集合,但是ListIterator只能用来遍历List。
Iterator对集合只能是前向遍历,ListIterator既可以前向也可以后向。
ListIterator实现了Iterator接口,并包含其他的功能,比如:增加元素,替换元素,获取前一个和后一个元素的索引,等等。
注意,迭代器 没有当前所在元素一说,它只有一个游标( cursor )的概念,这个游标总是在元素之间,
listiterator调用一次next()游标往后移动一位,调用一次previous()游标往前移动一位,所以调用next()后再调用provious()输出的值相同
并行和并发的区别?
并行是指两个或者多个事件在同一时刻发生;而并发是指两个或多个事件在同一时间间隔发生。
并行是在不同实体上的多个事件,并发是在同一实体上的多个事件。
Sleep和Wait的区别?
1、sleep是线程中的方法,但是wait是Object类中的方法。
2、sleep方法不会释放lock,但是wait会释放,而且会加入到等待队列中。
3 wait,notify和notifyAll只能在同步方法或者同步代码块里面使用,而sleep可以在任何地方使用
4 sleep必须指定时间,wait可以指定也可以不指定时间
run()和start()的区别?
线程的run()方法是由java虚拟机直接调用的,如果我们没有启动线程(没有调用线程的start()方法)而是在应用代码中直接调用run()方法,那么这个线程的run()方法其实运行在当前线程(即run()方法的调用方所在的线程)之中,而不是运行在其自身的线程中,从而违背了创建线程的初衷;
public class WelcomThread extends Thread {
//在该方法中实现线程的任务逻辑
public void run() {
//获取当前正在执行的线程名称
System.out.println(Thread.currentThread().getName());
}
}
public class TestDemo1 {
public static void main(String[] args) {
Thread welcome = new WelcomThread(); //创建线程(动态规划)
welcome.run(); //直接调用run()方法
System.out.println(Thread.currentThread().getName());
Thread welcome1 = new WelcomThread(); //创建线程
welcome1.start(); //启动线程
}
}
运行结果:main
main
Thread-1
数据库索引原理?
数据库索引是数据库管理系统中一个排序的数据结构,以协助快速查询或更新数据库表中数据。索引的实现通常使用BTree及其变种B+Tree
为什么使用索引?
数据库查询是数据库最主要的功能之一。而当数据量越来越大的时候,查询花费的时间会随之增长。索引可以加速数据的查询。因为索引是有序排列的,可以大大减少了存储引擎需要扫描的数据量
举个例子来说,假设我们有一个数据库表EpUser,这个表分别有三个字段:name,age,address。假设表中有1000条记录。
假如没有使用索引,当我们查询名为“James”的雇员的时候,即调用:select name,age,address from Employee where name = 'James';
此时数据库不得不在Employee表中对这1000条记录一条一条的进行判断name字段是否为“James”。这也就是所谓的全表扫描。
如果在EpUser表上的name字段上创建索引,在我们查询时,会通过索引去查询名为“James”的雇员,这时查找名为“James”的记录时会快很多,因为该索引已经按照字母顺序排列,名字首字母为“J”的雇员都是排列在一起的。通过该索引,能获取到表中对应的记录。
为什么使用B-Tree索引?
一般来说,索引本身也很大,不可能全部存储在内存中,因此索引往往以索引文件的形式存储在磁盘上,因此索引查找过程会产生IO消耗,
相对于内存存取,IO存取的消耗要高几个数量级,所以评价一个数据结构作为索引的优劣最重要的指标就是在查找过程中磁盘I/O操作次数的渐进复杂度。
换句话说就是索引的结构组织要尽量减少查找过程中磁盘的存取次数。
SQL优化方法?
(1)负向条件查询不能使用索引,可以优化为in查询
select from user where status != 0 (not in /not exist都不好);
select from user where status in(2,3);
(2)如果业务大部分是单条查询,使用Hash索引性能更好
因为B-tree索引的时间复杂度是O(log(n)) 而Hash索引的时间复杂度是O(1)
select from user where login_name=?
(3)单列索引不存null值,复合索引不存全为null的值,如果列可以为null,可能会得到不符合预期的结果集。
select from user where name!='kun'
如果name允许为null,索引不存null值,结果集中不会有这些记录,因此请使用not null 约束以及默认值。
(4)遵循符合索引最左前缀原则。最左前缀不是指SQL语句where顺序要和复合索引顺序一致
(5)使用枚举而不是字符串
(6)如果明确知道只有一条返回结果,limit 1能够提高效率
(7)不要使用select * 查询,只返回需要的列
(8)使用单表查询时,相同字段尽量不要用or,因为可能导致索引失效,用UNION代替。
select * from user where name='手机' or name ='电脑'(反面教材)
(9)索引不宜过多,根据实际情况决定,尽量不要超过10个。
(1) 表关联查询时务必遵循小表驱动大表原则
(2)分表,可根据业务字段尾数中的个位或十位或百位做表名达到分表的目的
(3)分库,可根据业务字段尾数中的个位或十位或百位做库名达到分库的目的
(4)表分区,类似于硬盘分区,可以将某个时间段的数据放在分区里,加快查询速度,可以配合分表+表分区结合使用
(5)使用非前导模糊查询
(6)在数据区分度大的字段上使用索引,一般能过滤80%的数据时就可以使用索引
(7)在属性上进行计算不能命中索引
神器EXPLAIN语句
explain显示了mysql如何使用索引来处理select语句及连接表。可以帮助选择更好的索引和写出更优化的查询语句
使用方法:在select语句前面加上explain就行
explain语句输出结果中各属性简介
table:显示这一行的数据是关于哪张表的
type:这是重要的列,显示连接使用了何种类型,从最好到最差的连接类型为const,eq_reg,ref,range,indexhe和all
possible_Keys:可能应用在这张表中的索引。如果为空,没有可能的索引。可以为相关的域从where语句中选择一个合适的语句
key:实际引用的索引。如果为null,则没有使用索引。很少的情况下,mysql会选择优化不足的索引。
这种情况下,可以在select语句中使用use index(indexname)来强制使用一个索引或者用ignore index(indexname)来强制mysql忽略索引。
key_len:使用索引的长度。在不损失精确性的情况下,长度越短越好。
ref:显示索引的哪一列被使用了,如果可能的话,是一个常数
rows:mysql认为必须检查的用来返回请求数据的行数
extra:关于mysql如何解析查询的额外信息