为啥我不能正确使用扩展类的方法?

Posted

技术标签:

【中文标题】为啥我不能正确使用扩展类的方法?【英文标题】:why can I not use methods of my extended class correctly?为什么我不能正确使用扩展类的方法? 【发布时间】:2022-01-03 05:45:54 【问题描述】:

我正在做一个使用抽象类的项目。我把 Item 类弄疯了,然后我做了一个“Snickers”和一个“Mars”类,它们都扩展了 Item 类。

我在堆栈中使用它,在填充这些堆栈后,我试图打印出顶部的名称,在本例中为 Snickers。我尝试直接调用 getName() 方法,但它告诉我它未声明。当我尝试使用像 System.out.println(snickersStack.top().super().getName()) 这样的 super 关键字来使用它时,会出现一个错误,上面写着“无法取消引用 void”,我无法真正理解,因为我尝试使用的方法是返回字符串的方法.

这是 Item 类:

public abstract class Item 
    private float preis;
    private String name;
    private boolean haltbar;
    
    public Item(float pPreis, String pName, boolean pHaltbar)
    
        preis = pPreis;
        name = pName;
        haltbar = pHaltbar;
    
    
    public float getPreis() 
        return preis;
    
    
    public String getName() 
        return name;
    
    
    public boolean getHaltbar() 
        return haltbar;
    
    
    public void setPreis(float pPreis) 
        preis = pPreis;
    
    
    public void setName(String pName) 
        name = pName;
    
    
    public void setHaltbar(boolean pHaltbar) 
        haltbar = pHaltbar;
    

显然有 getName() 方法,这是 Snickers 方法,它只是引用了 Item 类:

public class Snickers extends Item 
    public Snickers(boolean pHaltbar)  
        super(1.2f, "Snickers", pHaltbar);
    

这就是我将不同数量的项目填充到堆栈中的方式,在底部有我的问题所在的行。

public void fuelleStacks() 
    //random int 0 - 7
    randomInt = random.nextInt(8);
    
    //fuelle snickersStack
    while(randomInt != 0) 
        randomBool = random.nextBoolean();
        Snickers snickers = new Snickers(randomBool);
        
        snickersStack.push(snickers);
        randomInt--;
    
    
    //fuelle marsStack
    randomInt = random.nextInt(8);
    while(randomInt != 0) 
        randomBool = random.nextBoolean();
        Mars mars = new Mars(randomBool);
        
        marsStack.push(mars);
        randomInt--;
    
    System.out.println(snickersStack.top().super().getName());

我已经在同一个类中声明并初始化了堆栈本身,如下所示:

public class Automat 
    public Stack snickersStack;
    
    public Automat() 
        snickersStack = new Stack<Snickers>();
        marsStack = new Stack<Mars>();
    

我没有导入 Stack 类,而是有另一个名为 Stack 的类包含此代码(这就是为什么我使用 top(),而不是像使用普通 Stack 类那样使用 peek()):

public class Stack<ContentType> 

  private class StackNode 

    private ContentType content = null;
    private StackNode nextNode = null;

    public StackNode(ContentType pContent) 
      content = pContent;
      nextNode = null;
    

    public void setNext(StackNode pNext) 
      nextNode = pNext;
    

    public StackNode getNext() 
      return nextNode;
    

    /**
     * @return das Inhaltsobjekt vom Typ ContentType
     */
    public ContentType getContent() 
      return content;
    
  

  private StackNode head;
  private int anzahl;

  public Stack() 
    head = null;
    anzahl = 0;
  

  public boolean isEmpty() 
    return (head == null);
  

  public void push(ContentType pContent) 
    if (pContent != null) 
      StackNode node = new StackNode(pContent);
      node.setNext(head);
      head = node;
      anzahl++;
    
  

  public void pop() 
    if (!isEmpty()) 
      head = head.getNext();
      anzahl--;
    
  
  
  public ContentType top() 
    if (!this.isEmpty()) 
      return head.getContent();
     else 
      return null;
    
  
  
  public int getAnzahl() 
      return anzahl;
    

【问题讨论】:

问题不在于您粘贴的任何内容;它在您声明snickersStack 的位置。编辑您的问题并包含这部分代码。最好是粘贴自包含代码。对于本练习,这样做似乎微不足道。 你想用snickersStack.top().super().getName()做什么?你认为这应该怎么做? 旁注:当您在snickersStack.top().super().getName() 等长表达式中遇到错误时,您可以通过将其分解为更小的部分并将每个部分分配给一个变量来对其进行调试。这将更准确地告诉您问题出在哪里。 另一个注意事项:缩进代码的第一行是不够的。每行必须缩进额外的四个空格。如果您不这样做,那么前四个空格将被视为“这是一行代码”,而不是缩进以实际格式化您的代码。或者,您可以在每个代码块的上方和下方添加三个反引号以进行格式化。 【参考方案1】:

