字节一面凉经

23分钟的视频面试

1. 多态概念,实现方式

同一个事件发生在不同的对象上会产生不同的结果

  • 重载式多态(编译时多态)
  • 重写式多态(运行时多态): 通过动态绑定技术实现,是指在执行期间判断所引用对象的实际类型,根据其实际的类型调用其相应的方法。也就是说,只有程序运行起来,才知道调用的是哪个子类的方法。这种多态通过函数的重写以及向上转型来实现。
  • 向上转型: 就是想子类对象转为父类对象,此处父类对象可以是接口,向上转型时,子类单独定义的方法会丢失。

2. 重载和重写的区别

  • 重载发生在同一个类中,方法名必须相同,参数类型、参数个数、参数顺序不同,方法返回值和访问修饰符可以不同,发生在编译时。
  • 重写发生在父子类中,这里的父类可以是接口。方法名和参数类型、参数个数、参数顺序必须相同,返回值范围小于等于父类,抛出的异常范围小于等于父类,访问修饰符范围大于等于父类,如果父类访问修饰符为private则子类不能重写该方法。

3. 实现和系统重名的类(如String),怎么保证不会覆盖系统的类?

内部类可以和系统类重名。在java中,一般访问类需要导入包名,或直接写类的完整名称,即包名+类名。然而有一个包例外—java.lang包,它提供了我们常用的如Exception,String之类的API。使用它下面的类可以不导入包名,因为缺省情况下每个程序都为我们导入了。然而在程序中定义了一个相同名称的类时,程序会优先选择自己包内的类。

4. 双亲委派模型

JavaGuide-双亲委派模型
每一个类都有一个对应它的类加载器。系统中的 ClassLoder 在协同工作的时候会默认使用 双亲委派模型 。即在类加载的时候,系统会首先判断当前类是否被加载过。已经被加载的类会直接返回,否则才会尝试加载。加载的时候,首先会把该请求委派该父类加载器的 loadClass() 处理,因此所有的请求最终都应该传送到顶层的启动类加载器 BootstrapClassLoader 中。当父类加载器无法处理时,才由自己来处理。当父类加载器为null时,会使用启动类加载器 BootstrapClassLoader 作为父类加载器。

  • 双亲委派模型的好处:双亲委派模型保证了Java程序的稳定运行,可以避免类的重复加载(JVM 区分不同类的方式不仅仅根据类名,相同的类文件被不同的类加载器加载产生的是两个不同的类),也保证了 Java 的核心 API 不被篡改。如果没有使用双亲委派模型,而是每个类加载器加载自己的话就会出现一些问题,比如我们编写一个称为 java.lang.Object 类的话,那么程序运行的时候,系统就会出现多个不同的 Object 类。
  • 不想使用双亲委派模型怎么办:为了避免双亲委托机制,我们可以自己定义一个类加载器,然后重载 loadClass() 即可。
  • 自定义类加载器:除了 BootstrapClassLoader 其他类加载器均由 Java 实现且全部继承自java.lang.ClassLoader。如果我们要自定义自己的类加载器,很明显需要继承 ClassLoader。

5. Java泛型做什么用的,泛型擦除, < T>

泛型是一种能广泛适用的类型,泛型类,泛型方法,泛型接口。<>中的是类型参数,用于指代任何类型。无限定的通配符 有上限的通配符 又下限的通配符

6. Java动态代理

7. SynchronizedHashMap和ConcurrentHashMap的区别

ConcurrentHashMap和Hashtable的区别:
ConcurrentHashMap 和 Hashtable 的区别主要体现在实现线程安全的方式上不同。

  • 底层数据结构: JDK1.7的 ConcurrentHashMap 底层采用分段的数组+链表实现,JDK1.8 采用的数据结构跟HashMap1.8的结构一样,数组+链表/红黑二叉树。Hashtable 和 JDK1.8 之前的 HashMap 的底层数据结构类似都是采用数组+链表的形式,数组是 HashMap 的主体,链表则是主要为了解决哈希冲突而存在的;
  • 实现线程安全的方式(重要):在JDK1.7的时候,ConcurrentHashMap(分段锁)对整个桶数组进行了分割分段(Segment),每一把锁只锁容器其中一部分数据,多线程访问容器里不同数据段的数据,就不会存在锁竞争,提高并发访问率。到了JDK1.8 的时候已经摒弃了Segment的概念,而是直接用 Node 数组+链表+红黑树的数据结构来实现,并发控制使用 synchronized 和 CAS 来操作。(JDK1.6以后 对 synchronized锁做了很多优化)整个看起来就像是优化过且线程安全的 HashMap,虽然在JDK1.8中还能看到 Segment 的数据结构,但是已经简化了属性,只是为了兼容旧版本;②Hashtable(同一把锁):使用 synchronized 来保证线程安全,效率非常低下。当一个线程访问同步方法时,其他线程也访问同步方法,可能会进入阻塞或轮询状态,如使用 put 添加元素,另一个线程不能使用 put 添加元素,也不能使用 get,竞争会越来越激烈效率越低。

