1、面向对象的三大特性:封装、继承、多态。
每个说重点,方便记忆。
什么是封装?
1、封装是把一个对象的属性私有化,同时提供一些能被外界访问属性的getter和setter方法。
2、封装能容易地修改类的内部实现,无需修改使用了该类的代码,让代码更容易理解和维护。
什么是继承?
1、子类能够继承父类中的非private的属性、方法,让代码得到复用。
2、继承具有传递性,子类继承父类,父类继承爷爷类。
3、一个类只能继承一个父类,一个接口可以继承多个父类。
什么是多态?
1、多态是同一个行为具有不同的表现形式,使用同一个接口,不同的实例具有不同的操作。
2、多态三个必要条件:继承、重写、父类引用指向子类对象 Parent p = new Child();
3、多态调用方法时,先检查父类是否有该方法,没有就编译错误,有就调用子类同名方法。
2、String,StringBuffer与StringBuilder的区别?
String类采用利用final修饰的字符数组进行字符串保存,因此不可变。如果对String类型对象修改,需要新建对象,将老字符和新增加的字符一并存进去。
StringBuffer,采用无final修饰的字符数组进行保存,可理解为实现线程安全的StringBuilder。
StringBuilder,采用无final修饰的字符数组进行保存,因此可变。但线程不安全。
3、JAVA垃圾回收机制?
1、引用计数:一个对象被引用计数器加一,取消引用计数器减一。缺点是不能解决循环引用,A和B互相引用时无法回收。
2、可达性分析法(根搜索算法),将内存中每个对象看作一个节点,以 GC Root为起始点搜索,搜索路径上的对象可以到达,不可到达的对象被回收。缺点产生大量内存碎片,不利于大对象分配。
3、复制算法,将内存等分为两块,使用一块,将使用的存活对象复制到另一块中,清除使用的所有对象,适用于新生代垃圾回收。优点:不存在内存碎片。缺点:系统内存折半。
4、标记压缩算法,在可达性分析法基础上,先标记,再将存活对象移动到一起,不可达对象清除。
5、分代算法,新生代回收对象多,使用复制算法,老生带回收对象少,使用标记压缩算法。
4、GC是什么时候触发的?
GC 有 两种类型。YGC 和 FGC
1、YGC:当生成新对象并且向Eden申请空间失败时,就会触发 YGC。将 Eden存活的对象移动到survivor区,清空 Eden区。
2、FGC:当老年代或持久代被写满,或调用system.gc() 时触发。
5、List中的 ArrayList和 LinkedList?
ArrayList的底层数据结构是数组,LinkedList底层数据结构是链表。
数组创建时需要定义大小,而 ArrayList不用。当我们new ArrayList()的时候,默认会有一个空的Object数组,大小为0。当我们第一次add添加数据的时候,会给这个数组初始化一个大小,这个大小默认值为10。使用ArrayList在每一次add的时候,它都会先去计算这个数组够不够空间,如果空间是够的,那直接追加上去就好了。如果不够,那就得扩容。在源码里边,有个grow方法,每一次扩原来的1.5倍。比如说,初始化的值是10嘛。现在我第11个元素要进来了,发现这个数组的空间不够了,所以会扩到15。空间扩完容之后,会调用arraycopy来对数组进行拷贝。
ArrayList、Vector和LinkedList都是可伸缩的数组,即可以动态改变长度的数组。
ArrayList和Vector都是基于存储元素的Object[] array来实现的,它们会在内存中开辟一块连续的空间来存储,支持下标、索引访问。但在涉及插入元素时可能需要移动容器中的元素,插入效率较低。当存储元素超过容器的初始化容量大小,ArrayList与Vector均会进行扩容。
Vector是线程安全的,其大部分方法是直接或间接同步的。ArrayList不是线程安全的,其方法不具有同步性质。LinkedList也不是线程安全的。
LinkedList采用双向列表实现,对数据索引需要从头开始遍历,因此随机访问效率较低,但在插入元素的时候不需要对数据进行移动,插入效率较高。
源码:
源码:
//ArrayList Add方法:
public boolean add(E e){
ensureCapacity(size+1); //Increment modCount!!
elementData[size++] = e; //在数组末尾追加一个元素,并修改size
return true;
}
//ensureCapacity方法:处理ArrayList的大小
public void ensureCapacity(int minCapacity) {
modCount++;
int oldCapacity = elementData.length;
if (minCapacity > oldCapacity) {
Object oldData[] = elementData;
int newCapacity = (oldCapacity * 3)/2 + 1;//每次扩容,增大50%
if (newCapacity < minCapacity)
newCapacity = minCapacity; // minCapacity is usually close to size, so this is a win: elementData = Arrays.copyOf(elementData, newCapacity); }
}
6、重写和重载区别?
重写即子类重写父类的方法,方法对应的形参和返回值类型都不能变。
- 重写遵循“两同两小一大”
- “两同”,方法名相同、形参列表相同
- “两小”,子类返回值类型 ≤ 父类、子类抛出异常 ≤ 父类
- “一大”,子类方法的访问权限 ≥ 父类
重载即在一个类中,方法名相同,参数类型、数量、顺序不同,返回值类型和访问修饰符也可以不同。