snickersStack.top().super().getName() 是关键字super() 的错误使用。 super() 只能作为构造函数的第一行调用。事实上,你在这里正确地使用它:

public class Snickers extends Item 
    public Snickers(boolean pHaltbar)  
        super(1.2f, "Snickers", pHaltbar);
    

更多详情,check out this documentation about super。

【讨论】:

是的,我也是这么想的,我好像在某个网站的某个地方看到过,我不明白为什么我无论如何不能使用getName()方法,应该定义它? @gone 如果你做得对,你可以。您使用的是什么Stack 课程?代码顶部 Stack 的导入是什么? 哦,我忘记了,这当然不是你平时好好使用栈类的方式,这不是栈类的导入版本,是自己的类,这也是为什么它是top (),而不是 peek()。 @gone 请将Stack 类添加到您的问题中。我假设你有public void top() 对吗?这真的是你想要的吗?如果不是,那应该是什么?你有什么想法吗? 不,top 方法返回一个内容类型,正如你在堆栈的初始化中看到的,它有一个设置的 ContentType,这使得我无法使用该方法的事实Snickers ContentType 通常应该更奇怪【参考方案2】:

代码snickersStack.top().super().getName() 有两处错误。 您需要使用peek() 来查看堆栈的顶部元素。 super() 也不是一回事。 如果你想“达到”getName() 方法,你可以通过在从peek() 获得的对象上使用它来实现。该方法继承自基类。

【讨论】:

这是正确的。但是,很难知道peek() 是否会解决问题。我们不知道 OP 使用的是什么 Stack 类。 top() 不在标准 Stack 类中。所以这应该会导致不同的错误。 是的,我忘了说我没有导入堆栈类,但是我正在使用另一个版本的堆栈,它是项目中自己的类,这就是为什么它是顶部的,而不是 peek .【参考方案3】:

您将snickersStack 声明为原始类型:

public class Automat 
    public Stack snickersStack;

这意味着对于 java 编译器来说,它可以包含任何类型的对象。由于Object 没有getName() 方法,因此您不能在snickersStack.top() 的结果上调用getName()

要解决此问题,您必须将 snickersStack 声明为 Stack&lt;Snickers&gt;

public class Automat 
    public Stack<Snickers> snickersStack;

【讨论】:

【参考方案4】:

我同意 Thomas Kläger 的观点,您需要声明堆栈的类型:

public class Automat 
/** In your code you forgot the type of the Stack
 * you need to specify the type, for example: Stack<Snickers>, Stack<Item> */
public Stack<Snickers> snickersStack;
public Stack<Mars> marsStack;
public MyStack<Item> itemsStack; // **Using your Stack class, I named it MyStack**

public Automat() 
    /** In Java 8 and newer versions you can omit the type here
     * instead of
     * snickersStack = new Stack<Snickers>();
     * you can write "snickersStack = new Stack<>();" */
    snickersStack = new Stack<>();
    marsStack = new Stack<>();
    itemsStack = new MyStack<>();

我认为您需要在这里了解多态性的使用,这就是为什么您对使用 super() 关键字感到困惑的原因,所以我编写了一些代码,以便您可以看到在抽象类和 OOP 中更好地使用多态性:

Automat.java

import java.util.Random;
import java.util.Stack;
    