8. Java垃圾回收机制

Java 语言中一个显著的特点就是引入了垃圾回收机制,使c++程序员最头疼的内存管理的问题迎刃而解,它使得Java程序员在编写程序的时候不再需要考虑内存管理。由于有个垃圾回收机制,Java中的对象不再有”作用域”的概念,只有对象的引用才有”作用域”。垃圾回收可以有效的防止内存泄露,有效的使用可以使用的内存。垃圾回收器通常是作为一个单独的低级别的线程运行,不可预知的情况下对内存堆中已经死亡的或者长时间没有使用的对象进行清楚和回收,程序员不能实时的调用垃圾回收器对某个对象或所有对象进行垃圾回收。回收机制有分代复制垃圾回收和标记垃圾回收,增量垃圾回收。

9. 多线程引起死锁的根本原因,怎样避免死锁

线程1和2都需要资源a和b,当运行到某一时刻,有如下状态,线程1持有资源A,线程2持有资源B,线程1和2互相等待对方的资源,程序就陷入了死锁。
要避免死锁,只需要破坏产生的四个条件即可。

  1. 互斥条件:该资源任一时刻只由一个线程占用
  2. 请求与保持条件:一个进程因请求资源而阻塞时,对已获得资源保持不放
    (破坏方式:一次性申请所有资源)
  3. 不剥夺条件:线程已获得的资源在未使用完之前不能被其他线程强行剥夺,只有自己使用完毕后才释放资源
    (破坏方式:占用部分资源的线程进一步申请其他资源时,如果申请不到,可以主动释放它占有的资源)
  4. 循环等待条件:若干进程之间形成一种头尾相接的循环等待资源关系。
    (破坏方式:靠按需申请资源来预防,按某一顺序申请资源,释放则反序释放,破坏 循环等待条件)

10. HashMap底层数据结构,什么场景下使用HashMap

HashMap底层是数组加链表,也就是链表散列,数组中存放着链表的头结点JDK1.8中当链表长度超过阙值时(默认为8),将链表转换为红黑树。这种结构结合了数组寻址的优势和链表插入删除的优势,当既有寻址的需求有需要经常插入删除时就使用HashMap。

11. cookie和session区别,cookie和session都存什么

都是用来跟踪浏览器用户的会话方式,但是应用场景不太一样,Cookie一般用来保存用户信息

  1. 在cookie中保存已经登陆过得用户,下次登录可以自动帮你填写一些
  2. 保持登录,(存一个Token在Cookie中,根据Token来找),重新登录一般重写Token
  3. 登录一次网站后,访问网站其他页面不需要重新登录
    Session的主要作用就是通过服务端记录用户的状态,典型的场景购物车(服务器中存session,cookie中存一个session ID)

12. HTTP头里面有什么

13. GET和POST区别

  1. get用来从服务器获取数据,post用来向服务器提交数据
  2. get将表单中数据按照name=value形式添加到action所指向的url后面,用“?”连接,变量间用&连接,post将表单中的数据放在HTTP协议的请求头或消息体中,传到action所指的URL
  3. get传输的数据收到URL长度限制,而POST将表单中数据方在HTTP协议的请求头或消息体中,传到action指向的URL中
  4. get参数显示在地址栏,对于敏感数据用POST
  5. get使用百分号编码,保证被传送的数据由遵循规范的文本组成,例如空格编码是%20

14. HTTP和HTTPS区别(认证服务端证书合法的过程)

80端口”http:// ”443端口“https://”
http协议运行在TCP智商,传输内容明文,客户端服务端无法互验身份,
https是运行在SSL/TLS上的http协议,SSL/TLS运行在TCP之上,传输内容加密,加密方式:对称加密,
但对称加密的秘钥会用服务器方的证书进行非对称加密

15. 快速排序算法复杂度、算法流程

O(nlogn) 将第一个数据作为中间值,将比它大和小的元素分为两组,这两组在都将第一个数据作为中间值。。。。。。

16. 内存为什么以页为单位加载

算法题:打印一颗不完全二叉树每一层最左面的节点

用队列实现层次遍历,在取出每一层中的第一个节点。

你可能感兴趣的:(字节一面凉经)