Java第八课. 面向对象特征3-多态&抽象类
回顾
1. toString ( ) : 返回对象信息;
打印: syso ( 对象名. toString ( ) ) ; toString ( ) 可以省略, syso ( 对象名) ;
2. 继承: 关键字 [ extends ]
子类继承父类的的特征和行为( 公共的特征和行为) ; 构造方法不不能被继承;
extends 继承; 扩展
子类可以扩展父类 子类可以包含自己的特殊部分
3. 重写( 覆写) : 发生在继承父类的子类中, 在子类的某个方法, 方法的修饰符, 返回值类型, 方法名, 参数列表和父类的某个方法完全一样; ( Object 是所有类的父类)
4. 构造方法和继承: 在子类对象实例化的时候, 因为继承的原因会默认先调用父类的无参构造, 再调用子类的构造方法;
5. super 关键字: 子类可以用来调用父类的构造方法和普通方法; 调用构造方法时要放第一行, 普通方法时没有要求;
在调用构造方法时 this 和 super 不能同时使用;
1. 多态性
1.1 多态的引入
模拟课堂上课: 小张( JavaTeacher) 来了, 我们开始上正经的java课程; 小李( Driver) 来了, 我们就开始开车; 小王( OldDriver) 来了, 我们就上职业素养课, 飙车;
步骤1 : 先创建父类Teacher
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 ( ) {
super . teach ( ) ;
System. out. println ( "我们开始上正经的java课程" ) ;
}
}
public class Driver extends Teacher {
@Override
public void teach ( ) {
super . teach ( ) ;
System. out. println ( "我们就开始开车" ) ;
}
}
public class OldDriver extends Teacher {
@Override
public void 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) ;
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 ( ) 方法中进行测试
public class Instrument {
private String name;
public String getName ( ) {
return name;
}
public void setName ( String name) {
this . name = name;
}
public void play ( ) {
System. out. println ( "开始演奏:" + name) ;
}
}
public class Piano extends Instrument {
@Override
public void play ( ) {
super . play ( ) ;
System. out. println ( getName ( ) + "朵蕾咪发~" ) ;
}
}
public class Violin extends Instrument {
@Override
public void play ( ) {
super . play ( ) ;
System. out. println ( getName ( ) + "啦啦啦啦啦~" ) ;
}
}
public class InstrumentTest {
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 ( "这是子类特有的方法" ) ;
}
}
public abstract class Square extends Shape {
}
public class TestShape {
public static void main ( String[ ] args) {
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. 抽象方法必须用 public 或 protected 修饰( 因为如果为 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 ( ) ;
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 {
public String testDraw ( Draw draw) {
return draw. drawing ( ) ;
}
public static void main ( String[ ] args) {
TestDraw test= new TestDraw ( ) ;
System. out. println ( test. testDraw ( new Line ( 0 , 0 , "black" , 10 , 20 ) ) ) ;
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]