【问题标题】:Java how to make a method argument accept subclass type and superclassJava如何使方法参数接受子类类型和超类
【发布时间】:2019-11-05 12:54:03
【问题描述】:

我有一个超类和一个子类,其中包含一些变量,如下所示:

public class A{
    
    private int first;
    private int second;
    
    public A(int _first, int _second){
        first = _first;
        second = _second;
    }
    
    public int getFirst(){
        return first;
    }
    
}

public class B extends A{
    
    private int third;
    
    public B(int _first, int _second, int _third){
        super(_first, _second);
        third = _third;
    }
    
    public int getThird(){
        return third;
    }
    
}

我想在主类中构建一个方法,该方法接受可以是A 类型或B 类型的通用参数,如下所示:

public class Main{

    public int val = 2;

     public static void main(String []args){
        A a = new A(1, 2);
        B b = new B(1, 2, 3); 

        printObject(a);
        printObject(b);

     }
     
     public void printObject(A a){
         
         int f = a.getFirst() * val;
         int s = a.getSecond() * val;
         
         if(a instanceOf B){
             int t = a.getThird() * val; // compiler does not find the getThird() method this way
         }
     }
}

如何做到这一点?泛型是一种选择吗?我曾考虑在A 中创建printObject() 方法,然后在B 中覆盖它,但是我在main 中创建了一些其他变量,例如上面的val

更新

我尝试像上面的方法一样使用instanceOf。但是这种方式编译器找不到子类的具体方法。

【问题讨论】:

  • 如果 A 对象属于 A 类型,该脚本应该做什么?那么t 应该包含什么?
  • 评论中有一个 if 条件。 “如果对象是 B ... a.getThird 的一个实例”。我想相关的问题是方法属性可以同时接受 A 类(超类)和 B 类(子类)吗?
  • 请尝试编写一些涵盖此内容的代码。我不认为泛型可以帮助您 - 请查看泛型的概念并编辑您的问题以涵盖您的问题与泛型之间的任何联系
  • 我并不是说泛型是我唯一的选择。任何工作都很好。我认为这是一个非常合理的问题。如何编写一个接受基类中任何类型的方法?

标签: java oop generics inheritance subclassing


【解决方案1】:

首先,根据定义,如果您将 A 声明为任何方法的参数并且 B 是它的子类,那么任何 A 或 B 都可以传递给该方法。

可以然后使用 instanceof 运算符实现您想要的(检查传入的参数是否为 B 类型)。但是,通常应该使用继承/方法覆盖而不是 instanceof。

您可以将“val”传递给 A/B 上的 printObject() 方法。如果涉及多个变量,如“val”,您可以传入另一个对象,或者您可能需要将代码拆分为 A 类的多个方法(在 B 中被覆盖),并根据需要传入不同的值? (您通常不会在以打印对象为目的的方法中进行计算,但也许这只是一个示例?)

【讨论】:

    【解决方案2】:

    一切都简单多了)你可以在主类中去掉这个方法,因为它会产生一些冗余耦合。而这一切instanceof 在 2019 年真的很香。你可以让它更独立。

    A类:

    public class A{
    
        private int first;
        private int second;
    
        public A(int _first, int _second){
            first = _first;
            second = _second;
        }
    
        public int getFirst(){
            return this.first;
        }
    
        public int getSecond(){
            return this.second;
        }
    
        public void print(int multiplier) {
            System.out.println(this.first * multiplier);
            System.out.println(this.second * multiplier);
        }
    
    }
    

    B类:

    public class B{
    
        private int third;
    
        public B(int _first, int _second, int _third){
            super(_first, _second);
            third = _third;
        }
    
        public int getThird(){
            return this.third;
        }
    
        @Override
        public void print(int multiplier) {
            super.print(multiplier);
            System.out.println(this.third * multiplier);
        }
    
    }
    

    主类:

       public class Main{
    
             public int val = 2;
    
             public static void main(String []args){
                A a = new A(1, 2);
                B b = new B(1, 2, 3); 
    
                a.print(val);
                b.print(val);
    
             }
       }
    

    【讨论】:

    • 我明白了。只是打印方法比这更复杂。我实际上是在 android 平台上,print 方法实际上是根据子类或超类的值更新视图的元素(如文本和图像)
    • 嗯..所以,这里的主要思想是将所有对象特定的逻辑封装在这个对象中。如果此方法比您可能需要检查您的应用程序架构复杂。当然,您可以简单地使用所有这些“instanceof”和其他解决方法来解决您的问题,但它肯定会导致您使用意大利面条式代码和非常紧密的耦合。将来真的很难维护,所以我强烈建议考虑架构。
    • 如果 @user7331538 使用 MVP 模式,那么模型不应该包含任何关于如何“打印”或“显示”自身的逻辑,这是应该在视图中的代码!我正在寻找类似的问题:-(
    【解决方案3】:

    编写面向对象的代码不仅仅是扩展一个类,您的 API 和其他功能应该被设计为解决方案的一部分。

    在您的情况下,最合适的方法是将打印方法添加到对象本身,您可以覆盖整个函数或在覆盖类中调用超类。

    public class A{
        /// ... your code
    
     public void print(){
        System.out.println("first :"+first+", second : "+second);
    }
    }
    
    public class B extends A{
         /// ... your code
        public void print(){
           //Option A - use parent class getters/setters to implement print for object B
           System.out.println("first :"+super.getFirst()+", second : "+super.getsecond() +" third" + third);
          }
    
          //Option B (More usable to methods returning a value or performing an update) - Perform operation on parent variables, then perform on class specific variables       
           super.print()
           System.out.println("third : "+third);
        }    
    
    
    }
    

    然后

    A a  = new A();
    A b = new B();
    
    a.print();
    b.print();
    

    是否会根据各自的实际实现调用正确的运行时函数

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-06-22
      • 2018-07-29
      • 2015-03-12
      相关资源
      最近更新 更多