第九节:抽象类、接口(适配器模式)

一、抽象类

1.1、抽象类的引入

使用类是描述生活中的某一类事物,但是事物和事物之间又有继承的关系,因此我们描述的类和类之间也会有继承关系存在。

在继承中,越往顶层父类,其中描述的属性和行为更加的共性。

我们在描述事物的过程中,把共性的行为或属性不停的往父类中抽取,这样就会导致在父类中描述的行为越来越不具体,无法表示出事物的特有的特点。可是这时我们依然要进行抽取和简单的描述。

描述猫和狗:

 

猫:

吃鱼

抓老鼠

狗:

啃骨头

看家

狗和猫中有共性的吃的行为,这时我们可以抽取到父类动物类中,但是在动物类中,这个吃的行为的行为体是没有办法写的十分清楚和具体。

这时我们就需要使用Java中的抽象的概念来描述这个无法写清楚的行为。由于行为我们在Java中以函数的形式体现,也就是说这个函数就变成一个抽象的函数,一旦某个类中有了抽象的函数这个类就变成抽象类了。

1.2、抽象类举例

//把狗和猫中的共性抽取到Animal类中

abstract class Animal

{

       /*

              我们把狗和猫中的eat行为抽取到了Animal类中,

              但是我们没有办法去明确具体的函数体代码,

              这时不能只写一个空的大括号,如果写了空的大括号

              就表示这个函数体是一个空白,但是这个函数有函数体

              也就是说当前这个类中的这个函数是可以被调用执行的

 

 

              我们在描述事物的行为或者功能的时候,

              如果没有办法明确具体的函数体的时候这时可以把函数体省略。

              没有函数体的函数我们成为抽象的函数,这个函数必须使用Java

              中的抽象关键字修饰。

              抽象关键字:abstract

 

              当一个类中有抽象方法的时候,这个类必须使用 抽象关键字修饰

 

       */

       abstract void eat();

}

抽象类:

使用某个类描述事物的时候,如果这个类中在描述这个事物的某个行为或功能的时候,只知道这个事物有这个行为或功能,但没有办法书写清楚具体的功能体,函数体,这时可以使用抽象函数来表示这个行为或功能,由于类中有抽象的函数,这个类就会变成抽象类

 

 

当一个类继承某个抽象类,这时这个类要把这个抽象类中的所有抽象方法全部复写掉。如果子类没有把父类中的抽象函数复写完,或者根本就没有复写,这时这个子类还是一个抽象类

 

//把狗和猫中的共性抽取到Animal类中

abstract class Animal

{

       abstract void eat();

}





class Dog extends Animal

{

       void eat()

       {

              System.out.println("啃骨头");

       }

       void lookHome()

       {

              System.out.println("看家");

       }

}



class Cat extends Animal

{

      

       //复写Animal类中的抽象函数eat

       void eat()

       {

              System.out.println("吃鱼");

       }

       void catchMouse()

       {

              System.out.println("抓老鼠");

       }

}



class AbstractDemo

{

       public static void main(String[] args)

       {

              Cat c = new Cat();

              c.eat();



              //演示多态

              Animal a = new Cat();

              a.eat();

       }

}

1.3、抽象类的细节(重点)

1、抽象类中的抽象函数需要子类全部复写,我们不写抽象类更好,直接在子类中写这些函数。

后期我们大量的时间是学习如何去使用已经存在的类,然后创建这个类或者子类的对象,调用其中的功能,完成我们的需求。

 

在Java中使用类,一般我们都会去先查阅这个类继承体系中的顶层父类中的功能,如果顶层类中的功能已经可以满足我们的需求,这时不会关注具体哪个子类。一般在继承体系的顶层,描述的功能都是不具体的功能,也就是说我们是无法直接调用这些不具体的功能,开发中的做法是,创建顶层这个父类的引用,然后随便new一个子类对象(多态),然后就开始使用这个父类的引用,调用我们看到的函数了。

 

抽象类中定义所有子类的共性行为,然后由具体的子类针对自己的实际情况复写父类提供的基本行为,建立适合自己的功能体。

 

2、抽象类和一般的类什么区别:

抽象类肯定需要abstract修饰,一般类不能使用。

