目录
[1. 概念](#1. 概念)
[2. 格式](#2. 格式)
[3. 案例演示](#3. 案例演示)
[1. 成员变量的访问](#1. 成员变量的访问)
[2. 成员方法的访问](#2. 成员方法的访问)
[3. 对比(总结)](#3. 对比(总结))
[1. 类转换异常](#1. 类转换异常)
[2. Instanceof](#2. Instanceof)
一:认识
1. 概念
面向对象的三大特征:封装,继承,多态。多态的前提是 extends 继承 或 implements 实现;
多态性指一个对象的多种形态。是对于对象而言的,与类无关;
2. 格式
继承:父类名称 对象名= new 子类名称( );
实现:接口名称 对象名 = new 实现类名称( );
【即 左父右子】
3. 案例演示
定义一个 Animal类,然后定义一个 Cat类,最后定义一个测试类:
我们定义一个AnimalClass类,CatClass类,还有一个测试类,通过向上转型来访问父类的 eat方法。
java
public class AnimalClass {
String name;//姓名
int age;//年龄
public void eat(){//普通方法
System.out.println("吃饭饭");
}
}
java
public class CatClass extends AnimalClass{
public void sleep(){
System.out.println("爱睡觉");
}
}
java
public class Demo {
public static void main(String[] args) {
//左侧父类引用指向右侧子类对象
AnimalClass a=new CatClass();
a.eat();
}
}
java
C:\Java\jdk-17.0.11\bin\java.exe "-javaagent:C:\Program Files\JetBrains\IntelliJ IDEA 2022.1.3\lib\idea_rt.jar=2815:C:\Program Files\JetBrains\IntelliJ IDEA 2022.1.3\bin" -Dfile.encoding=UTF-8 -classpath C:\Test\classDemo\out\production\classDemo Multi01.Demo
吃饭饭
进程已结束,退出代码0
二:访问特点
1. 成员变量的访问
直接访问:直接通过对象名称访问成员变量,等号左边是谁, 就优先用谁,没有往上找;
间接访问:通过成员方法间接访问成员变量,**成员方法属于谁,**就优先用谁,没有往上找;
案例演示:
我们定义一个父类:AnimalClass , 定义一个子类:CatClass , 再定义一个测试类:Demo ;
测试类中对成员变量分别直接/间接访问;
另外,父类子类中的成员方法重名,子类优先调用自己的成员方法,若没有,再往上找,调用父类的;
java
package Multi01;
public class AnimalClass {
int age=66;//年龄
public void show(){//普通方法
System.out.println(age);
}
}
java
package Multi01;
public class CatClass extends AnimalClass{
int age=100;
public void show(){
System.out.println(age);
}
}
java
package Multi01;
public class Demo {
public static void main(String[] args) {
//左侧父类引用指向右侧子类对象
AnimalClass a=new CatClass();
System.out.println(a.age);//直接访问成员变量
System.out.println("=========");
a.show();//间接通过方法访问成员变量
}
}
java
C:\Java\jdk-17.0.11\bin\java.exe "-javaagent:C:\Program Files\JetBrains\IntelliJ IDEA 2022.1.3\lib\idea_rt.jar=2334:C:\Program Files\JetBrains\IntelliJ IDEA 2022.1.3\bin" -Dfile.encoding=UTF-8 -classpath C:\Test\classDemo\out\production\classDemo Multi01.Demo
66
=========
100
进程已结束,退出代码0
2. 成员方法的访问
看 new 的是谁,就优先用谁里面的方法,没有,往上找;
即对于成员方法来说:编译看左边,运行看右边;(没有往上找)
编译是指源文件转换为字节码文件的过程,运行是指执行字节码文件的过程;
我们定义一个父类:Man,定义一个子类:Child, 再定义一个测试类DemoMan.
java
public class Man {
String name; //成员变量
public void show(){ //成员方法
System.out.println(name);
}
public void play(){ //成员方法
System.out.println("这是父类的方法!");
}
}
java
package Multi01;
public class Child extends Man{
String name="刘备备";
public void show(){ //成员方法
System.out.println(name);
}
public void sleep(){
System.out.println("这是子类的方法");
}
}
java
package Multi01;
public class DemoMan {
public static void main(String[] args) {
Man m=new Child();//多态
//成员方法的调用:编译看左边,执行看右边,没有往上找
m.show();//子类中的show方法
m.play();//往上找到父类的成员方法
}
}
java
C:\Java\jdk-17.0.11\bin\java.exe "-javaagent:C:\Program Files\JetBrains\IntelliJ IDEA 2022.1.3\lib\idea_rt.jar=2780:C:\Program Files\JetBrains\IntelliJ IDEA 2022.1.3\bin" -Dfile.encoding=UTF-8 -classpath C:\Test\classDemo\out\production\classDemo Multi01.DemoMan
刘备备
这是父类的方法!
进程已结束,退出代码0
3. 对比(总结)
成员变量:编译看左边,执行看左边;
成员方法:编译看左边,运行看右边:
(图片为转载,非本人绘制)
三:向上转型
含义:把右侧的 "new 子类名( )"当作父类来使用;
格式:父类名 对象名 = **new 子类名( ),**就是多态的格式。
向上转型一定是安全的,是从小范围到大范围。类似于数据类型的自动类型转换;
其实咱们前面提到的多态都是向上转型的,这里就不提供代码进行举例;
四:向下转型
含义:将父类对象还原成为本来的子类对象;
格式:子类名 子类对象 = (子类名)父类对象 ;
我们定义一个父类 Man,一个子类 Child ,一个测试类DemoMan,将猫向上转型扩大范围当作动物来访问动物中的show,play方法;为了访问猫本身特有的方法,我们将其向下转型还原为本身来访问pure方法;
java
public class Man {
String name; //成员变量
public void show(){ //成员方法
System.out.println(name);
}
public void play(){ //成员方法
System.out.println("这是父类的方法!");
}
}
java
package Multi01;
public class Child extends Man{
String name="刘备备";
public void show(){ //成员方法
System.out.println(name);
}
public void pure(){
System.out.println("小孩子天真又可爱");
}
}
java
package Multi01;
public class DemoMan {
public static void main(String[] args) {
Man m=new Child(); //向上转型,孩子扩大范围为man
//成员方法的调用:编译看左边,执行看右边,没有往上找
m.show();//编译左边成功,执行右边子类中的show方法
m.play();//编译左边成功,执行右边子类中的pay,没有往上找
Child c=(Child) m;//向下转型,还原为Child本身
c.pure();//调用本类特有的方法
}
}
1. 类转换异常
但是,如果对象创建的时候不是猫,非要向下转型为猫,那么编译器不会报错,但会显示异常( 类转换异常:java.lang.ClassCastException );
java
package Multi01;
public class DemoMan {
public static void main(String[] args) {
Man m=new Child(); //向上转型,孩子扩大范围为man
//成员方法的调用:编译看左边,执行看右边,没有往上找
m.show();//编译左边成功,执行右边子类中的show方法
m.play();//编译左边成功,执行右边子类中的pay,没有往上找
Child c=(Child) m;//向下转型,还原为Child本身
c.pure();//调用本类特有的方法
System.out.println("========");
Dog d=(Dog) m;//编译不会报错,但会出现异常
}
}
java
C:\Java\jdk-17.0.11\bin\java.exe "-javaagent:C:\Program Files\JetBrains\IntelliJ IDEA 2022.1.3\lib\idea_rt.jar=4577:C:\Program Files\JetBrains\IntelliJ IDEA 2022.1.3\bin" -Dfile.encoding=UTF-8 -classpath C:\Test\classDemo\out\production\classDemo Multi01.DemoMan
刘备备
这是父类的方法!
小孩子天真又可爱
========
Exception in thread "main" java.lang.ClassCastException: class Multi01.Child cannot be cast to class Multi01.Dog (Multi01.Child and Multi01.Dog are in unnamed module of loader 'app')
at Multi01.DemoMan.main(DemoMan.java:12)
进程已结束,退出代码1
2. Instanceof
那么,我们怎么确定一个父类引用的对象,原本是哪一个类呢?
在向下转型的时候,我们可以使用 Instanceof 借助 if...else... 语句先判断父类引用的对象原来是哪个类的,再进行下面的操作;
格式 :if ( 父类对象 instangceof子类名 ) {
向下转型;
方法体;
}
java
package Multi01;
public class DemoMan {
public static void main(String[] args) {
Man m=new Child(); //向上转型,孩子扩大范围为man
//成员方法的调用:编译看左边,执行看右边,没有往上找
m.show();//编译左边成功,执行右边子类中的show方法
m.play();//编译左边成功,执行右边子类中的pay,没有往上找
if(m instanceof Child){
Child c=(Child) m;//向下转型,还原为Child本身
c.pure();//调用本类特有的方法
System.out.println("========");
}
if(m instanceof Dog){
Dog d=(Dog) m;//编译不会报错,但会出现异常
}
}
}
五:多态的好处
多态的好处就是向上转型时,等号左边都是 " 父类名 对象名 " ,对象名的类型都是父
类,不需要根据子类对象来 " 类名 对象名 = new 类名 " 创建,使用时更加灵活;
(图片为转载,非本人绘制)
六:总结
在我看来,向上转型就是把一个子类进行放大成父类使用,向下转型就是把一个类还原
为它本身进行使用。比如,父类为 Animal,子类为 Dog,向上转型就是把 Dog 当作
Amimal 使用 ,向下转型就是把 Dog 还原为 Dog ,以便访问其特有的方法;