Java第八课. 面向对象特征3-多态&抽象类

Java第八课. 面向对象特征3-多态&抽象类

回顾

1. toString(): 返回对象信息;  
打印:syso(对象名.toString()); toString()可以省略,syso(对象名);

2.继承: 关键字 [extends]
    子类继承父类的的特征和行为(公共的特征和行为);构造方法不不能被继承;
	extends 继承;扩展
    子类可以扩展父类  子类可以包含自己的特殊部分
        
3.重写(覆写): 发生在继承父类的子类中,在子类的某个方法,方法的修饰符,返回值类型,方法名,参数列表和父类的某个方法完全一样;(Object 是所有类的父类)

4.构造方法和继承: 在子类对象实例化的时候,因为继承的原因会默认先调用父类的无参构造,再调用子类的构造方法;

5.super 关键字: 子类可以用来调用父类的构造方法和普通方法;调用构造方法时要放第一行,普通方法时没有要求;
	在调用构造方法时 thissuper 不能同时使用;

1. 多态性

1.1 多态的引入
模拟课堂上课:小张(JavaTeacher)来了,我们开始上正经的java课程;小李(Driver)来了,我们就开始开车;小王(OldDriver)来了,我们就上职业素养课,飙车;
步骤1:先创建父类Teacher
/**
 * 创建一个父类
 * @author Administrator
 *
 */
public class Teacher {
	private String name;

	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}
	
	public void teach() {
		System.out.println(name+"来了");
	}
	
}
步骤2:再创建Teacher的各个子类
public class JavaTeacher extends Teacher {

	@Override
	public void teach() {
		//调用父类的teach方法
		super.teach();
		//自己内部的部分
		System.out.println("我们开始上正经的java课程");
	}
}

public class Driver extends Teacher {

	@Override
	public void teach() {
		//调用父类的teach方法
		super.teach();
		//自己内部的部分
		System.out.println("我们就开始开车");
	}
}

public class OldDriver extends Teacher {

	@Override
	public void teach() {
		//调用父类的teach方法
		super.teach();
		//自己内部的部分
		System.out.println("我们就上职业素养课,飙车");
	}
}
步骤3:创建一个教室,声明一个上课的方法,这个方法指定特定的老师来上课
public class Classroom {
	//给这个班级派老师过来上课 
	public void showLesson(JavaTeacher javaTeacher) {
		javaTeacher.teach();
	}

	//给这个班级派老师过来上课
	public void showLesson(Driver driver) {
		driver.teach();
	}

	//给这个班级派老师过来上课 
	public void showLesson(OldDriver oldDriver) {
		oldDriver.teach();
	}

}
步骤4:测试
public class TestClassroom {

	public static void main(String[] args) {
		//先创建教室
		Classroom classroom=new Classroom();
		//再派老师上课
		JavaTeacher javaTeacher=new JavaTeacher();
		javaTeacher.setName("小张");
		//执行上课的方法
		classroom.showLesson(javaTeacher);//javaTeacher:实际参数->实参
		
		Driver driver=new Driver();
		driver.setName("小李");
		classroom.showLesson(driver);
		
		
		OldDriver oldDriver=new OldDriver();
		oldDriver.setName("小王");
		classroom.showLesson(oldDriver);

	}
    
}

小张来了
我们开始上正经的java课程
小李来了
我们就开始开车
小王来了
我们就上职业素养课,飙车
[问题]:
每增加一个老师,这个类中就要多一个方法;
public class TestClassroom {
    public void showLesson(JavaTeacher javaTeacher) {
		javaTeacher.teach();
	}
}
[改进]:
将父类作为一个方法的参数,定义方法的时候,并不确定这个参数的实际对象;[因为前面3种老师都是Teacher的子类,就可以把形式参数改成父类的引用,然后再调用的时候将子类的对象作为实参传进去];
public void showLesson(Teacher teacher) {//形式参数->形参
		teacher.teach();
	}

在这里插入图片描述

对于不同的对象,JavaTeacher的对象和Driver的对象,OldDriver的对象;执行的过程和结果可能是不同的;[这就是多态]
1.2 多态性定义
Java中多态性指允许不同类的对象对同一消息做出响应。即同一消息可以
根据发送对象的不同而采用多种不同的行为方式
• 发送消息就是方法调用;
• 现实中,关于多态的例子不胜枚举。比方说按下 F1 键这个动作,如果当前在IE界面下弹出的浏览器的帮助文档;如果当前在 Word 下弹出的就是office帮助;在 Windows 下弹出的就是 Windows 帮助和支持
• 可见,同一个事件发生在不同的对象上会产生不同的结果,因此,多态的
主要作用适用于[消除类型之间的耦合关系];
1.3 多态实现方式1-使用继承
也是我们[面向对象的特征之一]
    
概念:多态是同一个方法具有多个不同的表现形态。
多态其实就是同一个父类(接口)的引用,使用不同的子类(实现类)而执行不同的操作。
    
