面向对象之抽象、接口、多态

 

抽象

接口

多态

1、抽象

1.1 抽象类的概述

抽象定义

抽象就是从多个事物中将共性的,本质的内容抽取出来。不具体,看不明白。

例如:狼和狗共性都是犬科,犬科就是抽象出来的概念。

抽象类

Java中可以定义没有方法体的方法,该方法的具体实现由子类完成,该方法称为抽象方法,包含抽象方法的类就是抽象类

另一种说法:在不断抽取过程中,将共性内容中的方法声明抽取,但是方法不一样,没有抽取,这时抽取到的方法,并不具体,需要被指定关键字abstract所标示,声明为抽象方法

抽象方法所在类一定要标示为抽象类,也就是说该类需要被abstract关键字所修饰。

 

抽象方法的由来

多个对象都具备相同的功能,但是功能具体内容有所不同,那么在抽取过程中,只抽取了功能定义,并未抽取功能主体,那么只有功能声明,没有功能主体的方法称为抽象方法。

例如:狼和狗都有吼叫的方法,可是吼叫内容是不一样的,所以抽象出来的犬科虽然有吼叫功能,但是并不明确吼叫的细节。

 

1.2 抽象类的特点:

1,抽象方法一定在抽象类中。抽象方法和抽象类都必须被abstract关键字修饰(可以描述类和方法,不可以描述变量)。

2,抽象方法只定义方法声明,并不定义方法实现。

3,抽象类不可以用new创建对象(实例化)。因为调用抽象方法没意义。

4,抽象类中的抽象方法要被使用(继承),必须由子类复写起所有的抽象方法后,建立子类对象调用。如果子类只覆盖了部分抽象方法,那么该子类还是一个抽象类。即只有通过子类继承抽象类并覆盖了抽象类中的所有抽象方法后,该子类才可以实例化。否则,该子类还是一个抽象类。

a)         抽象类和抽象方法必须用abstract关键字来修饰。

b)        抽象方法只有方法声明,没有方法体,定义在抽象类中。

          格式:修饰符 abstract返回值类型函数名(参数列表);

c)         抽象类不可以被实例化,也就是不可以用new创建对象,原因如下:

d)        抽象类是具体事物抽取出来的,本身是不具体的,没有对应的实例。例如:犬科是一个抽象的概念,真正存在的是狼和狗。

e)         而且抽象类即使创建了对象,调用抽象方法也没有意义。

f)         抽象类通过其子类实例化,而子类需要覆盖掉抽象类中所有的抽象方法后才可以创建对象,否则该子类也是抽象类。

1.3、抽象类举例代码讲解

老师示例,根据给出内容设计继承体系

具体事物:基础班老师,就业班老师

共性:姓名,所属教室,讲课。

学员示例(练习)

具体事物:基础班学员,就业班学员,

共性:姓名,学习,休假。

雇员示例:

需求:公司中程序员有姓名,工号,薪水,工作内容。

项目经理除了有姓名,工号,薪水,还有奖金,工作内容。

对给出需求进行数据建模。

1.4、抽象类的细节

1)        抽象类中是否有构造函数?

          有,用于给子类对象进行初始化。

2)      抽象关键字abstract和哪些不可以共存?

         final ,private , static

3)      抽象类中是否可以定义非抽象方法?

可以,其实,抽象类和一般类没有太大的区别,该如何描述事物,就如何描述事物,都是在描述事物,只不过抽象类在描述事物时,有些功能不具体,看不懂。这些不确定的部分,也是该事物的功能,需要明确出现,但是无法定义主体通过抽象方法来表示。所以抽象类和一般类在定义上,都是需要定义属性和行为的。只不过,抽象类比一般类多个了抽象函数,就是在类中可以定义抽象方法,而且比一般类少了一个创建对象的部分。即抽象类不可以实例化。

特殊:抽象类中可以不定义抽象方法,这样做仅仅是不让该类建立对象。

abstract class Student
{
	abstract final void study();//抽象方法必须放在抽象类中。
	//abstract void study1();
	void sleep()
	{
		System.out.println("躺着");
	}
}

4)        抽象类中可不可以没有抽象方法?

         可以。抽象方法目的仅仅为了不让该类创建对象。

