互联网科技

Java程序员开发三年,去网易社招,竟被问到这些面试题

2019-10-29  本文已影响0人  Java_苏先生

前言

前几天偶遇老同学,聊了聊工作;老同学和我分享了这次网易社招的面试题;文中篇幅有限,就和大家分享这么多;更多Java后端开发面试题请见文末!

1. 面向对象的特点有哪些?

①. 封装:所谓封装,就是将客观事物封装成抽象的类,并且类可以把数据和方法让可信的类或者对象进行操作,对不可信的类或者对象进行隐藏。类就是封装数据和操作这些数据代码的逻辑实体。在一个类的内部,某些属性和方法是私有的,不能被外界所访问。通过这种方式,对象对内部数据进行了不同级别的访问控制,就避免了程序中的无关部分的意外改变或错误改变了对象的私有部分。

②. 继承:继承有这样一种能力,就是能使用现有的类的所有功能,并无须重新编写原来的这些类的基础上对这些功能进行扩展。通过继承创建的新类称为子类或派生类,被继承的称为基类。继承有两种,一种是实现继承,另外一种是接口继承。实现继承可以直接使用基类的属性和方法而无需额外编码,接口继承是指使用属性和方法的名称,但是子必须提供实现的能力。

③. 多态:所谓多态就是对一个实例的相同方法在不同的情形下有不同的表现形式。多态机制使得不同内部结构的对象可以共享相同的外部接口,这就意味着,虽然不同的类的内部操作不同,但可以通过一个公共的类,它们可以通过相同的方式予以调用。

④. 抽象:提取现实世界中某事物的关键特性,为该事物构建模型的过程。对同一事物在不同的需求下,需要提取的特性可能不一样。得到的抽象模型中一般包含:属性(数据)和操作(行为)。这个抽象模型我们称之为类。对类进行实例化得到对象。

2. 列举几个java常用的package及其作用

3. 接口和抽象类有什么联系和区别

相同点

不同点

4. 重载和重写有什么区别

override(重写)

overload(重载)

5. java有哪些基本数据类型?

①. 四种整数类型(byte、short、int、long)

②. 两种浮点数类型(float、double)

③. 一种字符类型(char)
char:16 位,是整数类型,用单引号括起来的 1 个字符(可以是一个中文字符),使用 Unicode 码代表字符,0~2^16-1(65535) 。

④. 一种布尔类型(boolean):true 真 和 false 假。

⑤. 类型转换:char-->

⑥. 记忆

6. Java支持的数据类型有哪些?什么是自动拆装箱?

整数默认int型,小数默认是double型。Float和long类型的必须加后缀。

首先知道String是引用类型不是基本类型,引用类型声明的变量是指该变量在内存中实际存储的是一个引用地址,实体在堆中。引用类型包括类、接口、数组等。String类还是final修饰的。

而包装类就属于引用类型,自动装箱和拆箱就是基本类型和引用类型之间的转换,至于为什么要转换,因为基本类型转换为引用类型后,就可以new对象,从而调用包装类中封装好的方法进行基本类型之间的转换或者toString(当然用类名直接调用也可以,便于一眼看出该方法是静态的),还有就是如果集合中想存放基本类型,泛型的限定类型只能是对应的包装类型。

7. int 和 Integer 有什么区别

int 是基本数据类型;Integer是其包装类,注意是一个类。为什么要提供包装类呢?一是为了在各种类型间转化,通过各种方法的调用。否则 你无法直接通过变量转化。

比如,现在int要转为String

int a=0;
String result=Integer.toString(a);

在java中包装类,比较多的用途是用在于各种数据类型的转化中。
我写几个demo

//通过包装类来实现转化的
int num=Integer.valueOf("12");
int num2=Integer.parseInt("12");
double num3=Double.valueOf("12.2");
double num4=Double.parseDouble("12.2");
 
//其他的类似。通过基本数据类型的包装来的valueOf和parseXX来实现String转为XX
String a=String.valueOf("1234");//这里括号中几乎可以是任何类型
String b=String.valueOf(true);
String c=new Integer(12).toString();//通过包装类的toString()也可以
String d=new Double(2.3).toString();

再举例下。比如我现在要用泛型

List nums;

这里<>需要类。如果你用int。它会报错的。

8. 数组有没有length()方法?String有没有length()方法?

①. 数组没有length()方法,但有length属性

②. String类有length() 方法

如:

String[] arr = new String[]{"hello", "world"};
System.out.println(arr.length);
String str = "hello world";
System.out.println(str.length());

9. Java中符号>>>>>有什么区别?

对于正数而言,>>>>>没区别。

对于负数而言,-2 >>> 1,结果是2147483647(Integer.MAX_VALUE)-1 >>> 1,结果是2147483647(Integer.MAX_VALUE)

所以,要判断两个数符号是否相同时,可以这么干:

return ((a >> 31) ^ (b >> 31)) == 0;

10. Java类的实例化顺序

结论:对象初始化的顺序,先静态方法,再构造方法,每个又是先基类后子类。

11. 什么是值传递和引用传递

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