不管是抽象类,还是一般类,它们都是描述事物体系中的某个事物,只不过抽象类描述的一定是这个事物体系中的共性内容,抽象类一定是顶层的类,一定不是最底层的类。

 

3、抽象类有没有构造函数,能不能创建对象?

有构造函数,但不能创建对象。

抽象类一定是个类,类中肯定就会有构造函数。抽象类不能创建对象的原因是抽象类中有抽象函数,如果我们可以直接创建抽象类的对象,那么就可以使用这个对象调用哪个抽象函数,而抽象函数是没有函数体的函数,调用函数的最终目的是需要函数体的执行,完成我们想要的结果。因此我们如果可以创建抽象类的对象,那么就会导致可以调用抽象函数,而调用了抽象函数,却得不到任何想要的效果。这样的做法没有意义。因此sun公司在指定抽象类的规则时,不让程序直接创建抽象类的对象。

1.4、抽象类的特点

1、抽象类一定是父类吗?

一定是父类,但不一定是顶层父类。

抽象类中通常都有抽象函数,而抽象类中的抽象函数要求必须由子类来复写(由具体的子类来实现其中的函数体)。

子类的主要作用是复写抽象类中的抽象函数。

 

2、抽象类可以继承其他类吗?

抽象类还是一个类,因此它必须具备类的继承特点。它可以有父类。

 

3、抽象类中有构造函数吗?有什么作用?

有构造函数。但是这个类不能创建对象。因为抽象类一定有子类,而创建子类对象的时候,在子类的构造函数中一定有super语句会找自己的父类构造函数进行初始化动作。

 

4、抽象类中可以没有抽象函数吗?

可以。它的存在意义就是不让外界创建当前这个类的对象。这样的类符合的设计模式中的适配器模式

 

5、抽象关键字不能和哪些关键字共存?互斥

 

private :父类中私有的成员子类是不知道的,因此使用private 和abstract关键字一起修饰函数,导致子类根本无法知道父类中有个抽象函数,而且需要子类复写。

 

static:如果使用static和abstract关键字一起修饰抽象函数,导致这个函数可以使用类名直接调用,而调用抽象函数是没有意义的。

 

final :final修饰的函数子类是无法复写的,而abstract修饰的函数,要求子类必须复写。

 

 

抽象类何时使用:

当描述事物体系,一般在描述所有体系中最共性的内容时,通常是只知道体系的共性功能,却不能书写具体功能体,这时会使用抽象函数表示,那么这个类一定会使用抽象类表示。

 

二、接口

接口有2个功能:

  1. 给继承体系增加额外(扩展)功能。
  2. 可以给双方定义规则,约束双方。

接口的定义:

interface 关键字定义。

接口中的成员:

成员变量 有固定的 修饰符  public static final

成员函数 有固定的 修饰符  public abstract

 

类和类之间的关系:继承,并且只能单继承

类和接口之间的关系:实现,并且可以多实现

接口和接口之间的关系:继承,可以多继承

2.1、接口的引入

 

描述 猫和 狗 ,这2类事物 它们一定具备 动物这个体系的基本共性行为。

但是猫和狗经过后天的训练 , 可以具备一些本身不属于这个事物体系中的额外的功能。而这时假设猫和狗都具备了这个行为,也是相同的行为在不同的事物中同时存在,而在Java的设计中,只要是多个类中有共性的内容,我们就可以进行共性的抽取描述。而现在猫和狗经过训练而具备的后天的额外功能,不属于动物体系本身固有的行为。无法抽取到动物类中。

可是我们又要进行抽取,那么就可以使用Java中提供的接口来完成。

 

接口的定义格式:

类的定义格式:

修饰符 class 类名

{

}

接口的定义格式:

interface 接口名

{

}

2.2、接口的代码体现

//演示接口的简单使用

 

//把狗  猫  猪中的共性行为抽取到Animal中

 

abstract class Animal

{

