相同点:
抽象类和接口都不能直接实例化,接口的实现类或抽象类的子类都只有实现了接口或抽象类中的方法后才能实例化。
区别:
接口的普通方法只能有定义,不能有实现,jdk1.8后接口中的default方法才可以实现。而抽象类的方法可以在抽象类中实现。
一个类可以实现多个接口,但只能继承一个抽象类。
接口的成员变量默认为public static final,必须赋初值(这是由final决定的),不能被修改(也是由final决定的);其所有成员方法都是public abstract的(因此必须实现)。抽象类中的成员变量默认是default,可在子类中重新被定义,也可重新赋值;抽象类的成员方法如果被abstract修饰(就是抽象方法,子类必须重写父类所有抽象方法),不能被private(因为继承该类的子类必须要实现abstract方法,要是private子类就无法重写了)、static(abstract和static本来逻辑上就冲突,abstract不能修饰static方法或者构造方法,abstract是没有实现的,而static一定要有实现,static修饰的方法是静态方法,可以直接被类所调用,abstract修饰的方法为抽象方法,即无方法体的方法,不能够被直接调用,需要在子类或实现类中去编写完整的方法处理逻辑后才能使用)、synchronized(不能修饰abstract,abstract方法只有声明,不知道要同步个什么东西,当然抽象方法在被子类继承以后,可以添加同步)和native(native本来就和abstract逻辑上就冲突,abstract要把方法实现移交给子类实现,native却是移交给本地操作系统,同时出现,那到底移交给谁来实现呢)等修饰,不能再抽象类中被实现。
注意:如果一个方法被声明为抽象的,那么这个类也必须声明为抽象的。而一个抽象类中,可以有抽象方法,也可以有具体方法。所以一个类被声明为抽象的,它的方法却不一定要是抽象的。(也就是说类抽象是方法抽象的必要不充分条件)
附加:
synchronized修饰静态方法:
当 synchronized 作用于静态方法时,其锁就是当前类的 class 对象锁。由于静态成员不专属于任何一个实例对象,是类成员,因此通过 class 对象锁可以控制静态成员的并发操作。
注意如果一个线程 A 调用一个实例对象的非 static synchronized 方法,而线程 B 需要调用这个实例对象所属类的静态 synchronized 方法,是允许的,不会发生互斥现象,因为访问静态 synchronized 方法占用的锁是当前类的 class 对象,而访问非静态 synchronized 方法占用的锁是当前实例对象锁,二者的锁并不一样,所以不冲突。
public static synchronized void increase() {
i++;
}
修饰实例方法:
实例对象锁就是用 synchronized 修饰实例对象中的实例方法,注意是实例方法不包括静态方法。
public synchronized void increase() {
i++;
}