引用传递一般是对于对象型变量而言的,传递的是该对象地址的一个副本, 并不是原对象本身 。

一般认为,java内的传递都是值传递. java中实例对象的传递是引用传递 。

12. String能被继承吗?为什么?

不可以,因为String类有final修饰符,而final修饰的类是不能被继承的,实现细节不允许改变。平常我们定义的String str=”a”;其实和String str=new String(“a”)还是有差异的。

前者默认调用的是String.valueOf来返回String实例对象,至于调用哪个则取决于你的赋值,比如String num=1,调用的是

public static String valueOf(int i) {
    return Integer.toString(i);
}

后者则是调用如下部分:

public String(String original) {
    this.value = original.value;
    this.hash = original.hash;
}

最后我们的变量都存储在一个char数组中

private final char value[];

13. String和StringBuilder、StringBuffer的区别?

①. String 字符串常量(final修饰,不可被继承),String是常量,当创建之后即不能更改。(可以通过StringBuffer和StringBuilder创建String对象(常用的两个字符串操作类)。)

②. StringBuffer 字符串变量(线程安全),其也是final类别的,不允许被继承,其中的绝大多数方法都进行了同步处理,包括常用的Append方法也做了同步处理(synchronized修饰)。其自jdk1.0起就已经出现。其toString方法会进行对象缓存,以减少元素复制开销。

public synchronized String toString() {
    if (toStringCache == null) {
        toStringCache = Arrays.copyOfRange(value, 0, count);
    }
    return new String(toStringCache, true);
}

③. StringBuilder 字符串变量(非线程安全)其自jdk1.5起开始出现。与StringBuffer一样都继承和实现了同样的接口和类,方法除了没使用synch修饰以外基本一致,不同之处在于最后toString的时候,会直接返回一个新对象。

public String toString() {
    // Create a copy, don’t share the array
    return new String(value, 0, count);
}

14. Java集合框架的基础接口有哪些?

一些其它的接口有Queue、Dequeue、SortedSet、SortedMap和ListIterator。

15. Java集合框架是什么?说出一些集合框架的优点?

每种编程语言中都有集合,最初的Java版本包含几种集合类:Vector、Stack、HashTable和Array。随着集合的广泛使用,Java1.2提出了囊括所有集合接口、实现和算法的集合框架。在保证线程安全的情况下使用泛型和并发集合类,Java已经经历了很久。它还包括在Java并发包中,阻塞接口以及它们的实现。

集合框架的部分优点如下:

16. HashMap 与HashTable有什么区别

HashTable

HashMap

17. ArrayList 和 LinkedList 有什么区别?

ArrayList和LinkedList都实现了List接口,有以下的不同点:

18. 简单介绍Java异常框架

Java对异常进行了分类,不同类型的异常分别用不同的Java类表示,所有异常的根类为java.lang.Throwable,Throwable下面又派生了两个子类:Error和Exception。

Error 表示应用程序本身无法克服和恢复的一种严重问题,程序只有死的份了,例如,说内存溢出和线程死锁等系统问题。

Exception表示程序还能够克服和恢复的问题,其中又分为系统异常和普通异常,系统异常是软件本身缺陷所导致的问题,也就是软件开发人员考虑不周所导致的问题,软件使用者无法克服和恢复这种问题,但在这种问题下还可以让软件系统继续运行或者让软件死掉,例如,数组脚本越界(ArrayIndexOutOfBoundsException),空指针异常(NullPointerException)、类转换异常(ClassCastException);普通异常是运行环境的变化或异常所导致的问题,是用户能够克服的问题,例如,网络断线,硬盘空间不够,发生这样的异常后,程序不应该死掉。

java为系统异常和普通异常提供了不同的解决方案,编译器强制普通异常必须try..catch处理或用throws声明继续抛给上层调用方法处理,所以普通异常也称为checked异常,而系统异常可以处理也可以不处理,所以,编译器不强制用try..catch处理或用throws声明,所以系统异常也称为unchecked异常。

提示答题者:就按照三个级别去思考:虚拟机必须宕机的错误,程序可以死掉也可以不死掉的错误,程序不应该死掉的错误;

19. java中的throw 和 throws关键字有什么区别?

参考例子:

public class Test {
    public static void main(String[] args) {
        try {
            test(args);
        }
        catch (Exception e) {
            e.printStackTrace();
        }
    }
    public static void test(String[] args) throws Exception {
        if (args == null || args.length != 1 || !"true".equals(args[0])) {
            throw new IllegalArgumentException("Invalid argument!");
        }
    }
}

区别

throw是语句抛出一个异常,一般是在代码块的内部,当程序出现某种逻辑错误时由程序员主动抛出某种特定类型的异常

throws是方法可能抛出异常的声明。(用在声明方法时,表示该方法可能要抛出异常)

20. 列举几个常见的运行时异常?

常用的RuntimeException如

其它如

21. final, finally, finalize有什么区别

22. 描述Java内存模型

Java虚拟机规范中将Java运行时数据分为六种:

①. 程序计数器:是一个数据结构,用于保存当前正常执行的程序的内存地址。Java虚拟机的多线程就是通过线程轮流切换并分配处理器时间来实现的,为了线程切换后能恢复到正确的位置,每条线程都需要一个独立的程序计数器,互不影响,该区域为“线程私有”。

