java实习生入职_阿里《JAVA实习生入职测试题—2019最新》之答案详解(连载二)...

力争清晰完整准确(逐步完善,持续更新)

3、反射中,Class.forName和ClassLoader.loadClass的区别

更准确的说,是Class.forName("SomeClass")和ClassLoader.getSystemClassLoader().loadClass("SomeClass")的区别

Class.forName(“SomeClass”)= Class.forName(className,true,classloader)

ClassLoader.loadClass(className) = ClassLoader.loadClass(className,false)

第一个会用调用这段代码的class loader 来load class, 并且完成初始化(true——表示要初始化,即静态初始化会被执行,包括静态代码块,静态变量)

第二个会调用“system" class loader (这个会被覆盖掉),不会被初始化(如果用它来load  JDBC driver,那么它不会被注册,因此你无法使用JDBC)

4、session和cookie的区别与联系,session的生命周期,多个服务部署时session管理

这个得从HTTP协议是无状态说起。http协议就是客服端向服务器发起一次请求,链接,然后传数据,断开链接。

无状态(stateless)

就是第一次客户端A来了,在服务器要了些资源,干了些事,然后断开链接,走了。没有谁记录这次链接的一些状态,下一次客户端A再来一次,服务器不认识它,不知道它来过,也不知道它上次干过啥,完全当作新的一次链接访问来处理。就如同生活中有个陌生人来你家做客,吃饭打牌玩游戏,然后他回家了。下次这家伙又来,结果你有遗忘症,完全认不得这哥们。

有状态 (stateful)

就是第一次客户端A来了,在服务器要了些资源,干了些事,然后断开链接,走了。有东西记录这次访问的一些信息,比如操作记录、用户名密码等。这次就是有个陌生人来你家做客,吃饭打牌玩游戏,然后他回家了。下次这家伙又来,主人是有正常记忆的人,对这哥们有印象。

session和cookie的作用就是记录访问用户和服务器的交互状态。它们让http请求变成了能记录状态的会话。cookie存在客户端,B/S里客户端就是浏览器;session存在服务器。

cookie截图如下:

bfeebab42aa4e8d5e79be360c26b85c2.png

cookie

存放key/value键值对数据。当用户通过HTTP访问服务器,服务器会在reponse里将这些“键值对”信息给到客户端浏览器,并对这些数据做一定的限制。在条件符合的时候,用户再次访问这个服务器,数据又被完整带回服务器(在HTTP header里)。 Cookie设计的初衷是记录一段时间内用户访问Web应用的行为路径。

缺点:Cookie可能被盗和伪造等

session(会话)

session基于cookie工作的。同一客户端和服务器交互时,不需要每次都回传所有Cookie信息,只需要传个唯一ID(客户端第一次访问服务器时服务器生成的唯一标识),服务端每次回传这个唯一标识(sessionId),服务器就知道这个客户端是谁了,来服务器端干过啥。减少了客服端和服务端每次交互传输的数据量,节省带宽。在PV过亿的情况,节省的带宽就相当可观了

缺点:Session不易在多台服务器间共享等

session生命周期

多服务器部署的session管理

5、Java中的队列都有哪些,有什么区别

6、详谈一下Java的内存模型以及GC算法

Java内存模型(Java Memory Model, JMM)

为什么Java要抽象和实现这么一套东西?

简单地先从硬件角度说,CPU和存储设备速度相差几个数量级,而CPU高速运算的数据源及运算的结构,不可避免要和存储设备有读写交互,单靠寄存器搞不定。所以中间搞个高速缓存,解决CPU与内存的速度矛盾。这样一来,解决了问题,又增加了新的问题,复杂性增加了(自不待言),缓存一致性的问题又来了(Cache Coherence)。

Java虚拟机的“内存模型”可以说是对特定的内存和高速缓存读写过程的抽象,屏蔽掉各种硬件和操作系统的内存访问差异,确保Java程序在各种平台上运行效果一样,不需要再改代码(跨平台, Write once, run everywhere)。而诸如C++等语言,直接使用物理硬件和操作系统的内存模型,换个平台可能就会出错,所以在某些场景必须针对不同的平台编写不同的分支处理程序。

不说了,上图

