为什么String在java中是不可变的?
总的来说就是提高效率和安全性问题。
字符串在堆内存中有个常量池,新的字符串则new一个放在常量池里,有的话则直接从常量池中引用,比如String s1="a"和String s2="a",假设可以改变,两个引用其中一个修改会影响另外一个。
还有个就是维护其他对象的规则,比如我在set集合里面set了a b c 我如果这个时候把b又改成a不是违反了set的规则了吗
设置成不可变的变量也就是线程安全的让多个线程共享,不存在同步的问题。
说说常见的集合有哪些?
父接口的Collection的有List接口和Set接口
List类:ArrayList,LinkedList,Vector
Set类:HashSet,TreeSet,LinkedHashSet
Map类:HashMap,TreeMap,ConcurrentHashMap,HashTable
ConcurrentHashMap结合了HashMap和HashTable的优点, HashTable考虑了线程安全同步问题,但是每次执行都是要锁住整个结构,而ConcurrentHashMap的锁则是细微粒度的,在调用常用的方法只锁当前的桶。
Comparable 接口和 Comparator 接口有什么区别?
类要想实现排序可以实现上述两个接口,区别是Comparable接口实现后必须重写CompareTo方法,也就是说会动到类的源码,T而Comparator则无需动到源码,则集合排序前将其实现一般是匿名内部类,并重写对应的排序方法(相当于传入一个比较器)。
为什么java被称作与平台无关的语言?
java依赖于jvm虚拟机,能够将javac编译器编译的字节码文件,也就是.class,翻译成计算机底层硬件所熟悉的机器码文件,因此可以做到跨平台开发。
static关键字是什么意思?java能否重写一个static方法?
static关键字表明被修饰的成员变量或者方法可以在没有实例的情况下通过类名.直接调用。
不能重写一个static方法,因为static不参与继承体系,也就没有重写方法这一说。
是否可以在static环境中访问非static变量?
不能,因为static属于类,在jvm加载时最先初始化的就是static修饰的变量,而此时非static修饰的变量尚未被初始化,也就是对象实例尚未被创建出来。
java支持的数据类型有哪些?什么是自动装箱?
int long byte short char boolean double float
引用类型对基本类型的封装。也就是int - Integer,这是JDK1.5的新特性。
方法重载和方法重写的区别?
重载发生在同一个类中,方法名相同,但是参数列表不同。
重写发生在继承,多态体系中,方法重写子类必须有父类一致的方法名参数列表和返回值类型。
java中什么是构造方法?什么是构造重载?
构造方法在每一个对象实例被创建时都要调用,构造重载也就是在构造方法的基础上实现重载。
java中支持多继承吗?
不支持,如果支持的话可以看菱形继承问题,也就是B,C继承A并重写一个方法,D同时继承B,C,那编译器此时无法决定调用哪个方法。
什么是值传递,什么是引用传递?
值传递针对的是基本数据类型,传递的是具体的数据值,而引用传递真的是引用类型数据,传递的是地址值。
同步方法和同步代码块的区别是什么?
同步方法默认使用this或者当前类对象作为锁,同步代码块可以选择拿什么来加锁,相比于同步方法,同步代码块更细颗粒度,可以选择只同步会发生同步问题的地方,而不是整个方法。
实现多线程的方式有哪些?
继承Thread或者实现Runnable接口并重写run方法,通过start方法开启线程,还有两种是Excutor框架来创建线程池,以及实现Callable接口。
如何确保N个线程可以访问N个资源同时又不导致死锁?
在使用多线程时最简单的方式就是指定锁的获取顺序,并强制线程按照指定的顺序获取锁。
还有一种是超时放弃,当线程尝试获取锁时设置一个时间超过这个限定就放弃获取这个锁。
fail-fast(快速失败)
在迭代器遍历集合的时候,如果不是使用的迭代器自带的方法,改动了集合中的元素,则会抛出Concurrentt Modification Excetption(并发修改异常),其原理是,迭代器在遍历集合的时直接访问集合的内容,并且在遍历过程中使用一个modCount变量,每当集合的结构发生变化就会去改动modCount的值,迭代器在hasnext时都会去判断一下modCount的值,如果modCount值不等于expectedmodCount的话,则终止遍历并抛出异常。
HashSet和TreeSet有什么区别?
hashset底层是哈希表,无序,而 TreeSet底层是红黑树,有序,并且如果需要排序的话一般选择TreeSet。
finalize()什么时候被调用?
在gc垃圾回收开始准备回收对象所占内存时被调用。
throw和throws的区别?
throw在方法中声明抛出一个异常对象,并且只能是一个异常类型
throws则跟在方法名后声明抛出1个或多个异常类型。
异常处理完成,Exception对象发生什么变化?
等待下一个gc回收周期被回收。
finally和finalze的区别?
finally是异常处理最终代码块,不管有没有异常处理都会被执行,finalze是java垃圾回收机制在回收对象所占内存时调用。
什么是Servlet?
Servlet是运行于服务端上的一个小程序,用于处理收发客户端请求给服务端,负责响应信息给客户端。
说一下Servlet的生命周期?
Servlet默认只有在第一次被访问的时候才会进行初始化,也就是调用init方法完成初始化,
而每当客户端有一次请求抵达Servlet都会调用service方法,最后当web容器关闭时候,也就是Serlvet结束生命周期调用destory方法
为什么重写equals还要重写hashcode?
根据java的规则,如果equals相等则hashcode一定相等,假设new两个相同的String字符串,那么equlas相同,但是他们的内存地址不同,而hashcode是根据的对象的内存地址返回,这个时候按理来说应该是不同的,可实际结果是相同的。
介绍一下Syncronized锁,如果用这个关键字修饰一个静态方法,锁住了什么?如果修饰成员方法,锁住了什么?
Syncroized锁是同步锁,底层基于悲观锁,修饰静态方法则锁是类的字节码,只有该类的所有线程都必须等待同步线程执行,如果是成员方法则锁是对象锁,即当前对象的所有线程都必须等待同步线程执行。
锁有了解嘛,说一下Synchronized和lock
S锁是java中的一个关键字,而Lock锁则是一个接口,对于S锁不必过分关注死锁的问题,在遇到异常时JVM会主动释放锁,因此不会有死锁现象的产生,而Lock锁如果在遇到异常时没有通过unlock释放则容易产生死锁问题,因此通常需要finally代码块内释放锁,通过S锁无法判断锁的状态而Lock锁可以判断锁的状态。还有一个就是Lock锁相对S锁灵活一些,S锁无法让等待的线程响应中断,等待的线程会一直等下去,而Lock锁可以让等待的线程响应中断。
介绍一下什么是泛型?
泛型是一种设计理念,往集合中存放元素时事先规定存放的元素类型也就是泛型,这样在添加不符合的元素就能提前报错,同时也避免了ClassCastException,类型强制转换异常。
谈谈如何通过反射创建对象?
源文件阶段:classForName("类名")
字节码阶段:类名.class
实例化阶段:对象名.getclass
能说下为什么HashMap的数组长度一直是2的幂次吗?
HashMap对键调用hashcode得到的hash值并不直接做为散列表的索引,而是将结果和数组的长度-1与一下, 我们假设如果不为二次幂,我们用15做为数组的长度,最后一位是0,也就是说无论我怎么与,最后一位始终是0,也就是0011 0001这类的永远不会存储的上会造成空间的浪费。并且,由于最后一位始终是0,也容易会造成重复碰撞,进而影响hashmap的查询效率,因为还要去遍历链表拿到他的hash值获得键值对。实际上就是借助2的幂次来减少计算机二进制中0个数的生成。
了解线程池吗?
我们创建线程的方式有两种,继承Thread或者实现Runnalbe接口,但是我们知道线程有五个状态创建 就绪 运行 阻塞 死亡,当一个线程死亡的时候,就会变成垃圾等着被jvm回收, 而我们在创建线程和线程被回收的这个过程实际上不仅消耗系统资源和耗费时间,而且在线程未被回收前还会占用内存空间,因此就有了线程池的概念,我们可以把线程放在线程池里,用的时候就从池子里面拿,用完了放回去,这样节约线程的创建消耗的时间,并且节约了内存空间。
线程池有什么作用呢?
提高效率,创建好一个池子,用的时候拿用完了放回去,节约线程创建的时间。
方便管理,比如一个池子最大100个线程,此时101个请求过来,多余的一个请求就可以放到缓存队列中,而不是无休止的创建线程最后导致系统崩溃。
说说几种常用的线程池以及使用场景?
单线程化的线程池,他只会用唯一的工作线程执行任务,保证任务按照顺序执行。
能够控制线程最大并发数,超出的线程会在队列中等待。
支持定时及周期任务的线程池
可缓存线程池,如果线程池长度超过处理需要,会灵活回收空闲线程,没有的话则新创建线程。