②. Java虚拟机栈:线程私有的,与线程生命周期相同,用于存储局部变量表,操作栈,方法返回值。局部变量表放着基本数据类型,还有对象的引用。

③. 本地方法栈:跟虚拟机栈很像,不过它是为虚拟机使用到的Native方法服务。

④. Java堆:所有线程共享的一块内存区域,对象实例几乎都在这分配内存。

⑤. 方法区:各个线程共享的区域,储存虚拟机加载的类信息,常量,静态变量,编译后的代码。

⑥. 运行时常量池:代表运行时每个class文件中的常量表。包括几种常量:编译时的数字常量、方法或者域的引用。

23. java中垃圾收集的方法有哪些?

①. 标记-清除:这是垃圾收集算法中最基础的,根据名字就可以知道,它的思想就是标记哪些要被回收的对象,然后统一回收。这种方法很简单,但是会有两个主要问题:1.效率不高,标记和清除的效率都很低;2.会产生大量不连续的内存碎片,导致以后程序在分配较大的对象时,由于没有充足的连续内存而提前触发一次GC动作。

②. 复制算法:为了解决效率问题,复制算法将可用内存按容量划分为相等的两部分,然后每次只使用其中的一块,当一块内存用完时,就将还存活的对象复制到第二块内存上,然后一次性清楚完第一块内存,再将第二块上的对象复制到第一块。但是这种方式,内存的代价太高,每次基本上都要浪费一般的内存。 于是将该算法进行了改进,内存区域不再是按照1:1去划分,而是将内存划分为8:1:1三部分,较大那份内存交Eden区,其余是两块较小的内存区叫Survior区。每次都会优先使用Eden区,若Eden区满,就将对象复制到第二块内存区上,然后清除Eden区,如果此时存活的对象太多,以至于Survivor不够时,会将这些对象通过分配担保机制复制到老年代中。(java堆又分为新生代和老年代)

③. 标记-整理:该算法主要是为了解决标记-清除,产生大量内存碎片的问题;当对象存活率较高时,也解决了复制算法的效率问题。它的不同之处就是在清除对象的时候现将可回收对象移动到一端,然后清除掉端边界以外的对象,这样就不会产生内存碎片了。

④. 分代收集:现在的虚拟机垃圾收集大多采用这种方式,它根据对象的生存周期,将堆分为新生代和老年代。在新生代中,由于对象生存期短,每次回收都会有大量对象死去,那么这时就采用复制算法。老年代里的对象存活率较高,没有额外的空间进行分配担保,所以可以使用标记-整理 或者 标记-清除。

24. 常见的垃圾收集算法

主要分为三种算法

①. 标记-清除(Mark-Sweep)算法

首先进行标记工作,标识出所有要回收的对象,标记完成后统一进行清除。缺点有效率低,标记完成后会产生大量的内存碎片。空间内存太多可能会导致下一次分配较大对象时没有连续内存。

②. 复制算法

将可用的内存容量分为大小相等的两块,每次只使用其中的一块。当这一块的内存用完了,就将还存活着的对象复制到另外一块上面,然后再把已使用过的内存一次性清理掉。这样每次只对一个半区进行内存回收,内存分配时不用考虑内存碎片等问题。代价是只使用一半的内存空间。

现在大部分的新生代GC都是基于复制算法。新生代大部分的对象都是朝生夕死的。将内存分为一块较大的Eden区和两块较小的Survivor区域。每次使用Eden和一个Survivor.每次清理时把Eden和Survivor中还活着的区域复制到另外一块Survivor,最后清理掉刚才使用的Eden和Survivor区域。

③. 标记-整理(Mark-Compact)算法:

类似于标记-清除(Mark-Sweep)算法,但为了避免内存碎片化,它会在清理过程中将对象移动,以确保移动后的对象占用连续的内存空间

25. 在JVM GC中如何判断一个对象是否可以回收?

解析

①. 引用计数算法

顾名思义,为对象添加一个引用计数,用于记录对象被引用的情况。每当有一个地方引用它,计数器加1.引用失效,计数器-1。如果计数为0则表示对象可回收。优点:简单高效 缺点: 很难解决对象之间相互循环。

②. 引用的问题

可达性分析。通过一系列的称为GC Roots的对象作为起始点,从这些节点开始向下搜索,搜索所走过的路径称为引用链。如果一个对象到GC Roots没有任何引用链(图论的角度表示为不可达),则该对象可回收

写在最后

篇幅有限,文中只写出部分的面试题,其实老同学在复习的时候,就准备了一份完整的面试题;于是我厚着脸皮的找他要了一份,包含了Kafka、Mysql、Tomcat、Docker、Spring、MyBatis、Nginx、Netty、Dubbo、Redis、Netty、Spring cloud、分布式、高并发、性能调优、微服务等架构技术

需要的朋友请请点击下方传送门;即可免费领取完整的面试专题文件

传送门

部分面试题截图:

上一篇下一篇

猜你喜欢

热点阅读