文章目录
一、抽象类
1、抽象类定义
1、什么是抽象类?
- 类和类之间具有共同特征,将这些共同特征提取出来,形成的就是抽象类。
- 类到对象是实例化,对象到类是抽象。
- 抽象类无法实例化,无法创建对象。抽象类是类和类之间有共同特征,将这些具有共同特征的类再进一步抽象,就形成了抽象类。由于类本身是不存在的,所以抽象类无法创建对象,即无法实例化。
2、抽象类属于什么类型?
- 抽象类也属于引用数据类型。
3、抽象类的语法:
[修饰符列表] abstract class 类名{
类体;
}
4、抽象类是无法实例化的,无法创建对象,因此抽象类是用来被子类继承的。
- 抽象类的子类还可以是抽象类
//银行账户类
abstract class Account{
}
//信用卡类,子类继承抽象类,子类可以实例化对象
class CreditAccount extends Account{
}
//抽象类的子类还可以是抽象类
abstract class Credit extends Account{
}
5、抽象类虽然无法实例化,但是抽象类有构造方法,这个构造方法是为子类提供的
2、抽象方法
- 抽象方法表示没有实现的方法,没有方法体的方法。
- 抽象方法的特点:
- 1、没有方法体,以分好结尾
- 2、前面修饰符列表当中有abstract关键字
例如:
public abstract void doSome;
- 抽象类当中不一定有抽象方法,但是有抽象方法的类一定是抽象类。
- 抽象类当中可以有抽象方法也可以有非抽象方法。
- 抽象方法必须出现在抽象类当中,一个非抽象类继承抽象类,必须将抽象类当中的抽象方法进行实现。
abstract class Animal{
public abstract void move();
}
class Bird extends Animal{
//将抽象类当中的抽象方法进行重写
public void move(){};
}
上面当中,如果Bird类是抽象的话,则抽象方法也可以不重写。
public class Test01 {
public static void main(String[] args) {
//使用多态,父类型引用指向子类型对象
//Bird不是抽象类,可以创建对象,向上转型
Animal a=new Bird();//面向抽象编程
a.move();
//在编译的时候,a会检查Animal当中的move方法
//在执行的时候,a会使用Bird当中的move方法
}
}
判断题:java语言当中凡是没有方法体的方法都是抽象方法(错)
- Object类当中有很多方法都没有方法体,都是以分好结尾的,但是他们都不是抽象方法,例如:
public native int hashCode();
这个方法底层调用了C++写的动态链接库程序。前面修饰符列表中没有abstract。有一个native,表示调用JVM本地的程序。
二、接口
1、接口定义
1、接口也是一种引用数据类型,编译之后也是一个class字节码文件。
2、接口是完全抽象的。(抽象类是半抽象的)或者说接口是特殊的抽象类。
3、接口的定义:
[修饰符列表] interface 接口名{
}
4、接口支持多继承,一个接口可以继承多个接口。
//定义接口
interface A{
}
interface B{
}
//支持多继承
interface C extends A,B{
}
5、接口当中只包含两部分内容,一部分是:常量,一部分是:抽象方法。
//我的数学接口
interface MyMath{
public abstract int sum(int a,int b);
}
6、接口当中所有的元素都是public修饰的。
7、接口当中的抽象方法定义时:public abstract修饰符可以省略。
8、接口当中的方法都是抽象方法,所有接口当中的方法不能有方法体。
9、接口当中的方法不能有大括号,因为大括号就是方法体,而抽象方法不能有方法体。
10、接口当中常量的修饰符:public static final可以省略。
11、常量不能重新赋值。
interface MyMath{
double PI=3.1415926;
//PI是常量
int sub(int a,int b);//相减的抽象方法
int sum(int a,int b);//相加的抽象方法
}
2、类实现接口
接口的基础语法:
1、类和类之间叫做继承,类和接口之间叫做实现。(其实仍然可以将实现看成是继承)
- 继承使用extends关键字完成
- 实现使用implements完成
- 当一个非抽象类实现接口的话,必须将接口当中所有的抽象方法全部实现。
interface MyMath{
double PI=3.1415926;
//PI是常量
int sub(int a,int b);//相减的抽象方法
int sum(int a,int b);//相加的抽象方法
}
class My implements MyMath{
public int sub(int x,int y){
return x-y;
}
public int sum(int x,int y){
return x+y;
}
}
-
接口和接口之间支持多继承,一个类也可以同时实现多个接口。
-
这种机制弥补了java当中类与类之间只支持单继承的缺陷。
-
经过测试,接口和接口之间在进行强制类型转换的时候,没有继承关系,也可以强转。但是注意:在运行时可能会出现ClassCastException异常。
public class Test04 {
public static void main(String[] args) {
M m=new E();
K k=(K)m;
}
}
interface K{
}
interface M{
}
class E implements M{
}
-
最终实际上和之前一样,需要加instanceof运算符进行判断。
-
这句话不适合在接口当中:无论向上转型还是向下转型,两种类型之间必须要有继承关系,没有继承关系,则编译器会报错。
上面的代码更改如下:
if(m instanceof K){
K k=(K)m; //判断,否则会出现异常
}
3、接口与多态联合
public class Test02 {
public static void main(String[] args) {
MyMath m=new My();
//面向接口编程(调用接口里面的方法
int result=m.sub(10,20);
System.out.println(result);
int result2=m.sum(1,3);
System.out.println(result2);
}
}
//我的数学接口
interface MyMath{
double PI=3.1415926;
//PI是常量
int sub(int a,int b);//相减的抽象方法
int sum(int a,int b);//相加的抽象方法
}
class My implements MyMath{
public int sub(int x,int y){
return x-y;
}
public int sum(int x,int y){
return x+y;
}
}
4、extends和implements
问题:继承和实现都存在的话,代码应该怎么写?
- 如果同时出现继承和实现的话,继承的关键字在前面,实现的关键字在后面。
- 接口通常提取的是行为动作。
class Cat extends Animal1 implements Flyable{
}
public class Test04 {
public static void main(String[] args) {
Flyable f=new Cat();//多态
f.fly();
Flyable f1=new Pig();
f1.fly();
}
}
//动物类:父类
class Animal1{
}
//可飞翔的接口
interface Flyable{
void fly();
}
//动物类子类:猫类
//flybale是一个接口,即一对翅膀,通过接口插到猫身上,让猫可以飞翔
class Cat extends Animal1 implements Flyable{
public void fly(){
System.out.println("猫猫起飞!");
}
}
//动物类子类:蛇类
//如果不想让蛇飞,就不实现flyable接口
//没有实现这个接口就表示没有翅膀,那肯定不能飞翔
class Snack extends Animal1{
}
//动物类子类:猪类,想让猪飞,插接口
class Pig extends Animal1 implements Flyable{
public void fly(){
System.out.println("猪猪起飞!");
}
}
5、接口在开发当中的作用
- 接口在开发当中的作用,类似于多态在开发当中的作用。
多态:面向抽象编程,不面向具体编程,降低程序的耦合度,提高程序的扩展力。
- 面向抽象编程可以修改为:面向接口编程。因为有了接口就有了可插拔。可插拔表示扩展能力强,不是焊接死的。例如:主板和内存条之间有插槽,这个插槽就是接口,内存条坏了,可以重新买一个换,这就是高扩展性和低耦合度。
实现一个菜单接口:
- 中午去饭馆吃饭,这个过程当中有接口,接口是抽象的。
- 菜单是一个接口。(菜单上面有一个抽象的照片:西红柿炒鸡蛋)
- 顾客面向菜单点菜,调用接口。
- 后台的初始负责把西红柿鸡蛋做好,是接口的实现者。
- 这个菜单接口的作用:让顾客和厨师解耦合,顾客不用找后厨,后厨不用找顾客,他们之间完全依靠这个抽象的菜单进行沟通。符合OCP开发原则。
- 顾客有一个菜单 Customer has a FoodMenu,凡是能够使用has a 来描述的,统一以属性的方式存在
- Cat is a Animal 凡是满足 is a 的表示都可以设置为继承。
西餐厨师类:
//西餐厨师实现菜单上面的菜
public class AmericanCooker implements FoodMenu{
public void xiHongShiJidan(){
System.out.println("西餐中的西红柿炒鸡蛋");
}
public void yuXiangRouSi(){
System.out.println("西餐中的鱼香肉丝");
}
}
中餐厨师类:
//中餐厨师实现菜单上面的菜。厨师是接口的实现者。
public class ChinaCooker implements FoodMenu{
public void xiHongShiJidan(){
System.out.println("中餐中的西红柿炒鸡蛋");
}
public void yuXiangRouSi(){
System.out.println("中餐中的鱼香肉丝");
}
}
顾客类:
public class Customer{
//面向接口编程
private FoodMenu foodmenu;//私有化体现封装性,则要提供set和get方法
public Customer() {
}
public Customer(FoodMenu foodmenu) {
this.foodmenu = foodmenu;
}
public FoodMenu getFoodmenu() {
return foodmenu;
}
public void setFoodmenu(FoodMenu foodmenu) {
this.foodmenu = foodmenu;
}
public void order(){
//方法一:使用get方法拿到菜单
FoodMenu f=this.getFoodmenu();
//方法二:直接使用foodmenu,因为私有的属性可以在本类当中使用
foodmenu.xiHongShiJidan();
foodmenu.yuXiangRouSi();
}
}
菜单类:
public interface FoodMenu {
void xiHongShiJidan();
void yuXiangRouSi();
}
测试类:
public class Test {
public static void main(String[] args) {
//创建厨师对象(多态)
FoodMenu menu1=new ChinaCooker();
FoodMenu menu2=new AmericanCooker();
//创建顾客对象
Customer m1=new Customer(menu1);
Customer m2=new Customer(menu2);
//顾客点菜
m1.order();
m2.order();
}
}
- 任何一个接口都有调用者和实现者,接口可以将调用者和实现者解耦合。以后的大项目开发,一般都是将项目分离成一个一个的模块,模块之间采用接口衔接,降低耦合度。
6、is has like
-
is a :Cat is an Animal.(猫是一个动物)
- 凡是满足is a的就表示继承关系。
-
has a:He has a pen.(他有一只笔)
- 凡是能够满足has a 关系的表示关联关系。
- 关联关系通常以“属性”的形式存在。
-
like a :Cooker like a menu.(厨师就像一个菜单)
- 凡是满足like a 关系的表示实现关系。
- 实现关系通常是类实现接口。
7、抽象类与接口
抽象类与接口的区别:
- 抽象类是半抽象的,接口是完全抽象的。
- 抽象类中有构造方法,接口当中没有构造方法。
- 接口和接口之间支持多继承,类和类之间只支持单继承。
- 一个类可以同时实现多个接口,一个抽象类只能继承一个类(单继承)。
- 接口都在只允许出现常量和抽象方法。