1. String类能被继承吗
不能被继承,因为String类有final修饰符,而final修饰的类是不能被继承的。
2. String、StringBuffer、StringBuilder的区别
String为字符串常量(因为内部数组value[]有final修饰)
,而StringBuilder和StringBuffer均为字符串变量,即String对象一旦创建之后该对象是不可更改的,而后两者是变量,可以更改。- 在线程安全上,StringBuilder是线程不安全的,StringBuffer是线程安全的,因为StringBuffer在append()方法上添加了sychronized修饰。
- String变量创建后放入方法区的常量池,而StringBuilder和Stringbuffer则是放入堆中。
3. 构造String对象的方式
- String str = “123”;
- 通过引号直接创建字符串对象,先会从常量池中判断是否存在“123”对象,如果不存在,则先会在常量池中创建该对象,并且返回常量池中“123”对象的引用给str。如果存在,则直接返回引用。
- String str = new String(“123”);
- 首先“123”是一个常量字符串,因此先会在常量池创建“123”字符串对象,然后在堆中在创建一个字符串对象。将“123”的字符数组复制到堆中新创建的对象字符数组中,
因此该方式不仅会在堆中,还会在常量池中创建“123”字符串对象。
- String str = “123”.intern();
- 该方法与1类似,当常量池中存在“123”字符串常量时,则直接返回常量池中的符号引用;若不存在,则先在常量池创建“123”字符串对象,然后返回新创建对象的引用。常用 String str = str1.intern();避免经常创建对象。
4. 类的实例化顺序
Java程序的初始化一般遵循3个原则
- 静态变量优于非静态变量初始化。
- 父类优先于子类进行初始化
- 按照成员变量的顺序进行初始化。
当new时,他们的执行顺序为:父类静态变量、父类静态代码块、子类静态变量、子类静态代码块、父类非静态变量、父类非静态代码块、父类构造函数、子类非静态变量、子类非静态代码块、子类构造函数。
5. 继承、实现、依赖、聚合、组合、关联的关系
- 继承:指一个类继承另一个类,并且可以增加自己的新功能。
- 实现:是一个类实现了多个接口,表示一个类具有某些接口赋予的功能。
- 依赖:一个类使用到了另一个类,而且这种使用关系是偶然的,临时性的,比如类B作为参数被A使用。那么A就依赖于B。
- 关联:关联关系一般在java中使用成员变量来实现,如A中定义了一个类的成员变量B。
- 聚合:他体现的是一种整体和部分、拥有的关系,相互之间可以分离,拥有各自的生命周期。如公司和员工的关系。
- 组合:是一种强聚合,整体和部分之间不可分离。
6. 反射的原理,反射创建类实例的方式是什么
反射机制:Java反射机制是在
运行状态
中,对于任意一个类,如果知道这个类的名称,就能够知道这个类的所有属性和方法。对于任意一个对象,如果知道一个实例对象,都能够调用他的任意一个方法和属性;这种动态获取的信息以及动态调用对象的方法的功能称为Java语言的反射机制。
反射创建类的方式有
- 直接使用字节码文件获取对应实例,Object o = clazz.newInstance();
- 对带参数的构造函数的类,先获取到其构造对象,再通过该构造方法类获取实例。如下
7. 反射中,Class.forName和ClassLoader的区别
- ClassLoader是类加载器,通过一个类的全限定名来获取此类的二进制字节流,遵循双亲委派模型,将.class文件加载到jvm中,不会执行static中的内容,只有在newInstance时才会执行。
- class.forName()方法内部实际上也是调用ClassLoader来实现的,但会对类进行初始化,执行类中的静态代码块,以及对静态变量的赋值操作。
8. 为什么cglib可以对接口实现代理
cglib动态代理是继承并重写目标类,所以目标类和方法不能被声明为final,而接口是可以被继承的。
9 . error和exception的区别,CheckedException和RuntimeException的区别
Exception和Error都是继承于Throwable
类,在Java中只有Throwable类型的实例才可以被抛出或者捕获,他是异常处理机制的基本组成类型。- error表示系统级的错误和程序不必处理的异常,是java运行环境中的内部错误或者硬件问题,比如:内存资源不足,对于这种错误,程序基本无能为力。
- exception表示需要捕捉或者需要程序进行处理的异常。
Exception又分为运行时异常,受检查异常
- CheckedException 必须在编写代码时,使用try…catch捕获
- RuntimeException:编写代码时可以忽略捕获操作,这种异常是代码编写或者使用过程中通过规范可以避免发生的。
10. 在jdk1.5中引入了泛型,泛型的存在是用来解决什么问题的
- 类型安全:泛型的好处是在编译时检查类型安全,减少运行时由于对象类型不匹配引发的异常,在没有泛型的时候,程序员在处理容器时,常常需要使用Object类型来存储元素,丢失了元素的具体类型信息,后续操作中,必须使用强制类型转换。
- 代码复用:在泛型之前,如果需要为不同类型的元素编写相同的集合操作逻辑(如添加、删除、遍历等),程序员需要为每种可能的类型编写一个特定的版本。这不仅繁琐,而且维护起来也很困难。
泛型允许程序员编写与类型无关的通用代码
,然后在编译时通过类型参数来指定具体的类型,从而实现了代码的复用。这样,同一个集合类可以用于存储不同类型的对象,而无需为每种类型都编写一个专门的类。
11. select、poll和epoll之间的区别
目前支持IO多路复用的系统调用有select、poll和epoll。IO多路复用就是通过一种机制,一个进程可以监视多个描述符,一旦某个描述符就绪,能够通知程序进行相应的读写操作。但select、poll和epoll本质上都是同步IO,因为他们都需要在读写事件就绪后自己负责进行读写,也就是说这个读写过程是阻塞的。
- select
- select函数监视的文件描述符分为3类,分别是writefds、readfds和exceptfds。调用后select函数会阻塞,直到有描述符就绪,或者超时。当select函数返回后,可以遍历fdset,来找到就绪的描述符。
- 优点:跨平台性能好
- 缺点:单个线程能够监视的文件描述符数量存在最大限制,在linux上一般为1024;对socket进行扫描时是线性扫描,即采用轮询的方式,效率低;需要维护一个用来存放大量fd的数据结构,会使得用户空间和内核空间在传递该结构时复制开销大。
- poll
- poll 和select没有区别,他的优点是没有最大连接数的限制,原因是他基于链表来存储,但是同样有一个缺点,大量的fd数组被整体复制于用户态和内核地址之间。
- epoll
- epoll是select和poll的增强版本,他更加灵活,没有描述符数量限制。epoll使用一个文件描述符管理多个描述符,将用户关系的文件描述符事件存放到内核的一个事件表中,这样在用户空间和内核空间的copy只需一次,所有的fd都存入红黑树中。
epoll支持水平触发和边缘触发,最大的特点是边缘触发,他只告诉线程哪些fd刚刚变为就绪态,并且只会通知一次。还有一个特点是,epoll通过“事件”的就绪通知方式,通过epoll_ctl注册fd,一旦该fd就绪,内核就会采用类似回调机制把该fd放入到双向链表,epoll_wait便可以收到通知。- epoll的优点主要有三个方面
a. 没有最大并发连接的限制,能打开的fd上限远大于1024
b. 效率提升,不是使用轮训的方式,不会随着fd数量的增加效率下降
c. 内存拷贝,使用mmap减少了复制开销。
12. final修饰的变量是引用不可变,还是引用的对象不能改变
final 修饰的变量是引用不可变,但是引用的对象还是可以发生改变。
- 如果final修饰的是一个基本数据类型的变量,那么这个变量就不可以改变。
- 如果final修饰的是一个引用类型的变量,那么该变量存的是一个内存地址,该地址就不能变了。
13. Java中Comparable和Comparator接口的区别
- Comparable是排序接口,若一个类实现了Comparable接口,意味着这个类支持排序,不需要再去指定比较器,意味着这个类支持排序。
- Comparator是比较器接口,我们若需要对某个类集合进行排序,而该类本身不支持排序,那么就可以建立一个“该 类的比较器”来进行排序。
14. sleep()方法和yield()方法的区别
- sleep()方法给其他线程运行机会时不考虑线程的优先级,因此会给低优先级的线程运行的机会,yield()方法只会给相同优先级或者更高优先级的线程以运行的机会。
- 线程执行sleep()方法后转入阻塞状态,而执行yield()方法后转入就绪状态。
- sleep()方法会抛出InterruptedException,而yield()方法没有声明任何异常。
- sleep()方法比yield()方法具有更好的可移植性。
如果线程A希望立即结束线程B,则可以对线程B对应的Thread实例调用interrupt方法,如果此刻线程B正在wait、sleep、join,则线程B会立刻抛出InterruptedException,在catch中直接return即可安全的结束线程。