前言:大家好,我是小威,一个明天即将入职准大三学生。本篇将记录前几次面试中经常被问到的知识点。
本篇文章记录的基础知识,适合在学Java的小白,也适合复习中,面试中的大佬。
如果文章有什么需要改进的地方还请大佬不吝赐教。
小威在此先感谢各位大佬啦~~
以下正文开始
文章目录
- 创建线程的三种方法
- 继承Thread类
- 实现Runnable接口
- 实现Callable接口
- try…catch和finally
- Linux文件数字权限
- 深拷贝和前拷贝的区别
- 深拷贝
- 浅拷贝
- 什么时候用不到索引
- 子集
创建线程的三种方法
创建线程有三种方法,分别是:
- 继承Thread类;
- 实现Runnable接口,重写run()方法;
- 实现Callable接口
继承Thread类
定义一个类继承Thread类,并重写该类的run⽅法,该run方法的方法体里面就表示了线程要完成的任务。我们把run()方法称为执行体;
创建Thread子类的实例对象,也就是创建了线程对象;
手动调用线程对象的start()方法来启动该线程。
实现Runnable接口
因为类只支持单方面的继承,所以第一种创建线程的方法有一定的局限性,而接口可以实现多个。
定义一个Runnable接口的实现类,并重写该接⼝的run()⽅法,我们所重写的run()⽅法的⽅法体同样是该线程的线程执行体;
创建 Runnable实现类的实例对象;
使用Thread有参构造方法创建线程实例,并将Runnable接口的实现类的实例对象作为参数传入;
调⽤线程对象的start()⽅法来启动该线程。
实现Callable接口
通过Callable和Future创建线程
创建Callable接⼝的实现类,并且重写Callable接口里面的call()⽅法,该call()方法即为线程执⾏体,并且有返回值。
创建Callable实现类的实例,使⽤FutureTask类来包装Callable对象,该FutureTask对象封装了该Callable对象的call()⽅法的返回值。
使⽤FutureTask对象作为Thread对象的target创建并启动新线程。
调⽤FutureTask对象的get()⽅法来获得子线程执⾏结束后的返回值
try…catch和finally
首先,try…catch对异常的捕获是为了使程序能够有效地执行。
try…catch…finally结构
try
{
执行的代码,其中可能有异常。如果发现异常,会立即跳到catch执行。否则不会执行catch里面的内容
}
catch(Exception e)
{
try里面执行的代码发生了异常才会进行catch处理
}
finally
{
不管什么情况都会执行,包括try catch 里面用了return ,可以理解为只要执行了try或者catch,就一定会执行 finally
}
try-catch-finally的执行顺序是:
- 不管有没有出现异常,finally块中的代码都会执行;
- 当try和catch中有return时,finally仍然会执行;
- finally是在return后面的表达式运算后执行的
try-catch-finally 其中 catch 和 finally 都可以被省略,但是不能同时省略,也就是说有 try 的时候,必须后面跟一个 catch 或者 finally。
Linux文件数字权限
首先解释文件中r ,w, x, – 的含义,r是只读权限,w是写的权限,x是可执行权限, -是没有任何权限。
目录中 r w x的含义,r具有ls(列出目录下的文件)权限,w是在目录上可以增加、删除、创建权限,x是具有ls –l(以长格式的形式查看当前目录下所有可见文件的属性)权限。
数字如何表示权限呢?
我们规定读(r)为4,写(w)为2,执行权限(x)为1。
所以
rwx为7,rw为6,rx为5,wx为3等。
而它表示的权限分为自己,自己群组其他成员,其它组。例如:
chmod 777 file //所有人都可读,写,执行chmod 700 file //自己可读,写,执行,其他人不可以chmod 775 file //自己和同组人员可读,写,执行,而其他组可读,执行,不可写
深拷贝和前拷贝的区别
深拷贝和浅拷贝最近的这几次面试中经常问到的问题。
深拷贝
深拷贝和浅拷贝是指对象的拷贝,一个对象存在两种类型的属性,一种是基本数据类型,一种是引用类型。
深拷贝:即拷贝基本数据类型的值,也会针对实例对象的引用地址所指向的对象进行复制,深拷贝出来的对象,类的内部执行的对象不是同一个深拷贝是一个整个独立的对象拷贝,并且深拷贝会拷贝所有的属性,并拷贝属性指向的动态分配的内存。当对象和它所引用的对象一起拷贝时即发生深拷贝。
深拷贝把要复制的对象所引用的对象都复制了一遍。
浅拷贝
浅拷贝浅拷贝将原对象或原数组的引用直接赋给新对象,新数组,新对象/数组只是原对象的一个引用(拷贝后的引用都是指向同一个对象的实例,彼此之间的操作会互相影响)
浅拷贝复制的只是一层的变量,并不会复制深层变量绑定的变量。
区别:
深拷贝拷贝的是多层,每一层次的数据都会拷贝,并且深拷贝只拷贝内容,拷贝的两个对象也拥有不同的地址。拷贝出来的对象发生改变时,原来的对象不会发生改变,两者互不影响。浅拷贝只拷贝一层,更深层次对象级别只拷贝引用地址。当浅拷贝的对象发生改变时,原来的对象也会发生相同的改变。
什么时候用不到索引
如果面试官问到这里,可能是想要问最左匹配原则。
最左匹配原则,顾名思义:最左优先,以最左边的为起点任何连续的索引都能匹配上。同时遇到范围查询(>、<、between、like)就会停⽌匹配。
mysql创建复合索引的规则是⾸先对复合索引最左边的字段的数据进⾏排序,在此基础上,再对后⾯的字段进⾏排序,这样第⼀个字段是绝对有序的,后⾯的字段就是⽆序的了,⼀般情况下第⼆个字段进⾏条件判断是⽤不到索引的,可能出现type是index类型的,这就是mysql 最左前缀的原因。
举个栗子:假设创建了顺序为(a,b,c)的索引
1.当查询条件为a=1 and b=1 或b=1 and a=1(查询优化器会调换a与b的位置),这时候都可以走索引。
2.当查询条件为a=1 and b>1 and c=1 时 ,由于是范围查找,a和b走索引,c不走索引
3.当查询条件为b=1时查询时也不会走索引
子集
分享一道最近面试问到的算法题。
Leetcode78 子集
题目:
给你一个整数数组 nums ,数组中的元素 互不相同 。返回该数组所有可能的子集(幂集)。
解集 不能 包含重复的子集。你可以按 任意顺序 返回解集。
示例 1:
输入:nums = [1,2,3]
输出:[[],[1],[2],[1,2],[3],[1,3],[2,3],[1,2,3]]
示例 2:
输入:nums = [0]
输出:[[],[0]]
题解:本题用到了回溯的算法思想,题解如下。
class Solution {List<List<Integer>> result = new ArrayList<>();// 存放符合条件结果的集合LinkedList<Integer> path = new LinkedList<>();// 用来存放符合条件结果public List<List<Integer>> subsets(int[] nums) {if (nums.length == 0){result.add(new ArrayList<>());return result;}subsetsHelper(nums, 0);return result;}private void subsetsHelper(int[] nums, int startIndex){result.add(new ArrayList<>(path));//「遍历这个树的时候,把所有节点都记录下来,就是要求的子集集合」。if (startIndex >= nums.length){ //终止条件可以不加return;}for (int i = startIndex; i < nums.length; i++){path.add(nums[i]);subsetsHelper(nums, i + 1);path.removeLast();}}}
本篇文章到这里就结束了,希望小伙伴儿们通过这篇文章可以学到很多东西
小威再次感谢各位小伙伴儿们了
祝愿大家最后都能拿到自己心仪的offer