【备战秋招冲击大厂,java研发工程师面试问题

前言:

首先介绍一下我的同学,专科毕业应用电子技术专业,已经毕业快两年了。因为专业的原因工作一年觉得没什么发展前途就想转行,身为他的“好基友”,他觉得我这个工作挺好的,就咨询了我一下,经过的严厉拒绝下(各种诱惑下),还是阻挡不了他。随后他报名了北大某鸟进行培训,进行了为期半年的Java程序员速成加工。
因为年前结束培训他准备年后面试,谁知遇到这个大疫情,一直拖到了5月份。随后进行了长达2个月的面试历程。谁知昨天聊天的时候这个狗贼竟然通过了面试,而且还是12K,可把我羡慕坏了(我才11K),经过拜师才知道是他努力复习面试题的结果,今天就把偷学来的面试题分享给大家,希望大家都能拿到想要的offer!

  • 封装目的:增强安全性和简化编程,使用者不必在意具体实现细节,而只是通过外部接口即可访问类的成员。

2、继承

  • 继承是指将多个相同的属性和方法提取出来,新建一个父类。Java中一个类只能继承一个父类,且只能继承访问权限非private的属性和方法。 子类可以重写父类中的方法,命名与父类中同名的属性。

  • 继承目的:代码复用。

3、多态

  • 多态可以分为两种:设计时多态和运行时多态。

  • 设计时多态:即重载,是指Java允许方法名相同而参数不同(返回值可以相同也可以不相同)。

  • 运行时多态:即重写,是指Java运行根据调用该方法的类型决定调用哪个方法。要求方法名、参数和返回值必须相同。

  • 多态目的:增加代码的灵活度。

3. 多态程序绑定

  • 定义:绑定指的是一个方法的调用与方法所在的类或对象(方法主体)关联起来。对java来说,绑定分为静态绑定和动态绑定

  • 静态绑定(前期绑定):在程序执行前方法已经被绑定,此时由编译器或其它连接程序实现。在编译阶段,绑定的是类信息,即为定义的类的类型。针对java简单的可以理解为程序编译期的绑定;这里特别说明一点,java当中的方法,只有final,static,private,重载方法(overloaded methods)和构造方法是静态绑定。所有的变量都是静态绑定。

  • 动态绑定(后期绑定):在运行时根据具体对象的类型进行绑定。发生在运行阶段,绑定的是对象信息。重写方法(overridden methods)使用的是动态绑定

  • 动态绑定的过程:

1)虚拟机提取对象实际类型的方法表;

2)虚拟机搜索方法签名;

3)调用方法。

4. Java四种引用类型

  • 强引用:Java中默认声明的就是强引用,只要强引用存在,垃圾回收器将永远不会回收被引用的对象,哪怕内存不足时,JVM也会直接抛出OutOfMemoryError,不会去回收。如果想中断强引用与对象之间的联系,可以显示的将强引用赋值为null,这样一来,JVM就可以适时的回收对象了

  • 软引用:软引用是用来描述一些非必需但仍有用的对象。在内存足够的时候,软引用对象不会被回收,只有在内存不足时,系统则会回收软引用对象,如果回收了软引用对象之后仍然没有足够的内存,才会抛出内存溢出异常。这种特性常常被用来实现缓存技术,比如网页缓存,图片缓存等。

  • 弱引用:弱引用的引用强度比软引用要更弱一些,无论内存是否足够,只要 JVM 开始进行垃圾回收,那些被弱引用关联的对象都会被回收。(GC时发生)

  • 虚引用:虚引用是最弱的一种引用关系,如果一个对象仅持有虚引用,那么它就和没有任何引用一样,它随时可能会被回收,主要用来跟踪对象被垃圾回收的活动。

5. 不可变对象

  • 不可变对象:对象在创建完成后,不能再改变它的状态。即不能改变对象内的成员变量,包括基本数据类型的值不能改变,引用类型的变量不能指向其他的对象,引用类型指向的对象的状态也不能改变。

  • 不可变对象有什么好处?

1)不可变对象可以提高String Pool(字符串常量池)的效率和安全性。如果你知道一个对象是不可变动,那么需要拷贝的对象的内容时就不用复制它本身而只是复制它的地址,复制地址(通常一个指针的大小)需要很小的内存,效率也很好。二是对于其他引用同一个对象的其他变量也不会造成影响。

2)不可变对象对于多线程是安全的,因为在多线程同时进行的情况下,一个可变对象的值很可能被其他线程改变,这样会造成不可预期的结果,而使用不可变对象就可以避免这种情况出现。

6. String

  • String是否可变?

