黑马程序员(Java)----面向对象(多态、抽象类、接口)

------Java培训、Android培训、iOS培训、.Net培训、期待与您交流! -------

3.7 多态

3.7.1、理解多态

多态可以理解为事物存在的多种体现形态。例如下面的代码:

Cat c = new Cat();
Animal a = new Cat();

建立一个猫的对象,可以用猫这个类引用,也可以用动物这个类引用。

3.7.2、多态的前提

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

2、存在覆盖。父类中有方法被子类重写(其实没有也是可以的,但是如果没有这个就没有意义)。

3.7.3、多态中成员的特点

1、多态中非静态成员变量的特点

在编译时,参阅引用型变量所属的类中是否有调用的成员变量。如果有,编译通过,如果没有,编译失败。在运行时,调用的成员变量也是引用型变量所属的类中的成员变量。

简单来说:编译看左边,运行看左边。

class Fu{
	public int num = 100;

}
class Zi extends Fu{
	public int num = 200;
}
class DuoTaiDemo{
	public static void main(String[] args){
		Fu f = new Zi();
		System.out.println(f.num);
	}
}

运行结果:

2、多态中非静态成员方法的特点

在编译时,参阅引用型变量所属的类中是否有调用的方法。如果有,编译通过,如果没有,编译失败。在运行时,调用的方法是对象所属类中的该方法。

简单来说:编译看左边,运行看右边。

class Fu{
	public int num = 100;

	public void show_1(){
		System.out.println("show Fu_1");
	}
	public void show_2(){
		System.out.println("show Fu_2");
	}
}
class Zi extends Fu{
	public int num = 200;
	public void show_1(){
		System.out.println("show Zi_1");
	}
}
class DuoTaiDemo{
	public static void main(String[] args){
		Fu f = new Zi();
		//System.out.println(f.num);
		f.show_1();
		f.show_2();
	}
}

运行结果:

在调用show_1()方法时,调用的是子类中的该方法,在调用show_2()方法时,子类中没有,所以调用的是父类中的该方法。

3、多态中静态成员方法的特点

在编译时,参阅引用型变量所属的类中是否有调用的成员方法。如果有,编译通过,如果没有,编译失败。在运行时,调用的成员方法也是引用型变量所属的类中的成员方法。

简单来说:编译看左边,运行看左边。

class Fu{
	public int num = 100;

	public void show_1(){
		System.out.println("show Fu_1");
	}
	public void show_2(){
		System.out.println("show Fu_2");
	}
	public static void function(){
		System.out.println("function Fu");
	}
}
class Zi extends Fu{
	public int num = 200;
	public void show_1(){
		System.out.println("show Zi_1");
	}
	public static void function(){
		System.out.println("function Zi");
	}
}
class DuoTaiDemo{
	public static void main(String[] args){
		Fu f = new Zi();
		//System.out.println(f.num);
		//f.show_1();
		//f.show_2();
		f.function();
	}
}

运行结果:

3.7.4、多态的利弊

好处:提高了代码的扩展性

坏处:只能使用父类的引用访问父类中的成员。想要调用子类中特有的方法时,需要将父类的引用经过向下转型为子类成员。

class Animal{
	public void eat(){
		System.out.println("吃东西");
	}
}
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 lookDoor(){
		System.out.println("看门");
	}
}
class DuoTaiDemo2{
     public static void main(String[] args){
          //自动类型提升,猫对象提升到了动物类型。但是特有功能无法访问,作用就是限制对特有功能的访问。
          //专业讲:向上转型,将子类型隐藏。就不能使用子类的特有方法了。
          Animal a = new Cat();
          a.eat();
          //a.catchMouse();//报错

          //如果还想用具体动物猫的特有功能。
          //你可以将该对象进行向下转型。
          Cat c = (Cat)a; //向下转型的目的是为了能够使用子类中的特有方法。
          c.eat();
          c.catchMouse();

          //注意:对于转型,自始至终都是子类对象在做类型的变化。
          //Animal a = new Dog();
          //Cat c = (Cat)a;//但是类型不能随意转换,否则可能会报出ClassCastException的异常
     }