5)        抽象类中是否有构造函数?

         有,抽象类是一个父类,要给子类提供实例的初始化。

abstract: 关键字,和哪些关键字不能共存。

      final:  被final修饰的类不能有子类。而被abstract修饰的类一定是一个父类。

private:  抽象类中的私有的抽象方法,不被子类所知,就无法被复写。

                  而抽象方法出现的就是需要被复写。

 static:  如果static可以修饰抽象方法,那么连对象都省了,直接类名调用就可以了。

              可是抽象方法运行没意义。

举例:假如我们在开发一个系统时需要对员工进行建模,员工包含3个属性:姓名,工号以及工资,经理也是员工,除了含有员工的属性外,另外还有一个奖金属性,请使用继承的思想设计出员工类和经理类,要求类中提供必要的方法进行属性访问。

员工类:name id pay

经理类:继承了员工,并有自己特有的奖金bonus属性

class Employee
{
	private String name;
	private String id;
	private double pay;
	Employee(String name,String id,double pay)
	{
		this.name = name;
		this.id = id;
		this.pay = pay;
	}
	public abstract void work();
}
class Manager extends Employee
{
	private int bonus;
	Manager(String name,String id,double pay,int bonus)
	{
		super(name,id,pay);
		this.bonus = bonus;
	}
	public void work()
	{
		System.out.println("manager work");
	}
}
class Pro extends Employee
{
	Pro(String name,String id,double pay)
	{
		super(name,id,pay);
	}
	public void work()
	{
		System.out.println("pro work");
	}
}
class  
{
	public static void main(String[] args) 
	{
		System.out.println("Hello World!");
	}
}

需求:获取一段程序运行的时间

原理:获取程序开始和结束的时间并相减即可。

获取时间:System.currentTimeMillis();

当代码完成优化后,就可以解决这类问题。这种方式,模版方法设计模式。

什么是模版方法呢?

在定义功能时,功能的一部分是确定的,但是有一部分是不确定,而确定的部分在使用不确定的部分,

那么这时就将不确定的部分暴露出去。由该类的子类去完成。

模板方法设计模式:

解决的问题:当功能内部一部分实现时确定,一部分实现是不确定的。这时可以把不确定的部分暴露出去,让子类去实现。

abstract class GetTime
{     //获取某段时间的代码,其中runcode();是不确定的,暴露到外边去。其他的是确定的。
	public final void getTime()//此功能如果不需要复写,可加final限定
	{
		long start = System.currentTimeMillis();
		runcode();//不确定的功能部分,提取出来,通过抽象方法实现
		long end = System.currentTimeMillis();
		System.out.println("毫秒:"+(end-start));
	}
	public abstract void runcode();//抽象不确定的功能,让子类复写实现
}
class SubTime extends GetTime
{
	public void runcode()//子类复写功能方法
	{
		for(int x=0; x<4000; x++)
		{
			System.out.print(x);
		}
	}
}
class  TemplateDemo
{
	public static void main(String[] args) 
	{
		//GetTime gt = new GetTime();
		SubTime gt = new SubTime();
		gt.getTime();
	}
}

2、.接口

  初期理解:初期理解,可以认为是一个特殊的抽象类,当抽象类中的方法都是抽象的,那么该类可以通过接口的形式来表示。接口看上去是一个特殊的抽象类。里面存的都是抽象方法。

        格式:interface Inter{}

       1通过interface来定义

       2接口中常见成员:常量,抽象方法。

                    而且这些成员都有固定的修饰符。

                    常量publicstatic final

                  方法public abstract

                   interface  Inter

                   {

                              public static final intNUM = 3;

                             public  abstract  void   show();

                  }

       3,接口中的成员都是共有的。

      4,一个类可以对接口进行多实现,也弥补了多继承带来的安全隐患,所以java对多继承进行了改良。

                    用多实现方法来体现多继承的特性。

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

      6,接口与接口之间是继承关系,而且可以多继承。

记住:接口中的成员都是public;类与类之间是继承关系extends;类与接口之间是实现关系implements;接口与接口之间是继承关系。