操作步骤:创建父类, 创建子类, 重写父类的方法;特定的场景中,将父类作为形式参数,实际参数为子类,执行的过程和结果和子类对象有关;
不同的对象,对于同一个方法执行过程和响应是不同的.
1.4 练习
乐器(Instrument)分为:钢琴(Piano),小提琴(Violin)
各种乐器的弹奏(play)方法各不相同。
编写一个测试类InstrumentTest,要求:
编写方法testPlay,对各种乐器进行弹奏测试,要依据乐器的不同,进行相应的弹奏。
在main()方法中进行测试
/**
 * 自定义一个乐器类(父类)
 * @author Administrator
 *
 */
public class Instrument {
	private String name;

	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}
	
	/**
	 * 父类的play
	 */
	public void play() {
		System.out.println("开始演奏:"+name);
	}
	
}
/**
 * 自定义一个子类
 * @author Administrator
 *
 */
public class Piano extends Instrument {

	@Override
	public void play() {
		super.play();
		System.out.println(getName()+"朵蕾咪发~");
	}
}

/**
 * 自定义一个子类
 * @author Administrator
 *
 */
public class Violin extends Instrument {

	@Override
	public void play() {
		super.play();
		System.out.println(getName()+"啦啦啦啦啦~");
	}
}
public class InstrumentTest {
	//编写方法testPlay,对各种乐器进行弹奏测试,要依据乐器的不同,进行相应的弹奏。
	public void testPlay(Instrument ins) {//多态的体现
		ins.play();
	}

	public static void main(String[] args) {
		InstrumentTest test=new	InstrumentTest();
		Piano piano=new Piano();
		piano.setName("钢琴");
		test.testPlay(piano);
		
		Violin violin=new Violin();
		violin.setName("小提琴");
		test.testPlay(violin);

	}

}

开始演奏:钢琴
钢琴朵蕾咪发~
开始演奏:小提琴
小提琴啦啦啦啦啦~
1.5 多态总结:
• 可替换性(substitutability)
	• 多态对已存在代码具有可替换性;
• 可扩充性(extensibility)
	• 多态对代码具有可扩充性。增加新的子类不影响已存在类的多态性、继	 承性,以及其他特性的运行和操作。实际上新加子类更容易获得多态功能;
• 接口性(interface-ability)
	• 多态是超类通过方法签名,向子类提供了一个共同接口,由子类来完善	 或者覆盖它而实现的;
• 灵活性(flexibility)
	• 它在应用中体现了灵活多样的操作,提高了使用效率;
• 简化性(simplicity)
	• 多态简化对应用软件的代码编写和修改过程,尤其在处理大量对象的运	 算和操作时,这个特点尤为突出和重要;

2. 抽象类与抽象方法

2.1 抽象类
存在一个类,这个类不太好描述,但是确实是一个类;通常一个类中会有属性和方法 ;而这种类内部的方法又不太好实现;

[引入例子]:形状是否能定义成一个类,如果可以请问该类可以拥有什么属性和方法?边长?求面积的方法? 子类:圆形:R 矩形:w h
    
[出现问题]:如果将形状设置为父类,此时其实没有共同的属性;

[解决问题]:可以将这个类变成抽象;
[概念]:
在面向对象的概念中,所有的对象都是通过类来描绘,但是反过来,并不是所有的类都是用来描绘对象的。
    
[如果一个类中没有包含足够的信息来描绘一个具体的对象,这样的类就是抽象类]。
    
基本结构: 
abstract class  类名{} 
public abstract class Shape {
	/**
	 * 求面积
	 * 这个方法应该没有办法实现,所以没有方法体,但是这样写语法又是错误
	 */
	public abstract void getArea() ;//没有方法体
	public abstract void getLength() ;
	public void test() {
		System.out.println("普通方法");
	}
	
}
public class Circle extends Shape{
	private double r;

	public double getR() {
		return r;
	}

	public void setR(double r) {
		this.r = r;
	}

	@Override
	public void getArea() {
		//计算面积
		System.out.println("圆的面积:"+(Math.PI*r*r));
	}

	@Override
	public void getLength() {
		//计算周长
		System.out.println("圆的周长:"+(Math.PI*r*2));
	}
 
	public void testCircle() {
		System.out.println("这是子类特有的方法");
	}
}
/**
 * 如果一个类继承了一个抽象类,那么必须首先重写这个类的所有抽象方法?对不对
 * 这种说法不准确,因为还可以继承抽象,让下一代去做
 * @author Administrator
 *
 */
public abstract class Square extends Shape{
 
}
public class TestShape {

