记录(三)

2022-06-10 20:07:51 浏览数 (1)

网上看到的一些面试题,自己整理一下答案,查缺补漏。

Java 基础

1.0 JAVA中的几种基本数据类型是什么,各自占用多少字节。

byte, short, int, long, float, double, char, boolean

数据类型

字节

boolean

1 bit,不到一个字节

byte

8 bit,1字节

short

16 bit,2字节

char

16 bit,2字节

int

32 bit,4字节

float

32 bit,4字节

long

64 bit,8字节

double

64 bit,8字节

1.1 String类能被继承吗,为什么。

String类不能被继承,因为String类有final修饰符,final修饰的类不能被继承。

1.2 String,Stringbuffer,StringBuilder 的区别。

String 字符串常量 StringBuffer 字符串变量(线程安全) StringBuilder 字符串变量(非线程安全)

简要的说, String 类型和 StringBuffer 类型的主要性能区别其实在于 String 是不可变的对象, 因此在每次对 String 类型进行改变的时候其实都等同于生成了一个新的 String 对象,然后将指针指向新的 String 对象,所以经常改变内容的字符串最好不要用 String ,因为每次生成对象都会对系统性能产生影响,特别当内存中无引用对象多了以后, JVM 的 GC 就会开始工作,那速度是一定会相当慢的。而如果是使用 StringBuffer 类则结果就不一样了,每次结果都会对StringBuffer 对象本身进行操作,而不是生成新的对象,再改变对象引用。所以在一般情况下我们推荐使用 StringBuffer ,特别是字符串对象经常改变的情况下。而在某些特别情况下, String 对象的字符串拼接其实是被 JVM 解释成了 StringBuffer 对象的拼接,所以这些时候 String 对象的速度并不会比 StringBuffer 对象慢,而特别是以下的字符串对象生成中, String 效率是远要比 StringBuffer 快的: String S1 = “This is only a” “ simple” “ test”; StringBuffer Sb = new StringBuilder(“This is only a”).append(“ simple”).append(“ test”); 你会很惊讶的发现,生成 String S1 对象的速度简直太快了,而这个时候 StringBuffer 居然速度上根本一点都不占优势。其实这是 JVM 的一个把戏,在 JVM 眼里,这个 String S1 = “This is only a” “ simple” “test”; 其实就是: String S1 = “This is only a simple test”; 所以当然不需要太多的时间了。但大家这里要注意的是,如果你的字符串是来自另外的 String 对象的话,速度就没那么快了,譬如:String S2 = “This is only a”;String S3 = “ simple”;String S4 = “ test”;String S1 = S2 S3 S4;这时候 JVM 会规规矩矩的按照原来的方式去做 在大部分情况下 StringBuffer > StringStringBufferJava.lang.StringBuffer线程安全的可变字符序列。一个类似于 String 的字符串缓冲区,但不能修改。虽然在任意时间点上它都包含某种特定的字符序列,但通过某些方法调用可以改变该序列的长度和内容。可将字符串缓冲区安全地用于多个线程。可以在必要时对这些方法进行同步,因此任意特定实例上的所有操作就好像是以串行顺序发生的,该顺序与所涉及的每个线程进行的方法调用顺序一致。StringBuffer 上的主要操作是 append 和 insert 方法,可重载这些方法,以接受任意类型的数据。每个方法都能有效地将给定的数据转换成字符串,然后将该字符串的字符追加或插入到字符串缓冲区中。append 方法始终将这些字符添加到缓冲区的末端;而 insert 方法则在指定的点添加字符。例如,如果 z 引用一个当前内容是“start”的字符串缓冲区对象,则此方法调用 z.append("le") 会使字符串缓冲区包含“startle”,而 z.insert(4, "le") 将更改字符串缓冲区,使之包含“starlet”。在大部分情况下 StringBuilder > StringBufferjava.lang.StringBuildejava.lang.StringBuilder一个可变的字符序列是5.0新增的。此类提供一个与 StringBuffer 兼容的 API,但不保证同步。该类被设计用作 StringBuffer 的一个简易替换,用在字符串缓冲区被单个线程使用的时候(这种情况很普遍)。如果可能,建议优先采用该类,因为在大多数实现中,它比 StringBuffer 要快。两者的方法基本相同。

