[Java][华为云Java编程创造营][学习笔记][第二阶段][03_Java面向对象之多态]

网友投稿 450 2022-05-28

1,方法重写

1.1,子类和父类同名方法

1.1.1,子类和父类同名方法

子类和父类同名方法,方法重写

前提:需要有继承关系

方法重写表现:(方法名必须相同;参数列表必须相同;返回值类型必须相同;修饰符:范围可以扩大或相同,但是不能缩小public>protected>default)

1.1.2,方法重写

class Animal { public void eat() { System.out.println("动物在吃东西"); } } class Cat extends Animal { @Override public void eat() { System.out.println("猫吃鱼"); } } class Dog extends Animal { @Override public void eat() { System.out.println("狗吃肉"); } } public class Test { public static void main(String[] args) { /* * 输出结果 * 动物在吃东西 猫吃鱼 狗吃肉 * */ Animal animal = new Animal(); animal.eat(); //输出动物类eat()方法 Animal cat = new Cat(); cat.eat(); //输出猫类eat()方法 Animal dog = new Dog(); dog.eat(); //输出狗类eat()方法 } }

不能重写父类的private方法,如果定义的话只是定义了一个新方法,不是方法重写

class Animal { private void talk() { System.out.println("动物在说"); } } class Cat extends Animal { void talk() { System.out.println("猫在喵喵叫"); } } public class Test { public static void main(String[] args) { Animal animal = new Animal(); //方法不可见 //animal.talk(); //报错:'talk()' has private access in 'com.huawei.demo2.Animal' Cat cat = new Cat(); //父类指向子类,向上转型 Animal animal1 = cat; //方法不可见,说明talk()方法没有被子类重写 //animal1.talk(); //报错:'talk()' has private access in 'com.huawei.demo2.Animal' cat.talk(); //猫在喵喵叫` } }

1.1.3,运行时多态

如果被调用的方法在编译期无法被确定下来,

只能够在程序运行期间根据实际的类型绑定相关的方法,这种绑定方法也被称为后期绑定。

方法重写是根据实际的类型决定调用哪个重写的方法,发生在运行期间,也叫做运行时多态。

class Animal { public void eat() { System.out.println("动物吃东西"); } } class Cat extends Animal { @Override public void eat() { System.out.println("猫吃鱼"); } } class Dog extends Animal { @Override public void eat() { System.out.println("狗吃肉"); } } public class Test { public static void main(String[] args) { Animal animal = new Cat(); animal.eat(); //猫吃鱼 } }

1.2,static修饰同名方法

子类和父类static修饰的同名方法

static修饰的方法是静态方法,也叫做类方法

使用private或static或final修饰的变量或方法,是早期绑定

class Animal { static void eat() { System.out.println("动物吃东西"); } } class Cat extends Animal { static void eat() { System.out.println("猫吃鱼"); } } public class Test { public static void main(String[] args) { Animal animal = new Cat(); //animal.eat(); //报错:Static member 'com.huawei.demo4.Animal.eat()' accessed via instance reference } }

1.3,解耦合

1.3.1,动态绑定和解耦合简介

在运动时根据具体对象的类型进行绑定,也就是后期绑定。

解耦合,字面意思就是解除耦合关系。

尽可能减少代码耦合,如果发现代码耦合,就要采取解耦技术。

数据模型,业务逻辑和视图显示三层之间彼此降低耦合。

1.4,同名变量

class Father { int a = 1; static int b = 1; Father() { a = 10; b = 10; } } public class Son extends Father { int a = 2; static int b = 2; Son() { a = 20; b = 20; } public static void main(String[] args) { Son son = new Son(); Father father = son; System.out.println("father.a=" + father.a + ",father.b=" + father.b); //father.a=10,father.b=10 System.out.println("son.a" + son.a + ",son.b=" + son.b); //son.a20,son.b=20 } }

1.5,方法重载和方法重写区别

多态的具体表现

2,抽象类

2.1,抽象类的定义

动物Animal都有自己的行为,小鸟和老虎继承了动物的行为,但小鸟和老虎的行动方式不一样。在动物类中能给出行动的具体实现吗?

使用abstract关键字修饰的方法叫做抽象方法,抽象方法没有方法体。当一个类中包含了抽象方法,那么该类也必须使用abstract关键字来修饰,这种使用abstract关键字修饰的类就是抽象类。

抽象类及抽象方法定义的语法格式

/** * [修饰符] abstract class 类名 * { * //定义抽象方法 * [修饰符] abstract 方法返回值类型 方法名([参数列表]); * //其他方法或属性 * } * */

2.2,抽象类的作用

抽象类的作用类似于"模板",其目的是方便开发人员根据抽象类的格式来修改和创建新类。

抽象类主要用于继承,有利于程序的扩展。

abstract class Book { abstract String getAuthor(); } class ComputerBook extends Book { String getAuthor() { return "Java之父詹姆斯高斯林 James Gosling"; } } class EnglishBook extends Book { String getAuthor() { return "Tom"; } }

1,抽象类不能创建对象,如果创建,编译无法通过而报错,只能创建其非抽象子类的对象。

2,抽象类中,可以有构造器,是供子类创建对象时,初始化父类成员使用的。

3,抽象类中,不一定包含抽象方法,但是有抽象方法的类必定是抽象类。

4,抽象类的子类,必须重写抽象父类中所有的抽象方法,否则子类也必须定义成抽象类,不然编译无法通过而报错。

5,抽象类中的抽象方法不能用private,final,static修饰。

6,抽象类存在的意义是为了被子类继承,抽象类体现的是模板思想。

2.3,抽象类设计和场景

我们现在使用抽象类设计一个模板模式的应用

场景:

新司机:开门,点火,双手紧握方向盘,刹车,熄火

老司机:开门,点火,右手握方向盘左手抽烟,刹车,熄火

abstract class Driver { void go() { System.out.println("开门"); System.out.println("点火"); //将开车姿势设置为抽象类以提供模板 posture(); System.out.println("刹车"); System.out.println("熄火"); } abstract void posture(); } class NewDriver extends Driver { @Override void posture() { System.out.println("新司机双手紧握方向盘"); } } class OldDriver extends Driver { @Override void posture() { System.out.println("老司机右手握方向盘左手点烟"); } } public class DriverTest { public static void main(String[] args) { NewDriver newDriver = new NewDriver(); newDriver.go(); /*开门 点火 新司机双手紧握方向盘 刹车 熄火 */ OldDriver oldDriver = new OldDriver(); oldDriver.go(); /*开门 点火 老司机右手握方向盘左手点烟 刹车 熄火 */ } }

3,接口

3.1,接口的定义

接口就是某个事物对外提供的一些功能的声明。

可以利用接口实现多态,同时接口也弥补了Java单一继承的弱点

使用interface关键字定义接口

3.2,接口的特点和作用

接口允许多继承。

接口没有构造方法。

接口中的属性默认是用public static final修饰的。

接口中的方法默认使用public abstract修饰的。

接口继承接口用extends,不能implement。

public interface MyInterface { //设计接口和设计类有什么区别 //属性 public static final String STR = "my interface"; //接口中的属性默认就是final //接口中的属性一般设置为 public static final 修饰的常量 //方法 //接口中不能有构造方法 //MyInterface(){} //报错:Interface abstract methods cannot have body public void test(); public void test2(); //在JDK1.8之前接口中的方法都是抽象方法 }

在接口内部可以定义多个常量和抽象方法,定义常量时必须进行初始化赋值,定义默认方法和静态方法时,可以有方法体。

在接口中定义常量时,可以省略"public static final"修饰符,接口会默认为常量添加"public static final"修饰符。与此类似,在接口中定义抽象方法时,也可以省略"public abstract"

修饰符,定义default默认方法和static静态方法时,可以省略"public"修饰符,这些修饰符系统都会默认进行添加。

/** * [修饰符] interface 接口名 [extends 父接口1,父接口2,...] * { * [public] [static] [final] 常量类型 常量名 = 常量值; * [public] [abstract] 方法返回值类型 方法名([参数列表]); * [public] default 方法返回值类型 方法名([参数列表]) * { * //默认方法的方法体 * } * [public] static 方法返回值类型 方法名([参数列表]) * { * //类方法的方法体 * } * } * */

public interface MyInterface { //JDK1.8之后的新特征 //接口中可以定义默认方法(可以有多个),有方法体 default String showStr() { System.out.println("MyInterface 中的默认方法:showStr"); return STR; } default String showStr2() { System.out.println("MyInterface 中的默认方法:showStr2"); return STR; } //接口中可以定义静态方法,有方法体 static void showInfo() { System.out.println("MyInterface 中的静态方法:showInfo"); } static void showInfo2() { System.out.println("MyInterface 中的静态方法:showInfo2"); } }

接口代表一种能力,例如:“做这项工作需要一个程序员”。(程序员是一种能力,不关心具体是谁)

接口是一种能力(体现在接口的方法上)。

面向接口编程(关心实现类有何能力,而不关心实现细节;面向接口的约定而不考虑接口的具体实现)

1,从JDK8开始,接口中的方法除了包含抽象方法外,还包含默认方法和静态方法,默认方法和静态方法都可以有方法体,并且静态方法可以通过"接口.方法名"来调用。

2,当一个类实现接口时,如果这个类是抽象类,只需实现接口中的部分抽象方法即可,否则需要实现接口中的所有抽象方法。

3,一个类可以通过implements关键字同时实现多个接口,被实现的多个接口之间要用英文逗号隔开。

4,接口之间可以通过extends关键字实现继承,并且一个接口可以同时继承多个接口,接口之间用英文逗号隔开。

5,一个类在继承一个类的同时还可以实现接口,此时,extends关键字必须位于implements关键字之前。

3.3,接口的设计和使用场景

面向接口编程例子

需求:开发打印机

墨盒:黑白,彩色

纸张类型:A4,B5

墨盒和纸张都不是打印机厂商提供的

打印机厂商要兼容市场上的墨盒和纸张

输出结果:使用黑白墨盒在A4纸打印;使用彩色墨盒在B5纸打印;使用彩色墨盒在A4纸打印

//墨盒 public interface ColorBox { void useColor(); } public class BlackWhileBox implements ColorBox { @Override public void useColor() { System.out.print("使用黑白墨盒"); } } public class ColorfulBox implements ColorBox { @Override public void useColor() { System.out.print("使用彩色墨盒"); } } //纸张 public interface PaperSize { void usePaperSize(); } public class PaperA4 implements PaperSize { @Override public void usePaperSize() { System.out.print("在A4纸上打印"); } } public class PaperB5 implements PaperSize { @Override public void usePaperSize() { System.out.print("在B5纸上打印"); } } //主方法 public class TestPrinter { public static void main(String[] args) { BlackWhileBox blackWhileBox = new BlackWhileBox(); ColorfulBox colorfulBox = new ColorfulBox(); PaperA4 paperA4 = new PaperA4(); PaperB5 paperB5 = new PaperB5(); blackWhileBox.useColor(); paperA4.usePaperSize(); System.out.println(); // 使用黑白墨盒在A4纸上打印 colorfulBox.useColor(); paperB5.usePaperSize(); System.out.println(); // 使用彩色墨盒在B5纸上打印 colorfulBox.useColor(); paperA4.usePaperSize(); System.out.println(); // 使用彩色墨盒在A4纸上打印 } }

4,接口和抽象类的区别

4.1,抽象类is-a

抽象类的特点

1,抽象类不能创建对象,如果创建,编译无法通过而报错,只能创建其非抽象子类的对象。

2,抽象类中,可以有构造器,是供子类创建对象时,初始化父类成员使用的。

3,抽象类中,不一定包含抽象方法,但是有抽象方法的类必定是抽象类。

4,抽象类的子类,必须重写抽象父类中所有的抽象方法,否则子类也必须定义成抽象类,编译无法通过而报错。

5,抽象类中的抽象方法不能用private,final,static修饰。

6,抽象类存在的意义是为了被子类继承,抽象类体现的是模板思想。

继承与真实世界类似,只要说"猫是哺乳动物",猫的很多属性和行为就不言自明了。

符合 is-a 关系的设计使用继承

继承是代码重用的一种方式,将子类共有的属性和行为放到父类中,子类与父类是is-a关系。

[Java][华为云Java编程创造营][学习笔记][第二阶段][03_Java面向对象之多态]

4.2,接口has-a

下面以一个防盗门的例子来说明 is-a 与 has-a。

//Door public abstract class Door { public abstract void open(); //开门 public abstract void close(); //关门 } //Lock public interface Lock { void lockUp(); //锁 void openLock(); //开锁 } //TheftProofDoor public class TheftProofDoor extends Door implements Lock { //is-a:防盗门是门 //has-a:防盗门有开锁和关锁的功能 @Override public void open() { System.out.println("门打开了"); } @Override public void close() { System.out.println("门关上了"); } @Override public void lockUp() { System.out.println("把门锁上了"); } @Override public void openLock() { System.out.println("把门锁打开了"); } } //DoorTest /* * 实现防盗门功能(防盗门是一个门) * 防盗门有一个锁(上锁,开锁) * is-a的关系 * has-a的关系 * * */ public class DoorTest { public static void main(String[] args) { //创建具体防盗门对象 TheftProofDoor theftProofDoor = new TheftProofDoor(); theftProofDoor.close();//关门 theftProofDoor.lockUp();//锁门 theftProofDoor.openLock();//开锁 theftProofDoor.open();//开门 /* * 输出结果: * 门关上了 * 把门锁上了 * 把门锁打开了 * 门打开了 * */ } }

4.3,猜数字游戏实战

import java.util.Scanner; /* * 需求:编写程序随机生成一个1-10之间的随机数。程序提示用户输入一个数字,不停猜测, * 直到猜对为止,然后输出猜测的数字,和猜测的次数。 * 并且如果没有猜中要提示用户输入的值大了还是小了。 * */ public class GuessNumberDemo { public static void main(String[] args) { Scanner scanner = new Scanner(System.in); System.out.println("请输入一个正数,范围1-10之间:"); int guessNum = (int) (Math.random() * 10 + 1);//[0.0,1.0) int i = 0; while (true) //不知道要猜多少次,要死循环,满足条件结束循环 { System.out.print("猜第" + ++i + "次:"); int result = scanner.nextInt(); //接收用户每次从键盘输入的正数 if (result < guessNum) { System.out.println("小了"); } else if (result > guessNum) { System.out.println("大了"); } else { System.out.println("猜对了"); break; } } } }

Java

版权声明:本文内容由网络用户投稿,版权归原作者所有,本站不拥有其著作权,亦不承担相应法律责任。如果您发现本站中有涉嫌抄袭或描述失实的内容,请联系我们jiasou666@gmail.com 处理,核实后本网站将在24小时内删除侵权内容。

上一篇:复变函数与积分变换(一)学习笔记[复数的概念性质与常见的三角表达式]
下一篇:从二进制文件导入到GaussDB(DWS)
相关文章