▲ 图片来源知乎
虽然每年比亚迪招应届生都是几万几万的招,但这两年,高学历的应聘人才越来越多了。
去年比亚迪创造了 24 小时收 12w 份简历的惊人战绩!
太!恐!怖!了!
比亚迪的 HR 要从这 12 w 份简历中筛选出意向简历,如果纯人肉,估计比在沙滩上徒手找金针还难,不仅眼睛酸,手还可能先磨出茧子。
所以简单的方式就是直接卡双 211,甚至要卡双 985!
在我看来,更像是一种偷懒的行为。
目前比亚迪的研发团队中 61.3% 是硕士和博士,700 到 800 名来自于清华、北大等名校的毕业生。
笛子对学历的看重到了什么地步呢?之前在牛客上看到个帖子。
说是在迪子工作了 3 年也不一定能升到 E1(职级),而硕士应届生就可以直接进入这个级别。
▲ 图片来源牛客
这对于学历高,能力一般的人来说,确实是个捡漏的机会。
没错,我就是那个学历一般、能力也一般的人,😆,不知道比亚迪是否对我有意向哈~
对于 24 届秋招的同学来说,比亚迪可以说是秋招的神,挽救了很多同学的就业需求,目前这状况,我觉得只要招人、给钱、不毁约,就是好公司(dog)。
今年比亚迪秋招 5 万人,又扛起了就业大旗。讲真比亚迪的面试也比较中规中矩,还是那些比较常规的问题。
那接下来呢,苍何就以《Java 面霸进阶》中必看的基础面试题,来给还在找工作的小伙伴打打气。
内容较长,编写硬核干货不易,建议大家先收藏起来,面试的时候有备无患,我会结合多年的开发经验,用最自然的口吻,让你能背会的同时,还能理解和掌握。
当然了,我的目标是让所有面试选手都能成为面霸,在进阶之路上不断前行。
Java 语言特点和优势?
Java 并不是一种语言,Java 是一个完整的平台,有一个庞大的库,还有一个提供诸如安全性、跨操作系统的可移植性以及自动垃圾收集等服务。
——摘自《Java 核心技术》
1、面相对象:(封装,继承,多态),C++也是面相对象,但支持类多重继承,Java 中取而代之的是接口。
2、跨平台:一次编译到处执行(无论是你 windows、macos、还是 Linux,拿着编译后的. class 字节码文件就可以在安装了 Java 环境的这些系统中执行),源代码经过编译转换为字节码,拿着字节码通过 JVM 解释器 JIT 变为机器能识别的机器码。
3、垃圾回收:无用的对象称之为垃圾,不回收的话会占用内存,Java 提供自动垃圾回收功能,将内存管理交给 GC,程序员只需要专注于业务即可。
4、生态:发展了这么多年,Java 生态已经很全了,各种组件框架开箱即用,很方便。
Java 中序列化和反序列化
序列化和反序列化是用于对象的持久化处理机制,
序列化是指将对象转换为字节流的过程,或者通过网络传输,要使一个对象能够序列化,它的类必须实现 java. io. Serializable 接口。
反序列化是将字节流转换回 Java 对象的过程。反序列化时,读取字节流并重构对象。Java 默认的反序列化机制可能比较慢,可使用 protobuf,kryo 更加高效的反序列化框架。
注意
1、serialVersionUID 是用于版本控制的 id,如果类的定义发生了变化(如新增字段),没有匹配的 serialVersionUID 会导致反序列化失败。
2、transient 可以使某个字段不希望被序列化。
3、静态字段不能序列化:因为静态字段属于类,而不是实例对象。
JDK 8 有哪些新特性?
1、Lambda 表达式
2、函数式接口
3、Stream API
4、默认方法:接口可以有默认方法了
5、Optional 类:主要用于避免 NullPointerException
6、新日期时间 API,Calendar
7、用元空间替换了永久代
性能优化工具
性能监控和分析工具:
jps:Java 进程工具,显示所有正在运行的 Java 进程,便于监控和诊断。
jstack:生成线程堆栈信息的工具,常用于分析死锁和线程问题。
jmap:内存映射工具,可以生成堆转储(heap dump)文件,便于内存泄漏分析和垃圾回收优化。
jhat:堆分析工具,配合
jmap
使用,分析生成的堆转储文件,帮助开发者了解内存使用情况。jstat:JVM 统计监控工具,实时监控垃圾回收、内存、类加载等信息,帮助开发者调优 JVM 性能。
jconsole:图形化的 JVM 监控工具,可以监控应用程序的内存、线程和类加载情况,常用于监控和调试。
jvisualvm:功能强大的性能分析工具,支持堆、线程、GC 的详细监控,还提供内存分析和 CPU 性能分析。
诊断工具:
jinfo:用于查看和修改正在运行的 JVM 参数,便于动态调优和调整 JVM 行为。
jstatd:远程 JVM 监控工具,可以通过网络远程监控 JVM 的状态,适合分布式系统中的性能监控。
高级调试和性能优化工具
Java Mission Control (JMC):一个功能强大的工具,用于分析和优化 Java 应用程序的性能,提供了基于飞行记录器(Java Flight Recorder,JFR)的性能分析功能,可以详细查看垃圾回收、线程活动、CPU 使用率等指标,是进行深度性能分析的利器。
Java Flight Recorder (JFR):低开销的监控工具,能够记录 JVM 的运行时数据,适合生产环境中的性能分析,尤其是在高并发系统中使用频率较高。
= = 和 equals 区别
都是用来比较两个对象是否同一个引用地址(因为 equals 默认实现用的就是 = =),只不过有些类重写了 equals,用来比较内容是否相等,重写 equals 方法,需要重写 hashcode,因为:
hashcode 相同,不一定对象是相等的。
如果 equals 判断相同,那 hashcode 也一定相同。
动态代理
运行时创建代理对象称为动态代理,
代理可以看作是调用目标的一个包装,通常用来在调用真实的目标之前进行一些逻辑处理,消除一些重复的代码。
主要用途:简化代码、增强灵活性,实现 AOP 的基础。
Java 动态代理和 CGLIB 代理区别:
Java 动态代理是基于接口的实现的,所以代理的类必须是要有接口。代理类是在运行时动态生成的。
CGLIB 代理通过字节码技术动态生成目标类的子类来实现代码,final 方法不能代理
JDK 代理示例代码:
// 代理接口
public interface HelloService {
void sayHello();
}
// 接口实现
public class HelloServiceImpl implements HelloService {
@Override
public void sayHello() {
System.out.println("Hello");
}
}
// 代理处理器
public class HelloServiceInvocationHandler implements InvocationHandler {
private Object target;
public HelloServiceInvocationHandler(Object target) {
this.target = target;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("Before method");
Object result = method.invoke(target, args);
System.out.println("After method");
return result;
}
}
// 创建代理
public static void main(String[] args) {
HelloService helloService = new HelloServiceImpl();
HelloService proxy = (HelloService) Proxy.newProxyInstance(
helloService.getClass().getClassLoader(),
helloService.getClass().getInterfaces(),
new HelloServiceInvocationHandler(helloService)
);
proxy.sayHello();
}
CGLIB 代理示例代码:
import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;
import java.lang.reflect.Method;
// 被代理的类
public class HelloService {
public void sayHello() {
System.out.println("Hello");
}
}
// CGLIB 代理拦截器
public class HelloServiceInterceptor implements MethodInterceptor {
@Override
public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
System.out.println("Before method");
Object result = proxy.invokeSuper(obj, args);
System.out.println("After method");
return result;
}
}
// 创建代理
public static void main(String[] args) {
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(HelloService.class);
enhancer.setCallback(new HelloServiceInterceptor());
HelloService proxy = (HelloService) enhancer.create();
proxy.sayHello();
}
Java 的 SPI
Java 的 SPI(Service Provider Interface)是一种服务发现机制(插件机制),用于解耦模块之间的依赖关系,允许应用程序在运行时动态加载实现类。SPI 是 Java 平台模块化和扩展性设计的重要部分,通常用于框架和库中,让开发者能够扩展其功能。
有点类似于多态,都是在运行时让程序自动去识别使用哪个类,不同的是多态会在方法中指定要用哪个实现类,SPI 则是通过配置的方式指定程序使用哪个类。不过多态是在编译时就指定了具体的接口和实现类,SPI 是通过 ServiceLoader 在运行时动态加载配置 META-INF/services/下的实现类。
SPI 的基本流程
定义接口:服务提供者首先定义一个接口,客户端将使用该接口。
实现接口:服务提供者实现这个接口,提供实际的功能。
声明服务:在
META-INF/services/
目录下创建一个配置文件,文件名为接口的全限定名,文件内容为该接口的实现类的全限定名。加载服务:客户端使用
java.util.ServiceLoader
类动态加载该接口的实现类。
具体步骤
定义服务接口:
public interface MyService {
void execute();
}实现服务接口:
public class MyServiceImpl implements MyService {
@Override
public void execute() {
System.out.println("Service executed!");
}
}声明服务:创建文件
META-INF/services/com.example.MyService
,内容为:com.example.MyServiceImpl
加载服务:
ServiceLoader<MyService> serviceLoader = ServiceLoader.load(MyService.class);
for (MyService service : serviceLoader) {
service.execute();
}
SPI 的优势
解耦合:SPI 允许服务的实现和使用解耦,开发者无需在代码中直接依赖具体实现。
灵活性:可以动态地选择不同的服务实现,而无需修改代码。
扩展性:新服务的实现可以通过添加实现类和配置文件来轻松扩展系统的功能。
使用场景
JDBC:Java 数据库连接(JDBC)是 SPI 机制的典型例子,不同的数据库厂商可以通过提供 JDBC 驱动实现来支持其数据库。
日志框架:例如 SLF 4 J 和 Logback 也是基于 SPI 的,实现了不同日志框架之间的兼容性。
Java EE:很多 Java EE 组件(如 Servlet)也通过 SPI 来提供不同的实现。
SPI 机制在开发大型可扩展系统时非常有用,可以动态加载和替换模块,而不需要修改应用的核心逻辑。