       abstract void eat();

}

       假设猫和狗经过后天的训练具备 缉毒的功能

       这样导致猫和狗中有共性的行为,需要抽取,这时不能抽取到Animal中。

       发现缉毒功能不属于动物体系的共有行为,这时又要把这个行为进行抽取,

       于是我们就可以把这些功能抽取到 接口中

       把缉毒抽取到接口中之后,在接口中应该也没有办法把缉毒的行为描述具体,也应该使用抽象函数表示

    让类和接口之间产生关系:

              类和类之间的关系是继承,使用extends关键字完成

              类和接口之间的关系是实现,使用的 implements 关键字完成

interface 缉毒

{

       abstract void 缉毒();

}

 

//狗既具备了动物的固有功能,同时也具备了自己的额外功能

class Dog extends Animal implements 缉毒

{

       void eat()

       {

              System.out.println("啃骨头");

       }

 

       void lookHome()

       {

              System.out.println("看家");

       }

 

       public void 缉毒()

       {

              System.out.println("狗缉毒");

       }

}

 

class Cat extends Animal implements 缉毒

{

       void eat()

       {

              System.out.println("吃鱼");

       }

       void catchMouse()

       {

              System.out.println("抓老鼠");

       }

       public void 缉毒()

       {

              System.out.println("猫缉毒");

       }

}

class Pig extends Animal
{
	void eat()
	{
		System.out.println("吃糠");
	}

	void gongDi()
	{
		System.out.println("拱地");
	}
}

2.3、接口中成员的特点

在类的成员位置上可以定义:成员变量、函数、构造函数、静态代码块、构造代码块

 

在接口的成员位置上:成员变量,和成员函数

 

接口不是类,它的出现仅仅是给描述这个事物体系增加额外的共性功能。因此在接口中是没有构造函数的。也就是说接口是不能new对象的。

 

接口中的所有成员都具有固定的修饰符:

 

       接口中的成员变量修饰:

              public static final ,这个三个修饰符 可以省略不写。

              接口中的变量,都是常量。因此接口中的变量名一般都会全部大写。

 

       接口中的成员函数:

              public abstract 返回值类型  函数名( 参数列表 );

              public abstract 可以省略,但是建议可以省略 abstract ,不要省略 public

在Java中只支持类的单继承,不支持多继承。而Java对这个多继承进行改良,修改成了多实现。

一个类在继承一个父类的同时,可以实现多个接口。

interface A
{
void show();
}
interface B
{
void show();
}
interface C
{
void show();
}
interface D
{
void show();
}

class Fu
{

}

class Demo extends Fu implements A,B,C,D
{
public void show()
{
}
}

A  f  =  new Demo();
f.show();

多态:

一个子类的对象赋值给了父类的引用,或者赋值给了接口的引用,都属于多态。

 

一个类实现多个接口,这时由于接口中的函数都是抽象函数,只有子类实现了接口中的所有函数之后,最后我们需要创建实现类的对象,最后执行的函数,还是实现类中实现的函数,不管有多少个接口,即使它们的函数同名,由于都是抽象的,不会发生任何问题,最后运行还是实现类中函数。

 

但是如果接口中有多个同名的成员变量,这时在实现类中使用接口中的成员变量,就会发生调用的不确定性。

因此后期再定义接口的时候,多个接口中尽量不要有同名的成员变量。

 

总结:

类和类:继承关系,一个类只能继承一个父类。

类和接口:实现关系,一个类可以实现多个接口。

接口和接口:继承关系,一个接口可以继承多个接口。

 

类和类之间是继承,存在子类和父类的关系。子类需要覆盖父类的函数时,我们称为函数的复写、覆盖、重写。

类和接口时间是实现关系,实现接口的类,一般称为实现类,实现类中对接口中的函数进行重写的书写。这时称为实现类对接口的方法进行的实现。

三、抽象类和接口

3.1、接口和抽象类的使用

需求:数据建模

          描述程序员和项目经理

分析:

              程序员:

                     属性:

                            姓名

                            年龄

                            部门

                            薪水

                     行为:

                            编码

                    

                    

              项目经理:

                     属性:

                            姓名

                            年龄

                            部门

                            薪水

                            奖金

                     行为:

                            管理

//程序员和经理的共性内容抽取到父类雇员这个类中
abstract class Employee
{
	private String name;
	private int age;
	private String dept;
	private double salary;

