java基础
1、Arrays。sort实现原理和Collections.sort实现原理?
Collections.sort方法底层会调用Arrays.sort方法,底层实现都是TimeSort实现的。TimSort算法就是找到已经排好序数据的子序列,然后对剩余部分排序,然后合并起来。
2、foreach和while的区别(编译之后)
先看表面的
foreach是运用在数组和集合上的 ,可以不用知道循环的次数,他内部把集合或数组的长度默认作为循环次数
while后面是可以加条件的,条件通过,true的时候才会进入,并且循环着判断条件,与其上都是循环遍历
3、线程池的种类,区别和使用场景?
有以下种类以及解释:
CachedThreadPool
这类线程池的特点就是里面没有核心线程,全是非核心线程,其maximumPoolSize设置为Integer.MAX_VALUE,线程可以无限创建,当线程池中的线程都处于活动状态的时候,线程池会创建新的线程来处理新任务,否则会用空闲的线程来处理新任务,这类线程池的空闲线程都是有超时机制的,keepAliveTime在这里是有效的,时长为60秒,超过60秒的空闲线程就会被回收,当线程池都处于闲置状态时,线程池中的线程都会因为超时而被回收,所以几乎不会占用什么系统资源。任务队列采用的是SynchronousQueue,这个队列是无法插入任务的,一有任务立即执行,所以CachedThreadPool比较适合任务量大但耗时少的任务。
FixedThreadPool
这类线程池的特点就是里面全是核心线程,没有非核心线程,也没有超时机制,任务大小也是没有限制的,数量固定,即使是空闲状态,线程不会被回收,除非线程池被关闭,从构造方法也可以看出来,只有两个参数,一个是指定的核心线程数,一个是线程工厂,keepAliveTime无效。任务队列采用了无界的阻塞队列LinkedBlockingQueue,执行execute方法的时候,运行的线程没有达到corePoolSize就创建核心线程执行任务,否则就阻塞在任务队列中,有空闲线程的时候去取任务执行。由于该线程池线程数固定,且不被回收,线程与线程池的生命周期同步,所以适用于任务量比较固定但耗时长的任务。
ScheduledThreadPool
这类线程池核心线程数量是固定的,好像和FixThreadPool有点像,但是它的非核心线程是没有限制的,并且非核心线程一闲置就会被回收,keepAliveTime同样无效,因为核心线程是不会回收的,当运行的线程数没有达到corePoolSize的时候,就新建线程去DelayedWorkQueue中取ScheduledFutureTask然后才去执行任务,否则就把任务添加到DelayedWorkQueue,DelayedWorkQueue会将任务排序,按新建一个非核心线程顺序执行,执行完线程就回收,然后循环。任务队列采用的DelayedWorkQueue是个无界的队列,延时执行队列任务。综合来说,这类线程池适用于执行定时任务和具体固定周期的重复任务。
SingleThreadPool
这类线程池顾名思义就是一个只有一个核心线程的线程池,从构造方法来看,它可以单独执行,也可以与周期线程池结合用。其任务队列是LinkedBlockingQueue,这是个无界的阻塞队列,因为线程池里只有一个线程,就确保所有的任务都在同一个线程中顺序执行,这样就不需要处理线程同步的问题。这类线程池适用于多个任务顺序执行的场景。
以上种类转储原文为
什么是线程?
注:
1、创建/销毁线程伴随着系统开销,过于频繁的创建/销毁线程,会很大程度上影响处理效率。
2、线程并发数量过多,抢占系统资源从而导致阻塞。
3、对线程进行一些简单的管理。比如:延时执行、定时循环执行的策略等。运用线程池都能进行很好的实现。
4、分析线程池的实现原理和线程的调度过程
ThreadPoolExecutor
调度线程执行器ScheduledThreadPoolExecutor是线程执行器ThreadPoolExecutor的扩展,在ThreadPoolExecutor基础之上添加了在一定时间间隔之后调度任务的核心功能,也包括之后的按既定时间间隔去调度任务的功能
5、线程池如何调优
1、设置最大线程数和最小线程数。
2、选择合适的任务队列和拒绝策略。
6、线程池的最大线程数目根据什么确定
- CPU
- IO
- 并行
- 并发
线程池性质
Java动态代理的几种方式
3种动态代理方式
jdk、cglib、javaassist
案例:https://blog.csdn.net/fly_grass_fish/article/details/84553817
HashMap的并发问题
不知道
了解LinkedHashMap的应用
HashMap 是 Java Collection Framework 的重要成员,也是Map族(如下图所示)中我们最为常用的一种。不过遗憾的是,HashMap是无序的,也就是说,迭代HashMap所得到的元素顺序并不是它们最初放置到HashMap的顺序。
HashMap的这一缺点往往会造成诸多不便,因为在有些场景中,我们确需要用到一个可以保持插入顺序的Map。庆幸的是,JDK为我们解决了这个问题,它为HashMap提供了一个子类 —— LinkedHashMap。虽然LinkedHashMap增加了时间和空间上的开销,但是它通过维护一个额外的双向链表保证了迭代顺序。
特别地,该迭代顺序可以是插入顺序,也可以是访问顺序。因此,根据链表中元素的顺序可以将LinkedHashMap分为:保持插入 顺序的LinkedHashMap和保持访问顺序的LinkedHashMap,其中LinkedHashMap的默认实现是按插入顺序排序的。
反射的原理,反射创建类实例的三种方式是什么
class,Constructor,Field,Method;
其中class代表的时类对 象,
Constructor-类的构造器对象,
Field-类的属性对象,
Method-类的方法对象。
//第一种表示方式
实际在告诉我们任何一个类都有一个隐含的静态成员变量class
Class class1 = Foo.class;
//第二种表示方式
已经知道该类的对象通过getClass方法
Class class2 = foo1.getClass();
System.out.println(class1==class2);//true’
//第三种表达方式
Class class3 = null;
try {
class3 = Class.forName(“com.imooc.reflect.Foo”);
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
cloneable接口实现原理,浅拷贝or深拷贝
Java NIO使用
Non IO 同步非阻塞 IO,是传统 IO 的升级,客户端和服务器端通过 Channel(通道)通讯,实现了多路复用。
答案
hashtable和hashmap的区别及实现原理,hashmap会问到数组索引,hash碰撞怎么解决
区别
存储:HashMap 运行 key 和 value 为 null,而 Hashtable 不允许。
线程安全:Hashtable 是线程安全的,而 HashMap 是非线程安全的。
推荐使用:在 Hashtable 的类注释可以看到,Hashtable 是保留类不建议使用,推荐在单线程环境下使用 HashMap 替代,如果需要多线程使用则用 ConcurrentHashMap 替代。
原理
HashMap的底层主要是基于数组和链表来实现的,它之所以有相当快的查询速度主要是因为它是通过计算散列码来决定存储的位置。HashMap预定义了一个很长的数组,每个数组元素相当于一个取放存取对象的桶。这有点类似基数排序中用到的技巧,利用数组的存取性能,达到空间换取时间的目的。但如果仅仅是这样,就需要定义一个足够长的数组,而且还要找到key与数组下标的一种映射关系。
关于定义一个足够长的数组这好解决,可以参考ArrayList的实现,先设定一个长度默认值,当存放的值个数多了时候,再对数组进行扩容。为了在时间和空间上都能找到一个比较令人满意的处理方式,通过散列码来查询函数下标。这又带来一个问题,不同的对象的散列码可能值是一样的(不同对象可能equal,但hashcode可能一样,反之不成立)。为了解决这种碰撞问题,我们不得不让每个桶维系一个链表,用于存放key值碰撞的对象。
碰撞
Java中HashMap是利用“拉链法”处理HashCode的碰撞问题。在调用HashMap的put方法或get方法时,都会首先调用hashcode方法,去查找相关的key,当有冲突时,再调用equals方法。hashMap基于hasing原理,我们通过put和get方法存取对象。当我们将键值对传递给put方法时,他调用键对象的hashCode()方法来计算hashCode,然后找到bucket(哈希桶)位置来存储对象。当获取对象时,通过键对象的equals()方法找到正确的键值对,然后返回值对象。HashMap使用链表来解决碰撞问题,当碰撞发生了,对象将会存储在链表的下一个节点中。hashMap在每个链表节点存储键值对对象。当两个不同的键却有相同的hashCode时,他们会存储在同一个bucket位置的链表中。键对象的equals()来找到键值对。
arraylist和linkedlist区别及实现原理
反射中,Class.forName和ClassLoader区别
Java中Class.forName和classloader都可以用来对类进行加载。
Class.forName(“className”);
其实这种方法调运的是:Class.forName(className, true, ClassLoader.getCallerClassLoader())方法
参数一:className,需要加载的类的名称。
参数二:true,是否对class进行初始化(需要initialize)
参数三:classLoader,对应的类加载器
ClassLoader.laodClass(“className”);
其实这种方法调运的是:ClassLoader.loadClass(name, false)方法
参数一:name,需要加载的类的名称
参数二:false,这个类加载以后是否需要去连接(不需要linking)
可见Class.forName除了将类的.class文件加载到jvm中之外,还会对类进行解释,执行类中的static块。
而classloader只干一件事情,就是将.class文件加载到jvm中,不会执行static中的内容,只有在newInstance才会去执行static块。
String,StringBuffer,StringBuilder的区别
String声明的是不可变的,每次操作都会声明一个新的对象,然后将指针指向新的 String 对象,而 StringBuffer、StringBuilder 可以在原有对象的基础上进行操作,所以在经常改变字符串内容的情况下最好不要使用 String。
StringBuffer 和 StringBuilder 最大的区别在于,StringBuffer 是线程安全的,而 StringBuilder 是非线程安全的,但 StringBuilder 的性能却高于 StringBuffer,所以在单线程环境下推荐使用 StringBuilder,多线程环境下推荐使用 StringBuffer。
有没有可能2个不相等的对象有相同的hashcode
有
因为hashcode是为了确定对象保存在散列表的位置,但是我们都知道会发生哈希冲突,就是因为对象的hashcode会相同,导致哈希冲突。
参考