一、面试题(基础知识点)
1,集合
Collection与Collections,
Collection是所有集合类的根接口;
Collections是提供集合操作的工具类;
集合类和数组不同,
数组元素可以为基本数据类型值/对象引用;
集合元素只能为对象引用;
Java的集合类由Collection接口和Map接口派生,
Set代表无序集合,无序不可重复;
List代表有序集合,有序可重复;
Map集合存储键值对;
简介
1、List(有序、可重复)
List里存放的对象是有序的,同时也是可以重复的,List关注的是索引,拥有一系列和索引相关的方法,查询速度快。因为往list集合里插入或删除数据时,会伴随着后面数据的移动,所有插入删除数据速度慢。
2、Set(无序、不能重复)
Set里存放的对象是无序,不能重复的,集合中的对象不按特定的方式排序,只是简单地把对象加入集合中。
3、Map(键值对、键唯一、值不唯一)
Map集合中存储的是键值对,键不能重复,值可以重复。根据键得到值,对map集合遍历时先得到键的set集合,对set集合进行遍历,得到相应的值。
对比如下:
2,树的遍历
先序遍历:每到一层,先记录根节点,然后遍历左子树,再遍历右子树;
中序遍历:先遍历左子树,当到达叶节点时,记录该结点,然后记录其父节点,然后是右节点;
后序遍历:先遍历左子树,然后记录左边叶节点,右边叶节点,然后是父节点。
4.层序遍历 :层序遍历就是按照二叉树的层次由上到下的进行遍历,每一层要求访问的顺序为从左到右。
3,什么是IoC和DI?DI是如何实现的?
详解可参考:https://blog.csdn.net/javazejian/article/details/54561302
IoC叫控制反转,是Inversion of Control的缩写,控制反转是把传统上由程序代码直接操控的对象的调用权交给容器,通过容器来实现对象组件的装配和管理。所谓的"控制反转"就是对组件对象控制权的转移,从程序代码本身转移到了外部容器,由容器来创建对象并管理对象之间的依赖关系。
一句话描述:利用反射技术,通过配置文件的完全限定类名,在运行时创建所需要的实现类。我们唯一要做的就是把需要创建的类和其他类依赖的类以配置文件的方式告诉IOC容器需要创建那些类和注入哪些类即可。
控制反转——Spring通过一种称作控制反转(IoC)的技术促进了松耦合。当应用了IoC,一个对象依赖的其它对象会通过被动的方式传递进来,而不是这个对象自己创建或者查找依赖对象,是容器在对象初始化时不等对象请求就主动将依赖传递给它。通过IOC反转控制DI依赖注入完成各个层之间的注入,使得层与层之间实现完全脱耦,增加运行效率利于维护。
IOC 与依赖注入的区别
IOC:控制反转:将对象的创建权,由Spring管理.
DI(依赖注入):在Spring创建对象的过程中,把对象依赖的属性注入到类中。
Spring依赖注入(DI)的三种方式,分别为:
1. 注解注入
2. Setter方法注入
3. 构造方法注入
@Autowired是默认按类型匹配的(byType),如果需要按名称(byName)匹配的话,可以使用@Qualifier注解与@Autowired结合。
@Resource注解默认按byName模式注入。无法标注构造函数。
4,各种排序的稳定性,时间复杂度和空间复杂度总结:
5,Java的内存回收机制
1,回收的意义
在C++中,对象所占的内存在程序结束运行之前一直被占用,在明确释放之前不能分配给其它对象;而在Java中,当没有对象引用指向原先分配给某个对象的内存时,该内存便成为垃圾。JVM的一个系统级线程会自动释放该内存块。
6,Volatile
在多线程并发编程中synchronized和Volatile都扮演着重要的角色,Volatile是轻量级的synchronized,它在多处理器开发中保证了共享变量的“可见性”。可见性的意思是当一个线程修改一个共享变量时,另外一个线程能读到这个修改的值。
volatile可以保证线程可见性且提供了一定的有序性,但是无法保证原子性。
二、笔试题
1,在JAVA中怎样求二维数组的行数和列数
object [][] array ;
array.length 就是行数
array [0].length 就是列数
2,字符替换
//将空格替换为 %20
public class Solution {
public String replaceSpace(StringBuffer str) {
return str.toString().replaceAll("\\s", "%20");
}
}
3,输入一个链表,从尾到头打印链表每个节点的值。(利用Stack来实现)
/**
* public class ListNode {
* int val;
* ListNode next = null;
*
* ListNode(int val) {
* this.val = val;
* }
* }
*
*/
import java.util.Stack;
import java.util.ArrayList;
public class Solution {
public ArrayList<Integer> printListFromTailToHead(ListNode listNode) {
Stack<Integer> stack = new Stack<>();
while (listNode != null) {
stack.push(listNode.val);
listNode = listNode.next;
}
ArrayList<Integer> list = new ArrayList<>();
while (!stack.isEmpty()) {
list.add(stack.pop());
}
return list;
}
}
//java 递归超简洁版本,利用递归倒置
public class Solution {
ArrayList<Integer> arrayList=new ArrayList<Integer>();
public ArrayList<Integer> printListFromTailToHead(ListNode listNode) {
if(listNode!=null){
this.printListFromTailToHead(listNode.next);
arrayList.add(listNode.val);
}
return arrayList;
}
}
4,Java中的Arrays.copyOfRange()方法
要使用这个方法,首先要import java.util.*;
Arrays.copyOfRange(T[ ] original,int from,int to)
将一个原始的数组original,从小标from开始复制,复制到小标to,生成一个新的数组。
注意这里包括下标from,不包括下标to。
5,输入某二叉树的前序遍历和中序遍历的结果,请重建出该二叉树。假设输入的前序遍历和中序遍历的结果中都不含重复的数字。
例如输入前序遍历序列{1,2,4,7,3,5,6,8}和中序遍历序列{4,7,2,1,5,3,8,6},则重建二叉树并返回。
import java.util.*;
/**
* Definition for binary tree
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode(int x) { val = x; }
* }
*/
//巧妙利用递归思想还原二叉树
public class Solution {
public TreeNode reConstructBinaryTree(int [] pre,int [] in) {
if(pre.length == 0||in.length == 0){
return null;
}
TreeNode node = new TreeNode(pre[0]);
for(int i = 0; i < in.length; i++){
if(pre[0] == in[i]){
node.left = reConstructBinaryTree(Arrays.copyOfRange(pre, 1, i+1), Arrays.copyOfRange(in, 0, i));
node.right = reConstructBinaryTree(Arrays.copyOfRange(pre, i+1, pre.length), Arrays.copyOfRange(in, i+1,in.length));
}
}
return node;
}
}
不能通过先序遍历和后序遍历得到唯一中序遍历。
6,java.util.Scanner类
//Scanner默认使用空格作为分割符来分隔文本,但允许你指定新的分隔符
Scanner s=new Scanner(System.in);
// s.useDelimiter(" |,|\\.");
// --将注释行去掉,可以使用空格或逗号或点号作为分隔符,输出结果如下:
while (s.hasNext()) {
System.out.println(s.next());
}
next.Byte(),nextDouble(),nextFloat,nextInt(),nextLine(),nextLong(),nextShot()
下面是一些API函数的用法:
delimiter() 返回此 Scanner 当前正在用于匹配分隔符的 Pattern。
hasNext() 判断扫描器中当前扫描位置后是否还存在下一段。
hasNextLine() 如果在此扫描器的输入中存在另一行,则返回 true。
next() 查找并返回来自此扫描器的下一个完整标记。
nextLine() 此扫描器执行当前行,并返回跳过的输入信息。
7,输入一个整数,输出该数二进制表示中1的个数。其中负数用补码表示。
public class Solution {
public int NumberOf1(int n) {
String temp = "";
if(n == 0){
return 0;
}else if(n> 0){
temp = Integer.toBinaryString(n);
}else{
//如果该数字为负数,那么进行该负数的绝对值取反的值加一后的二进制码,然后将它保存在temp结果中
temp = Integer.toBinaryString(~(-n)+1);
}
int count = 0;
for(int i = 0;i< temp.length();i++){
if(temp.charAt(i) == '1'){
count++;
}
}
return count;
}
}
重点在于java的取反操作(~n)和二进制转换函数Integer.toBinaryString()。
后来补充:
Integer.toBinaryString(-5)可直接返回-5的补码。n<0时,~(-n)+1 = n。所以原文的转换有多余操作。
8,java运算符
JAVA中位运算符:
~ 按位非(NOT)(一元运算)
& 按位与(AND)
| 按位或(OR)
^按位异或(XOR)
>>带符号右移 -5>>2: 1111 1011------>1111 1110 补了标志位,两个11
>>>无符号右移,左边空出的位以0填充 -5>>>2: 1111 1011-------->0011 1110 补了两个0
<<左移
&= 按位与赋值
|= 按位或赋值
^=按位异或赋值
>>=右移赋值
>>>=右移赋值,左边空出的位以0填充
<<=左移赋值
8,Java虚拟机类加载机制
public class SSClass
{
static
{
System.out.println("SSClass");
}
}
public class SuperClass extends SSClass
{
static
{
System.out.println("SuperClass init!");
}
public static int value = 123;
public SuperClass()
{
System.out.println("init SuperClass");
}
}
public class SubClass extends SuperClass
{
static
{
System.out.println("SubClass init");
}
static int a;
public SubClass()
{
System.out.println("init SubClass");
}
}
public class NotInitialization
{
public static void main(String[] args)
{
System.out.println(SubClass.value);
}
}
运行结果:
SSClass
SuperClass init!
123
解释:对于静态字段,只有直接定义这个字段的类才会被初始化,因此通过其子类来引用父类中定义的静态字段,只会触发父类的初始化而不会触发子类的初始化。
上面就牵涉到了虚拟机类加载机制。