Java中String类就是对字符数组的封装。Jdk8中String类有两个成员变量char value[]和int hash,value是private final的,hash被private修饰,也就是说在String类内部,一旦初始化就不能被改变。所以可以认为String对象是不可变的。

  • String为什么要设计为不可变?

java将String设成不可变最大的原因是效率和安全。

1)字符串常量池的需要,只有字符串不可变时,字符串常量池才能实现。

2)多线程安全

3)字符串不变性保证了hash码的唯一性,因此可以放心的进行缓存,这也是一种性能优化手段,意味着不必每次都重新计算新的哈希码,使得字符串很适合作为 Map的键

4)类加载器要用到字符串,不可变提供了安全性,以便类被正确地加载。

5)String被许多的Java类(库)用来当做参数,例如网络连接地址URL,文件路径path,还有反射机制所需要的String参数等, 假若String不是固定不变的,将会引起各种安全隐患。

  • String对象真的不可变吗?

用反射,可以反射出String对象中的value属性, 进而改变通过获得的value引用改变数组的结构。可以通过类对象的getDeclaredField()方法字段(Field)对象,然后再通过字段对象的setAccessible(true)将其设置为可以访问,接下来就可以通过get/set方法来获取/设置字段的值了。

7. Java创建对象的4种方式

  • 使用new关键字:new关键字直接在堆内存上创建对象。

  • 反射:使用Class类的newInstance方法可以调用无参的构造器来创建对象,如果是有参构造器,则需要使用Class的forName方法和Constructor来进行对象的创建。

  • 使用Clone方法:调用一个对象的clone方法,JVM就会创建一个新的对象,将前面的对象的内容全部拷贝进去,用clone方法创建对象并不会调用任何构造函数。

  • 反序列化:一个对象实现了Serializable接口,就可以把对象写入到文件中,并通过读取文件来创建对象。

8. 反射

JAVA语言编译之后会生成一个.class文件,反射就是通过字节码文件找到某一个类、类中的方法以及属性等。反射机制指的是程序在运行时能够获取自身的信息。在JAVA中,只要给定类的名字,那么就可以通过反射机制来获取类的所有信息。Java 的动态就体现在反射。通过反射我们可以实现动态装配,降低代码的耦合度;动态代理等。反射的过度使用会严重消耗系统资源。

反射的实现主要借助以下四个类:Class:类的对象,Constructor:类的构造方法,Field:类中的属性对象,Method:类中的方法对象。

  • 反射的作用:

1)可以使用反射动态地创建类型的实例,将类型绑定到现有对象,或从现有对象中获取类型

2)应用程序需要在运行时从某个特定的程序集中载入一个特定的类型,以便实现某个任务时可以用到反射。

3)反射主要应用于类库,这些类库需要知道一个类型的定义,以便提供更多的功能。

9. StringBuffer和StringBuilder

  • 相同点:StringBuffer 和 StringBuilder 类的对象能够被多次的修改,并且不产生新的未使用对象。底层实现上的话,StringBuffer其实就是比StringBuilder多了Synchronized修饰符。

  • 区别:

1)StringBuilder 的方法不是线程安全的(不能同步访问)

2)StringBuilder 相较于 StringBuffer 有速度优势,所以多数情况下建议使用 StringBuilder 类。

  • 小结:

1)如果要操作少量的数据用 String;

2)多线程操作字符串缓冲区下操作大量数据 StringBuffer;

3)单线程操作字符串缓冲区下操作大量数据 StringBuilder。

10. java.lang.Object的常用方法

  • getClass() 获取类结构信息

  • toString() 把对象转变成字符串

  • hashCode() 获取哈希码

  • equals(Object) 默认比较对象的地址值是否相等,子类可以重写比较规则

  • notify() 多线程中唤醒功能

  • notifyAll() 多线程中唤醒所有等待线程的功能

  • wait()让持有对象锁的线程进入等待

  • wait(long timeout)让持有对象锁的线程进入等待,设置超时毫秒数时间

  • wait(long timeout, int nanos)让持有对象锁的线程进入等待,设置超时纳秒数时间

11. 为什么Java把wait与notify放在Object中?

  • 功能角度

1)wait与notify的原始目的,是多线程场景下,某条件触发另一逻辑,该条件对应的直接关系为某种对象,进而对应为Object,其对应为内存资源。

2)Thread对应为CPU,与具体条件不是直接关系,Thread是对象的执行依附者。

  • 内存角度

1)线程的同步需要Monitor的管理,其与实际操作系统的重型资源(锁)相关。

2)只有涉及多线程的场景,才需要线程同步,如果wait与notify放在Thread,则每个Thread都需要分配Monitor,浪费资源。

