我的面试宝典:一线互联网大厂Java核心面试题库
以下是我个人的一些做法,希望可以给各位提供一些帮助:
整理了很长一段时间,拿来复习面试刷题非常合适,其中包括了Java基础、异常、集合、并发编程、JVM、Spring全家桶、MyBatis、Redis、数据库、中间件MQ、Dubbo、Linux、Tomcat、ZooKeeper、Netty等等,且还会持续的更新…可star一下!
283页的Java进阶核心pdf文档
Java部分:Java基础,集合,并发,多线程,JVM,设计模式
数据结构算法:Java算法,数据结构
开源框架部分:Spring,MyBatis,MVC,netty,tomcat
分布式部分:架构设计,Redis缓存,Zookeeper,kafka,RabbitMQ,负载均衡等
微服务部分:SpringBoot,SpringCloud,Dubbo,Docker
还有源码相关的阅读学习
//remove()
arrayList.remove(student2);
//删除arrayList中的student2,但是student1没了,表示remove()方法底层调用的也是equals()方法
System.out.println(arrayList.size());//0
}
}
//Student类
class Student{
private String name;
//构造方法
public Student() {
}
public Student(String name) {
this.name = name;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Student student = (Student) o;
return Objects.equals(name, student.name);
}
}
1.4 Collection方法中remove()方法深入
public class CollectionTest04 {
public static void main(String[] args) {
Collection arrayList = new ArrayList();
//如果集合机构发生了改变,但是不重新获取新的迭代器就会:
//java.util.ConcurrentModificationException
//Iterator iterator = arrayList.iterator();
arrayList.add(“abc”);
arrayList.add(“def”);
//获取迭代器
Iterator iterator = arrayList.iterator();
while(iterator.hasNext()){
System.out.println(iterator.next());
}
//在迭代元素的过程中,不能调用集合对象的remove()方法
Collection arrayList1 =new ArrayList();
arrayList1.add(123);
arrayList1.add(456);
arrayList1.add(789);
/*//迭代
Iterator iterator1 = arrayList1.iterator();
while(iterator1.hasNext()){
System.out.println(iterator1.next());
//ConcurrentModificationException
//arrayList1.remove(123);
}*/
//解决办法:
Iterator iterator1 = arrayList1.iterator();
while (iterator1.hasNext()){
Object object = iterator1.next();
//iterator1.remove(456);//直接通过集合删除元素,没有通知迭代器(导致迭代器的快照和元集合状态不同)
iterator1.remove();//删除的一定是当前元素
System.out.println(object);
}
System.out.println(arrayList1.size());//0 删除干净了
}
}
二.泛型
泛型的优点:
* 第一:集合中存储的元素更加统一
* 第二:从集合中取出的元素是泛型指定的类型,不需要进行大量的“向下转型”
*
* 缺点:
* 导致集合中存储的元素缺乏多样性
*
* 实际开发中,其实主要是同一种类型
*
* 但是如果是子类的特有方法,还是要向下转型
2.1 泛型的基础语法
public class GenericTest01 {
public static void main(String[] args) {
Animal animal =new Animal();
Bird bird =new Bird();
Cat cat =new Cat();
//使用了泛型,那么 arrayList 这个集合只能放 Animal 类的元素
Collection arrayList = new ArrayList();
arrayList.add(animal);
arrayList.add(bird);
arrayList.add(cat);
//arrayList.add(“123”);报错
//迭代
//记住这里也要泛型,表示迭代器迭代的是Animal类型
Iterator iterator = arrayList.iterator();
while(iterator.hasNext()){
iterator.next().move();
}
/*Animal is moving
Bird is moving
Cat is moving
*/
}
}
class Animal{
public void move(){
System.out.println(“Animal is moving”);
}
}
class Cat extends Animal{
@Override
public void move() {
System.out.println(“Cat is moving”);
}
public void catMouse(){
System.out.println(“猫抓老鼠!!!”);
}
}
class Bird extends Animal{
@Override
public void move() {
System.out.println(“Bird is moving”);
}
public void fly(){
System.out.println(“鸟儿在飞翔!!!”);
}
}
2.2泛型的自动类型推断机制(钻石表达式)
import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
public class GenericTest02 {
public static void main(String[] args) {
//ArrayList<这里的类型会只动推断>,JDK8之后才允许
//自动类型推断
Collection arrayList = new ArrayList<>();
arrayList.add(new Animal());
arrayList.add(new Cat());
arrayList.add(new Bird());
//迭代
Iterator iterator =arrayList.iterator();
while(iterator.hasNext()){
iterator.next().move();
}
/*Animal is moving
Cat is moving
Bird is moving
*/
}
}
2.3 自定义泛型
/*
-
自定义泛型
-
< > 里面是一个标识符
-
java中经常出现是
-
<E>和<T>
E是Element首字母
T是Typ首字母
- */
public class GenericTest03 {
public void dosome(E abc){
System.out.println(“dosome …”);
}
public static void main(String[] args) {
GenericTest03 genericTest03 =new GenericTest03<>();
genericTest03.dosome(“???”);
//genericTest03.dosome(123);只能是String类型
GenericTest03 genericTest031 = new GenericTest03<>();
genericTest031.dosome(123);
}
}
三.增强For循环
//JDK5.0之后推出了一个新特性:增强for循环,或者叫for each
//缺点:没下标,在需要使用下标的时候不建议使用增强for循环
public class ForEachTest01 {
public static void main(String[] args) {
//创建数组
int[] array = {1,2,3,4,5};
//创建集合
Collection arrayList =new ArrayList();
arrayList.add(1);
arrayList.add(2);
arrayList.add(3);
arrayList.add(4);
arrayList.add(5);
//遍历数组
for (int i:array){
System.out.print(i + " ");
}
System.out.println();
//遍历集合
for (Object o : arrayList){
System.out.print(o + " ");
}
}
}
四.List接口
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;
import java.util.Vector;
/*
-
测试list接口常用方法
-
1.list集合存储元素特点:有序可重复
-
有序:list集合元素有下标
-
从零开始以一递增
-
可重复:存储了一个1还可以再存储一个1
-
2.list既是Collection接口的子接口,那么肯定有list接口自己的特有的方法
-
以下只列出list接口常见特有的方法:
-
void add(int index, Object element) 在列表的指定位置插入指定元素(可选操作)。
-
Object get(int index) 返回列表中指定位置的元素
-
int indexOf(Object o) 返回此列表中第一次出现的指定元素的索引;如果此列表不包含该元素,则返回 -1。
-
int lastIndexOf(Object o) 返回此列表中最后出现的指定元素的索引;如果列表不包含此元素,则返回 -1。
-
Object remove(int index) 移除列表中指定位置的元素(可选操作)
-
Object set(int index, E element) 用指定元素替换列表中指定位置的元素(可选操作)。
-
*/
public class ListTest {
public static void main(String[] args) {
//创建集合对象
List linkedList= new LinkedList();
List vector= new Vector();
List arrayList = new ArrayList();
//添加元素
arrayList.add(“A”);//默认添加到最后一项
arrayList.add(“B”);//默认添加到最后一项
arrayList.add(“D”);//默认添加到最后一项
//void add(int index, Object element) 在列表的指定位置插入指定元素(可选操作)。
arrayList.add(2,“C”); // 添加到指定位置
//Object get(int index) 返回列表中指定位置的元素
System.out.println(arrayList.get(3));//D
/*
-
int indexOf(Object o) 返回此列表中第一次出现的指定元素的索引;如果此列表不包含该元素,则返回 -1。
-
int lastIndexOf(Object o) 返回此列表中最后出现的指定元素的索引;如果列表不包含此元素,则返回 -1。
-
*/
arrayList.add(“D”);
arrayList.add(“C”);
arrayList.add(“B”);
arrayList.add(“A”);
System.out.println(arrayList.indexOf(“A”));//0
System.out.println(arrayList.indexOf(“F”));//-1
System.out.println(arrayList.lastIndexOf(“A”));//7
System.out.println(arrayList.lastIndexOf(“F”));//-1
//Object remove(int index) 移除列表中指定位置的元素(可选操作)
arrayList.remove(0);
//Collection 还有remove(Object o)方法,删除元素
System.out.println(arrayList.get(0));//B A被删除了
//Object set(int index, E element) 用指定元素替换列表中指定位置的元素(可选操作)。
for (Object o : arrayList){
System.out.print(o + " ");//B C D D C B A
}
arrayList.set(0,“A”);
System.out.println();
for (Object o : arrayList){
System.out.print(o + " ");//A C D D C B A
}
}
}
五.ArrayList集合
public class ArrayListTest01 {
public static void main(String[] args) {
//构造方法
//默认容量是10
ArrayList arrayList1 =new ArrayList();
指定初始化容量
ArrayList arrayList2 =new ArrayList(100);
//public ArrayList(Collection c)
// 构造一个包含指定 collection 的元素的列表
// 这些元素是按照该 collection 的迭代器返回它们的顺序排列的。
//创建一个HashSet集合
Collection hashSet= new HashSet();
hashSet.add(1);
hashSet.add(2);
hashSet.add(3);
ArrayList arrayList =new ArrayList(hashSet);
//遍历
for (int i = 0; i <arrayList.size() ; i++) {
System.out.print(arrayList.get(i) + " ");//1 2 3
}
}
}
六.LinkedList集合
6.1 模拟单向链表
//模拟单链表
//链表的基本单元的Node
//对于单向链表来说:Node中存储了当前节点的数据,以及下一节点的内存地址
public class Node {
//存储的数据
Object element;
//下一节点的内存地址
Node next;
//构造方法
public Node() {
}
public Node(Object element, Node next) {
this.element = element;
this.next = next;
}
}
//单向链表类
public class Link {
//头节点
Node heard = null;
//size
int size = 0;
public int size(){
return this.size;
}
//向链表末尾中添加元素
public void add(Object o){
//判断是否是头文件
if (heard == null){
heard = new Node(o,null);
}else{
//头不是空
//找出当时的末尾节点
Node currentNode = findCurrentNode(heard);
currentNode = new Node(o,null);
}
size ++;
}
/**
-
@param node 起始节点
-
@return 末尾节点
*/
public Node findCurrentNode(Node node) {
//递归
if (node.next == null){
return node;
}else {
return findCurrentNode(node.next);
}
}
}
public class LinkTest {
public static void main(String[] args) {
Link myLink = new Link();
myLink.add(1);
myLink.add(2);
myLink.add(3);
myLink.add(4);
myLink.add(5);
//元素个数
System.out.println(myLink.size);
}
}
6.2 LinkedList
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
/*
-
链表的优点:
-
由于链表上的元素在空间上的内存地址不连续
-
因为随机增删的时候不会有大量的元素位移,因此随机增删效率较高
-
在以后的开发中,如果遇到随机增删集合中的元素业务较多时,建议使用LinkedList
-
*/
public class LinkedListTest {
public static void main(String[] args) {
//创建一个LinkedList对象
List linkedList= new LinkedList();
//添加元素
linkedList.add(1);
linkedList.add(2);
linkedList.add(3);
linkedList.add(4);
linkedList.add(5);
//遍历
//for each
for(Object o:linkedList){
System.out.print(o + " ");
}
System.out.println();
//迭代器迭代
Iterator iterator = linkedList.iterator();
while(iterator.hasNext()){
System.out.print(iterator.next() + " ");
}
System.out.println();
LinkedList集合底层也是有下标的
//注意:ArrayList之所以检索效率高,不单是因为有下标,主要是底层是数组的原因
//LikedList集合照样有下标,但是检索/查找效率某个元素效率比较低,因为只能从头节点开始一个一个遍历
//下标循环
for (int i = 0; i <linkedList.size() ; i++) {
System.out.print(linkedList.get(i) + " ");
}
//LinkedList集合有初始化吗?没有
//最初这个链表中没有任何元素,first和last引用都是null
//不管是LikedList还是ArrayList,以后写代码不需要关系具体是哪个
//因为我们要面向接口编程,调用的方法都是接口中的方法
//List list2 = new ArrayList();//这样写表示调用了数组
List list2 = new LinkedList();//这样写表示底层调用了双向链表
list2.add(“123”);
list2.add(“456”);
list2.add(“789”);
for (int i = 0; i < list2.size(); i++) {
System.out.println(list2.get(i));
}
}
}
七.Vector集合
import java.util.*;
/*
-
Vector:
-
1.底层也是一个数组
-
2.初始化容量:10
-
3.扩容之后是原来的二倍
-
ArrayList是原来的1.5倍
-
4.Vector的方法都带 synchronized 关键字,线程安全,效率较低
-
6.怎么将一个线程不安全的ArrayList转换成线程安全的Vector?
-
使用集合工具类:
-
Java.util.Collections
-
java.util.Collection是集合接口
-
java.util.Collections是集合工具类
-
*/
public class VectorTest{
public static void main(String[] args) {
//多态
Collection vector= new Vector();
//添加元素
vector.add(1);
vector.add(2);
vector.add(3);
vector.add(4);
vector.add(5);
//遍历/迭代
Iterator iterator =vector.iterator();
while(iterator.hasNext()){
System.out.print(iterator.next() + " ");
}
//Vector 是线程安全的
//ArrayList不是线程安全的
//怎么将ArrayList变成线程安全的呢?
List arrayList = new ArrayList();
//集合工具类
Collections.synchronizedList(arrayList);
//现在 arrayList 是线程安全的了
}
}
八.Set接口
import java.util.HashSet;
import java.util.Set;
public class SetTest {
public static void main(String[] args) {
//Set是Collection的子接口,不能new set对象
//‘Set’ is abstract; cannot be instantiated
//Set set =new Set();
Set hashSet= new HashSet();
}
}
九.HashSet集合
import java.util.HashSet;
import java.util.Iterator;
import java.util.Set;
/*
-
HashSet集合:
-
无序不可重复
-
*/
public class HashSetTest {
public static void main(String[] args) {
Set hashSet = new HashSet<>();
hashSet.add(3);
hashSet.add(1);
hashSet.add(2);
hashSet.add(5);
hashSet.add(8);
hashSet.add(4);
hashSet.add(3);
hashSet.add(1);
hashSet.add(3);
//遍历
Iterator iterator= hashSet.iterator();
while(iterator.hasNext()){
System.out.print(iterator.next() + " " );
}
}
}
十.TreeSet集合
10.1 TreeSet集合的基础语法
import java.util.Iterator;
import java.util.Set;
import java.util.TreeSet;
/*
-
TreeSet集合存储元素特点:
-
1.无序不可重复,但是存储的元素可以自动按照大小排序
-
称为:可排序集合
-
2.无序:这里的无序是指存进去的顺序和取出来的顺序不同,且没有下标
-
3.TreeSet底层实际上是一个TreeMap
-
4.TreeMap底层是一个二叉树
-
5.放到TreeSet集合里的元素,等同于放到TreeMap集合的key里面
-
6.TreeSet集合中的元素:无序不可重复,但是按着元素的大小排序
-
称为:可排序集合*/
public class TreeSetTest01 {
public static void main(String[] args) {
Set treeSet= new TreeSet<>();
treeSet.add(10);
treeSet.add(5);
treeSet.add(20);
treeSet.add(1);
//迭代
Iterator iterator =treeSet.iterator();
while(iterator.hasNext()){
System.out.print(iterator.next() + " ");//1 5 10 20 排序了
}
System.out.println();
treeSet.clear();
treeSet.add(“A”);
treeSet.add(“Z”);
treeSet.add(“B”);
treeSet.add(“F”);
treeSet.add(“D”);
treeSet.add(“H”);
for (Object o :treeSet){
System.out.print(o + " ");//A B D F H Z 小到大的排序
}
}
}
10.2 自定义类在TreeSet里怎么排序
第一种方法:
`import java.util.Comparator;
import java.util.Iterator;
import java.util.TreeSet;
public class TreeSetTest03 {
public static void main(String[] args) {
//创建顾客对象
Customer customer1 =new Customer(1);
Customer customer2 =new Customer(2);
Customer customer3 =new Customer(3);
Customer customer4 =new Customer(4);
Customer customer5 =new Customer(5);
//创建TreeSet对象
TreeSet treeSet =new TreeSet<>();
//添加元素
treeSet.add(customer1);
treeSet.add(customer2);
treeSet.add(customer3);
treeSet.add(customer4);
treeSet.add(customer5);
//迭代
Iterator iterator = treeSet.iterator();
while(iterator.hasNext()){
System.out.println(iterator.next());
}
/*Customer{age=1}
Customer{age=2}
Customer{age=3}
Customer{age=4}
Customer{age=5}
*/
}
}
//放在TreeSet集合中的元素要实现java.lang.Comparable接口
//并且实现compareTo方法,equals可以不重写
//这里要泛型,要不然下面会报错
class Customer implements Comparable{
int age;
public Customer(){
}
public Customer(int age){
this.age = age;
}
//需要在这个方法中编写比较的逻辑
//k.compareTo(t.key)
//拿着参数k和集合的每一个key比较,返回值可能是大于零,可能是小于零,可能是等于零
//比较规则还是由程序员来定
@Override
public int compareTo(Customer c) {
/*if (this.age == c.age){
return 0;
}else if (this.age >c.age){
return 1;
}else if (this.age < c.age){
return 1;
}*/
return this.age -c.age;
}
//重写toString方法
@Override
public String toString() {
return “Customer{” +
“age=” + age +
‘}’;
}
}
`
import java.util.TreeSet;
public class TreeSetTest04 {
public static void main(String[] args) {
//创建Vip对象
Vip vip1 =new Vip(10,“A”);
Vip vip2 =new Vip(20,“A”);
Vip vip3 =new Vip(10,“Z”);
Vip vip4 =new Vip(30,“Z”);
Vip vip5 =new Vip(15,“D”);
//创建集合对象
TreeSet treeSet =new TreeSet<>();
//添加元素
treeSet.add(vip1);
treeSet.add(vip2);
treeSet.add(vip3);
treeSet.add(vip4);
treeSet.add(vip5);
//遍历
for (Vip vip : treeSet){
System.out.println(vip);
}
/*Vip{age=10, name=‘A’}
Vip{age=10, name=‘Z’}
Vip{age=15, name=‘D’}
Vip{age=20, name=‘A’}
Vip{age=30, name=‘Z’}
*/
}
}
//先按照年龄升序,如果年龄一样在按着姓名升序
class Vip implements Comparable{
private int age;
private String name;
//构造方法
public Vip() {
}
public Vip(int age, String name) {
this.age = age;
this.name = name;
}
//实现 compareTo 方法
@Override
public int compareTo(Vip o) {
if (this.age == o.age){
//String类实现了 compareTo 方法
return this.name.compareTo(o.name);
}else {
return this.age - o.age;
}
}
@Override
public String toString() {
return “Vip{” +
“age=” + age +
“, name='” + name + ‘’’ +
‘}’;
}
}
第二种方法:
import java.util.Comparator;
import java.util.TreeSet;
//TreeSet集合元素可排序的第二种方式:使用比较器的方式
/*放到TreeSet或者TreeMap集合key部分的元素想要做到排序,有两种方式:
-
第一种:放在集合中的元素实现 java.lang.Comparable接口
-
第二种:在构造TreeSet或者TreeMap集合的时候给它传一个比较器对象。
-
Comparable和Comparator怎么选择?
-
如果比较规则一直不变的话,或者比较规则只有一个:Comparable
-
如果比较规则经常改变的话,或者比较规则有多个 :Comparator*/
public class TreeSetTest05 {
public static void main(String[] args) {
//给构造方法传一个比较器
//TreeSet testTreeSet = new TreeSet<>(new AnimalTestComparator());
//或者用匿名内部类
TreeSet testTreeSet = new TreeSet<>(new Comparator() {
@Override
public int compare(AnimalTest o1, AnimalTest o2) {
return o1.getNo() - o2.getNo();
}
});
//创建AnimalTest对象
AnimalTest animalTest1 =new AnimalTest(10);
AnimalTest animalTest2 =new AnimalTest(5);
AnimalTest animalTest3 =new AnimalTest(15);
AnimalTest animalTest4 =new AnimalTest(1);
AnimalTest animalTest5 =new AnimalTest(20);
//添加元素
testTreeSet.add(animalTest1);
testTreeSet.add(animalTest2);
testTreeSet.add(animalTest3);
testTreeSet.add(animalTest4);
testTreeSet.add(animalTest5);
for (AnimalTest a:testTreeSet){
System.out.println(a);
}
/*AnimalTest{no=1}
AnimalTest{no=5}
AnimalTest{no=10}
AnimalTest{no=15}
AnimalTest{no=20}
*/
}
}
class AnimalTest{
private int no;
public AnimalTest() {
}
public AnimalTest(int no) {
this.no = no;
}
public int getNo() {
return no;
}
public void setNo(int no) {
this.no = no;
}
@Override
public String toString() {
return “AnimalTest{” +
“no=” + no +
‘}’;
}
}
/*
//单独编写一个比较器
//比较器实现java.util.Comparator接口。(Comparable是java.lang包下的)
class AnimalTestComparator implements Comparator{
@Override
//比较方法
public int compare(AnimalTest o1, AnimalTest o2) {
return o1.getNo() - o2.getNo();
}
}*/
十一.Map接口
11.1 Map集合的常用方法
总结
就写到这了,也算是给这段时间的面试做一个总结,查漏补缺,祝自己好运吧,也希望正在求职或者打算跳槽的 程序员看到这个文章能有一点点帮助或收获,我就心满意足了。多思考,多问为什么。希望小伙伴们早点收到满意的offer! 越努力越幸运!
金九银十已经过了,就目前国内的面试模式来讲,在面试前积极的准备面试,复习整个 Java 知识体系将变得非常重要,可以很负责任的说一句,复习准备的是否充分,将直接影响你入职的成功率。但很多小伙伴却苦于没有合适的资料来回顾整个 Java 知识体系,或者有的小伙伴可能都不知道该从哪里开始复习。我偶然得到一份整理的资料,不论是从整个 Java 知识体系,还是从面试的角度来看,都是一份含技术量很高的资料。
est1 =new AnimalTest(10);
AnimalTest animalTest2 =new AnimalTest(5);
AnimalTest animalTest3 =new AnimalTest(15);
AnimalTest animalTest4 =new AnimalTest(1);
AnimalTest animalTest5 =new AnimalTest(20);
//添加元素
testTreeSet.add(animalTest1);
testTreeSet.add(animalTest2);
testTreeSet.add(animalTest3);
testTreeSet.add(animalTest4);
testTreeSet.add(animalTest5);
for (AnimalTest a:testTreeSet){
System.out.println(a);
}
/*AnimalTest{no=1}
AnimalTest{no=5}
AnimalTest{no=10}
AnimalTest{no=15}
AnimalTest{no=20}
*/
}
}
class AnimalTest{
private int no;
public AnimalTest() {
}
public AnimalTest(int no) {
this.no = no;
}
public int getNo() {
return no;
}
public void setNo(int no) {
this.no = no;
}
@Override
public String toString() {
return “AnimalTest{” +
“no=” + no +
‘}’;
}
}
/*
//单独编写一个比较器
//比较器实现java.util.Comparator接口。(Comparable是java.lang包下的)
class AnimalTestComparator implements Comparator{
@Override
//比较方法
public int compare(AnimalTest o1, AnimalTest o2) {
return o1.getNo() - o2.getNo();
}
}*/
十一.Map接口
11.1 Map集合的常用方法
总结
就写到这了,也算是给这段时间的面试做一个总结,查漏补缺,祝自己好运吧,也希望正在求职或者打算跳槽的 程序员看到这个文章能有一点点帮助或收获,我就心满意足了。多思考,多问为什么。希望小伙伴们早点收到满意的offer! 越努力越幸运!
金九银十已经过了,就目前国内的面试模式来讲,在面试前积极的准备面试,复习整个 Java 知识体系将变得非常重要,可以很负责任的说一句,复习准备的是否充分,将直接影响你入职的成功率。但很多小伙伴却苦于没有合适的资料来回顾整个 Java 知识体系,或者有的小伙伴可能都不知道该从哪里开始复习。我偶然得到一份整理的资料,不论是从整个 Java 知识体系,还是从面试的角度来看,都是一份含技术量很高的资料。
[外链图片转存中…(img-Iv4KuRYX-1715585503674)]