cb5aac0e251223f11e5f629e4ca31178.png

运行时数据区域

4333784d7a244a812b1531e1e7976f67.png

这个和前面的划分不是同一层次角度,面试时有面试官,随手写段代码,让我区分里面的变量等分别是放在那个区域的。

1)程序计数器(Program Counter Register)

据说可以理解为JAVA底层执行的字节码的行号指示器,通过改变此的数值,来选取执行不同的字节码指令,完成分支、循环、跳转、异常处理、线程恢复等编程语言基本都具备的基础功能

不会抛出OutOfMemoryError

线程私有(有游戏主程问我哪些是线程私有的,这个问题在思考什么呢)

2)  Java虚拟机栈(Java Virtual Machine Stacks)

生命周期 = 线程的生命周期,数据结构:stack

栈帧(Stack Frame) ,存储局部变量表、操作数栈、动态链接、方法出口等。和方法息息相关,方法的调用一直到执行完毕,对应着一个栈桢的入栈到出栈之全过程。

局部变量表,存放8种基本数据类型(boolean、byte、char、short、integer、long、float、double)、对象引用、returnAddress(指向一条字节码指令的地址)

会抛出StackOverflowError及OutOfMemoryError

线程私有

3)  本地方法栈 (Native Method Stack)

为Native方法服务(类似虚拟机栈)

实现方式、数据结构、语言可灵活处理,如Sun HotSpot 虚拟机把本地方法栈和虚拟机栈合二为一

会抛出StackOverflowError及OutOfMemoryError

4)堆(heap)

存放几乎所有对象

细分为新生代和老年代(内存空间占比为1:2),新生代根据死亡概率,会有不同的回收算法(有游戏主程专门问到,老年代的回收算法有哪些?)

77342ade99d2e03f315532170a4396b5.png

会抛出OutOfMemoryError

线程共享

5)   方法区(Method Area)

存储被虚拟机加载的类信息、常量、静态变量、即时编译器编译后的代码等

会抛出OutOfMemoryError

线程共享

6)运行时常量池(Runtime Constant Pool)

存放编译期生成的各种字面量和符号引用及直接引用(?)

动态可变,即在运行期也可将新的常量放入池中,如通过String类的intern()方法

会抛出OutOfMemoryError

GC算法

7、JAVA10、JAVA11的新特性

新增Optional.orElseThrow()方法

新增几个Unmodifiable CollectionsAPI,如Collectors 类新增 toUnmodifiableList, toUnmodifiableSet, 和toUnmodifiableMap 方法

...

卧槽,最近jdk更新有点快,都13了

8、Java内存泄漏的问题调查定位:jmap, jstack的使用

9、Spring的体系结构和jar用途

10、Spring MVC的运行原理

11、Spring Boot的执行过程

spring boot 类加载过程和tomcat类加载过程的区别,也是面试常问

12、Spring IOC和AOP的底层实现

14、Spring boot 的优势和劣势,以及适用场景等

15、讲一下Sping Cloud和Dubbo的优缺点

16、什么是Hystrix?它如何实现容错?

17、什么Netflix Feign?它的优点是什么?

18、谈一谈分布式一致性到CAP理论,BASE理论

CAP — C:Consistency(一致性),A:Avaliaility(可用性)和P:Partition tolerance(分区容错性)

三者至多同时满足其中的两个,具体参见CAP猜想:

BASE — BA: Basic Available(基本可用),S: Soft state(软状态)和 E: Eventually consistent(最终一致性)

基于大规模互联网分布式实践经验和CAP理论,权衡考虑CAP中的一致性和可用性,大家发现即使难以满足强一致性(Strong consistency),但应用应该结合自身业务特点,实现在有限时间内达到最终一致性(Eventual consistency)

19、常用的线程池模式以及不同线程池的使用场景—面试出现频率非常高

FixedThreadPool

定长线程池

988f09150f3a51d63d6c8f92c24efdff.png

源码如下:

public static ExecutorService newFixedThreadPool(intnThreads) {return newThreadPoolExecutor(nThreads, nThreads,0L, TimeUnit.MILLISECONDS,new LinkedBlockingQueue());

}

CachedThreadPool

可缓存的线程池

