1.JAVA中的几种基本数据类型是什么,各自占用多少字节?
答:
常见问题:
1.byte,short,int 计算自动提升类[41] 型,
2. 自动转换:byte-->short-->int-->long-->float-->double (从小到大)
强制转换:1.容易丢失精度,产生误差(小数点后面的全部舍弃)
2.赋值时容易超出取值范围
数字常量池[42] :-128-127 ,在这范围内直接从常量池取不重新创建。
2. String类能被继承吗,为什么?
答:String 类是不能被继承的,因为他是被final关键字修饰的。
public final class String
implements java.io.Serializable, Comparable<String>, CharSequence {
/** The value is used for character storage. */
private final char value[];
还有一点就是String类的Immutable(不可变)属性,从上面代码也可以看出,String类实际是一个char[]数组存储数据的。而这个数组也是被final关键字修饰的
3. String , StringBuffer, StringBuilder的区别?
答:String的值是不可以变的,每次对String的操作都会产生一个新的对象。不可变字符串,可以空赋值
StringBuffer 和StringBuilder 类的对象能多次修改且不产生新的对象,不能空赋值
StringBuffer :可变字符串,效率低,线程安全
StringBuilder :可变字符序列,效率高,线程不安全。
4. Arraylist和LinkedList有什么区别?
答:都是List集合的实现类
ArrayList 底层基于动态数组实现,LinkedList 基于链表实现
查询 ArrayList 要快,直接索引去命中,LinkedList需要移动指针遍历相对要慢
对于add,remove 来说,LinkedList 要比ArrayList 要快,ArrayList需要涉及数组的拷贝,移动,扩容
5.讲讲类的实例化顺序,比如父类静态数据,构造函数,字段,子类静态数据,构造函数,字段,当new的时候,他们的执行顺序。
答:
父类静态变量--
父类静态代码块--
子类静态变量--
子类静态代码块--
父类非静态变量(父类实例成员变量)--
父类构造函数--
子类非静态变量(子类实例成员变量)--
子类的构造函数
6.用过哪些Map类,都有什么区别, HashMap是线程安全的吗?并发下使用的Map是什么,他们内部原理分别是什么,比如存储方式, hashcode ,扩容,默认容量等
答:1.常用Map实现类有:HashMap,ConcurrentHashMap(JDK1.8),LinkedHashMap,TreeMap,HashTable;.最频繁:HashMap 和ConcurrentHashMap
2.HashMap 是非线程安全的,并发下可使用ConcurrentHashMap 和HashTable ,
3. 原理与区别:
ConcurrentHashMap的hash计算公式:(key.hascode()^ (key.hascode()>>> 16)) & 0x7FFFFFFF
HashTable的hash计算公式:key.hascode()&0x7FFFFFFF
HashTable存储方式都是链表+数组,数组里面放的是当前hash的第一个数据,链表里面放的是hash冲突的数据
ConcurrentHashMap是数组+链表+红黑树
HashTable 是在每一个操作方法上面都加synchronized来达到线程安全,
ConcurrentHashMap线程是使用CAS(compore and swap)开保证线程安全的。
4.默认容量都是16,负载因子是0.75.就是当HashMap填充了75%的busket时就会扩容,最小是(16*0.75)一般为原内存的2倍
7. JAVA8的ConcurrentHashMap为什么放弃了分段锁,有什么问题吗,如果你来设计,你如何设计。
答: jdk1.8放弃分段锁而是用了Node锁,减低锁的粒度,提高性能,并使用了CAS操作来确保Node的一些操作的原子性,取代了锁。
ConcurrentHashMap 的一些操作使用了synchronized 锁,
8.有没有有顺序的Map实现类,如果有,他们是怎么保证有序的
答:LinkedHashMap,TreeMap
LinkedHashMap是基于元素进入集合的顺序或者被访问的先后顺序排序的,
TreeMap是基于元素固有顺序(由Comparator 或者Comparable确定的,默认升序)
9.抽象类和接口的区别,类可以继承多个类么,接口可以继承多个接口么,类可以实现多个接口么.
答:
1.抽象类可以有自己的实现方法,接口在jdk8以后也可以有自己的实现方法(default)
2.抽象类的抽象方法是由非抽象类的子类实现,接口的抽象方法有接口的实现类实现
3.接口不能有私有的方法跟对象,抽象类可以有自己的私有的方法跟对象
4.类不可以继承多个类,接口可以继承多个接口,类可以实现多个接口
10继承和聚合的区别在哪?
答:
继承指的是一个类(称为子类、子接口)继承另外的一个类(称为父类、父接口)的功能,并可以增加它自己的新功能的能力,继承是类与类或者接口与接口之间最常见的关系;在Java中此类关系通过关键字extends明确标识,在设计时一般没有争议性;
聚合是关联关系的一种特例,他体现的是整体与部分、拥有的关系,即has-a的关系,此时整体与部分之间是可分离的,他们可以具有各自的生命周期,部分可以属于多个整体对象,也可以为多个整体对象共享;比如计算机与CPU、公司与员工的关系等;表现在代码层面,和关联关系是一致的,只能从语义级别来区分;
原文:https://blog.csdn.net/qq_35661171/article/details/80181192
11.IO模型有哪些,讲讲你理解的NIO ,它和BIO , AIO的区别是啥,谈谈reactor模型.
答:IO是面向流的,NIO 是面向缓冲区的
BIO:同步阻塞式IO,
NIO:同步非阻塞式IO,通常采用Reactor模式
AIO:通常采用Proactor模式,简化了程序的编写,stream的读取和写入都有OS来完成,不需要像NIO那样子遍历Selector
reactor模型:反应器模式(事情驱动模式)当一个主体发生改变时,所有的属性都得到通知,类似观察者模式。
参考:
https://zhuanlan.zhihu.com/p/23488863
http://developer.51cto.com/art/201103/252367.htm
http://www.jianshu.com/p/3f703d3d804c
12.反射的原理,反射创建类实例的三种方式是什么。
答:
如果知道一个类名称或者它的一个实例对象,就能把这个类的所有方法和变量的信息(方法名,变量名,方法,修饰符,类型,方法参数等等所有信息)找出来。
反射创建类实例的三种方式:
- Class.forName("com.A"); 包全路径名
- new A().getClass(); 对象.getClass()
- A.class;类.Class()
反射是运行期,操作字节码对象
13.反射中, Class.forName和Classloader区别.
答:
class.forName()除了将类的.class文件加载到jvm中之外,还会对类进行解释,执行类中的static块。
classLoader只干一件事情,就是将.class文件加载到jvm中,不会执行static中的内容,只有在newInstance才会去执行static块。
14,描述动态代理的几种实现方式,分别说出相应的优缺点。
答:
分别是:JDK动态代理,CGLIB动态代理
jdk (jdk底层是利用反射机制) 动态代理的前提是目标类必须实现一个接口,代理对象跟目标类实现一个接口,从而规避虚拟机的交易
cglib 动态代理是继承并重写目标类,所有目标类和方法不能被声明成final,
基于asm框架,实现了无反射机制进行代理,利用空间来换取了时间,代理效率高于jdk
15.动态代理与cglib实现的区别。
答:
jdk (jdk底层是利用反射机制) 动态代理的前提是目标类必须实现一个接口,代理对象跟目标类实现一个接口,从而规避虚拟机的交易
cglib 动态代理是继承并重写目标类,所有目标类和方法不能被声明成final,
基于asm框架,实现了无反射机制进行代理,利用空间来换取了时间,代理效率高于jdk
https://blog.csdn.net/sinat_32366329/article/details/79435366
16为什么CGlib方式可以对接口实现代理。
答: cglib动态代理是继承并重写目标类,所以目标类和方法不能被声明成final。而接口是可以被继承的。
Jdk cglib jdk底层是利用反射机制,需要基于接口方式,这是由于
Proxy.newProxyInstance(target.getClass().getClassLoader(),
target.getClass().getInterfaces(), this);
Cglib则是基于asm框架,实现了无反射机制进行代理,利用空间来换取了时间,代理效率高于jdk
17.final的用途。
答:
- final修饰的对象不能被修改;
- final修饰的类不能被继承;
- final修饰的方法不能被重写
18.写出三种单例模式实现
答:
能解决什么问题:保证一个类在内存中的对象唯一性。
比如:多程序读取一个配置文件时,建议配置文件封装成对象。会方便操作其中数据,又要保证多个程序读到的是同一个配置文件对象,就需要该配置文件对象在内存中是唯一的。
Runtime()方法就是单例设计模式进行设计的。
懒汉,线程不安全
public class Singleton {
private static Singleton instance;
//构造函数私有
private Singleton (){}
//加了同步锁的获取对象的方法
public static synchronized Singleton getInstance() {
//当这个对象为空的时候才去创建
if (instance == null) {
instance = new Singleton();
}
return instance;
}
}
这种写法能够在多线程中很好的工作,而且看起来它也具备很好的lazy loading,但是,遗憾的是,效率很低,99%情况下不需要同步。
饿汉式
public class Singleton {
//构造函数私有
private Singleton (){}
//一进来创建对象
private static Singleton instance = new Singleton();
//提供公用的方法获取对象
public static Singleton getInstance() {
return instance;
}
}
这种方式基于classloder机制避免了多线程的同步问题,instance在类装载时就实例化。目前java单例是指一个虚拟机的范围,因为装载类的功能是虚拟机的,所以一个虚拟机在通过自己的ClassLoader装载饿汉式实现单例类的时候就会创建一个类的实例。这就意味着一个虚拟机里面有很多ClassLoader,而这些classloader都能装载某个类的话,就算这个类是单例,也能产生很多实例。当然如果一台机器上有很多虚拟机,那么每个虚拟机中都有至少一个这个类的实例的话,那这样 就更不会是单例了。(这里讨论的单例不适合集群!)
静态内部类
public class Singleton {
private static class SingletonHolder {
private static final Singleton INSTANCE = new Singleton();
}
private Singleton (){}
public static final Singleton getInstance() {
return SingletonHolder.INSTANCE;
}
}
这种方式同样利用了classloder的机制来保证初始化instance时只有一个线程,这种方式是Singleton类被装载了,instance不一定被初始化。因为SingletonHolder类没有被主动使用,只有显示通过调用getInstance方法时,才会显示装载SingletonHolder类,从而实例化instance。想象一下,如果实例化instance很消耗资源,我想让他延迟加载!这个时候,这种方式相比第2种方式就显得很合理。
https://my.oschina.net/dyyweb/blog/609021
https://blog.csdn.net/zw235345721/article/details/69944933
https://blog.csdn.net/alanlonglong/article/details/79070417
19.如何在父类中为子类自动完成所有的hashcode和equals实现?这么做有何优劣。
答:复写hashcode和equals方法,优势可以添加自定义逻辑,且不必调用超类的实现。
父类的equals不一定满足子类的equals需求。比如所有的对象都继承Object,默认使用的是Object的equals方法,在比较两个对象的时候,是看他们是否指向同一个地址。
但是我们的需求是对象的某个属性相同,就相等了,而默认的equals方法满足不了当前的需求,所以我们要重写equals方法。
如果重写了equals 方法就必须重写hashcode方法,否则就会降低map等集合的索引速度。
20.请结合00设计理念,谈谈访问修饰符public.private, protected, default在应用设计中的作用。
OO 设计理念:封装,继承,多态
封装,也就是把客观事物封装成抽象的类,并且类可以把自己的数据和方法只让可信的类或者对象操作,对不可信的进行信息隐藏。所以我们可以通过public、private、protected、default 来进行访问控制
关键字
类内部
本包
子类
外部包
public
√
√
√
√
protected
√
√
√
×
default
√
√
×
×
private
√
×
×
×
java访问控制符的含义和使用情况
21.深拷贝和浅拷贝区别.
答: 浅拷贝只拷贝该对象的基本变量属性,不拷贝该对象中的引用变量。
深拷贝除了会拷贝该对象的基本变量属性也会拷贝该对象中的引用变量,拷贝一个完整的结构。
http://www.oschina.net/translate/java-copy-shallow-vs-deep-in-which-you-will-swim
22.数组和链表数据结构描述,各自的时间复杂度
答:
- 数组是将元素在内存中连续存放,由于每个元素占用内存相同,可以通过下标迅速访问数组中任何元素。
- 链表恰好相反,链表中的元素在内存中不是顺序存储的,而是通过存在元素中的指针联系到一起。
- 访问数组中第 n 个数据的时间花费是 O(1) 但是要在数组中查找一个指定的数据则是 O(N) 。
- 当向数组中插入或者删除数据的时候,最好的情况是在数组的末尾进行操作,时间复杂度是 O(1) ,
- 但是最坏情况是插入或者删除第一个数据,时间复杂度是 O(N) 。
- 在数组的任意位置插入或者删除数据的时候,后面的数据全部需要移动,移动的数据还是和数据个数有关所以总体的时间复杂度仍然是 O(N) 。
- 在链表中查找第 n 个数据以及查找指定的数据的时间复杂度是 O(N) ,但是插入和删除数据的时间复杂度是 O(1)
数组:
- 查找复杂度:O(1)
- 添加/删除复杂度:O(n)
链表:
- 查找复杂度:O(n)
- 添加/删除复杂度:O(1)
23.error和exception的区别, CheckedException, RuntimeException的区别
答:
Error(错误)表示系统级的错误和程序不必处理的异常,是java运行环境中的内部错误或者硬件问题。比如:内存资源不足等。对于这种错误,程序基本无能为力,除了退出运行外别无选择,它是由Java虚拟机抛出的。
Exception(违例)表示需要捕捉或者需要程序进行处理的异常,它处理的是因为程序设计的瑕疵而引起的问题或者在外的输入等引起的一般性问题,是程序必须处理的。
Exception又分为运行时异常,受检查异常。
RuntimeException(运行时异常),表示无法让程序恢复的异常,导致的原因通常是因为执行了错误的操作,建议终止程序,因此,编译器不检查这些异常。
CheckedException(受检查异常),是表示程序可以处理的异常,也即表示程序可以修复(由程序自己接受异常并且做出处理), 所以称之为受检查异常。
https://blog.csdn.net/riemann_/article/details/87522352
24.请列出5个运行时异常。
答:
NullPointerException 空指针异常
IndexOutOfBoundsException 下标越界异常
ClassCastException 类型转换异常
IllegalArgumentException (非法参数异常)
ConcurrentModificationException 并发修改异常
25.在自己的代码中,如果创建一个javalang.String类,这个类是否可以被类加载器加载?为什么
答:不可以,双亲委派模式会保证父类加载器先加载类,就是BootStrap(启动类)加载器加载jdk里面的java.lang.String类,而自定义的java.lang.String类永远不会被加载到
26.Java中的HashSet内部是如何工作的。
答:
public HashSet() {
map = new HashMap<>();
}
默认使用的是HaseMap;
27.什么是序列化,怎么序列化,为什么序列化,反序列化会遇到什么问题,如何解决.
答:
把对象转换为字节序列的过程称为对象的序列化,把字节序列恢复为对象的过程称为对象的反序列化。
序列化是一种用来处理对象流的机制 ,所谓对象流就是将对象的内容进行流化。
序列化是为了解决在对对象流进行读写操作时所引发的问题。
序列化的实现:将需要被序列化的类实现Serializable接口,该接口没有需要实现的方法,implements Serializable只是为了标注该对象是可被序列化的,然后使用一个输出流(如:FileOutputStream)来构造一个ObjectOutputStream(对象流)对象,接着,使用ObjectOutputStream对象的writeObject(Object obj)方法就可以将参数为obj的对象写出(即保存其状态),要恢复的话则用输入流;
28. 在jdk1.5中,引入了泛型,泛型的存在是用来解决什么问题。
答:泛型的好处是在编译的时候检查类型安全,并且所有的强制转换都是自动和隐式的。
将运行期异常提前到编译期
避免类型转换异常
29. 有没可能 2个不相等的对象有同hashcode。
答:有可能,最简单的方法,百分百实现的方式就是重写hascode();
30.这样的a.hashCode()有什么用,与a.equals() 有什么关系
答:hashcode()方法提供了对象的hashCode值,是一个native方法,返回的默认值与System.identityHashCode(obj)一致。
通常这个值是对象头部的一部分二进制位组成的数字,具有一定的标识对象的意义存在,但绝不定于地址。
作用是:用一个数字来标识对象。比如在HashMap、HashSet等类似的集合类中,如果用某个对象本身作为Key,即要基于这个对象实现Hash的写入和查找,那么对象本身如何实现这个呢?就是基于hashcode这样一个数字来完成的,只有数字才能完成计算和对比操作。
hashcode是否唯一
hashcode只能说是标识对象,在hash算法中可以将对象相对离散开,这样就可以在查找数据的时候根据这个key快速缩小数据的范围,但hashcode不一定是唯一的,所以hash算法中定位到具体的链表后,需要循环链表,然后通过equals方法来对比Key是否是一样的。equals与hashcode的关系
equals相等两个对象,则hashcode一定要相等。但是hashcode相等的两个对象不一定equals相等。
31.java8的新特性。
- Lambda表达式
- 函数式接口
- *方法引用和构造器调用
- Stream API
- 接口中的默认方法和静态方法
- 新时间日期API
https://blog.csdn.net/54powerman/article/details/73188951
https://blog.csdn.net/qq_29411737/article/details/80835658
32.try{ }里面return, finally里的代码会不会执行,什么时候被执行?
答:会执行. 在方法返回给调用者前执行.因为如果存在finally代码块, try中的return语句不会立马返回调用者, 而是记录下返回值待finally代码块执行完毕之后在返回.
33.Thread类中的sleep()和对象的wait()有什么区别?
答:
- sleep方法是Thread的静态方法,wait方法是Object类的普通方法
- sleep方法不释放同步锁,wait方法释放同步锁(执行notify方法唤醒wait的线程时是不释放同步锁的)
- wait方法用于线程间通信,而sleep方法用于短暂的暂停线程
- sleep针对当前线程,而wait针对被同步代码块加锁的对象
- sleep方法是当前线程暂停指定时间,将执行机会让给其它线程,时间结束后进入就绪状态等待
- 调用wait方法会暂停线程,当前线程释放对象的同步锁,进入等待池(wait pool),只有调用对象的notify或者notifyAll方法唤醒时,线程进入等锁池(lock pool),直到线程再次获得对象的锁才会进入就绪状态
- wait方法(notify,notifyAll)只能在同步方法或者同步块中使用(如果在non-synchronized函数或non-synchronizedblock中进行调用,虽然能编译通过,但在运行时会发生illegalMonitorStateException的异常);sleep方法可以在任意位置使用
注:如果线程A希望立即结束线程B,则可以对线程B对应的Thread实例调用interrupt方法。如果此刻线程B正在wait/sleep/join,则线程B会立刻抛出InterruptedException,在catch() {} 中直接return即可安全地结束线程https://www.cnblogs.com/tiancai/p/8855125.html
34.线程的sleep()方法和yield()方法有什么区别?
① sleep()方法给其他线程运行机会时不考虑线程的优先级,因此会给低优先级的线程以运行的机会;yield()方法只会给相同优先级或更高优先级的线程以运行的机会;
② 线程执行sleep()方法后转入阻塞(blocked)状态,而执行yield()方法后转入就绪(ready)状态;
③ sleep()方法声明抛出InterruptedException,而yield()方法没有声明任何异常;
④ sleep()方法比yield()方法(跟操作系统CPU调度相关)具有更好的可移植性。
35.说说你对同步和异步的理解.
Java 中同步与异步,阻塞与非阻塞都是用来形容交互方式,区别在于它们描述的是交互的两个不同层面。
同步与异步
- 同步与异步更关注交互双方是否可以同时工作。
- 以同步的方式完成任务意味着多个任务的完成次序是串行的,假设任务 A 依赖于任务 B,那么任务 A 必须等到任务 B 完成之后才能继续,执行流程为 A->B;
- 以异步的方式完成任务意味着多个任务的完成可以是并行的,这种情况多适用于任务之间没有因果关系,假如任务 A 中需要执行任务 B,而任务 A 的完成不依赖于任务 B 的结果,那么任务 A 调用任务 B 后可以继续执行后续步骤而不需要等待任务 B 完成,也不关心任务 B 是否执行完毕,此时任务 A 和任务 B 是并行的。
为了加深对同步和异步的理解,可以使用打电话和发短信的类别同步和异步的交互方式。打电话时,一方的后续操作必须等到另一方说完才能进行,这种交互方式就是同步的。发短信则意味着我们不关心对方看到短信后的结果,我们关心自己是否发了短信,发完短信后,我们可以接着手头上的工作,这种交互方式就是异步的。
阻塞与非阻塞
阻塞与非阻塞关注的是交互双方是否可以弹性工作。
- 假设对象 A 和对象 B 进行交互,而对象 B 对一个问题需要思考一段时间才能回复 A,那么对象 A 可以选择等待对象 B 回复,这种方式就是一种阻塞式交互,
- 与此同时,对象 A 可以选择在对象 B 进行思考的时间去完成别的工作,等到对象 B 完成思考后再进行后续交互,这种方式就是一种非阻塞式的交互。
一般来说,阻塞与非阻塞式用来形容 CPU 消耗的。我们把 CPU 停下来等待慢操作完成以后再接着工作称为阻塞;把 CPU 在慢操作完成之前去完成其他工作,等慢操作完成后再接着工作称为非阻塞。
36.什么是ORM?
答: 对象关系映射(Object-Relational Mapping,简称ORM) 是一种为了解决程序的面向对象模型与数据库的关系模型互不匹配问题的技术;
简单的说,ORM是通过使用描述对象和数据库之间映射的元数据(在Java中可以用XML或者是注解), 将程序中的对象自动持久化到关系数据库中或者将关系数据库表中的行转换成Java对象, 其本质上就是将数据从一种形式转换到另外一种形式。
37.说一说spring 中依赖注入和AOP的实现机制。
答:依赖注入(Dependecy Injection)和控制反转(Inversion of Control)是同一个概念,具体的讲:当某个角色需要另外一个角色协助的时候,在传统的程序设计过程中,通常由调用者来创建被调用者的实例。但在spring中创建被调用者的工作不再由调用者来完成,因此称为控制反转。创建被调用者的工作由spring来完成,然后注入调用者 因此也称为依赖注入
依赖注入常见三种 分别为构造注入,设置注入,接口注入
面向切面编程(AOP)完善spring的依赖注入(DI),面向切面编程在spring中主要表现为两个方面
1.面向切面编程提供声明式事务管理
2.spring支持用户自定义的切面实现AOP的技术,主要分为两大类:一是采用动态代理技术,利用截取消息的方式,对该消息进行装饰,以取代原有对象行为的执行;二是采用静态织入的方式,引入特定的语法创建“方面”,从而使得编译器可以在编译期间织入有关“方面”的代码.
简单点解释,比方说你想在你的biz层所有类中都加上一个打印‘你好’的功能,这时就可以用aop思想来做.你先写个类写个类方法,方法经实现打印‘你好’,然后Ioc这个类 ref=“biz.*”让每个类都注入即可实现。
38.当一个线程进入一个对象的synchronized方法A之后,其它线程是否可进入此对象的synchronized方法B?
答:
- 一个线程在访问一个对象的同步方法时,另一个线程可以同时访问这个对象的非同步方法。
- 一个线程在访问一个对象的同步方法时,另一个线程不能同时访问这个同步方法 。 前提条件:多个线程所持有的对象锁共享且唯一,如果每个线程所持有的对象锁不一样,那么该对象是锁不住的!
- 一个线程在访问一个对象的同步方法时,另一个线程不能同时访问这个对象的其他同步方法
39.如何让多个线程顺序执行?
答:(1)用线程中的join()方法 ,利用了join()的阻塞特点, 底层调用wait()方法
唤醒是在jvm中实现调用notifyall()方法
(2)利用Executors线程池中的 newSingleThreadExecutor()方法, 创建一个单线程的线程池
40.反射用到了哪些接口,哪些类?反射机制中可以获取private成员的值吗?
答:
类:
- Class(Class 对象是在加载类时由 Java 虚拟机以及通过调用类加载器中的defineClass 方法自动构造的)
- Constructor(反射获取各个构造器)
- Field(反射获取成员属性)
- Method(反射获取成员方法)
接口
- Serializable 序列化接口
- GenericDeclaration
- Type
- AnnotationElement
- ----
- 射机制中可以获取private成员的值,但是要通过设置(setAccessible(true))进行暴力反射,解除权限。
41.Java并发编程:Synchronized及其实现原理
答:
Synchronized的作用主要有三个:
- 确保线程互斥的访问同步代码
- 保证共享变量的修改能够及时可见
- 有效解决重排序问题。
从语法上讲,Synchronized总共有三种用法:
- 修饰普通方法
- 修饰静态方法
- 修饰代码块
点击更多 42-54
https://blog.csdn.net/wtr15889957965/article/details/88621004