Java 多态
多态是同一个行为具有多个不同表现形式或形态的能力。
多态就是同一个接口,使用不同的实例而执行不同操作。
多态的优点
- 消除类型之间的耦合关系
- 可替换性
- 可扩充性
- 接口性
- 灵活性
- 简化性
多态存在的三个必要条件
继承
重写
父类引用指向子类对象
比如:
Parent p = new Child();
当使用多态方式调用方法时,首先检查父类中是否有该方法,如果没有,则编译错误;如果有,再去调用子类的同名方法。
多态的好处:可以使程序有良好的扩展,并可以对所有类的对象进行通用处理。
多态的主要的实现⽅式
▸ 继承和接口
▸ ⽗类和接口类型的变量赋值⼦类对象
▸ 调⽤被override的⽅法
示例代码
以下是 Main.java
package com.company;
import com.company.model.*;
public class Main {
public static void main(String[] args) {
News news = new News("abc", "父类");
FileNews fileNews = new FileNews("abc", "子类");
Video video = new Video();
// 以下这其实就是 多态 。。。。
viewNews(news); // implements 接口
viewNews(video); // implements 接口
viewNews(fileNews); // extends 继承了父类 News 的 接口
Displayable displayable = new Video();
displayable.display();
News new1 = read(new UrlNewsReader(), "path_sample"); //抽象类
News new2 = read(new FileNewsReader(), "path_sample2"); //抽象类
NewsReader newsReader = new UrlNewsReader(); //父类接口类型的变量赋值子类对象
newsReader.readNews("path_simple"); //调用被 override 的方法
}
//使用 继承 抽象类 简化代码!!!
private static News read(NewsReader reader, String path) {
return reader.readNews(path);
}
/////////////////////////////////////////////////////////
// private static News read(UrlNewsReader reader, String path) {
// return reader.readNews(path);
// }
//
// private static News read(FileNewsReader reader, String path) {
// return reader.readNews(path);
// }
///////////////////////////////////////////////////////////////
// 使用 接口 简化代码!!!
private static void viewNews(Displayable item) {
item.display();
System.out.println("news播放完毕");
}
//////////////////////////////////////////////////////////
// private static void viewVodeo(Video video) {
// video.display();
// System.out.println("video播放完毕");
// }
//
// private static void viewLecture(Lecture lecture) {
// lecture.display();
// System.out.println("lecture播放完毕");
// }
///////////////////////////////////////////////////////////
}
抽象类为 NewsReader , FileNewsReader类 和 UrlNewsReader类 均继承于 NewsReader。
以下是 NewsReader.java
package com.company.model;
public abstract class NewsReader {
private Integer x;
public Integer getX() {
return x;
}
public void setX(Integer x) {
this.x = x;
}
public void test() {
}
public News readNews(String path) {
System.out.println("来自父类");
//模拟读取!!!
return null;
}
; //具有这个功能,但是具体的功能实现,在子类中确定!
}
以下是 FileNewsReader.java
package com.company.model;
public class FileNewsReader extends NewsReader {
@Override
public News readNews(String path) {
super.readNews(path);
//从文件读取,解析
System.out.println("File reading ......");
return null;
}
}
以下是 UrlNewsReader.java
package com.company.model;
public class UrlNewsReader extends NewsReader {
@Override
public News readNews(String path) {
super.readNews(path);
//从网络读取,解析
System.out.println("URL reading .........");
return null;
}
}
以下是 接口 Displayable.java
package com.company.model;
public interface Displayable {
void display();
}
News 、 FileNews 、 Lecture 、 Video 均使用了 接口 Displayable
其中
public class FileNews extends News
,
public class News implements Displayable
,
public class Lecture implements Displayable
,
public class Video implements Displayable
,
以下是 News.java
package com.company.model;
public class News implements Displayable {
protected String title;
protected String content;
protected News() {
}
//构造的自由和责任交给用户!!
public News(String title, String content) {
this.title = title;
this.content = content;
}
public String getTitle() {
return title;
}
public String getContent() {
return content;
}
//控制如何显示
@Override
public void display() {
System.out.println(title + "\n" + content);
}
}
以下是 FileNews.java
package com.company.model;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
public class FileNews extends News {
public FileNews(String title, String content) {
super(title, content); //super 要和父类的构造方法一致
}
public FileNews() {
super();
}
//子类 自己的 方法
public void read(String url) {
try {
BufferedReader reader = new BufferedReader(new FileReader(new File(url)));
title = reader.readLine(); //读取title
reader.readLine(); //跳过空行
content = reader.readLine(); //读取content
} catch (java.io.IOException e) {
System.out.println("新闻读取出错");
}
}
//子类 重新实现 父类的 方法
@Override
public void display() {
System.out.println(title + ":" + content);
}
}
以下是 Lecture.java
package com.company.model;
public class Lecture implements Displayable {
@Override
public void display() {
System.out.println("look a lecture");
}
}
以下是 Video.java
package com.company.model;
public class Video implements Displayable {
@Override
public void display() {
System.out.println("playing a movie");
}
}
抽象类
在面向对象的概念中,所有的对象都是通过类来描绘的,但是反过来,并不是所有的类都是用来描绘对象的,如果一个类中没有包含足够的信息来描绘一个具体的对象,这样的类就是抽象类。
抽象类除了不能实例化对象之外,类的其它功能依然存在,成员变量、成员方法和构造方法的访问方式和普通类一样。
由于抽象类不能实例化对象,所以抽象类必须被继承,才能被使用。也是因为这个原因,通常在设计阶段决定要不要设计抽象类。
父类包含了子类集合的常见的方法,但是由于父类本身是抽象的,所以不能使用这些方法。
在Java中抽象类表示的是一种继承关系,一个类只能继承一个抽象类,而一个类却可以实现多个接口。
以下为 抽象类 NewsReader.java
package com.company.model;
public abstract class NewsReader {
private Integer x;
public Integer getX() {
return x;
}
public void setX(Integer x) {
this.x = x;
}
public void test() {
}
public News readNews(String path) {
System.out.println("来自父类");
//模拟读取!!!
return null;
}
; //具有这个功能,但是具体的功能实现,在子类中确定!
}
继承抽象类 FileNewsReader.java 、 UrlNewsReader.java
package com.company.model;
public class FileNewsReader extends NewsReader {
@Override
public News readNews(String path) {
super.readNews(path);
//从文件读取,解析
System.out.println("File reading ......");
return null;
}
}
package com.company.model;
public class UrlNewsReader extends NewsReader {
@Override
public News readNews(String path) {
super.readNews(path);
//从网络读取,解析
System.out.println("URL reading .........");
return null;
}
}
抽象类总结
▸ ⽬的就是⽤于继承之后定义⼦类的类, 必然会⽤于定义⼦类
▸ 抽象类除了不能实例化对象之外,类的其它功能依然存在,成员变量、成员⽅法和
构造⽅法的访问⽅式和普通类⼀样
▸ 由于抽象类不能实例化对象,所以抽象类必须被继承,才能被使⽤
▸ 使⽤修饰符 abstract 声明⼀个类似抽象类, ⼀般具有抽象⽅法: abstract void
method(); 抽象⽅法只有声明, 没有实现
▸ ⼦类继承抽象类之后, 必须实现抽象⽅法, 不然仍然为抽象类, 可以override其他⽅法
▸ static⽅法不能声明为抽象⽅法
▸ is-a 关系!
接口
以下是 接口 Displayable.java
package com.company.model;
public interface Displayable {
void display();
}
通过 implements 使用接口
package com.company.model;
public class News implements Displayable {
protected String title;
protected String content;
protected News() {
}
//构造的自由和责任交给用户!!
public News(String title, String content) {
this.title = title;
this.content = content;
}
public String getTitle() {
return title;
}
public String getContent() {
return content;
}
//控制如何显示
@Override
public void display() {
System.out.println(title + "\n" + content);
}
}
因为
public class FileNews extends News
,public class News implements Displayable
,所以FileNews也可以使用接口 Displayable
package com.company.model;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
public class FileNews extends News {
public FileNews(String title, String content) {
super(title, content); //super 要和父类的构造方法一致
}
public FileNews() {
super();
}
//子类 自己的 方法
public void read(String url) {
try {
BufferedReader reader = new BufferedReader(new FileReader(new File(url)));
title = reader.readLine(); //读取title
reader.readLine(); //跳过空行
content = reader.readLine(); //读取content
} catch (java.io.IOException e) {
System.out.println("新闻读取出错");
}
}
//子类 重新实现 父类的 方法
@Override
public void display() {
System.out.println(title + ":" + content);
}
}
接口小结
接⼝是⼀系列抽象⽅法 (但不需要abstract修饰, 隐式是public abstract)的集合
▸ 语义上表示具有⼀定的特性, ⽐如:
▸ ⾏⾛: 但是没有如何⾏⾛的定义
▸ 显示: 表示可以显示, 但是没有如何显示的定义
▸ 接⼝成员变量只能是 static final的. 因为它不是类, 不能实例化对象, 所以不会有状态,
只有属性
▸ 类通过关键字 implements 表达实现⼀个接⼝, 从⽽声明这个类具有接⼝定义的属性
和⾏为
▸ 类可以实现多个接⼝! 例如表示: ⼀个⽂件即可以显示也可以打印