1.3 ArrayList 和 LinkedList 有什么区别。
  • ArrayList,采用数组数据结构的List,创建一个数组a,加索引即角标就可以访问到数据,数组在内容中是一段连续的数据,可以支持随机访问。a则表示数组的内存地址,索引则是数据所处位置距离第一个元素的偏移量,如a0表示当前第一个元素,和a指的是一个位置,所以无论任何位置,只需要两步,找到a的位置,然后获取偏移量即可访问到数据,时间复杂度是O(1)。数组创建时需要指定长度,ArrayList可以一直增加是因为当超过长度时,会新创建一个新的数组,把原来的数据拷贝进去,然后将老的数组抛弃掉。ArrayList支持随机访问,实现了RandomAccess接口。查询多的情况使用ArrayList,当需要删除数据时,当前数据的后续数据角标都发现改变,所以时间复杂度是O(n-i),所以适合用在查询多,增删少的情况下。
  • LinkedList,采用链表数据结构的List,不支持随机,在创建时并没有指定长度,使用时是由系统分配内存,所以在内存中的位置是随机。LinkedList在添加数据时不光会记录当前数据,还会记录上个元素的位置,所以通过上个元素访问这个元素,通过一个个元素互相指向形成一个链条一样的结构。当需要访问一个位置的数据时,只能通过第一个元素,一步一步寻找,时间复杂度是O(n),不能随机访问。所以查询的效率很慢,当删除时,只需要将数据删除后,再下个元素的指向到上个元素即可,删除的时间复杂度是O(1),所以适合用在频繁增删的情况下。

具体可以看以前转的一篇文章:关于一次List的面试 之前写过的ArrayList相关内容:ArrayList的扩容机制

1.4 讲讲类的实例化顺序,比如父类静态数据,构造函数,字段,子类静态数据,构造函数,字段,当 new 的时候,他们的执行顺序。

顺序为:

  1. 父类静态变量、
  2. 父类静态代码块、
  3. 子类静态变量、
  4. 子类静态代码块、
  5. 父类非静态变量(父类实例成员变量)、
  6. 父类构造函数、
  7. 子类非静态变量(子类实例成员变量)、
  8. 子类构造函数。

代码验证可以看这个:Java基础-类的实例化顺序

1.5 用过哪些 Map 类,都有什么区别,HashMap 是线程安全的吗,并发下使用的 Map是什么,他们内部原理分别是什么,比如存储方式,hashcode,扩容,默认容量等。

用过 HashMap、LinkedHashMap、TreeMap、 具体查看这个 笔记(三) - Java集合 HashMap不是线程安全的,并发下应该使用 ConcurrentHashMap,

1.6 JAVA8的 ConcurrentHashMap 为什么放弃了分段锁,有什么问题吗,如果你来设计,你如何设计。
1.7 有没有有顺序的 Map 实现类,如果有,他们是怎么保证有序的。

Hashmap和Hashtable 都不是有序的。

TreeMap和LinkedHashmap都是有序的。(TreeMap默认是key升序,LinkedHashmap默认是数据插入顺序)

TreeMap是基于比较器Comparator来实现有序的。

LinkedHashmap是基于链表来实现数据插入有序的。

1.8 抽象类和接口的区别,类可以继承多个类么,接口可以继承多个接口么,类可以实现多个接口么。

之前有写过,点击 这里 查看

1.9 继承和聚合的区别在哪。
  • 继承 指的是一个类(称为子类、子接口)继承另外的一个类(称为父类、父接口)的功能,并可以增加它自己的新功能的能力,继承是类与类或者接口与接口之间最常见的关系;在Java中此类关系通过关键字extends明确标识,在设计时一般没有争议性;
  • 聚合 聚合是关联关系的一种特例,他体现的是整体与部分、拥有的关系,即has-a的关系,此时整体与部分之间是可分离的,他们可以具有各自的生命周期,部分可以属于多个整体对象,也可以为多个整体对象共享;比如计算机与CPU、公司与员工的关系等;表现在代码层面,和关联关系是一致的,只能从语义级别来区分;

在Family类中包含一个Child.并且包含Child的get,set方法,可以只先创建Family然后通过构造器或者get,set给Child赋值

参考:继承、实现、依赖、关联、聚合、组合的联系与区别

2.0 IO 模型有哪些,讲讲你理解的 nio ,他和 bio,aio 的区别是啥,谈谈 reactor 模型。

具体看 面试题之IO 模型有哪些,讲讲你理解的 nio ,他和 bio,aio 的区别是啥,谈谈 reactor 模型。

2.1 反射的原理,反射创建类实例的三种方式是什么。