fa6cb1735d631f45de9d409e6a066df3.png

源码如下:

public staticExecutorService newCachedThreadPool() {return new ThreadPoolExecutor(0, Integer.MAX_VALUE,60L, TimeUnit.SECONDS,new SynchronousQueue());

}

SingleThreadExecutor

单一线程池

2031f36973a18111d314e3219345092c.png

1)只会创建一个工作线程,即corePoolSize和maxiumPoolSize都被设置1,其它的同FixedThreadPool

public staticExecutorService newSingleThreadExecutor() {return newFinalizableDelegatedExecutorService

(new ThreadPoolExecutor(1, 1,0L, TimeUnit.MILLISECONDS,new LinkedBlockingQueue()));

}

2)采用的阻塞队列为LinkedBlockingQueue

ScheduledThreadPool

可调度线程池  (处理延时或定时任务)

df087c8f8844ba900a0dab1f28d4eadc.png

源码如下:

public ScheduledThreadPoolExecutor(intcorePoolSize) {super(corePoolSize, Integer.MAX_VALUE, 0, NANOSECONDS,newDelayedWorkQueue());

}

线程池如果满了,会抛什么异常,拒绝策略包含哪些?(游戏主程的问题)

抛出 "RejectedExecutionException"异常,拒绝策略包括4种(implements RejectedExecutionHandler),

CallerRunsPolicy —— 让新来的task在调用它的线程里自己跑

AbortPolicy —— 不执行新来的task,直接抛出异常——默认

DiscardPolicy —— 静悄悄地丢弃掉被拒绝地task,不抛出异常通知一下哈

DiscardOldestPolicy —— 丢弃掉最早地未处理地请求;如果线程池关闭,则丢弃掉新来的task

20、ReentrantLock 和 synchronized的区别

21、AtomicInteger和volatile等线程安全操作的关键字的理解和使用

关于线程安全,我的理解就是一段代码在单线程下跑完的结果在多线程下跑完一样。

volatie作用于fields,语义表示内存可见性。也就是说,一旦最新对此值作了修改,所有的线程都知道;又可防止指令重排序,保证多线程下的线程安全。

AtomicInteger的存储值的value被volatile修饰符限定,即保证了其线程安全。主要用来计数

源码片段如下:

private static final Unsafe unsafe =Unsafe.getUnsafe();private static final longvalueOffset;static{try{

valueOffset= unsafe.objectFieldOffset

(AtomicInteger.class.getDeclaredField("value"));

}catch (Exception ex) { throw newError(ex); }

}private volatile int value;

AtomicInteger源码比较简单,主要的几个接口,都是调用Unsafe类的compareAndSwapInt()、getAndAddInt()、getAndSetInt()实现。

valueOffset,也就是内存偏移量。AtomicInteger的原子操作就是依靠内存偏移量来实现的。

关于CAS(compareAndSwap)后面单独写篇博客吧,乐观锁的机制就是CAS

public final boolean compareAndSet(int expect, intupdate) {return unsafe.compareAndSwapInt(this, valueOffset, expect, update);

}

简单说,就是更新之前,先读取,看读取的actual vulue 和原来的值(expect)是否是一致的。如果一致,就直接更新;否则更新expect,再次读取。保证了在不加锁的情况下,不会出问题,效率还高

Unsafe类读写速度很快,类似C的指针,可以操作系统内存资源、自主管理内存。没有JVM的内存管理,可能会有内存泄漏等安全问题,所以JAVA官方不推荐使用

关于volatile详情,请参见:

关于

22、分布式锁三种实现方式

23、socket框架netty的使用,以及NIO的实现原理,为什么是异步非阻塞

24、简述NIO的最佳实践

25、Zookeeper的用途,选举的原理是什么

26、手写一个哈夫曼树

哈夫曼树(Huffman Tree)又称最优二叉树

*****************************************************************************************************

精力有限,想法太多,专注做好一件事就行

我只是一个程序猿。5年内把代码写好,技术博客字字推敲,坚持零拷贝和原创

写博客的意义在于锻炼逻辑条理性,加深对知识的系统性理解,锻炼文笔,如果恰好又对别人有点帮助,那真是一件令人开心的事

*****************************************************************************************************

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值