3)如果放在Object,单线程场景不分配Monitor,只在多线程分配。分配Monitor的方法为检测threadId的不同。

12. 装箱和拆箱

装箱是通过调用包装器类的 valueOf 方法实现的;拆箱是通过调用包装器类的 xxxValue 方法实现的,xxx代表对应的基本数据类型。如int装箱的时候自动调用Integer的valueOf(int)方法;Integer拆箱的时候自动调用Integer的intValue方法。包含算术运算会触发自动拆箱。存在大量自动装箱的过程,如果装箱返回的包装对象不是从缓存中获取,会创建很多新的对象,比较消耗内存。

  • 整型的包装类 valueOf 方法返回对象时,在常用的取值范围内,会返回缓存对象。

  • 浮点型的包装类 valueOf 方法返回新的对象。

  • 布尔型的包装类 valueOf 方法 Boolean类的静态常量 TRUE | FALSE。

13. Integer和String的比较操作

  • 使用 == 比较:

  • 基本类型 - 基本类型、基本类型 - 包装对象返回 true

  • 包装对象 - 包装对象,非同一个对象(对象的内存地址不同)返回 false;对象的内存地址相同返回 true,如值等于 100 的两个 Integer 对象(原因是 JVM 缓存部分基本类型常用的包装类对象,如 Integer -128 ~ 127 是被缓存的)

  • 使用 equals() 比较

  • 包装对象-基本类型返回 true

  • 包装对象-包装对象返回 true

Integer a = 1;

Integer b = 1;

Integer c = 128;

Integer d = 128;

// [-128,127]范围的自动装箱(box),同值是同一个对象

System.out.println(a == b); // true

// 不在[-128,127]范围装箱的Integer,值相同也不是同一个对象

System.out.println(c == d); // false

// 使用new一个对象的方法

Integer a = new Integer(1);

Integer b = new Integer(1);

System.out.println(a == b); // false

System.out.println(a.equals(b)); // true

System.out.println(a.equals(1)); // true

System.out.println(a == 1); // true, Integer和int用==比较,Integer自动拆箱unbox,转换为普通int间的比较

/**

  • String的比较,==是引用比较,比较字符串是否相同用equals

*/

//用引号创建一个字符串的时候,首先会去常量池中寻找有没有相等的常量对象,没有的话就在常量池中创建这个常量对象;有的话就直接返回这个常量对象的引用

String str1 = “haha”;

String str2 = “haha”;

String str3 = new String(“haha”);

String str4 = new String(“haha”);

// true,首先 String str1 = “hello”,会先到常量池中检查是否有“hello”的存在,发现是没有的,于是在常量池中创建“hello”对象,并将常量池中的引用赋值给str1;第二个字面量 String str2 = “hello”,在常量池中检测到该对象了,直接将引用赋值给str2。

System.out.println(str1 == str2);

// false, 每个String对象都是不同的,所以引用指向的堆地址肯定也不同,所以false。

System.out.println(str3 == str4);

// false,因为==比较的是引用的地址,s2指的是常量池中常量对象的地址,而s1指的是堆中String对象的地址,肯定不同。

System.out.println(str1 == str3);

// true,因为jdk重写了equals()方法,比较的是字符串的内容。

System.out.println(str1.equals(str2));

//true, JDK 1.7后,intern方法还是会先去查询常量池中是否有已经存在,如果存在,则返回常量池中的引用,这一点与之前没有区别,区别在于,如果在常量池找不到对应的字符串,则不会再将字符串拷贝到常量池,而只是在常量池中生成一个对原字符串的引用。

System.out.println(str3.intern()==str1);

14. 动态链接库和静态链接库

  • 静态链接库:当要使用时,连接器会找出程序所需的函数,然后将它们拷贝到执行文件,由于这种拷贝是完整的,所以一旦连接成功,静态程序库也就不再需要了。

  • 动态链接库:某个程序在运行中要调用某个动态链接库函数的时候,操作系统首先会查看所有正在运行的程序,看在内存里是否已有此库函数的拷贝了。如果有,则让其共享那一个拷贝;只有没有才链接载入。在程序运行的时候,被调用的动态链接库函数被安置在内存的某个地方,所有调用它的程序将指向这个代码段。因此,这些代码必须使用相对地址,而不是绝对地址。在编译的时候,我们需要告诉编译器,这些对象文件是用来做动态链接库的,所以要用地址无关代码(Position Independent Code (PIC))。动态链接库的加载方式有两种:隐式加载和显示加载。