interface A
{
	void methodA();
}
interface B extends A
{
	void methodB();
}
interface C extends B
{
	void methodC();
}
class D implements C
{
	public void methodA(){}
	public void methodC(){}
	public void methodB(){}
}//建立D的对象必须实现3个方法。
接口之间可以多继承。Java支持多继续,只有接口之间有多继承 。类之间是单继承
interface A
{
	void methodA();
}
interface B 
{
	void methodB();
}
interface C extends B,A
{
	void methodC();
}

接口:是不可以创建对象的,因为有抽象方法。需要被子类实现,子类对接口中的抽象方法全都覆盖后,子类才可以实例化。否则子类是一个抽象类。

接口可以被类多实现,也是对多继承不支持的转换形式。java支持多实现。

2.2接口的特点

a)         接口是对外暴露的规则。

b)        接口是程序的功能扩展

c)         接口可以用来多实现。

d)        类与接口之间是实现关系,而且类可以继承一个类的同时实现多个接口。

e)         接口与接口之间可以有继承关系。

接口都用于设计上,设计上的特点:(可以理解主板上提供的接口)

1:接口是对外提供的规则。

2:接口是功能的扩展。

3:接口的出现降低了耦合性。别忘了说的时候,需要举例。usbpci,主板。插座。

抽象类与接口:

抽象类:一般用于描述一个体系单元,将一组共性内容进行抽取,特点:可以在类中定义抽象内容让子类实现,可以定义非抽象内容让子类直接使用。它里面定义的都是一些体系中的基本内容。

接口:一般用于定义对象的扩展功能,是在继承之外还需这个对象具备的一些功能。

抽象类和接口的共性:

相同:

1,都可以在内部定义抽象方法。

2,通常都在顶层。都是不断向上抽取的结果。

3,都不可以实例化,都需要子类来实现。

抽象类和接口的区别:

1:抽象类只能被继承,而且只能单继承。

      接口需要被实现,而且可以多实现。也就是说:接口的出现避免了单继承的局限性。

2:抽象类中可以定义抽象方法和非抽象方法,子类可以直接继承使用。

      接口中只能定义抽象方法,需要子类去实现。

3:继承和实现的关系不一致,抽象类使用的是 is a 关系。

     接口使用的 like a关系。

4:抽象类的成员修饰符可以自定义。

     接口中的成员修饰符是固定的。全都是public的。

在开发之前,先定义规则,AB分别开发,A负责实现这个规则,B负责使用这个规则。至于A是如何对规则具体实现的,B是不需要知道的。这样这个接口的出现就降低了AB直接耦合性。

3、多态(面向对象特征之一):函数本身就具备多态性,某一种事物有不同的具体的体现。

定义:某一类事物的多种存在形态。即可以理解为事物存在的多种体现形态。

例如:人:男人,女人

动物中猫,狗。

猫这个对象对应的类型是猫类型

猫 x=new 猫();

同时猫也是动物中的一种,也可以把猫称为动物。

动物 y=new 猫();

动物是猫和狗具体事物中抽取出来的父类型。

父类型引用指向了子类对象。

1,多态的体现

    父类的引用指向了自己的子类对象。Animal a = new Cat();

    父类的引用也可以接收自己的子类对象。

2,多态的前提

      必须是类与类之间有关系。要么继承,要么实现。

      通常还有一个前提:存在覆盖操作。

3,多态的好处

      多态的出现大大的提高程序的扩展性。

4,多态的弊端:

     当父类引用指向子类对象时,虽然提高了扩展性,但是只能访问父类中具备的方法,不可以访问子类中特有的方法。(前期不能使用后期产生的功能,即访问的局限性)即:提高了扩展性,但是只能使用父类的引用访问父类中的成员。

5,多态的出现思想上也做着变化:以前是创建对象并指挥对象做事情。有了多态以后,我们可以找到对象的共性类型,直接操作共性类型做事情即可,这样可以指挥一批对象做事情,即通过操作父类或接口实现。

6,多态的应用

动物,

猫,狗。

