抽象类与接口
抽象类
- 抽象类不能被实例化,只能被继承。
- 抽象类可以实现接口中的所有方法或其中几个方法
- 被关键字 abstract 修饰的类称为抽象类;
- 包含抽象方法的类一定是抽象类,但抽象类不一定包含抽象方法(抽象类可以包含普通方法)
- 被 abstract 修饰的方法称为抽象方法,抽象方法只有方法声明没有方法体,但普通方法可以包含方法体
- 一个类继承于一个抽象类,则子类必须实现抽象类的抽象方法,如果子类没有实现父类的抽象方法,那子类必须定义为抽象类。
- 抽象方法的权限修饰符只能为 public、protected 或 default,默认情况下为 public。···
接口
- 接口支持多继承,即一个接口可以继承(extends)多个接口,间接解决了 Java 中类不能多继承的问题。
- 一个类可以同时实现多个接口,一个类实现某个接口则必须实现该接口中的抽象方法,否则该类必须被定义为抽象类。
抽象类和接口的应用场景
抽象类应用场景
(1)父类只知道其子类应该包含怎样的方法,不能准确知道这些子类如何实现这些方法的情况下,使用抽象类。
(2)从多个具有相同特征的类中抽象出一个抽象类,以这个抽象类作为子类的模板,从而避免了子类设计的随意性。
接口的应用场景:
(1)一般情况下,实现类和它的抽象类之前具有 “is-a” 的关系,但是如果我们想达到同样的目的,但是又不存在这种关系时,使用接口。
(2)由于 Java 中单继承的特性,导致一个类只能继承一个类,但是可以实现一个或多个接口,此时可以使用接口。
什么时候使用抽象类和接口:
(1)如果拥有一些方法并且想让它们有默认实现,则使用抽象类。
(2)如果想实现多重继承,那么必须使用接口。因为 Java 不支持多继承,子类不能继承多个类,但可以实现多个接口,因此可以使用接口。
(3)如果基本功能在不断改变,那么就需要使用抽象类。如果使用接口并不断需要改变基本功能,那么就需要改变所有实现了该接口的类。
链表
1.链表数据结构
public class LinkedList<E> extends AbstractList<E> {
// 1.linkedlist有size和first(即第一个结点,头节点node)
// 2.每个节点内部有真正的元素element和next下一个结点
private int size;
private Node<E> first;
private static class Node<E>{
E elementE;
Node<E> next;
public Node(E elementE, Node<E> next) {
this.elementE = elementE;
this.next = next;
}
}
}
2.获取index处对应的结点对象
private Node<E> node(int index) {
rangeCheck(index);//检查索引范围
Node<E> node = first;
for (int i = 0; i < index; i++) {
node = node.next;
}
return node;
}
3.查看元素索引
public int indexOf(E element) {
// 1.判断所查对象是否为null
if(element == null){
Node<E> node = first;
for (int i = 0; i < size; i++){
if (node.elementE == null)
return i;
node = node.next;
}
}else {
Node<E> node = first;
for(int i = 0; i < size; i++){
if (element.equals(node.elementE))
return i;
node = node.next;
}
}
return 0;
}
4.在任意位置添加结点
public void add(int index, E element) {
rangeCheckForAdd(index);//检查索引范围
if(index == 0){// 在链表的头部加
first = new Node<E>(element, first);
} else {
Node<E> prev = node(index - 1);
prev.next = new Node<E>(element, prev.next);
size++;
}
}
// 在链表尾部加
public void add(E element) {
add(size, element);
}
5.删除任意位置的结点
public E remove(int index) {
rangeCheck(index);//检查索引范围
Node<E> node = first;
if(index == 0) {
first = first.next;
}
Node<E> prev = node(index - 1);//node为一个方法
node = prev.next;
prev.next = prev.next.next;
return node.elementE;
}
检查索引范围封装代码
protected void outOfBounds(int index) {
throw new IndexOutOfBoundsException("Index:" + index + ", Size:" + size);
}
protected void rangeCheck(int index) {
if (index < 0 || index >= size) {
outOfBounds(index);
}
}
protected void rangeCheckForAdd(int index) {
if (index < 0 || index > size) {
outOfBounds(index);
}
}