15. 正则表达式

  • 定义:在编写处理字符串的程序时,经常会有查找符合某些复杂规则的字符串的需要。正则表达式就是用于描述这些规则的工具。换句话说,正则表达式就是记录文本规则的代码。

  • Java中的String类提供了支持正则表达式操作的方法,包括:matches()、replaceAll()、replaceFirst()、split()。

16. Java基本数据类型及其包装类

Java 为每个原始类型提供了包装类型:

  • 原始类型:boolean,char,byte,short,int,long,float,double

  • 包装类型:Boolean,Character,Byte,Short,Integer,Long,Float,Double

17. 值传递和引用传递

一般认为,java内的传递都是值传递

  • 值传递是对基本型变量而言的,传递的是该变量的一个副本,改变副本不影响原变量。

  • 引用传递一般是对于对象型变量而言的,传递的是该对象地址的一个副本, 并不是原对象本身。所以对引用对象进行操作会同时改变原对象。

18. 深拷贝和浅拷贝

  • 浅拷贝:复制基本类型的属性、引用类型的属性、栈中的变量和变量指向堆内存中的对象的指针,不复制堆内存中的对象。

  • 深拷贝:复制基本类型的属性、引用类型的属性、栈中的变量和变量指向堆内存中的对象的指针和堆内存中的对象。

19. 为什么会出现4.0-3.6=0.40000001这种现象?

2进制的小数无法精确的表达10进制小数,计算机在计算10进制小数的过程中要先转换为2进制进行计算,这个过程中出现了误差。

20. 十进制的数在内存中是怎么存的?

补码的形式

  • 正数的原反补一样

  • 负数的反码是将原码除了符号位的其余位取反,补码是给反码加1.

21. Lamda表达式

  • 定义:Lambda 表达式(lambda expression)是一个匿名函数,Lambda 规定接口中只能有一个需要被实现的方法,不是规定接口中只能有一个方法

  • 思想:函数式编程思想

  • 优点:1. 简洁。2. 非常容易并行计算。

  • 缺点:1. 若不用并行计算,很多时候计算速度没有比传统的 for 循环快。(并行计算有时需要预热才显示出效率优势)2. 不容易调试。

22. Java 8系列之Stream

Stream 是用函数式编程方式在集合类上进行复杂操作的工具,其集成了Java 8中的众多新特性之一的聚合操作,开发者可以更容易地使用Lambda表达式,并且更方便地实现对集合的查找、遍历、过滤以及常见计算等。

  • Stream的操作分类,在一次聚合操作中,可以有多个Intermediate,但是有且只有一个Terminal。Intermediate主要是用来对Stream做出相应转换及限制流,实际上是将源Stream转换为一个新的Stream,以达到需求效果。
  • Intermediate:map (mapToInt, flatMap 等)、 filter、 distinct、 sorted、 peek、 skip、 parallel、 sequential、 unordered

  • Terminal:forEach、 forEachOrdered、 toArray、 reduce、 collect、 min、 max、 count、iterator

  • Short-circuiting:anyMatch、 allMatch、 noneMatch、 findFirst、 findAny、 limit

23. final关键字

  • 使用final的原因:第一个原因是把方法锁定,以防任何继承类修改它的含义;第二个原因是效率。

  • 作用:

1)当用final修饰一个类时,表明这个类不能被继承。final类中的所有成员方法都会被隐式地指定为final方法。

2)对于一个final变量,如果是基本数据类型的变量,则其数值一旦在初始化之后便不能更改;

3)如果是引用类型的变量,则在对其初始化之后便不能再让其指向另一个对象。

24. final/finally/finalize

  • final 用于声明属性,方法和类,分别表示属性不可变,方法不可覆盖,类不可继承。

  • finally是异常处理语句结构的一部分,表示总是执行。

  • finalize是Object类的一个方法,在垃圾收集器执行的时候会调用被回收对象的此方法,可以覆盖此方法提供垃圾收集时的其他资源回收,例如关闭文件等。

25. Java中的IO流

java.io包中还有许多其他的流,主要是为了提高性能和使用方便。

  • 按照流向划分为输入流和输出流

  • 按照操作单元分划分为字节流和字符流

  • 字节流:InputStream、OutputStream

  • 字符流:InputStreamReader、OutputStreamWriter

  • 按照流的角色划分为节点流和处理流

26. 既然有了字节流,为什么还要有字符流?

字符流是由 Java 虚拟机将字节转换得到的,这个过程非常耗时,并且,如果我们不知道编码类型就很容易出现乱码问题。所以, I/O 流提供了一个直接操作字符的接口,方便我们平时对字符进行流操作。如果音频文件、图片等媒体文件用字节流比较好,如果涉及到字符的话使用字符流比较好。