abstract class Animal
{
	abstract void eat();
}
class Cat extends Animal
{
	public void eat()
	{
		System.out.println("吃鱼");
	}
	public void catchMouse()
	{
		System.out.println("抓老鼠");
	}
}
class Dog extends Animal
{
	public void eat()
	{
		System.out.println("吃骨头");
	}
	public void kanJia()
	{
		System.out.println("看家");
	}
}
class Pig extends Animal
{
	public void eat()
	{
		System.out.println("饲料");
	}
	public void gongDi()
	{
		System.out.println("拱地");
	}
}

《《《——————————————

class 毕姥爷{

    void 讲课(){

        System.out.println("企业管理");

    }

    void 钓鱼(){

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

    }

}

class 毕老师 extends 毕姥爷{

    void 讲课(){

        System.out.println("JAVA");

    }

    void 看电影(){

        System.out.println("看电影");

    }

}

class {

    public static void main(String[] args) {

        毕姥爷 x = new 毕老师(); //毕老师对象被提升为了毕姥爷类型。

//      x.讲课();

//      x.看电影();  //错误.

        毕老师 y = (毕老师)x; //将毕姥爷类型强制转换成毕老师类型。

        y.看电影();//在多态中,自始自终都是子类对象在做着类型的变化。

    }

}

————————》》》》

如果想用子类对象的特有方法,如何判断对象是哪个具体的子类类型呢?

可以可以通过一个关键字 instanceof ;//判断对象是否实现了指定的接口或继承了指定的类

 

格式:<对象 instanceof类型> ,判断一个对象是否所属于指定的类型。

Studentinstanceof Person = true;//student继承了person类

多态在子父类中的成员上的体现的特点:

1,成员变量:在多态中,子父类成员变量同名。

    在编译时期:参考的是引用型变量所属的类中是否有调用的成员。(编译时不产生对象,只检查语法错误)

    运行时期:也是参考引用型变量所属的类中是否有调用的成员。

    简单一句话:无论编译和运行,成员变量参考的都是引用变量所属的类中的成员变量。

    再说的更容易记忆一些:成员变量---编译运行都看 =左边。

2,成员函数。

    编译时期:参考引用型变量所属的类中是否有调用的方法。

    运行时期:参考的是对象所属的类中是否有调用的方法。

 为什么是这样的呢?因为在子父类中,对于一模一样的成员函数,有一个特性:覆盖。

    简单一句:成员函数,编译看引用型变量所属的类,运行看对象所属的类。

    更简单:成员函数 --- 编译看 =左边,运行看 = 右边。

3,静态函数。

    编译时期:参考的是引用型变量所属的类中是否有调用的成员。

    运行时期:也是参考引用型变量所属的类中是否有调用的成员。

 为什么是这样的呢?因为静态方法,其实不所属于对象,而是所属于该方法所在的类。

    调用静态的方法引用是哪个类的引用调用的就是哪个类中的静态方法。

    简单说:静态函数 --- 编译运行都看 =左边。

《《《《————————————————————》》》》

------java.lang.Object

Object所有类的直接或者间接父类,Java认为所有的对象都具备一些基本的共性内容,这些内容可以不断的向上抽取,最终就抽取到了一个最顶层的类中的,该类中定义的就是所有对象都具备的功能。

具体方法:

1,boolean equals(Object obj):用于比较两个对象是否相等,其实内部比较的就是两个对象地址。

而根据对象的属性不同,判断对象是否相同的具体内容也不一样。所以在定义类时,一般都会复写equals方法,建立本类特有的判断对象是否相同的依据。

  public  boolean  equals(Object obj){

      if(!(obj  instance of  Person))

          return false;

      Person p = (Person)obj;

      return   this.age == p.age;

  }

2,String toString():将对象变成字符串;默认返回的格式:类名@哈希值 =getClass().getName() + '@' + Integer.toHexString(hashCode())

  为了对象对应的字符串内容有意义,可以通过复写,建立该类对象自己特有的字符串表现形式。

  public String toString(){

      return "person : "+age;

  }

3,Class getClass():获取任意对象运行时的所属字节码文件对象。

4,int hashCode():返回该对象的哈希码值。支持此方法是为了提高哈希表的性能。

通常equals,toString,hashCode,在应用中都会被复写,建立具体对象的特有的内容。

 

———蜗牛小将,加油!明天继续努力中。。。。    濛濛

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值