public class Automat 
    // In your code you forgot the type of the Stack
    // you need to specify the type, for example: Stack<Snickers>, Stack<Item> 
    public Stack<Snickers> snickersStack;
    public Stack<Mars> marsStack;
    public MyStack<Item> itemsStack; // **Using your Stack class, I named it MyStack**
    
    public Automat() 
        /** In Java 8 and newer versions you can omit the type here
         * instead of
         * snickersStack = new Stack<Snickers>();
         * you can write "snickersStack = new Stack<>();"
         */
         snickersStack = new Stack<>();
         marsStack = new Stack<>();
         itemsStack = new MyStack<>();
     
     public void fuelleStacks() 
         Random random = new Random();
         //random int 0 - 7
         int randomInt = random.nextInt(8);
         boolean randomBool = false;
    
         //fuelle snickersStack
         while(randomInt != 0) 
             randomBool = random.nextBoolean();
             Snickers snickers = new Snickers(randomBool);
             snickersStack.push(snickers);
             randomInt--;
         
    
         //fuelle marsStack
         randomInt = random.nextInt(8);
         while(randomInt != 0) 
             randomBool = random.nextBoolean();
             Mars mars = new Mars(randomBool);
             marsStack.push(mars);
             randomInt--;
         
    
         //fuelle items Stack with Snickers and Mars
         // See the benefit of using Polymorphism here, which I assume is what you
         //      wanted to do in your code.
         // "You want to create an items Stack, with any item Snickers or Mars"
         // This is how I would do it.
         randomInt = random.nextInt(8);
         while(randomInt != 0) 
             randomBool = random.nextBoolean();
             Item itemMars = new Mars(randomBool);
            Item itemSnickers = new Snickers(randomBool);
    
             if (randomInt % 2 != 0) 
                 itemsStack.push(itemMars);
             
             if (randomInt % 2 == 0) 
                 itemsStack.push(itemSnickers);
             
             randomInt = random.nextInt(8);
         
         // let's check the stacks
         if (!snickersStack.isEmpty()) 
             System.out.println("snickersStack: ");
             System.out.println(snickersStack.peek().getName());
             snickersStack.peek().printMyName(); // see the use of super in printMyName()
          else 
             System.out.println("** Empty Snickers Stack **");
         
         if (!marsStack.isEmpty()) 
             System.out.println("marsStack: ");
             System.out.println(marsStack.peek().getName());
             marsStack.peek().printMyName(); // see the use of super in printMyName()
          else 
             System.out.println("** Empty Mars Stack **");
         
    
         // This is the best part, you have a Stack with items (Snickers, Mars, etc) that you can do operations on it
         // Here you can see the item Stack
         // You do not use super() here, you call super() "within the context of" the Derived class
         //      to refer to a method from the Base class
         // I am using your Stack class here
         if (!itemsStack.isEmpty()) 
             // let's print the items names from the Stack
             System.out.println();
             System.out.println("First item on itemsStack : " + itemsStack.top().getName());
    
             System.out.println("Let's see the items Stack :");
             while (!itemsStack.isEmpty()) 
                 System.out.println("top item: " + itemsStack.top().getName());
                 itemsStack.top().printMyName();// see the use of super in printMyName()
                 itemsStack.pop();
             
          else 
             System.out.println("** Empty Items Stack **");
         
     

Item.java

public abstract class Item 
    private float preis;
    private String name;
    private boolean haltbar;

    public Item(float pPreis, String pName, boolean pHaltbar)
    
        preis = pPreis;
        name = pName;
        haltbar = pHaltbar;
    

    public float getPreis() 
        return preis;
    

    public String getName() 
        return name;
    

    public boolean getHaltbar() 
        return haltbar;
    

    public void setPreis(float pPreis) 
        preis = pPreis;
    

    public void setName(String pName) 
        name = pName;
    

    public void setHaltbar(boolean pHaltbar) 
        haltbar = pHaltbar;
    

    public void printMyName() 
        System.out.println("call printMyName() in Base class Item : " + name);
    

Mars.java

public class Mars extends Item 
    public Mars(boolean pHaltbar) 
        super(2.2f, "Mars", pHaltbar); // you used super() correctly here
    

    @Override
    public void printMyName() 
        super.printMyName(); // See another way to use super() from Derived class
        System.out.println("call printMyName() in Derived class Mars : " + getName());
    

Snickers.java

public class Snickers extends Item 
    public Snickers(boolean pHaltbar) 
        super(1.2f, "Snickers", pHaltbar); // you used super() correctly here
    

    @Override
    public void printMyName() 
        super.printMyName(); // See another way to use super() from Derived class
        System.out.println("call printMyName() in Derived class Snickers : " + getName());
    

Demo.java

public class Demo 
    public static void main(String args[])
        Automat automat = new Automat();
        automat.fuelleStacks();
    

【讨论】:

以上是关于为啥我不能正确使用扩展类的方法?的主要内容,如果未能解决你的问题,请参考以下文章

为啥 Blazor 的 ComponentBase 类的扩展方法只能通过这个获得?

为啥 Inputmask 不能正确处理日期?

为啥我们不能在实现两个接口由相同方法组成的类的方法中使用访问修饰符?

为啥 doInbackground 方法不能有空体?

为啥我不能在 Typescript 中扩展“任何”?

为啥我不能使用 list 的 count 方法? [复制]