     public static void method(Animal a){//接收时用Animal类的对象接收
          a.eat();
     }
}

运行结果:

多态练习:

1、猫狗案例多态版

/*
多态练习:猫狗案例
*/
class Animal{
	public void eat(){
		System.out.println("吃饭");
	}
}
class Dog extends Animal{
	public void eat(){
		System.out.println("狗吃肉");
	}
	public void lookDoor(){
		System.out.println("狗看门");
	}
}
class Cat extends Animal{
	public void eat(){
		System.out.println("猫吃鱼");
	}
	public void playGame(){
		System.out.println("猫玩游戏");
	}
}
class DuoTaiTest{
	public static void main(String[] args){
		//定义为狗
		Animal a = new Dog();
		a.eat();
		System.out.println("------------");
		//还原成狗
		Dog d = (Dog)a;
		d.eat();
		d.lookDoor();
		System.out.println("------------");
		//变成猫
		a = new Cat();
		a.eat();
		System.out.println("------------");
		//还原成猫
		Cat c = (Cat)a;
		c.eat();
		c.playGame();

		//Dog dd = (Dog)a; 运行时出错,ClassCastException
		//Dog dd = new Animal(); 编译时出错,不兼容类型
		//Dog dd = new Cat(); 编译时出错,不兼容类型
	}
}

运行结果:

3.8 抽象类

3.8.1 抽象类的概述

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

抽象方法是怎么来的呢?

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

3.8.2 抽象类的特点

1、抽象类和抽象方法必须用abstract关键字修饰。

2、抽象类中不一定有抽象方法,但是有抽象方法的类必须定义为抽象类。

3、抽象类不可以用new建立对象,但是有构造方法, 构造方法的作用是用于子类访问父类数据的初始化。

4、抽象类中的抽象方法要想被使用,必须由子类复写所有抽象方法后,然后建立子类对象调用。如果子类只复写了部分抽象方法,那么该子类还是一个抽象类。

abstract class Animal{
	//抽象方法
	public abstract void eat();
	//public abstract void eat(){}//这个是空方法体,不是没有方法体,所以会报错
	//抽象类有构造方法
	public Animal(){}
}
//子类是抽象类
abstract class Dog extends Animal {}

//子类是具体类,重写所有抽象方法
class Cat extends Animal {
	public void eat() {
		System.out.println("猫吃鱼");
	}
}

class AbstractDemo {
	public static void main(String[] args) {
		//创建对象
		//Animal是抽象的; 无法实例化
		//Animal a = new Animal();
		//通过多态的方式
		Animal a = new Cat();
		a.eat();
	}
}

运行结果:

3.8.3
抽象类的成员特点

代码:

/*
抽象类的成员特点:
    成员变量:可以使变量,也可以是常量。
	构造方法:有,用于子类访问父类数据的初始化。
	成员方法:既可以是抽象的,也可以是非抽象的。

*/
abstract class Animal{
	//成员变量
	public int num = 10;
	public final int num2 = 20;
	//构造方法
	public Animal(){}
	//成员方法
	public abstract void show();
	public void method(){
		System.out.println("method run");
	}
}
class Dog extends Animal{
	public void show(){
		System.out.println("Dog show");
	}
}
class AbstractDemo2{
	public static void main(String[] args){
		//采用多态
		Animal a = new Dog();
		a.num = 100;
		System.out.println(a.num);
		//a.num2 = 200;
		System.out.println(a.num2);
		System.out.println("-----------------");
		a.show();
		a.method();
	}
}

运行结果:

结论:

抽象类的成员变量可以使变量,也可以是常量;构造方法也有,作用是用于子类访问父类数据的初始化;成员方法既可以是抽象的,也可以是非抽象的。

3.8.4 练习题

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

分析:

普通员工类(以程序员为例):

成员变量:姓名、工号、工资

构造方法:

成员方法:工作

经理类:

成员变量:姓名、工号、工资、奖金

构造方法:

成员方法:工作

//定义员工类
abstract class Employee{
	private String name;
	private String id;
	private int salary;

