⭐️vivo 2024 校招面经,很简单
vivo 2024 校招已经开奖了,今年给的确实不多,base 相对大厂有点太低了:
- Java 开发:17*15,南京,白菜价
- 软开:20*15,深圳,SP
- 测开:15*15,上海,白菜价
- 后端:17*15,深圳,白菜价
- 算法:24 * 15,深圳,SP
因为薪资给的确实有点低,很多拿到 offer 的朋友都拒了,多少都觉得这薪资有点...。
下面,给大家分享一位读者面试 vivo Java 岗位的面经,大家感受一下难度。
面试题
八股较多,但都偏基础,难度较低。
我对一二面提到的部分有代表性的面试问题进行了整理,并添加了参加答案供大家复习参考。
1、自我介绍
一个好的自我介绍应该包含这几点要素:
- 用简单的话说清楚自己主要的技术栈于擅长的领域,例如 Java 后端开发、分布式系统开发;
- 把重点放在自己的优势上,重点突出自己的能力比如自己的定位的 bug 的能力特别厉害;
- 避免避实就虚,适当举例体现自己的能力,例如过往的比赛经历、实习经历;
- 自我介绍的时间不宜过长,一般是 1~2 分钟之间。
2、介绍自己的实习经历,做了什么,学到了什么
如果你有实习经历的话,自我介绍之后,第二个问题一般就是聊你的实习经历。面试之前,一定要提前准备好对应的话术,突出介绍自己实习期间的贡献。
很多同学实习期间可能接触不到什么实际的开发任务,大部分时间可能都是在熟悉和维护项目。对于这种情况,你可以适当润色这段实习经历,找一些简单的功能研究透,包装成自己参与做的,大部分同学都是这么做的。不用担心面试的时候会露馅,只要不挑选那种明显不会交给实习生做的任务,你自己也能讲明白就行了。不过,还是更建议你在实习期间尽量尝试主动去承担一些开发任务,这样整个实习经历对个人提升也会更大一些。
3、重载和重写什么区别?项目中用到了吗?
重写就是子类对父类方法的重新改造,外部样子不能改变,内部逻辑可以改变。
区别点 | 重载方法 | 重写方法 |
---|---|---|
发生范围 | 同一个类 | 子类 |
参数列表 | 必须修改 | 一定不能修改 |
返回类型 | 可修改 | 子类方法返回值类型应比父类方法返回值类型更小或相等 |
异常 | 可修改 | 子类方法声明抛出的异常类应比父类方法声明抛出的异常类更小或相等; |
访问修饰符 | 可修改 | 一定不能做更严格的限制(可以降低限制) |
发生阶段 | 编译期 | 运行期 |
4、构造方法可以有多个吗?能被重写吗?
构造方法具有以下特点:
- 名称与类名相同:构造方法的名称必须与类名完全一致。
- 没有返回值:构造方法没有返回类型,且不能使用
<font style="color:rgb(59, 69, 78);">void</font>
声明。 - 自动执行:在生成类的对象时,构造方法会自动执行,无需显式调用。
构造方法不能被重写(override),但可以被重载(overload)。因此,一个类中可以有多个构造方法,这些构造方法可以具有不同的参数列表,以提供不同的对象初始化方式。
5、接口和抽象类如何选择?为什么?
接口和抽象类的共同点
- 实例化:接口和抽象类都不能直接实例化,只能被实现(接口)或继承(抽象类)后才能创建具体的对象。
- 抽象方法:接口和抽象类都可以包含抽象方法。抽象方法没有方法体,必须在子类或实现类中实现。
接口和抽象类的区别
- 设计目的:接口主要用于对类的行为进行约束,你实现了某个接口就具有了对应的行为。抽象类主要用于代码复用,强调的是所属关系。
- 继承和实现:一个类只能继承一个类(包括抽象类),因为 Java 不支持多继承。但一个类可以实现多个接口,一个接口也可以继承多个其他接口。
- 成员变量:接口中的成员变量只能是
<font style="color:rgb(59, 69, 78);">public static final</font>
类型的,不能被修改且必须有初始值。抽象类的成员变量可以有任何修饰符(<font style="color:rgb(59, 69, 78);">private</font>
,<font style="color:rgb(59, 69, 78);">protected</font>
,<font style="color:rgb(59, 69, 78);">public</font>
),可以在子类中被重新定义或赋值。 - 方法:
- Java 8 之前,接口中的方法默认是
<font style="color:rgb(59, 69, 78);">public abstract</font>
,也就是只能有方法声明。自 Java 8 起,可以在接口中定义<font style="color:rgb(59, 69, 78);">default</font>
(默认) 方法和<font style="color:rgb(59, 69, 78);">static</font>
(静态)方法。 自 Java 9 起,接口可以包含<font style="color:rgb(59, 69, 78);">private</font>
方法。 - 抽象类可以包含抽象方法和非抽象方法。抽象方法没有方法体,必须在子类中实现。非抽象方法有具体实现,可以直接在抽象类中使用或在子类中重写。
- Java 8 之前,接口中的方法默认是
在 Java 8 及以上版本中,接口引入了新的方法类型:<font style="color:rgb(59, 69, 78);">default</font>
方法、<font style="color:rgb(59, 69, 78);">static</font>
方法和 <font style="color:rgb(59, 69, 78);">private</font>
方法。这些方法让接口的使用更加灵活。
Java 8 引入的<font style="color:rgb(59, 69, 78);">default</font>
方法用于提供接口方法的默认实现,可以在实现类中被覆盖。这样就可以在不修改实现类的情况下向现有接口添加新功能,从而增强接口的扩展性和向后兼容性。
public interface MyInterface {
default void defaultMethod() {
System.out.println("This is a default method.");
}
}
Java 8 引入的<font style="color:rgb(59, 69, 78);">static</font>
方法无法在实现类中被覆盖,只能通过接口名直接调用( <font style="color:rgb(59, 69, 78);">MyInterface.staticMethod()</font>
),类似于类中的静态方法。<font style="color:rgb(59, 69, 78);">static</font>
方法通常用于定义一些通用的、与接口相关的工具方法,一般很少用。
public interface MyInterface {
static void staticMethod() {
System.out.println("This is a static method in the interface.");
}
}
Java 9 允许在接口中使用 <font style="color:rgb(59, 69, 78);">private</font>
方法。<font style="color:rgb(59, 69, 78);">private</font>
方法可以用于在接口内部共享代码,不对外暴露。
public interface MyInterface {
// default 方法
default void defaultMethod() {
commonMethod();
}
// static 方法
static void staticMethod() {
commonMethod();
}
// 私有静态方法,可以被 static 和 default 方法调用
private static void commonMethod() {
System.out.println("This is a private method used internally.");
}
// 实例私有方法,只能被 default 方法调用。
private void instanceCommonMethod() {
System.out.println("This is a private instance method used internally.");
}
}
6、什么是序列化?什么是反序列化?
如果我们需要持久化 Java 对象比如将 Java 对象保存在文件中,或者在网络传输 Java 对象,这些场景都需要用到序列化。
简单来说:
- 序列化:将数据结构或对象转换成可以存储或传输的形式,通常是二进制字节流,也可以是 JSON, XML 等文本格式
- 反序列化:将在序列化过程中所生成的数据转换为原始数据结构或者对象的过程
对于 Java 这种面向对象编程语言来说,我们序列化的都是对象(Object)也就是实例化后的类(Class),但是在 C++这种半面向对象的语言中,struct(结构体)定义的是数据结构类型,而 class 对应的是对象类型。
下面是序列化和反序列化常见应用场景:
- 对象在进行网络传输(比如远程方法调用 RPC 的时候)之前需要先被序列化,接收到序列化的对象之后需要再进行反序列化;
- 将对象存储到文件之前需要进行序列化,将对象从文件中读取出来需要进行反序列化;
- 将对象存储到数据库(如 Redis)之前需要用到序列化,将对象从缓存数据库中读取出来需要反序列化;
- 将对象存储到内存之前需要进行序列化,从内存中读取出来之后需要进行反序列化。
维基百科是如是介绍序列化的:
序列化(serialization)在计算机科学的数据处理中,是指将数据结构或对象状态转换成可取用格式(例如存成文件,存于缓冲,或经由网络中发送),以留待后续在相同或另一台计算机环境中,能恢复原先状态的过程。依照序列化格式重新获取字节的结果时,可以利用它来产生与原始对象相同语义的副本。对于许多对象,像是使用大量引用的复杂对象,这种序列化重建的过程并不容易。面向对象中的对象序列化,并不概括之前原始对象所关系的函数。这种过程也称为对象编组(marshalling)。从一系列字节提取数据结构的反向操作,是反序列化(也称为解编组、deserialization、unmarshalling)。
综上:序列化的主要目的是通过网络传输对象或者说是将对象存储到文件系统、数据库、内存中。
https://www.corejavaguru.com/java/serialization/interview-questions-1
序列化协议对应于 TCP/IP 4 层模型的哪一层?
我们知道网络通信的双方必须要采用和遵守相同的协议。TCP/IP 四层模型是下面这样的,序列化协议属于哪一层呢?
- 应用层
- 传输层
- 网络层
- 网络接口层
如上图所示,OSI 七层协议模型中,表示层做的事情主要就是对应用层的用户数据进行处理转换为二进制流。反过来的话,就是将二进制流转换成应用层的用户数据。这不就对应的是序列化和反序列化么?
因为,OSI 七层协议模型中的应用层、表示层和会话层对应的都是 TCP/IP 四层模型中的应用层,所以序列化协议属于 TCP/IP 协议应用层的一部分。