文章开始前,我们先抛出一个链式问题:
Java中父类能调用子类的方法吗?
如果不可以,原因?如果可以,如何做?
每种实现方式,在实际项目被允许吗?
不被允许的原因有哪些?
如果在实际项目中,的确有这样的特殊业务场景,应如何“正确的” - “变相”的去实现?1.Java中父类能调用子类的方法吗?
1.1 实现方式描述
(1)在父类中直接new子类相关对象或者通过构造函数传入子类对象,然后调用其方法
(2)将子类相关方法声明为static,在父类中调用子类的static方法
(3)在父类中通过反射调用子类的相关方法
(4)通过注册监听,然后通过回调接口调用子类相关方法
在看了相关描述之后,大家肯定迫切想看一下,四种方法的代码如何进行编写,或者您已经想到了。1.2 四种实现方式的代码
接下来我们一起看一下这四种 “奇葩” 的实现方式的代码。
测试代码很简单,包含三个类:
TestTwo 测试功能类、Father父类、Son子类package test; * @author itbird public class Father { private SonFuctionListener mListenr; public Father() { * 在父类中直接new子类相关对象,然后调用其方法 public void realizeWay1() { Son son = new Son(); son.testSonMethod("在父类中直接new子类相关对象,然后调用其方法"); * 在父类中调用子类的static方法 public void realizeWay2() { Son.testSonMethod1("在父类中调用子类的static方法"); * 在父类中通过反射调用子类的相关方法 public void realizeWay3() { try { Class cls = Class.forName("test.Son"); Son son = (Son) cls.newInstance(); son.testSonMethod("在父类中通过反射调用子类的相关方法"); } catch (Exception e) { e.printStackTrace(); * 通过监听回调 * @param listener public void setSonListener(SonFuctionListener listener) { mListenr = listener; public void realizeWay4() { if (mListenr != null) { mListenr.callTestMethod1(); public interface SonFuctionListener { void callTestMethod1();package test; import test.Father.SonFuctionListener; * @author itbird public class Son extends Father implements SonFuctionListener{ public Son() { setSonListener(this); public void testSonMethod(String str) { System.out.println(str + ": this is testSonMethod"); public static void testSonMethod1(String str) { System.out.println(str + ": this is static testSonMethod"); @Override public void callTestMethod1() { testSonMethod("通过监听回调");package test; * 测试功能类 * @author itbird public class TestTwo { public static void main(String[] args) { Son son = new Son(); //在父类中直接new子类相关对象,然后调用其方法 son.realizeWay1(); //在父类中调用子类的static方法 son.realizeWay2(); //在父类中通过反射调用子类的相关方法 son.realizeWay3(); //通过监听回调 son.realizeWay4();看一下四种实现方式,可以达到我们预期结果:
2.上述几种实现方式,在实际项目被允许吗?
如果各位看官细细品味了上面的样例代码,并且稍微熟悉面向对象的继承和多态特性的话,会得出一个显而易见的结论,不允许
看到这儿,如果仍有看官,不太明白为什么不允许话,小编只能在上面的样例基础上,简单提醒以下几点,还需各位看官在实际项目研发过程中细细品味 & 时常总结,敬请见谅。因为毕竟涉及到面向对象的基本属性、项目经验,有些东西本来就是约定、规则、经验,无法进行明说。(1)Java继承概念中,父类是不确定子类的,但子类可以确定其父类--多态特性的来源之一
(2)父类是不可调用子类的方法的,但子类可以调用父类所有非private的方法-继承特性的特征之一
(3)存在明显的代码漏洞,例如:因为Java继承的关系,所以类进行加载时,是先加载的父类,才去加载子类,如果恰巧这是父类的某个方法调用了子类的方法,而子类方法的某些常量因为子类还未加载没有实例化,就会直接导致程序崩溃
(4)如果通过上述方法实现了相关效果,那么请这样做的各位Coder反思一个问题,您的子类继承父类的意义到底在哪里?3.如果在实际项目中,的确有这样的特殊业务场景,即有些实现并不确定,需要具体子类去实现,但是又必须在父类规定其调用顺序与场景,应如何做?
同样,先上代码,各位先认真品味
package test; * @author itbird public abstract class Father { // 基本方法 protected abstract void doSomething(); // 基本方法 protected abstract void doAnything(); // 模板方法 public void templateMethod() { * 调用基本方法,完成相关的逻辑 this.doAnything(); this.doSomething();package test; * @author itbird public class Son extends Father{ @Override protected void doSomething() { System.out.println("Son doSomething"); @Override protected void doAnything() { System.out.println("Son doAnything");package test; * 测试功能类 * @author itbird public class TestTwo { public static void main(String[] args) { Son son = new Son(); son.templateMethod();基本方法:基本方法也叫做基本操作,是由子类实现的方法,并且在模板方法中被调用。
● 封装不变部分,扩展可变部分
模板方法:可以有一个或者几个,一般是具体的方法,也就是一个框架,实现对基本方法的调度,完成固定的逻辑。
● 提取公共部分代码,便于维护