	public Employee(){}
	public Employee(String name,String id,int salary){
		this.name = name;
		this.id = id;
		this.salary = salary;
	}

	public String getName(){
		return name;
	}
	public void setName(String name){
		this.name = name;
	}
	public String getId(){
		return id;
	}
	public void setId(String id){
		this.id = id;
	}
	public int getSalary(){
		return salary;
	}
	public void setSalary(int salary){
		this.salary = salary;
	}
	public abstract void work();
}
class Programmer extends Employee{
	public Programmer(){}
	public Programmer(String name,String id,int salary){
		super(name,id,salary);
	}
	public void work(){
		System.out.println("写代码");
	}
}
class Manager extends Employee{
	//奖金
	private int bonus;

	public Manager(){}
	public Manager(String name,String id,int salary){
		super(name,id,salary);
	}
	public Manager(String name,String id,int salary,int bonus){
		super(name,id,salary);
		this.bonus = bonus;
	}
	public void work(){
		System.out.println("跟客户谈需求");
	}
	public int getBonus(){
		return bonus;
	}
	public void setBonus(int bonus){
		this.bonus = bonus;
	}
}
class AbstractTest4{
	public static void main(String[] args){
		//测试普通员工类
		Employee e = new Programmer();
		e.setName("小明");
		e.setId("czbk001");
		e.setSalary(10000);
		System.out.println(e.getName()+"---"+e.getId()+"---"+e.getSalary());
		e.work();
		System.out.println("---------------------");
		e = new Programmer("小明","czbk001",10000);
		System.out.println(e.getName()+"---"+e.getId()+"---"+e.getSalary());
		e.work();
		System.out.println("---------------------");
		/*
		e = new Manager();
		e.setName("小刚");
		e.setId("czbk010");
		e.setSalary(8K);
		e.setBonus(2K);
		*/
		//由于子类有特有的内容,所以我们用子类来测试
		Manager m = new Manager();
		m.setName("小刚");
		m.setId("czbk010");
		m.setSalary(8000);
		m.setBonus(2000);
		System.out.println(m.getName()+"---"+m.getId()+"---"+m.getSalary()+"---"+m.getBonus());
		m.work();
		System.out.println("---------------------");

		m = new Manager("小刚","czbk010",8000,2000);
		System.out.println(m.getName()+"---"+m.getId()+"---"+m.getSalary()+"---"+m.getBonus());
		m.work();
	}
}

运行结果:

  面试题:

1、一个类如果没有抽象方法,可不可以定义为抽象类?如果可以,有什么意义?

可以,目的就是为了不让创建对象。

2、abstract不能和哪些关键字共存?

private、final、static

3.9 接口

3.9.1 理解接口

抽象类中的方法可以没有一个抽象方法,也可以抽象方法和一般方法各占一些,还可以全都是抽象方法。当抽象类中的方法全都是抽象方法时,这个类可以通过接口的形式来实现。接口使用interface来定义,格式为:interface 接口名 { }。子类中用implements来实现,格式为:子类名 implements 接口名 { }。

3.9.2 接口的成员特点

成员变量:只能是常量,并且是静态的。默认修饰符:public static final

构造方法:接口类没有构造方法。

成员方法:只能是抽象方法。默认修饰符:public abstract

3.9.3 类与类、类与接口、接口和接口的关系

类与类:继承关系,只能单继承,可以多层继承

类与接口:实现关系,可以单实现,也可多实现,并且还可以在继承一个类的同时实现多接口。

接口与接口:继承关系,可以单继承,也可以多继承

3.9.4 抽象类和接口的区别

1、成员区别

成员变量:在抽象类中可以是变量,也可以是常量;在接口中只能是常量。

构造方法:抽象类有构造方法;接口没有构造方法。

成员方法:在抽象类中可以是抽象的,也可以是非抽象的;在接口中必须是抽象的。

2、设计理念区别

抽象类:被继承体现的是:”is a”的关系。抽象类中定义的是该继承体系的共性功能。

接口:被实现体现的是:”like a”的关系。接口中定义的是该继承体系的扩展功能。