	Employee( String name , int age , String dept , double salary )
	{
		this.name = name;
		this.age = age;
		this.dept = dept;
		this.salary = salary;
	}
	//程序员和经理都需要工作,但工作的内容不同,这时在雇员这个类中只能使用抽象函数表示
	abstract void work();
}

//可以把培训行为抽取到接口中
interface Inter
{
	void peiXun();
}


//程序员类
class Programmer extends Employee  implements Inter
{
	
	//对外提供构造函数,对程序员对象进行初始化
	Programmer( String name , int age , String dept , double salary )
	{
		//通过super 把共性的属性交给父类进行初始化
		super(name,age,dept,salary);
	}
	//程序员实现工作的行为
	void work()
	{
		System.out.println("编代码.....");
	}

	//程序员具备的培训功能
	public void peiXun()
	{
		System.out.println("培训其他的新入职员工");
	}
}

//经理类
class Manager extends Employee
{
	//奖金
	private double comm;

	Manager( String name , int age , String dept , double salary , double comm )
	{
		super(name,age,dept,salary);
		this.comm = comm;
	}
	//经理实现工作的行为
	void work()
	{
		System.out.println("管理...程序员..");
	}
}

class InterfaceTest
{
	public static void main(String[] args)
	{
		Manager m = new Manager("荆小六",19,"项目部",8888,10000);
		m.work();

		//Programmer p = new Programmer("楚乔",22,"开发部",9999);
		//p.work();
		//要求所有的培训师做事,关注培训这个功能
		Inter i = new Programmer("楚乔",22,"开发部",9999);
		i.peiXun();

	}
}

后期在使用其他已经存在的类和接口的时候,一定要从最顶层开始查阅,只要顶层能满足,这时子类或者实现类中肯定会对这些功能进行自己的复写或实现。那么我们就一定会使用多态的技术来操作。

使用父类的引用或接口的引用 指向 自己的子类或实现类对象。

3.2、抽象类和接口的区别

接口和抽象类都是描述事物的共性行为,并且描述的行为一般都是抽象的。需要子类或实现类对这些行为进行实现或复写。

 

抽象类:它依然描述的事物体系中一类。而接口描述的共性行为是事物体系的额外功能(扩展功能)。

 

抽象类依然是类,属于整个事物体系中一种,而接口不属于这个事物体系。



四、没有抽象函数的抽象类

如果一个接口中有多个函数,而实现类仅仅只需要其中部分,或则个别函数。这时由于实现类实现了接口,就必须对接口中的所有函数进行实现。

如果这个实现没有把接口中的所有函数全部实现,那么这个实现类中就隐藏这个抽象函数,那么这个实现类就变成抽象类。外界就无法直接创建这个类的对象,调用已经实现了的函数。

 

当用户需要使用一个接口中的部分函数,或者个别函数时,而不是接口中的全部函数,那么要求定义这个接口的人,给这个接口定义一个实现类,然后把接口中的函数全部给空实现(函数体什么都不写)。而当外界需要使用接口中的函数时,不要直接去实现接口,而去继承这个实现类,然后复写需要使用函数即可

interface Inter
{
	public void show1();
	public void show2();
	public void show3();
	public void show4();
	public void show5();
	public void show6();
	public void show7();
	public void show8();
}
//可以对这个接口定义一个实现类
abstract class AdapterImpl implements Inter   适配器类
{
	public void show1(){}
	public void show2(){}
	public void show3(){}
	public void show4(){}
	public void show5(){}
	public void show6(){}
	public void show7(){}
	public void show8(){}
}

//假设只需要使用show1 和show2方法

class InterImpl extends AdapterImpl
{
	public void show1()
	{
		System.out.println("show1......");
	}
	public void show2()
	{
		System.out.println("show2......");
	}
}

4.1、适配器设计模式

在设计接口的时候,如果接口中的函数过多,这时需要给接口定一个实现类,这个实现类称为适配器类,这个类中的函数都是空实现,函数体中没有任何代码。这时这个适配器类需要定义成抽象类

适配器类主要的作用是从  接口 过渡到 真实类

适配器三元素:

 1、接口(多余的方法)

2、适配器类(抽象类)

3、适配器类的集成和方法重写(继承抽象类的实体类)

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值