	public static void main(String[] args) {
		//抽象类不能直接实例化
		//1.父类  引用名=父类对象???  X
		//Shape shape=new Shape();
		//2.子类  引用名=子类对象
		Circle circle=new Circle();

		circle.setR(2.5);
		circle.getArea();//自己做实现
		circle.test();//从父类继承过来的
        
圆的面积:19.634954084936208
普通方法
抽象类能否包含普通方法? [可以 反之不行];
如果某个类中包含抽象方法,那么这个类就必须定义成抽象类;
(有抽象方法一定是抽象类,但抽象类不一定只有抽象方法)

抽象类的普通方法,子类能不能继承?   [可以]
2.2 抽象类和抽象方法的特点
①抽象方法:被 abstract 修饰的方法就是抽象方法,没有方法体。{}

②抽象类:一个类中如果有至少1个抽象方法,那么这么类必须也是抽象类,抽象类中也可以包含普通方法。
    
③抽象类不能直接实例化,只可以被继承,如果一个类继承了抽象类,需要重写抽象类中的所有抽象方法(如果不想重写可以把这个子类设置成抽象类)

在这里插入图片描述

④抽象类中有构造方法,但是不能被 abstract 修饰(被修饰了就必须要重写,但构造方法不能被继承),因为子类构造的时候需要调用父类的构造方法。
2.3 对象向上造型
[向上转型]:父类的引用指向子类对象
    
	父类 引用名=new 子类()
    
	//父类 引用名=子类对象
    Shape s=new Circle();//向上转型 父类引用指向子类对象 
    s.test();
    circle.testCircle();
    
	普通方法
	这是子类特有的方法
        
[注意]:
只能调用["父类的所有属性和方法+子类和父类共有的属性和方法"],对于["只存在子类中的方法或属性"]无法调用;
2.4 抽象类的作用
为什么要用抽象类:
分析,设计,定规则规范;A(分配 告诉大家要做什么 设计, 不做具体实现) B(要做具体实现) C(要做具体实现).实现之前做一个标准->定规范->抽象类;
2.5【面试题】普通类和抽象类的区别
1. 普通类中不能包含抽象方法,但抽象方法中可以包含普通方法;一个类中有抽象方法存在就会被定义为抽象方法;
2. 抽象方法必须用 publicprotected 修饰(因为如果为 private 则子类无法继承,也就无法重写该方法);
4. 普通类可以实例化对象,抽象类则不可以直接实例化;
5. 如果一个类继承抽象类,则需要实现父类的抽象方法;如果子类没有实现父类的抽象方法,则必须将子类也定义为 abstract;
2.6练习:

在这里插入图片描述

public abstract class Draw {
	private int x;
	private int y;
	private String color;
    
	public int getX() {
		return x;
	}
	public void setX(int x) {
		this.x = x;
	}
	public int getY() {
		return y;
	}
	public void setY(int y) {
		this.y = y;
	}
	public String getColor() {
		return color;
	}
	public void setColor(String color) {
		this.color = color;
	}
	/**
	 * 绘制方法(抽象方法)
	 */
	public abstract String  drawing();
	
	/**
	 * 有参构造->创建对象时直接对属性赋值
	 * @param x
	 * @param y
	 * @param color
	 */
	public Draw(int x, int y, String color) {
		super();
		this.x = x;
		this.y = y;
		this.color = color;
	}
    //父类无参构造
	public Draw() {
        
	}
	
}
public class Line extends Draw {
	private int endX;
	private int endY;

	public int getEndX() {
		return endX;
	}
	public void setEndX(int endX) {
		this.endX = endX;
	}
	public int getEndY() {
		return endY;
	}
	public void setEndY(int endY) {
		this.endY = endY;
	}
	
    //重写父类抽象方法
	@Override
	public String drawing() {
		
		return "线条的绘制功能 [endX=" + endX + ", endY=" + endY + ", X=" + getX() + ", Y=" + getY() + ", Color="
				+ getColor() + "]";
	}

    //子类有参构造
	public Line(int x, int y, String color, int endX, int endY) {
		
		super(x, y, color);
		this.endX = endX;
		this.endY = endY;
	}
	
}
public class Rectangle extends Draw{
	private int width;
	private int height;
	
	public int getWidth() {
		return width;
	}
	public void setWidth(int width) {
		this.width = width;
	}
	public int getHeight() {
		return height;
	}
	public void setHeight(int height) {
		this.height = height;
	}

    //重写父类抽象方法
	@Override
	public String drawing() {
		
		return "矩形的绘制功能: [width=" + width + ", height=" + height + ", X=" + getX() + ", Y=" + getY()
		+ ", Color=" + getColor() + "]";
	}

    //子类有参构造
	public Rectangle(int x, int y, String color, int width, int height) {
		super(x, y, color);
		this.width = width;
		this.height = height;
	}

}
public class TestDraw {

	/**
	 * 多态
	 * @param draw 数据类型->父类 父引用
	 */
	public String testDraw(Draw draw) {
		return draw.drawing();//因为子类方法里用的时return返回值,所以也要用return
	}
	
	public static void main(String[] args) {
		TestDraw test=	new TestDraw();
		//String line=test.testDraw(new Line(0,0, "black", 10, 20));
		//System.out.println(line);
 
		System.out.println(test.testDraw(new Line(0,0, "black", 10, 20)));//等价于下面这两句
		/*Line line=new Line(0,0, "black", 10, 20);
		System.out.println(test.testDraw(line)); */
		
		System.out.println(test.testDraw(new Rectangle(0, 0, "red", 80, 90)));
	}

}

线条的绘制功能 [endX=10, endY=20, X=0, Y=0, Color=black]
矩形的绘制功能: [width=80, height=90, X=0, Y=0, Color=red]
  • 3
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值