重庆分公司,新征程启航
为企业提供网站建设、域名注册、服务器等服务
在优锐课架构学习中,了解了关于用多态方法调用将你的大脑包围在Java方法调用周围
成都创新互联云计算的互联网服务提供商,拥有超过13年的服务器租用、托管服务器、云服务器、网络空间、网站系统开发经验,已先后获得国家工业和信息化部颁发的互联网数据中心业务许可证。专业提供云主机、网络空间、域名与空间、VPS主机、云服务器、香港云服务器、免备案服务器等。
根据传说中的Venkat Subramaniam,多态是面向对象编程中最重要的概念。 多态性(或对象根据其类型执行特殊操作的能力)使Java代码具有灵活性。 诸如 四个人帮 之类的设计模式(例如Command,Observer,Decorator,Strategy和许多其他模式)都使用某种形式的多态性。 精通此概念可极大地提高你思考解决编程难题的能力。
Juggy:
public abstract class JavaMascot {
public abstract void executeAction();}public class Duke extends JavaMascot {
@Override
public void executeAction() {
System.out.println("Punch!");
}}public class Juggy extends JavaMascot {
@Override
public void executeAction() {
System.out.println("Fly!");
}}public class JavaMascotTest {
public static void main(String... args) {
JavaMascot dukeMascot = new Duke();
JavaMascot juggyMascot = new Juggy();
dukeMascot.executeAction();
juggyMascot.executeAction();
}}
Punch!Fly!
多态性的接口和继承
借助此Java Challenger,我们将致力于多态性与继承之间的关系。 要记住的主要事情是多态性需要继承或接口实现。 你可以在下面的示例中看到这一点,其中包括Duke和
由于其特定的实现方式,Duke和Juggy的动作都将被执行。
方法是否重载了多态性?
许多程序员对多态与方法重写和方法重载之间的关系感到困惑。 实际上,只有方法重载才是真正的多态性。 重载使用相同的方法名称,但参数不同。 多态性是一个广义术语,因此始终会有关于该主题的讨论。
多态性的目的是什么?
使用多态的最大优点和目的是将客户端类与实现代码分离。 客户端类无需进行硬编码,而是接收实现以执行必要的操作。 这样,客户端类就足够了解执行其动作的知识,这是松耦合的示例。
为了更好地了解多态的目的,请看一下
public abstract class SweetProducer {
public abstract void produceSweet();}public class CakeProducer extends SweetProducer {
@Override
public void produceSweet() {
System.out.println("Cake produced");
}}public class ChocolateProducer extends SweetProducer {
@Override
public void produceSweet() {
System.out.println("Chocolate produced");
}}public class CookieProducer extends SweetProducer {
@Override
public void produceSweet() {
System.out.println("Cookie produced");
}}public class SweetCreator {
private List sweetProducer;
public SweetCreator(List sweetProducer) {
this.sweetProducer = sweetProducer;
}
public void createSweets() {
sweetProducer.forEach(sweet -> sweet.produceSweet());
}}public class SweetCreatorTest {
public static void main(String... args) {
SweetCreator sweetCreator = new SweetCreator(Arrays.asList(new CakeProducer(),
new ChocolateProducer(), new CookieProducer()));
sweetCreator.createSweets();
}}
在此示例中,你可以看到SweetCreator类仅知道SweetProducer类。 它不知道每个甜食的实现。 这种分离使我们可以灵活地更新和重用我们的类,并使代码易于维护。 设计代码时,请始终寻找使代码尽可能灵活和可维护的方法。 多态性是用于这些目的的一种非常强大的技术。
提示:@Override注释使程序员有义务使用必须重写的相同方法签名。 如果未重写该方法,则将出现编译错误。
方法覆盖中的协变返回类型
如果它是协变类型,则可以更改覆盖方法的返回类型。 协变量类型基本上是返回类型的子类。 考虑一个例子:
public abstract class JavaMascot {
abstract JavaMascot getMascot();}public class Duke extends JavaMascot {
@Override
Duke getMascot() {
return new Duke();
}}
由于Duke是JavaMascot,因此我们可以在覆盖时更改返回类型。
Java核心类的多态性
我们一直在核心Java类中使用多态。 一个非常简单的示例是当我们实例化ArrayList类时,将List接口声明为一种类型:
List list = new ArrayList<>();
为了进一步讲解,请考虑使用Java Collections API且无多态性的以下代码示例:
public class ListActionWithoutPolymorphism {
// Example without polymorphism
void executeVectorActions(Vector
丑陋的代码,不是吗? 想象一下要维护它! 现在来看具有多态性的相同示例
public static void main(String … polymorphism) {ListAction listAction = new ListAction();
listAction.executeListActions();}public class ListAction {
void executeListActions(List list) {
// Execute actions with different lists
}}public class ListActionInvoker {
public static void main(String... masterPolymorphism) {
ListAction listAction = new ListAction();
listAction.executeListActions(new Vector<>());
listAction.executeListActions(new ArrayList<>());
listAction.executeListActions(new LinkedList<>());
listAction.executeListActions(new CopyOnWriteArrayList<>());
}}
多态性的好处是灵活性和可扩展性。 除了创建几种不同的方法外,我们可以只声明一个接收通用List类型的方法。
在多态方法调用中调用特定方法
可以在多态调用中调用特定的方法,但是这样做会牺牲灵活性。 这是一个例子:
public abstract class MetalGearCharacter {
abstract void useWeapon(String weapon);}public class BigBoss extends MetalGearCharacter {
@Override
void useWeapon(String weapon) {
System.out.println("Big Boss is using a " + weapon);
}
void giveOrderToTheArmy(String orderMessage) {
System.out.println(orderMessage);
}}public class SolidSnake extends MetalGearCharacter {
void useWeapon(String weapon) {
System.out.println("Solid Snake is using a " + weapon);
}}public class UseSpecificMethod {
public static void executeActionWith(MetalGearCharacter metalGearCharacter) {
metalGearCharacter.useWeapon("SOCOM");
// The below line wouldn't work
// metalGearCharacter.giveOrderToTheArmy("Attack!");
if (metalGearCharacter instanceof BigBoss) {
((BigBoss) metalGearCharacter).giveOrderToTheArmy("Attack!");
}
}public static void main(String... specificPolymorphismInvocation) {
executeActionWith(new SolidSnake());
executeActionWith(new BigBoss());
}}
我们在这里使用的技术是广播或在运行时故意更改对象类型。
请注意,只有在将通用类型转换为特定类型时才可以调用特定方法。 一个很好的类比是对编译器明确地说:“嘿,我知道我在这里做什么,所以我将对象转换为特定类型并使用特定方法。”
参考上面的示例,一个重要原因是编译器拒绝接受特定的方法调用:正在传递的类可能是SolidSnake。 在这种情况下,编译器无法确保MetalGearCharacter的每个子类都声明了giveOrderToTheArmy方法。
保留关键字的实例
请注意实例化的保留字。 在调用特定方法之前,我们询问了MetalGearCharacter是否为BigBoss的“实例”。 如果不是BigBoss实例,我们将收到以下异常消息:
线程“主”中的异常java.lang.ClassCastException:com.javaworld.javachallengers.polymorphism.specificinvocation.SolidSnake无法转换为com.javaworld.javachallengers.polymorphism.specificinvocation.BigBoss
超级保留关键字
如果我们想引用Java超类的属性或方法怎么办? 在这种情况下,我们可以使用超级保留字。 例如:
public class JavaMascot {
void executeAction() {
System.out.println("The Java Mascot is about to execute an action!");
}}public class Duke extends JavaMascot {
@Override
void executeAction() {
super.executeAction();
System.out.println("Duke is going to punch!");
}
public static void main(String... superReservedWord) {
new Duke().executeAction();
}}
在Duke的executeAction方法中使用保留字super调用超类方法。 然后我们从杜克(Duke)执行特定操作。 因此,我们可以在下面的输出中看到两条消息:
Java Mascot即将执行一个动作!Duke要出拳了!
接受多态挑战!
让我们尝试一下你对多态性和继承的了解。首先,请仔细分析以下代码:
public class PolymorphismChallenge {
static abstract class Simpson {
void talk() {
System.out.println("Simpson!");
}
protected void prank(String prank) {
System.out.println(prank);
}
}
static class Bart extends Simpson {
String prank;
Bart(String prank) { this.prank = prank; }
protected void talk() {
System.out.println("Eat my shorts!");
}
protected void prank() {
super.prank(prank);
System.out.println("Knock Homer down");
}
}
static class Lisa extends Simpson {
void talk(String toMe) {
System.out.println("I love Sax!");
}
}
public static void main(String... doYourBest) {
new Lisa().talk("Sax :)");
Simpson simpson = new Bart("D'oh");
simpson.talk();
Lisa lisa = new Lisa();
lisa.talk();
((Bart) simpson).prank();
}}
你怎么看? 最终输出将是什么? 不要使用IDE来解决这个问题! 关键是要提高代码分析技能,因此请尝试自己确定输出。
了解多态
对于以下方法调用:
new Lisa().talk("Sax :)");
输出为“ I love Sax!”,这是因为我们正在向该方法传递字符串,而Lisa具有该方法。
对于下一个调用:
Simpson simpson = new Bart("D'oh");
simpson.talk();
输出将是“Eat my shorts!” 这是因为我们正在使用Bart实例化Simpson类型。
现在检查一下,这有点棘手:
Lisa lisa = new Lisa();
lisa.talk();
在这里,我们使用带有继承的方法重载。 我们没有将任何内容传递给talk方法,这就是调用Simpsontalk方法的原因。 在这种情况下,输出将是:
"Simpson!"
这里还有一个:
((Bart) simpson).prank();
在这种情况下,当我们使用new Bart(“ D'oh”);实例化Bart类时,会传递恶作剧字符串。 在这种情况下,首先将调用super.prank方法,然后是来自Bart的特定恶作剧方法。 输出将是:
"D'oh""Knock Homer down"
视频挑战! 调试Java多态性和继承
调试是完全吸收编程概念并改善代码的最简单方法之一。 在此视频中,你可以在调试和解释Java多态性挑战时继续学习:
多态性的常见错误
认为无需使用强制转换就可以调用特定方法是一个常见的错误。
另一个错误是不确定多态实例化类时将调用哪种方法。 请记住,要调用的方法是创建的实例的方法。
还要记住,方法重载不是方法重载。
如果参数不同,则无法覆盖方法。 如果返回类型是超类方法的子类,则可以更改重写方法的返回类型。
喜欢这篇文章的可以点个赞,欢迎大家留言评论,记得关注我,每天持续更新技术干货、职场趣事、海量面试资料等等
> 如果你对java技术很感兴趣也可以交流学习,共同学习进步。
不要再用"没有时间“来掩饰自己思想上的懒惰!趁年轻,使劲拼,给未来的自己一个交代
文章写道这里,欢迎完善交流。最后奉上近期整理出来的一套完整的java架构思维导图,分享给大家对照知识点参考学习。有更多JVM、MySQL、Tomcat、Spring Boot、Spring Cloud、Zookeeper、Kafka、RabbitMQ、RockerMQ、redis、ELK、Git等Java干货
关于多态性要记住什么
创建的实例将确定使用多态时将调用哪种方法。
@ Override注释使程序员有义务使用覆盖的方法; 否则,将出现编译器错误。
多态可以与普通类,抽象类和接口一起使用。
大多数设计模式取决于某种形式的多态性。
在多态子类中使用特定方法的唯一方法是使用强制转换。
可以使用多态性在代码中设计功能强大的结构。
运行测试。 这样做,你将能够掌握这个强大的概念!