27. java序列化

  • 定义:序列化是将 Java 对象转换成字节流的过程。反序列化是将字节流转换成 Java 对象的过程。

  • 作用:当Java对象需要在网络上传输或者持久化存储到文件时,就需要对Java对象进行序列化处理。

  • 实现:类实现 Serializable 接口,这个接口没有需要实现的方法。实现 Serializable 接口是为了告诉 jvm 这个类的对象可以被序列化。

28. Java 序列化中如果有些字段不想进行序列化,怎么办?

对于不想进行序列化的变量,使用 transient 关键字修饰。transient 关键字的作用是:阻止实例中那些用此关键字修饰的的变量序列化;当对象被反序列化时,被 transient 修饰的变量值不会被持久化和恢复。transient 只能修饰变量,不能修饰类和方法。

29. 泛型

  • 定义:泛型,即“参数化类型”。将类型作为参数传入方法中,如List。

  • 优点:在编译的时候检查类型安全,并且所有的强制转换都是自动和隐式的,提高代码的重用率。

  • Java泛型的实现方法:类型擦除

Java的泛型是伪泛型,因为Java在编译期间,所有的泛型信息都会被擦掉。Java的泛型基本上都是在编译器这个层次上实现的,在生成的字节码中是不包含泛型中的类型信息的,使用泛型的时候加上类型参数,在编译器编译的时候会去掉,这个过程称为类型擦除。

30. 抽象类和接口

  • 声明方法的存在而不去实现它的类被叫做抽象类(abstract class),它用于要创建一个体现某些基本行为的类,并为该类声明方法,但不能在该类中实现该类的情况。不能创建abstract 类的实例。然而可以创建一个变量,其类型是一个抽象类,并让它指向具体子类的一个实例。不能有抽象构造函数或抽象静态方法。Abstract 类的子类为它们父类中的所有抽象方法提供实现,否则它们也是抽象类。取而代之,在子类中实现该方法。知道其行为的其它类可以在类中实现这些方法。

  • 接口(interface)是抽象类的变体。在接口中,所有方法都是抽象的。多继承性可通过实现这样的接口而获得。接口中的所有方法都是抽象的,没有一个有程序体。接口只可以定义static final成员变量。接口的实现与子类相似,除了该实现类不能从接口定义中继承行为。当类实现特殊接口时,它定义(即将程序体给予)所有这种接口的方法。然后,它可以在实现了该接口的类的任何对象上调用接口的方法。由于有抽象类,它允许使用接口名作为引用变量的类型。通常的动态联编将生效。引用可以转换到接口类型或从接口类型转换,instanceof 运算符可以用来决定某对象的类是否实现了接口。

  • 区别:

1)接口中所有的方法隐含的都是抽象的。而抽象类则可以同时包含抽象和非抽象的方法。

《一线大厂Java面试真题解析+Java核心总结学习笔记+最新全套讲解视频+实战项目源码》开源

Java优秀开源项目:

  • ali1024.coding.net/public/P7/Java/git

总结

面试建议是,一定要自信,敢于表达,面试的时候我们对知识的掌握有时候很难面面俱到,把自己的思路说出来,而不是直接告诉面试官自己不懂,这也是可以加分的。

以上就是蚂蚁技术四面和HR面试题目,以下最新总结的最全,范围包含最全MySQL、Spring、Redis、JVM等最全面试题和答案,仅用于参考

一份还热乎的蚂蚁金服面经(已拿Offer)面试流程4轮技术面+1轮HR

。当类实现特殊接口时,它定义(即将程序体给予)所有这种接口的方法。然后,它可以在实现了该接口的类的任何对象上调用接口的方法。由于有抽象类,它允许使用接口名作为引用变量的类型。通常的动态联编将生效。引用可以转换到接口类型或从接口类型转换,instanceof 运算符可以用来决定某对象的类是否实现了接口。

  • 区别:

1)接口中所有的方法隐含的都是抽象的。而抽象类则可以同时包含抽象和非抽象的方法。

《一线大厂Java面试真题解析+Java核心总结学习笔记+最新全套讲解视频+实战项目源码》开源

Java优秀开源项目:

  • ali1024.coding.net/public/P7/Java/git

总结

面试建议是,一定要自信,敢于表达,面试的时候我们对知识的掌握有时候很难面面俱到,把自己的思路说出来,而不是直接告诉面试官自己不懂,这也是可以加分的。

以上就是蚂蚁技术四面和HR面试题目,以下最新总结的最全,范围包含最全MySQL、Spring、Redis、JVM等最全面试题和答案,仅用于参考

[外链图片转存中…(img-kgpv8dk1-1649571365669)]

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值