关于反射可以看这个反射相关内容

  • 方式一 通过对象的getClass方法进行获取。这种方式需要具体的类和该类的对象,以及调用getClass方法。 Class class2 = foo1.getClass(); System.out.println(class1==class2);//true'
  • 方式二 任何数据类型(包括基本数据类型)都具备着一个静态的属性class,通过它可直接获取到该类型对应的Class对象。这种方式要使用具体的类,然后调用类中的静态属性class完成,无需调用方法,性能更好。 Class class1 = Foo.class;
  • 方式三 通过Class.forName()方法获取。这种方式仅需使用类名,就可以获取该类的Class对象,更有利于扩展。 ` Class class3 = null; try { class3 = Class.forName("com.imooc.reflect.Foo"); } catch (ClassNotFoundException e) { e.printStackTrace(); }

System.out.println(class2==class3);//true

代码语言:txt复制
2.2 反射中,Class.forName 和 ClassLoader 区别。

在java中Class.forName()和ClassLoader都可以对类进行加载。

区别:

  1. Class.forName除了将类的.class文件加载到jvm中之外,还会对类进行解释,执行类中的static块。
  2. 而classloader只干一件事情,就是将.class文件加载到jvm中,不会执行static中的内容,只有在newInstance才会去执行static块。

看简书文章讲的比较细致,反射中,Class.forName和ClassLoader区别

2.3 描述动态代理的几种实现方式,分别说出相应的优缺点。
2.4 动态代理与 cglib 实现的区别。
2.5 为什么CGlib 方式可以对接口实现代理。
2.6 final 的用途。
  1. 被final修饰的类不可以被继承
  2. 被final修饰的方法不可以被重写
  3. 被final修饰的变量不可以被改变

另外还有:

  1. 被final修饰的方法,JVM会尝试为之寻求内联,这对于提升Java的效率是非常重要的。因此,假如能确定方法不会被继承,那么尽量将方法定义为final的
  2. 被final修饰的常量,在编译阶段会存入调用类的常量池中
2.7 写出三种单例模式实现。

详细的看 设计模式之单例模式

2.8 如何在父类中为子类自动完成所有的 hashcode 和 equals实现?这么做有何优劣。
2.9 请结合OO 设计理念,谈谈访问修饰符 public、private、protected、default 在应用设计中的作用。
3.0 深拷贝和浅拷贝区别。
3.1 数组和链表数据结构描述,各自的时间复杂度。
3.2 error和exception 的区别,CheckedException,RuntimeException 的区别。
3.3 请列出5 个运行时异常。

ClassCastException(类转换异常) IndexOutOfBoundsException(数组越界) NullPointerException(空指针) ArrayStoreException(数据存储异常,操作数组时类型不一致) 还有IO操作的BufferOverflowException异常

3.4 在自己的代码中,如果创建一个 java.lang.String 类,这个类是否可以被类加载器加载?为什么。

在《深入理解java虚拟机》一书中有这样一段话,“即使自定义了自己的类加载器,强行使用defineClass()方法去加载一个以‘java.lang’开头的类也不会成功,如果尝试这样做的话,将会收到一个由虚拟机自己抛出的‘java.lang.SecurityException:Prohibited package name:java.lang’异常”。 所以如果创建一个java.lang.String的类,是不能被类加载器加载的。因为虚拟机会抛出异常。

说到类加载,就必须对类加载机制非常熟悉。

类加载使用的是双亲委派模型,当你想要加载一个类的时候,必须先给你的父加载器,它再去想办法加载,如果它不能加载,再告诉我们,我们自己想办法。

所以,在java中java.lang.String肯定在上层的ClassLoader被加载过了,所以你自己写的完全没有机会加载。

3.5 说一说你对 java.lang.Object 对象中 hashCode 和 equals 方法的理解。在什么场景下需要重新实现这两个方法。
3.6 在 jdk1.5 中,引入了泛型,泛型的存在是用来解决什么问题。

泛型主要针对向下转型时所带来的安全隐患,其核心组成是在声明类或接口时,不设置参数或属性的类型。

3.7 这样的a.hashcode() 有什么用,与 a.equals(b)有什么关系。
3.8 有没有可能 2 个不相等的对象有相同的 hashcode。

有可能,两个不相等的对象可能会有相同的 hashcode 值,这就是为什么在hashmap 中会有冲突。相等 hashcode 值的规定只是说如果两个对象相等,必 须有相同的 hashcode 值,但是没有关于不相等对象的任何规定。

3.9 Java 中的 HashSet 内部是如何工作的。
4.0 什么是序列化,怎么序列化,为什么序列化,反序列化会遇到什么问题,如何解决。
4.1 java8 的新特性。

Java8 新增了非常多的特性,我们主要讨论以下几个:

  • Lambda 表达式 − Lambda 允许把函数作为一个方法的参数(函数作为参数传递到方法中)。
  • 方法引用 − 方法引用提供了非常有用的语法,可以直接引用已有Java类或对象(实例)的方法或构造器。与lambda联合使用,方法引用可以使语言的构造更紧凑简洁,减少冗余代码。
  • 默认方法 − 默认方法就是一个在接口里面有了一个实现的方法。
  • 新工具 − 新的编译工具,如:Nashorn引擎 jjs、 类依赖分析器jdeps。
  • Stream API −新添加的Stream API(java.util.stream) 把真正的函数式编程风格引入到Java中。
  • Date Time API − 加强对日期与时间的处理。
  • Optional 类 − Optional 类已经成为 Java 8 类库的一部分,用来解决空指针异常。
  • Nashorn, JavaScript 引擎 − Java 8提供了一个新的Nashorn javascript引擎,它允许我们在JVM上运行特定的javascript应用。

JVM

4.2 什么情况下会发生栈内存溢出。
4.3 JVM 的内存结构,Eden 和 Survivor 比例。
4.4 JVM内存为什么要分成新生代,老年代,持久代。新生代中为什么要分Eden和Survivor。
4.5 JVM 中一次完整的 GC流程是怎样的,对象如何晋升到老年代,说说你知道的几种主要的 JVM 参数。
4.6 你知道哪几种垃圾收集器,各自的优缺点,重点讲下 cms和 G1,包括原理,流程,优缺点。
4.7 垃圾回收算法的实现原理。

以前写过的 垃圾回收算法

4.8 当出现了内存溢出,你怎么排错。
4.9 JVM 内存模型的相关知识了解多少,比如重排序,内存屏障,happen-before,主内存,工作内存等。
5.0 简单说说你了解的类加载器,可以打破双亲委派么,怎么打破。
5.1 讲讲JAVA的反射机制。
5.2 你们线上应用的 JVM 参数有哪些。
5.3 g1 和 cms区别,吞吐量优先和响应优先的垃圾收集器选择。
5.4 怎么打出线程栈信息。

开源框架

5.5 简单讲讲 tomcat 结构,以及其类加载器流程,线程模型等。
5.6 tomcat如何调优,涉及哪些参数。

Tomcat 调优及 JVM 参数优化 springboot内置tomcat参数调优

5.7 讲讲 Spring加载流程。
5.8 Spring AOP的实现原理。
5.9 讲讲 Spring事务的传播属性。
6.0 Spring如何管理事务的。
6.1 Spring怎么配置事务(具体说出一些关键的 xml 元 素 )。
6.2 说说你对 Spring 的理解,非单例注入的原理?它的生命周期?循环注入的原理,aop的实现原理,说说 aop 中的几个术语,它们是怎么相互工作的。
6.3 Springmvc 中 DispatcherServlet 初始化过程。
6.4 netty的线程模型,netty如何基于 reactor 模型上实现的。
6.5 为什么选择 netty。
6.6 什么是TCP粘包,拆包。解决方式是什么。
6.7 netty的 fashwheeltimer 的用法,实现原理,是否出现过调用不够准时,怎么解决。
6.8 netty的心跳处理在弱网下怎么办。
6.9 netty的通讯协议是什么样的。
7.0 springmvc 用到的注解,作用是什么,原理。
7.1 springboot 启动机制。

  • 1.通过 SpringFactoriesLoader加载 META-INF/spring.factories⽂件,获取并创建 SpringApplicationRunListener对象
  • 2.然后由 SpringApplicationRunListener来发出 starting 消息
  • 3.创建参数,并配置当前 SpringBoot 应用将要使用的 Environment
  • 4.完成之后,依然由 SpringApplicationRunListener来发出 environmentPrepared 消息
  • 5.创建 ApplicationContext
  • 6.初始化 ApplicationContext,并设置 Environment,加载相关配置等
  • 7.由 SpringApplicationRunListener来发出 contextPrepared消息,告知SpringBoot 应用使用的 ApplicationContext已准备OK
  • 8.将各种 beans 装载入 ApplicationContext,继续由SpringApplicationRunListener来发出 contextLoaded 消息,告知 SpringBoot 应用使用的 ApplicationContext已装填OK
  • 9.refresh ApplicationContext,完成IoC容器可用的最后⼀步
  • 10.由 SpringApplicationRunListener来发出 started 消息
  • 11.完成最终的程序的启动
  • 12.由 SpringApplicationRunListener来发出 running 消息,告知程序已运行起来了

操作系统

7.2 Linux 系统下你关注过哪些内核参数,说说你知道的。

这个比较复杂 Linux内核参数配置 Linux内核参数优化

7.3 Linux下 IO 模型有几种,各自的含义是什么。
7.4 epoll 和poll 有什么区别。

面试经典问题---select、poll、epoll之间有什么区别

7.5 平时用到哪些 Linux命令。

head、tail、tar、ssh、sftp、telnet、curl、wget、cp、mv、sed、su cd、ls、grep、find、rm、kill、ps、cat、chown、chmod、

7.6 用一行命令查看文件的最后五行。

tail -5f filename

7.7 用一行命令输出正在运行的 java 进程。

ps -ef|grep java

7.8 介绍下你理解的操作系统中线程切换过程。
7.9 进程和线程的区别。
8.0 top 命令之后有哪些内容,有什么作用。
8.1 线上 CPU爆高,请问你如何找到问题所在。

Copyright: 采用 知识共享署名4.0 国际许可协议进行许可

Links: https://cloud.tencent.com/developer/article/2020458

0 人点赞