3.9.5 接口练习

猫狗案例,加入跳高的额外功能

/*
猫狗案例,加入跳高的额外功能
分析:从具体到抽象
	猫:
		姓名,年龄
		吃饭,睡觉
	狗:
		姓名,年龄
		吃饭,睡觉
	由于有共性功能,所以我们抽取了一个父类:
	动物:
		姓名,年龄
		吃饭();
		睡觉(){}
	猫 继承动物
	狗 继承动物

	跳高的额外功能是一个新扩张功能,所以我们要定义一个接口
	接口:
		跳高
	部分猫 实现跳高接口
	部分狗 实现跳高接口
*/
interface Jumpping{
	//跳高功能
	public abstract void jump();
}
abstract class Animal{
	private String name;
	private int age;

	public Animal(){}
	public Animal(String name,int age){
		this.name = name;
		this.age = age;
	}

	public String getName(){
		return name;
	}
	public void setName(String name){
		this.name = name;
	}
	public int getAge(){
		return age;
	}
	public void setAge(int age){
		this.age = age;
	}

	//吃饭是抽象的
	public abstract void eat();
	//睡觉是具体的
	public void sleep(){
		System.out.println("睡觉");
	}
}
//具体猫类
class Cat extends Animal{
	public Cat(){}
	public Cat(String name,int age){
		super(name,age);
	}

	public void eat(){
		System.out.println("猫吃鱼");
	}
}
//具体狗类
class Dog extends Animal{
	public Dog(){}
	public Dog(String name,int age){
		super(name,age);
	}

	public void eat(){
		System.out.println("狗吃肉");
	}
}
//有跳高功能的猫
class JumpCat extends Cat implements Jumpping{
	public JumpCat(){}
	public JumpCat(String name,int age){
		super(name,age);
	}

	public void jump(){
		System.out.println("跳高猫");
	}
}
//有跳高功能的狗
class JumpDog extends Dog implements Jumpping{
	public JumpDog(){}
	public JumpDog(String name,int age){
		super(name,age);
	}
	public void jump(){
		System.out.println("跳高狗");
	}
}
class InterfaceTest{
	public static void main(String[] args){
		JumpCat jc = new JumpCat();
		jc.setName("多啦A梦");
		jc.setAge(3);
		System.out.println(jc.getName()+"---"+jc.getAge());
		jc.eat();
		jc.sleep();
		jc.jump();
		System.out.println("--------------------");
		jc = new JumpCat("加菲猫",2);
		System.out.println(jc.getName()+"---"+jc.getAge());
		jc.eat();
		jc.sleep();
		jc.jump();
	}
}

运行结果:

版权声明:本文为博主原创文章,未经博主允许不得转载。

时间: 2024-08-06 15:10:18

黑马程序员(Java)----面向对象(多态、抽象类、接口)的相关文章

黑马程序员——JAVA面向对象的特性:封装,继承,多态

                                       - ----------android培训.java培训.java学习型技术博客.期待与您交流!------------  一.java面向对象的特性,封装.继承.多态         封装 封装是对象和类概念的主要特性. 封装,也就是把客观事物封装成抽象的类,并且类可以把自己的数据和方法只让可信的类或者对象操作,对不可信的进行信息隐藏. 继承 面向对象编程 (OOP) 语言的一个主要功能就是"继承".继承是

黑马程序员_面向对象之抽象类与接口

抽象类(abstract)???? 当编写一个类时,时常会为该类定义一些方法,这些方法的使用用以描述该类的行为方式,那么这些方法都有具体的方法体.但是在某些情况下,某个父类只是知道子类应该包含怎样的放过,但是无法精确的知道这些子类是如何实现这些方法,例如定义一个GetTime类,该类提供了一个计算某一段程序运行时间的gettime方法,但是无法知道具体运行什么方法体,这时就需要使用抽象方法来实现了. 抽象类概念 当多个类中出现相同功能,但是功能主体不同,这时候可以进行向上抽取,只抽取功能定义,而

黑马程序员——JAVA面向对象学习总结

