路漫漫其修远兮,吾将上下而求索
抽象类
定义:如果一个类中存在抽象方法,那么该类就必须声明为抽象类。
格式:权限修饰符 abstract class 类名{
}
抽象方法:将共性的行为(方法)抽取到父类之后,发现该方法的实现逻辑无法在父类中给出具体实现,该方法就可以定义为抽象方法。
格式: 修饰符 abstract 返回值类型 方法名(参数列表);
抽象类的特点:
- 抽象类无法创建对象,但是可以向上转型;
- 抽象类可以没有抽象方法,但有抽象方法的类一定是抽象类;
- 子类继承抽象类要么重写所有抽象方法,要么子类也必须定义为抽象类。
抽象类和普通类的区别:
抽象类和普通类相比,可以说是有得有失。
有得:得到定义抽象方法的能力。
有失:失去创建对象的能力。
除此之外,普通类有的,抽象类都具备,因为抽象类的本质还是类,可以有类的各种成员,也可以有静态属性和静态方法。
Question:抽象方法能否被private, static, final这些关键字修饰?
答:抽象方法一定要重写才有意义, private, static, final修饰的方法,这个方法就不能被重写,就会产生冲突。
接口
定义:Java接口是一系列方法的声明,是一些方法特征的集合,一个接口只有方法的特征没有方法的实现,因此这些方法可以在不同的地方被不同的类实现,这些实现可以具有不同的行为(功能)。接口是比抽象类更加彻底的抽象,接口不是类,不能使用new 。Java接口主要是对功能的描述和规范。
Java中使用interface关键字定义接口。
格式:
权限修饰符 interface 接口名{
}
接口的成员特点:
- 接口的权限修饰符只能是public或者缺省(不写)。
- 接口中没有构造方法,所以接口不能创建对象。
- JDK8之前,接口中只能定义常量和抽象方法,不能有其他成分。
- 其中常量:默认都是 public static final修饰的,可以都省略不写也可任意省略哪个,与它们的排列先后顺序无关,注意只能是 public,用 private 修饰会报编译错误。
- 其中抽象方法:默认都是 public abstract 修饰的,可以省略不写。【注意:接口的抽象方法只能是 public abstract,其他修饰符都会报错,抽象类中的抽象方法的public abstract不能省略!!】
- 接口是隐式抽象的,当声明一个接口的时候,不必使用abstract关键字。
- 接口中每一个方法也是隐式抽象的,声明时同样不需要abstract关键字。
- 接口中的方法都是公有的。
public interface Test{
int a = 2;
static int b = 3;
public int c = 4;
final int d = 5;
public final int e = 6; //上面这些变量写法都正确
public void run(); //接口中每个方法都是隐式抽象的,声明时不需要abstract关键字
}
接口是用来被类实现的,实现接口的类称为实现类。一个类可以实现多个接口,实现关键字是 implements。
接口和接口是多继承的关系,一个接口可以同时继承多个接口。
格式:
权限修饰符 interface 接口名 extends 接口1, 接口2, 接口3{
}
注意:一个类实现接口,必须重写接口的所有抽象方法,否则这个类需要定义成抽象类。
接口的重要意义
接口多用于约束和统一功能,一个接口体现的是能做什么,而不关心怎么做。
接口可以提高程序的扩展性和维护性。
JDK8之前接口中只能定义常量和抽象方法。
小tips:
1. 子类继承父类并实现接口:
当一个类,既继承父类,又实现接口时,父类中的成员方法与接口中的默认方法相同,子类就近选择执行父类的成员方法。
2. 类实现多个接口:
实现的多个接口有相同的抽象方法时,实现类只需要重写一次。
实现的多个接口有相同的默认方法时,实现类需要重写该默认方法。(继承多接口也一样)
实现的多个接口有相同的静态方法时,使用不会冲突,因为静态方法通过各自的接口名调用。
接口和抽象类的区别
抽象类:
- 抽象类中可以定义抽象方法外也可以定义构造器,可以包含静态方法静态变量,以及普通方法普通变量,总之就只是失去创建对象的能力,除此之外,普通类有的,抽象类都具备;
- 一个类只能继承一个抽象类;
- 有抽象方法的类必须声明为抽象类,而抽象类未必要有抽象方法;
- 抽象类中抽象方法的访问类型可以是public、protected和default。
接口:
- JDK7之前,接口中的只能定义常量和抽象方法。
JDK8之后,接口中可以有默认方法,静态方法,JDK9又新增私有方法等非抽象方法。 - 接口中不能定义构造方法。
- 一个类可以实现多个接口。
- 抽象方法默认都是 public abstract 修饰的,可以省略不写。
- 常量默认都是 public static final修饰的,可以都省略不写也可任意省略哪个。
相同点:
- 都不能被实例化。
- 一个类如果继承了某个抽象类或者实现了某个接口,都需要对其中的抽象方法全部进行实现,否则该类仍需要被声明为抽象类。
作用区别:
1.抽象类可以被子类继承,而且只能单继承。
2.接口可以被子类实现,而且支持多实现;接口也可以被其他接口继承,而且是多继承。
设计思想:
1.抽象类是对子类共同特征的抽取,可以将多个子类中相同的属性和行为抽取到父类中,
某些实现细节定义成抽象方法,子类可以继承和重写,以达到简化代码,复用功能的目的。
2.接口是对功能的统一和约束,实现接口的目的是为了扩展类的功能。
对于接口中final常量的一些小知识:
由于在接口中成员变量被默认添加了final,也就是被定义成了常量,必须要初始化赋值,不能只声明。当定义一个成员变量时,如果加了final不赋值的话就会报错,但是如果是局部变量,就不会报错,也就是说局部变量可以只声明不初始化。
class Demo {
//final String name = "小明"; //直接赋值,这种写法值是写死的
System.out.println("---------------------------------")
final String name; //通常用构造器赋值
public Demo(String name){
this.name = name;
}
}
例题:下列代码能够正确编译的是( ABC)
A:
public class Student{
final String name;
public Student(){
this.name = "Tom";
}//写死的值
}
B:
public class Student{
final String name;
public Student(){
this.name = "Tom";
}
public Student(String name){
this.name = name;
}
//无参(写死的)有参(通过参数赋值)两种构造方法可供选择。
}
C:
public class Student{
final String name = "Tom";
//写死的,等价于A的写法
}
D:
public class Student{
final String name;
}