Java 基础方面
1.什么是面向对象(OOP)?
面向对象就是程序的一种设计模式,或者说是一种设计规范。
基本思想就是使用对象、类、继承、封装、多态等基本概念来进行程序设计。
从现实世界中客观存在的事物(即对象)出发来构造软件系统,并且在系统构造中尽可能运用人类的自然思维方式。
https://blog.csdn.net/u013728021/article/details/102851884
2.什么是多态?实现多态的机制是什么?
所谓多态,就是可以用统一的方法对不同的对象进行同样的操作,在java中是指在父类中定义的属性或方法被子类继承之后,可以具有不同的数据类型或表现出不同的行为。
这使得同一个属性或方法在父类及其各个子类中具有不同的语义。
例如:"几何图形"的"绘图"方法,"椭圆"和"多边形"都是"几何图"的子类,其"绘图"方法功能不同。
Java的多态性体现在两个方面:
- 由方法重载实现的静态多态性(编译时多态)
- 方法重写实现的动态多态性(运行时多态)
编译时多态:
在编译阶段,具体调用哪个被重载的方法,编译器会根据参数的不同来静态确定调用相应的方法。
运行时多态:
由于子类继承了父类所有的属性(私有的除外),所以子类对象可以作为父类对象使用。程序中凡是使用父类对象的地方,都可以用子类对象来代替。一个对象可以通过引用子类的实例来调用子类的方法。
https://blog.csdn.net/u013728021/article/details/102851884
3.重写(Override)与重载(Overload)的区别?
重载(Overloading)
方法重载是让类以统一的方式处理不同数据类型的手段。
一个类中可以创建多个方法,它们具有相同的名字,但具有不同的参数和不同的定义。调用方法时通过传递给它们的不同参数个数和参数类型来决定具体使用哪个方法。
返回值类型可以相同也可以不相同,无法以返回型别作为重载函数的区分标准。
重写(Overriding)
子类对父类的方法进行重新编写。如果在子类中的方法与其父类有相同的的方法名、返回类型和参数表,我们说该方法被重写 (Overriding)。
如需父类中原有的方法,可使用super关键字,该关键字引用了当前类的父类。
子类函数的访问修饰权限不能低于父类的。
https://blog.csdn.net/u013728021/article/details/102851884
4.接口(Interface)与抽象类(Abstract Class)的区别?
在实际使用中,使用抽象类,也就是继承,是一种强耦合的设计,用来描述“A is a B”的关系,即如果说A继承于B,那么在流程中将A当做B去使用应该完全没有问题。
比如在Android中,各种控件都可以被当做View去处理。
如果在你设计中有两个类型的关系并不是“is a”,而是“is like a”,那就必须慎重考虑继承。
而接口则多用于描述各个类型的对象间所共有的行为,表示“所有实现了这个接口的类的对象都能这么干”。
非常典型的就是各种客户端编程里面的按钮点击监听(OnClickListener,TouchListener等等),这个接口,可以由任何类型实现,表示“这个类的对象可以处理按钮点击事件”,至于它是Activity、还是Fragment、还是匿名内部类,对于持有引用的View来说,一毛钱关系都没有,它只要在点击事件触发时执行实现了OnClickListener的XXXX类对象的 onClick()方法,然后就执行到 onClick()方法中的实现了。
换句话说,所有实现了OnClickListener的类的对象,都可以让View “onClick”;同理,比如我们在编写应用网络层框架的时候,所有实现了RequestCallback(自己写的回调接口)的类的对象,都可以让Request “Callback”,这就是所谓 “共有的行为”。
https://www.zhihu.com/question/20149818
5.父类的静态方法能否被子类重写?
JAVA的静态方法形式上可以重写,但是本质上不是JAVA的重写,所以答案是不能。
为什么
静态方法只与类有关,不与实例有关,重写只适用于实例方法,不适用于静态方法。
非静态方法,按重写规则,调用相应的类的实现方法,而静态方法只与类有关。
因为静态方法是程序一运行就已经分配好了内存地址,而且该地址是固定的,所有引用到该方法的对象(父类或者子类)所指向的始终是同一个内存地址中的数据,即该静态方法。
如果子类定义了相同名称的静态方法,只会新增一个内存地址,并不会重写
6.什么是内部类?内部类、静态内部类、局部内部类和匿名内部类的区别及作用?
内部类就是在类的里面在定义一个类。
内部类的作用
- 直接调用外部类的属性和方法。
- 可以很好的隐藏自身(可以用private修饰)。
- 实现多重继承。
为什么要设计静态内部类
静态内部类就是个独立的类。之所以要弄这么个东西,只是起到一个注释的效果,而且这个注释可静态检查。
比如有A,B两个类,B有点特殊,虽然可以独立存在,但只被A使用。
这时候怎么办?
如果把B并入A里,复杂度提高,搞得A违反单一职责。
如果B独立,又可能被其他类(比如同一个包下的C)依赖,不符合设计的本意。
所以不如将其变成A.B,等于添加个注释,告诉其他类别使用B了,它只跟A玩。非静态的才是真正的内部类,对其外部类有个引用。
https://blog.csdn.net/u013728021/article/details/87358517
7.== 和 equals() 和 hashCode() 的区别?
==
在比较基本数据类型时比较的是他们的值
在比较引用数据类型时比较的是他们的地址
还有一些小细节,参见下面博客。
equals()方法
本身是Object里面的方法,如果子类没有重写就会调用Object里面的方法。String类重写的比较经典,参见下面博客。
hashcode()方法
主要是对象放入集合中使用的方法。hash运算相当于把对象的处理成一个映射,从而用来区别不同的对象。就行指纹识别中不同的指纹代表不同的人一样。
https://blog.csdn.net/u013728021/article/details/84234733
8.Integer 和 int 之间的区别?
int 是基本类型,直接存数值,而integer是对象,用一个引用指向这个对象。
当需要往ArrayList,HashMap中放东西时,像int,double这种内建类型是放不进去的,因为容器都是装 object的,这是就需要这些内建类型的外覆类了。
//自动装箱
Integer a = 1 ;
https://www.cnblogs.com/shenliang123/archive/2011/10/27/2226903.html
9.自动装箱实现原理?类型转换实现原理?
自动装箱就是Java自动将原始类型值转换成对应的对象。
比如将int的变量转换成Integer对象,这个过程叫做装箱,
反之将Integer对象转换成int类型值,这个过程叫做拆箱。
因为这里的装箱和拆箱是自动进行的非人为转换,所以就称作为自动装箱和拆箱
自动装箱时编译器调用valueOf将原始类型值转换成对象,
同时自动拆箱时,编译器通过调用类似intValue(),doubleValue()这类的方法将对象转换成原始类型值
https://www.jianshu.com/p/0ce2279c5691
10.对 String 的了解?
- String类是被final修饰的,也就是不能再被继承。
- String对象是不能更改的。
- String的一些方法都是返回一个new String对象。
- Jvm中有一个字符串常量池专门又来存储String对象。
String 为什么要设计成不可变的?
如下声明两个字符串时,str1和str2会指向同一个对象的地址。所以String对象设计成不可变,防止其中一个更改内容,影响另外一个引用。
String str1="abc";
String str2="abc";
https://blog.csdn.net/u013728021/article/details/102862439
https://segmentfault.com/a/1190000009888357
String 转换成 Integer 的方式及原理
Java中Integer.parseInt 和 Integer.valueOf 区别
https://blog.csdn.net/u013728021/article/details/102863750
11.String、StringBuffer、StringBuilder 之间的区别?
-
String是不可变字符串,所有的change操作都会创建新对象,StringBuilder与StringBuffer都是可变字符串(字符数组长度可变)
-
StringBuilder与StringBuffer在实现上基本完全一致,但是StringBuffer中的大部分方法都使用了synchronized进行修饰
-
String和StringBuffer是线程安全的,StringBuilder不是,因为String是不可变的,显然安全,而StringBuffer中的方法大都采用了synchronized 关键字进行修饰,因此也是线程安全的
-
通常情况下执行效率StringBuilder > StringBuffer > String,但不是绝对的,具体情况具体分析
-
当字符串基本不改动或改动很少时使用String,频繁改动使用StringBuilder,频繁改动且涉及多线程,则使用StringBuffer
-
使用+号连接字符串的操作是通过StringBuilder的append和toString方法实现的
12.final、finally 和 finalize 的区别?
-
final 用于声明属性,方法和类, 分别表示属性不可变, 方法不可覆盖, 类不可继承.
-
finally 是异常处理语句结构的一部分,表示总是执行.
-
finalize 是Object类的一个方法,在垃圾收集器执行的时候会调用被回收对象的此方法,可以覆盖此方法提供垃圾收集时的其他资源回收,例如关闭文件等. JVM不保证此方法总被调用.
final这块是重点考察区域。
- final可以修饰普通基本类变量和修饰引用类型变量。
- 修饰普通基本类型变量最能清楚直白的表现出final的作用,它能使变量的值无法改变,因为变量不能再次被赋值。
- 修饰引用类型变量时,我们可以保证变量不能被再次赋值, 但我们无法保证对象值的改变。也就是说这个引用指向的地址不会变的,至于地址里面的内容还是可以变的。
- final可以保证实例变量必须被初始化。
- 用final修饰方法,假如方法所属的类被继承,方法将不能在子类中被重写
- final修饰类时, 表示此类是密封的, 无法被继承,如String。
https://zhuanlan.zhihu.com/p/33083924
13.static 关键字有什么作用?
被static关键字修饰的方法或者变量不需要依赖于对象来进行访问,只要类被加载了,就可以通过类名去进行访问。
在类的首次加载的时候会去执行static的变量或者块,它是先于对象被加载的。所以不依赖于对象
这个文章讲的很好,从jvm的角度分析static关键字。
https://www.jianshu.com/p/b1259f641d09
14.列举 Java 的集合以及集合之间的继承关系?
关于java集合这块,要深入理解HashMap和ConcurrentHashMap的源码,这个经常被问到,
包括里面用到的数据结构、初始化时的操作、JDK7和JDK8中HashMap的区别等等。
JDK7与JDK8中HashMap的差异
https://blog.csdn.net/u013728021/article/details/84286234
List、Set、Map 的区别?
java集合大致可分为Set、List和Map三种体系,
- 其中Set代表无序、不可重复的集合;
- List代表有序、重复的集合;
- 而Map则代表具有映射关系的集合。
Java 5之后,增加了Queue体系集合,代表一种队列集合实现。
ArrayList、LinkedList 的区别?
LinkedList是一个链表维护的序列容器。和ArrayList都是序列容器,一个使用数组存储,一个使用链表存储。
数组和链表2种数据结构的对比:
1.查找方面。数组的效率更高,可以直接索引出查找,而链表必须从头查找。
2.插入删除方面。特别是在中间进行插入删除,这时候链表体现出了极大的便利性,只需要在插入或者删除的地方断掉链然后插入或者移除元素,然后再将前后链重新组装,但是数组必须重新复制一份将所有数据后移或者前移。
3.在内存申请方面,当数组达到初始的申请长度后,需要重新申请一个更大的数组然后把数据迁移过去才行。而链表只需要动态创建即可。
如上LinkedList和ArrayList的区别也就在此。根据使用场景选择更加适合的List。
https://blog.csdn.net/u013728021/article/details/84108829
HashMap,HashTable,ConcurrentHashMap 实现原理以及区别?
ConcurrentHashMap 采用了分段锁技术,其中 Segment 继承于 ReentrantLock。不会像 HashTable 那样不管是 put 还是 get 操作都需要做同步处理,理论上 ConcurrentHashMap 支持 CurrencyLevel (Segment 数组数量)的线程并发。每当一个线程占用锁访问一个 Segment 时,不会影响到其他的 Segment。
https://blog.csdn.net/u013728021/article/details/84141809
https://zhuanlan.zhihu.com/p/40327960
为什么HashMap的容量长度要是2的mod倍(2的多少次方,比如16、8、32)
因为获取table的bucketIndex时要把hashcode和(length-1)进行按位与操作,比如
16的二进制数 0001 0000
那么15的二进制就是 0000 1111,这样hash的低四位都可以利用起来,是减少hash冲突的一种措施。
hashMap在多线程中会出现什么问题,怎么解决。
HashSet 与 HashMap 怎么判断集合元素重复?
看过源码之后,这个问题还是挺简单的。就是判断新加入的key和已经存在的key是否有hash码相同,并且equals()方法返回true的对象。如果有就不会add或者put到集合中。
https://blog.csdn.net/u013728021/article/details/102891249
15.什么是序列化?怎么实现?有哪些方式?
序列化就是把实体对象状态按照一定的格式写入到有序字节流,反序列化就是从有序字节流重建对象,恢复对象状态
为什么需要序列化与反序列化
当两个Java进程进行通信时,实现进程间的对象传送
换句话说,一方面,发送方需要把这个Java对象转换为字节序列,然后在网络上传送;另一方面,接收方需要从字节序列中恢复出Java对象。
当我们明晰了为什么需要Java序列化和反序列化后,我们很自然地会想Java序列化的好处。其好处一是实现了数据的持久化,通过序列化可以把数据永久地保存到硬盘上(通常存放在文件里),二是,利用序列化实现远程通信,即在网络上传送对象的字节序列。
总的来说可以归结为以下几点:
(1)永久性保存对象,保存对象的字节序列到本地文件或者数据库中;
(2)通过序列化以字节流的形式使对象在网络中进行传递和接收;
(3)通过序列化在进程间传递对象;
序列化算法一般会按步骤做如下事情:
(1)将对象实例相关的类元数据输出。
(2)递归地输出类的超类描述直到不再有超类。
(3)类元数据完了以后,开始从最顶层的超类开始输出对象实例的实际数据值。
(4)从上至下递归输出实例的数据
https://blog.csdn.net/xlgen157387/article/details/79840134
16.对反射的了解?
https://blog.csdn.net/u013728021/article/details/82775699
17.对泛型的了解?
https://blog.csdn.net/s10461/article/details/53941091