------Java培训.Android培训.iOS培训..Net培训.期待与您交流! ------- www.itheima.com 首先,面向对象是一种思想. 有一种面向过程的思想,面向对象就是基于面向过程的. 举个例子:把大象放进冰箱中. 面向过程: 用我们程序模拟 (java是纯面向对象语言) class Demo{ public static void main(String[] args){ /* 这几个动作相当于功能 既然是功能就用方法封装 */ //先打开冰箱门 open();

黑马程序员---java基础-----多态、内部类、异常、包

------<a href="http://www.itheima.com" target="blank">Java培训.Android培训.iOS培训..Net培训</a>.期待与您交流! ------- 第一讲     多态 多态可以理解为事物存在的多种体现形态. 例:动物中猫,狗.猫这个对象对应的类型是猫类型,如:猫 x = new猫();同时猫也是动物中的一种,也可以把猫称为动物.动物  y = new猫();那么动物就是猫和狗具体事

黑马程序员-Java面向对象编程学习总结

------<a href="http://www.itheima.com" target="blank">Java培训.Android培训.iOS培训..Net培训</a>.期待与您交流! ------- Java面向对象编程学习总结: 重要知识点总结如下: 1,抽象,封装,继承,多态是面向对象程序设计中得四个特点. 2,面向对象得软件开发大体分为:面向对象的分析,面向对象的设计,面向对象的实现. 可概括为如下过程:分析用户需求,从问题中抽

黑马程序员————java中的抽象类

------<a href="http://www.itheima.com" target="blank">Java培训.Android培训.iOS培训..Net培训</a>.期待与您交流! ------- 抽象类集中的体现了java面向对象的特性,对于每一种事物通过五个方面:属性,方法,构造器,代码块,内部类,来重新解构再进行组装,然后将类似的事物归为一类,这是面向对象的思想.java中常说万物皆对象,那么很显然我们可以进一步的将其中的方法

黑马程序员-Java面向对象下《二》

                         ------- android培训.java培训.期待与您交流! ---------- 1.继承的概念 面向对象的特点之一,可以实现对类的复用.可以通过以下两种方法实现 a.合成/聚合关系(包含其他类):将一个类当作另一个类的属性. b.派生类:一个类继承另一个类,实现继承的类称为派生类,被继承类称为父类,基类,超类. 父类的成员方法和成员变量被子类继承,但是父类的构造方法没有被继承. 在Java中只支持单继承,和C++多继承不一样. 2.sup

黑马程序员——Java基础---多态、内部类、异常、包

------Java培训.Android培训.iOS培训..Net培训.期待与您交流! ------- 一.多态 多态(Polymorphism)按字面的意思就是“多种状态”.在面向对象语言中,接口的多种不同的实现方式即为多态.引用Charlie Calverts对多态的描述——多态性是允许你将父对象设置成为和一个或更多的他的子对象相等的技术,赋值之后,父对象就可以根据当前赋值给它的子对象的特性以不同的方式运作.简单的说,就是一句话:允许将子类类型的对象赋值给父类类型的引用. 猫这个对象对应的类

黑马程序员——java基础--多态

------Java培训.Android培训.iOS培训..Net培训.期待与您交流! ------- 模板方法设计模式: 解决的办法:当功能内部一部分是现实确定,一部分是现实不确定的,这时间不可把不确定的部分暴漏出去,让子类实现. 实例:统计一个程序的的运行时间 思路:程序的结束时间减去程序的开始时间 abstract class Gettime{ public final void getTime(){//这段功能用final限制 long start = System.currentTim

黑马程序员-Java面向对象上《二》

                         ------- android培训.java培训.期待与您交流! ---------- 1.面向对象的设计思想  面向过程:是以一个流程为单位,考虑它的实现方法,关心的是它的功能实现. 面向对象:是以具体事物为单位,考虑它的属性(特征)和动作(行为). 2.面向对象思考问题的方式 有哪些对象? 对象有什么特征和功能? 对象之间的关系? 3.类和对象 3.1,面向对象的编程思想:是力图使计算机语言中对事物的描述尽可能的与现实中的该事物的本来面目一致