1.抽象类格式 关键字: abstract
1.1抽象类:
abstract class 类名{}
public abstract class ClassName{
int a;
public abstract void fun();
}
-
除非该继承的子类也是抽象类,否则继承了抽象类的所有类都要重写抽象类的抽象方法
-
不能 new 一个 java 抽象类,有点像c++中的抽象类,即含纯虚函数的抽象类,需要子类完全重载(java中的重写)后才能生成实例
-
抽象类内可以有变量,变量写法与普通类一致
-
抽象类中有构造方法
1.2 抽象类内的抽象方法
修饰符 abstract 返回值类型 方法名(参数列表);
public abstract void fun();//不能写函数体代码块
-
抽象类不一定有抽象方法,但是有抽象方法的类必须定义成抽象方法
-
不包含抽象方法的抽象类,目的就是不想让调用者实例化该对象,通常用于某些特殊的类的结构设计
-
抽象方法的修饰符可以是 public 或者是 protected, 省缺情况下默认是 public
-
抽象类的构造方法能不能是抽象方法?
public abstract class Student { String name; abstract Student();//直接报错! } /*抽象类的构造方法不能是抽象方法 原因很简单:执行子类构造函数之前需要执行父类的构造函数,如果父类的构造函数可以是抽象方法的话,需要在子类重写,但是调用父类构造函数时,子类的构造函数尚未执行,拿来的重写? */
1.3 抽象类中静态方法的调用
- 直接 [抽象类].[静态方法] !!!
public abstract class Student {
public static void fun(){};
public abstract void fun2();
}
public class main {
public static void main(String[] args) {
Student.fun();
}
}
2.接口
**接口的本质是规范,定义的是一组规则 **
-
类的关键字是class, 接口的关键字是 interface
class Person{}//类 interface Person{}//接口
-
接口内的所有方法都是抽象的,不能写函数体代码块
-
接口内的方法都是 (public abstract) 类型,不写的话编译器自动补全
-
接口与抽象类一样,其内同样可以定义变量
-
接口内定义的变量都是 (public static final) 类型的全局静态常量,所有比较少用
interface Person{//接口 public static final String name= “name”; void getName(); public abstract void getName() }
2.1 实现类
-
实现了接口的类简称实现类
-
接口都需要有实现类, 用法类似于类继承,把关键字 extends 换成 implements
public class [实现类名 = "接口名" + Impl] implements [接口名],[接口名]{}
例如:
public interface Person{}//接口
public interface Man{}//接口
public class PersonImpl implements Person,Man{}//实现类
注意:
- 实现类还没有把继承的所有接口里的所有抽象方法全重写之前,编译器会一直报错,这是正常现象
- 正如上面格式中所写,一个实现类是可以继承多个接口的,也就是伪多继承!!!
- 接口的多继承,在 implements 后可跟多个接口名,用逗号隔开,且都不需要在接口名字面前写关键字interface
- 实现类推荐的命名方式为 对应接口名 + Impl
2.2 JDK8的新变化
- JDK 8 之前接口只能定义抽象方法,JDK8中接口也可以定义默认方法 default 和静态方法 static
- 默认方法允许接口提供默认实现,从而减少实现类的工作量。当接口的实现类没有提供该方法的具体实现时,将使用默认方法
- 静态方法可以为接口提供与接口相关的工具方法,静态方法可以直接通过接口名来调用,而不需要创建实现类的实例。因为静态方法无法被实现类覆盖或继承。
public interface MyInterface {
default void fun1() {
// 默认方法的实现代码,即实现代码是在接口中定义的
}//default 需要明写,因为不写默认是public
static void fun2(){
//同上,实现代码是在接口中定义的
}
}
public class main {
public static void main(String[] args) {
MyInterface.fun2();//用接口名直接调用静态方法
}
}
2.2.1 默认方法冲突问题
当一个实现类继承了多个接口,且接口中有同名的默认方法时,必须 显式调用 接口A的默认方法(注意是显式调用!!!不是必须重写!,在不重写的情况下显式调用就不报错!)
格式:[接口名] . super . [默认方法名]
interface A {
default void doSomething() {
System.out.println("Do something in A");
}
}
interface B {
default void doSomething() {
System.out.println("Do something in B");
}
}
class MyClass implements A, B {
@Override
public void doSomething() {
A.super.doSomething(); // 显式调用接口A的默认方法
}
}
3.抽象类与接口的异同
异:
- 接口中没有构造方法,抽象类中有构造方法
- 接口的关键字为interface 和 implements,抽象类的关键字为 class 和 extends
- 接口可以多继承,抽象类只有单继承
- 接口中的方法必须全是抽象方法,抽象类中可以有非抽象方法(JDK8 后接口也可以定义默认方法和静态方法)
- 接口中的变量都是 public static final 类型(全局静态常量),抽象了没有要求
- 接口的抽象方法一定是 public abstract, 抽象类的抽象方法可以是public abstract 或者是 protected abstract。(此条不适用于 JDK8)
- 接口的抽象方法省缺时默认为 public abstract, 抽象类的抽象方法只可以省缺public ,因为省缺默认是public, 而 abstract 必须写
同:
- 接口和抽象类的抽象函数都是用abstract
- 接口和抽象类都是为了定义一些约束
- 接口和抽象类都不能直接实例化,只有继承其的子类(接口为实现类)在完全重写抽象方法后,才能生成子类实例