总结
虽然面试套路众多,但对于技术面试来说,主要还是考察一个人的技术能力和沟通能力。不同类型的面试官根据自身的理解问的问题也不尽相同,没有规律可循。
上面提到的关于这些JAVA基础、三大框架、项目经验、并发编程、JVM及调优、网络、设计模式、spring+mybatis源码解读、Mysql调优、分布式监控、消息队列、分布式存储等等面试题笔记及资料
有些面试官喜欢问自己擅长的问题,比如在实际编程中遇到的或者他自己一直在琢磨的这方面的问题,还有些面试官,尤其是大厂的比如 BAT 的面试官喜欢问面试者认为自己擅长的,然后通过提问的方式深挖细节,刨根到底。
相比于逐个知识点的去讲解,一条更偏向于用面试题的方式呈现,原因如下:
- 节省时间,有很多朋友都是面试前临时抱佛脚,从
helloworld
开始讲,根本来不及好吗
- 重点突出,有些东西面试官是不会问的,也没法问,暂时就可以不看
- 转换思维,最重要的一点,有很多时候这个东西你知道,但一问就不会,有没有,有的评论区扣1
ok,我们看题
JVM、JDK、JRE、JMM什么区别
你要是没听过这几个东西,别说你学过Java
JVM
java虚拟机,可以说是核心的核心,如果你简历上敢写精通jvm,面试官一定把你问的怀疑人生。
其主要是用来执行java字节码(二进制的形式)的虚拟计算机。运行在操作系统之上的,与硬件没有任何关系。我们说Java的跨平台特性,就是靠它实现的。
关于jvm,有类加载机制,组成结构,垃圾回收,内存调优等问题可以问。
JDK
Java Development Kit,我们学java的第一天就要安装的东西,其包含包括 Java 运行环境(Java Runtime Envirnment,简称 JRE),Java 工具(比如 javac、java、javap 等等),以及 Java 基础类库(比如 rt.jar)
JRE
对,就是刚刚提到的jre,他包含运行JAVA程序所必须的环境的集合,包含JVM标准实现及Java核心类库。
JMM
Java内存模型,一个抽象的概念,主要在并发编程时用到,具有原子性,有序性,一致性。
字节码
我们写好的java代码需要编译成字节码文件才能被计算机执行,字节码的开头是CAFFBABE
,正好对应Java的图标。
Java有几种数据类型,占多少字节?
出自美术宝、元气森林
面试官一问这道题你是不是以为他在侮辱你,太简单了好吗
但是,千万不要轻敌,简单题,我们要回答的流畅,深刻
Java 语言提供了 8 种基本类型,大致分为 4 类(8位=1字节)
-
整数型
-
byte
- 1字节 -
short
- 2字节 -
int
- 4字节 -
long
- 8字节,赋值时一般在数字后加上l
或L
-
浮点型
-
float
- 4字节,直接赋值时必须在数字后加上f
或F
-
double
- 8字节,赋值时一般在数字后加d
或D
-
字符型
-
char
- 2字节,存储 Unicode 码,用单引号赋值 -
布尔型
-
boolean
- 1字节,只有 true 和 false 两个取值,一个字节就够了
挺简单哈,回答的不错,关于这道题,还能追问什么呢?
float f=3.4; 是否正确
不正确。3.4 是双精度数,将双精度型(double)赋值给浮点型(float)属于下转型(down-casting,也称为窄化)会造成精度损失,因此需要强制类型转换float f =(float)3.4; 或者写成 float f =3.4F;。
short s1 = 1; s1 = s1 + 1;有错吗?
对于 short s1 = 1; s1 = s1 + 1;
由于 1 是 int 类型,因此 s1+1
运算结果也是int
型,需要强制转换类型才能赋值给 short
型。
short s1 = 1; s1 += 1;有错吗
short s1 = 1; s1 += 1;
可以正确编译,因为 s1+= 1;
相当于s1 = (short(s1 + 1);
其中有隐含的强制类型转换。
char可以存储汉字吗?
出自元气森林
当然是可以的,char类型中存储的是Unicode
编码,Unicode
编码中是存在中文的,所以char
自然可以存储汉字,但是!仅限于Unicode
中存在的汉字。
一个汉字的占两个字节,一个Unicode
也是占两个字节 ,char存储汉字完全没有问题。
char和boolean的默认值是多少?
char
是'\u0000'
,可以理解成一个空格。
boolean
默认是false
。
你都答对了吗?
基本数据类型和引用数据类型有什么区别?
简单来说,所有的非基本数据类型都是引用数据类型,除了基本数据类型对应的引用类型外,类、 接口类型、 数组类型、 枚举类型、 注解类型、 字符串型都属于引用类型。
主要有以下区别:
1、存储位置
-
基本变量类型在方法中定义的非全局基本数据类型变量的具体内容是存储在栈中的
-
引用数据类型变量其具体内容都是存放在堆中的,而栈中存放的是其具体内容所在内存的地址
2、传递方式
-
基本数据类型是按值传递
-
引用数据类型是按引用传递
看下面两段代码理解
//基本数据类型作为方法参数被调用
public class Main{
public static void main(String[] args){
int msg = 100;
System.out.println(“调用方法前msg的值:\n”+ msg); //100
fun(msg);
System.out.println(“调用方法后msg的值:\n”+ msg); //100
}
public static void fun(int temp){
temp = 0;
}
}
//引用数据类型作为方法参数被调用
class Book{
String name;
double price;
public Book(String name,double price){
this.name = name;
this.price = price;
}
public void getInfo(){
System.out.println(“图书名称:”+ name + “,价格:” + price);
}
public void setPrice(double price){
this.price = price;
}
}
public class Main{
public static void main(String[] args){
Book book = new Book(“一条IT”,66.6);
book.getInfo(); //图书名称:一条IT,价格:66.6
fun(book);
book.getInfo(); //图书名称:一条IT,价格:99.9
}
public static void fun(Book temp){
temp.setPrice(99.9);
}
}
==和equals()有什么区别
出自moka
我们都知道==
操作符用来两个对象的地址是否相同,即是否是指相同一个对象。
equals()比较的两个对象的值是否相同,不管是不是一个对象。
但其实object类下的equals()和==
是一样的,我们用的都是被重写之后的。
String、StringBuffer、StringBuilder什么区别?
三者共同之处:
都是final类,不允许被继承,所以string每次改变值都会新建一个对象。
StringBuffer是线程安全,可以不需要额外的同步用于多线程中;
StringBuilder是非同步,运行于多线程中就需要使用着单独同步处理,但是速度就比StringBuffer快多了;
StringBuffer与StringBuilder两者共同之处:可以通过append、indert进行字符串的操作。
位运算
这块可能不会直接问你,但做算法题会有奇效,所以不能不会。
-
^
(亦或运算) ,针对二进制,相同的为0,不同的为1 -
&
(与运算),针对二进制,只要有一个为0,就为0 -
<<
(向左位移),针对二进制,转换成二进制后向左移动3位,后面用0补齐 -
>>
(向右位移), 针对二进制,转换成二进制后向右移动3位 -
>>>
(无符号右移) 无符号右移,忽略符号位,空位都以0补齐。>>>
与>>
唯一的不同是它无论原来的最左边是什么数,统统都用0填充,正数做>>>运算的时候和>>是一样的。区别在于负数运算
运算符优先级
一般而言,单目运算符优先级较高,赋值运算符优先级较低。算术运算符优先级较高,关系和逻辑运算符优先级较低。多数运算符具有左结合性,单目运算符、三目运算符、赋值运算符具有右结合性。
其实java一共分为14个优先级,很不好记,也不实用,记住常用的,不确定就加括号,面试官要是追着你问这个,让他“滚”,我说的,耶稣来了都不行。
| 优先级 | 运算符 | 结合性 |
| — | — | — |
| 1 | ()、[]、{} | 从左向右 |
| 2 | !、+、-、~、++、– | 从右向左 |
| 3 | *、/、% | 从左向右 |
| 4 | +、- | 从左向右 |
| 5 | «、»、>>> | 从左向右 |
| 6 | <、<=、>、>=、instanceof | 从左向右 |
| 7 | ==、!= | 从左向右 |
| 8 | & | 从左向右 |
| 9 | ^ | 从左向右 |
| 10 | | | 从左向右 |
| 11 | && | 从左向右 |
| 12 | || | 从左向右 |
| 13 | ?: | 从右向左 |
| 14 | =、+=、-=、*=、/=、&=、|=、^=、~=、«=、»=、>>>= | 从右向左 |
访问修饰符
访问修饰符就是限制变量的访问权限的。
比如你有个“赚钱”的方法,谁都不想给用,那就把方法设成private
(私有);
后来你有了老婆孩子,你想让他们也会赚钱,就得设置成default
(同一个包);
后来你又有了第二个孩子,但你发现他不会赚钱的方法,为啥呢?因为你被绿了(default不支持不同包的子类);
可为了大局,你还是选择接受这个孩子,悄悄把方法设置成了proteced
(保护子类,即使不同包);
后来你老了,明白了开源才是共赢,就设置成了public
(公有的);
不知道你听懂了吗,估计看到被那啥了就不想看了吧,没关系,看图(也是绿的)
如何理解接口和抽象类?
抽象类:
被abstract修饰的类,不能创建实例对象。
含有抽象方法的类必须定义为抽象类,但抽象类中的方法不必须是抽象的。
抽象类中定义抽象方法必须在子类中实现,如果子类没有实现抽象父类中的所有抽象方法,那么子类也是抽象类。
接口:
可以说成是抽象类的一种特例,接口中的所有方法都必须是抽象的。
接口中的方法定义默认为public abstract类型,接口中的成员变量类型默认为public static final。
区别:
1.抽象类可以有构造方法,接口中不能有构造方法。
2.抽象类中可以有普通成员变量,接口中没有普通成员变量
3.抽象类中可以包含非抽象的普通方法,接口中的所有方法必须都是抽象的,不能有非抽象的普通方法。
4.一个类可以实现多个接口,但只能继承一个抽象类。
具体应用:
接口在系统架构设计方法中发挥着巨大作用,主要用于定义模块之间的通信契约。
而抽象类在代码实现方面发挥作用,可以实现代码的重用。
如何理解static关键字
主要意义:
我日常调用方法都是对象.方法,static
的主要意义就是可以创建独立于具体对象的域变量或者方法。也就是实现即使没有创建对象,也能使用属性和调用方法!
另一个比较关键的作用就是 用来形成静态代码块以优化程序性能。static
块可以置于类中的任何地方,可以有多个。在类初次被加载的时候,会按照static
块的顺序来执行每个static
块,并且只会执行一次,可以用来优化程序性能
通俗理解:
static
是一个可以让你升级的关键字,被static
修饰,你就不再是你了。
如何理解final关键字
final
翻译成中文是“不可更改的,最终的”,顾名思义,他的功能就是不能再修改,不能再继承。我们常见的String类
就是被final
修饰的。
将类、方法、变量声明为final能够提高性能,这样JVM就有机会进行估计,然后优化。
按照Java代码惯例,final变量就是常量,而且通常常量名要大写:
-
final关键字可以用于成员变量、本地变量、方法以及类。
-
final成员变量必须在声明的时候初始化或者在构造器中初始化,否则就会报编译错误。
-
不能够对final变量再次赋值。
-
final方法不能被重写。
-
final类不能被继承。
-
接口中声明的所有变量本身是final的。
-
final和abstract这两个关键字是反相关的,final类就不可能是abstract的。
重写和重载
出自moka
老生常谈的问题,除了答出定义,更应该说明他们的区别和应用
方法的重载和重写都是实现多态的方式,区别在于前者实现的是编译时的多态性,而后者实现的是运行时的多态性。
重载:发生在同一个类中,方法名相同参数列表不同(参数类型不同、个数不同、顺序不同),与方法返回值和访问修饰符无关,即重载的方法不能根据返回类型进行区分
重写:发生在父子类中,方法名、参数列表必须相同,返回值小于等于父类,抛出的异常小于等于父类,访问修饰符大于等于父类(里氏代换原则);如果父类方法访问修饰符为private则子类中就不是重写。
构造器是否可被重写?
构造器不能被继承,因此不能被重写,但可以被重载。
代码块的执行顺序?
基本上代码块分为三种:Static静态代码块、构造代码块、普通代码块
代码块执行顺序:静态代码块——> 构造代码块 ——> 构造函数——> 普通代码块
继承中代码块执行顺序:父类静态块——>子类静态块——>父类代码块——>父类构造器——>子类代码块——>子类构造器
泛型
泛”就是宽泛,泛指的意思,所谓泛型就是不指定具体类型,而是作为参数传递。
最早接触泛型是在集合中,我们最常用的集合类之一便是List,假如我们想让这个List只放Integer类型的元素,可以这样创建集合类:
List list = new ArrayList;
List.add(new Integer(11));
我们说Integer是这个集合的泛型,那如果创建一个Double的类型的呢,是不是也是可以的,怎么做到的?
看一些创建时的提示,<E>:
类型参数是用来表示自定义标识符,用来传递数据的类型。
泛型的优点:
使用泛型类时指明了数据类型,赋给其他类型的值会抛出异常,既不需要向下转型,也没有潜在的风险。
除了定义泛型类,还可以定义泛型接口和泛型方法,使用泛型方法时不必指明参数类型,编译器会根据传递的参数自动查找出具体的类型。
限制泛型的可用类型:
通过 extends 关键字可以限制泛型的类型
泛型代码与JVM:
最后
分布式技术专题+面试解析+相关的手写和学习的笔记pdf
还有更多Java笔记分享如下:
建时的提示,<E>:
类型参数是用来表示自定义标识符,用来传递数据的类型。
泛型的优点:
使用泛型类时指明了数据类型,赋给其他类型的值会抛出异常,既不需要向下转型,也没有潜在的风险。
除了定义泛型类,还可以定义泛型接口和泛型方法,使用泛型方法时不必指明参数类型,编译器会根据传递的参数自动查找出具体的类型。
限制泛型的可用类型:
通过 extends 关键字可以限制泛型的类型
泛型代码与JVM:
最后
分布式技术专题+面试解析+相关的手写和学习的笔记pdf
还有更多Java笔记分享如下:
[外链图片转存中…(img-EQ6IGB5m-1715717385602)]