如何将对象转换为不继承的类型?

时间:2015-06-27 16:43:53

标签: java inheritance

我应该修改程序以在GUI中显示输出。除了一个字段外,这大部分都是完成的。我无法显示的唯一字段是'重新进货费',它位于DVD的子类中。 Inventory是主要类,然后DVD类和MovieTitleDVD的子类。除restockingFee子类中的MovieTitle外,一切都正确显示。例外是:

Exception in thread "main" java.lang.ClassCastException: inventoryProgram3.DVD cannot be cast to inventoryProgram3.MovieTitle
    at inventoryProgram3.Inventory.myRedraw(Inventory.java:204)
    at inventoryProgram3.Inventory.<init>(Inventory.java:149)
    at inventoryProgram3.Inventory.main(Inventory.java:156)  

如何从子类调用restockfee方法?

这是Inventory类:

package inventoryProgram4;

import java.awt.BorderLayout;
import java.awt.Container;
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.text.DecimalFormat;
import java.text.NumberFormat;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JTextField;

@SuppressWarnings("serial")
public class Inventory extends JFrame implements ActionListener {
    // declare instance attributes
    private final JPanel buttonJPanel;
    private final JPanel areaJPanel;
    private final JButton buttons[];
    private final BorderLayout layout;
    private final Container pane;
    private final JLabel l0;
    private final JLabel l1;
    private final JLabel l2;
    private final JLabel l3;

    private final JLabel l4;
    private final JLabel l5;
    private final JLabel totalInv;

    // Text fields
    static private JTextField t0;
    static private JTextField t1;
    static private JTextField t2;
    static private JTextField t3;
    static private JTextField t4;
    static private JTextField t5;

    static private JTextField totalInvValue;
    static private DVD rb[];
    static private int index;

    static private DVD[] DVD;

    public Inventory() { // constructor
        super("DVD Inventory");

        DVD = new DVD[5];
        DVD[0] = new DVD("1", " Fast and Furious 6", 10, 15);
        DVD[1] = new DVD("2", " The Matrix Reloaded", 8, 5);
        DVD[2] = new DVD("3", " In Pursuit of Happiness", 8, 5);
        DVD[3] = new DVD("4", " Darknet", 8, 5);
        DVD[4] = new DVD("5", " Goonies", 8, 5);

        DVD = sortDVD(DVD);

        rb = DVD;
        index = 0;

        // setting layout
        layout = new BorderLayout(25, 15);
        setLayout(layout);

        // getting pane
        pane = getContentPane();

        // set up areaJPanel
        areaJPanel = new JPanel();
        areaJPanel.setLayout(new GridLayout(0, 2));

        // create area components
        l0 = new JLabel("   DVD Title:   ");
        l1 = new JLabel("   Title Name: ");
        l2 = new JLabel("   DVD's in Stock:    ");
        l3 = new JLabel("   DVD Price:  ");

        l4 = new JLabel("   Restock Fee: ");
        l5 = new JLabel("   Inventory value: ");
        totalInv = new JLabel("   Value of entire inventory: ");
        totalInvValue = new JTextField(10);
        totalInvValue.setEditable(false);

        t0 = new JTextField(15);
        t0.setEditable(false); // making text box non editable
        t1 = new JTextField(15);
        t1.setEditable(false);
        t2 = new JTextField(10);
        t2.setEditable(false);
        t3 = new JTextField(10);
        t3.setEditable(false);
        t4 = new JTextField(10);
        t4.setEditable(false);
        t5 = new JTextField(10);
        t5.setEditable(false);

        // adding components
        areaJPanel.add(l0); // n x 2 grid: label - textfield
        areaJPanel.add(t0);
        areaJPanel.add(l1);
        areaJPanel.add(t1);
        areaJPanel.add(l2);
        areaJPanel.add(t2);
        areaJPanel.add(l3);
        areaJPanel.add(t3);

        areaJPanel.add(t4);
        areaJPanel.add(l4);
        areaJPanel.add(t4);
        areaJPanel.add(l5);
        areaJPanel.add(t5);
        areaJPanel.add(totalInv);
        areaJPanel.add(totalInvValue);

        // Adding four buttons: first, next, previous, last
        // create array of buttons, size 4
        buttons = new JButton[4];

        // create a JPanel for the buttons
        buttonJPanel = new JPanel();
        // set panel layout to 1 row and columns = size of array
        buttonJPanel.setLayout(new GridLayout(1, buttons.length));

        // adding button "next"
        buttons[1] = new JButton("Previous"); // instantiate button "next"
        buttons[1].setActionCommand("Previous"); // identifies the action event
        buttons[1].addActionListener(this); // add an action listener for button
        buttonJPanel.add(buttons[1]); // add button to the button JPanel

        // adding button "previous"
        buttons[2] = new JButton("Next"); // instantiate button "previous"
        buttons[2].setActionCommand("next"); // identifies the action event
        buttons[2].addActionListener(this); // add an action listener for button
        buttonJPanel.add(buttons[2]); // add button to the button JPanel

        pane.add(buttonJPanel, BorderLayout.SOUTH); // place buttons at bottom of pane
        pane.add(areaJPanel, BorderLayout.WEST);

        myRedraw(); // showing first item

    }// end constructor

    public static void main(String args[]) {

        // creating frame
        Inventory panelFrame = new Inventory();
        // close the frame on clicking X button
        panelFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        // setting size
        panelFrame.pack();
        // setting visibility
        panelFrame.setVisible(true);

    }// end main method

    static DVD[] sortDVD(DVD[] DVD) {
        int in, out, NumOfEle = DVD.length;

        for (out = 1; out < NumOfEle; out++) {
            DVD temp = DVD[out];
            in = out;

            while (in > 0 && DVD[in - 1].getTitle().compareTo(temp.getTitle()) > 0) {
                DVD[in] = DVD[in - 1];
                --in;
            }
            DVD[in] = temp;
        }
        return DVD;
    }

    private static double calculateEntireInventory(DVD[] DVD1) {// method to return inventory total
        double totalInventory = 0;
        for (DVD DVD : DVD1) {
            totalInventory += (DVD.getInventoryValue());
        }
        return totalInventory;
    }

    // method to display contents
    static void myRedraw() {
        // currency formatter
        NumberFormat nf = new DecimalFormat("$#,##0.00");
        // reference to object under consideration
        DVD f = (DVD) rb[index];
        double inventoryValue = f.getInventoryValue();
        // set values for indicated object attribute
        t0.setText(f.getTitle()); // item name
        t1.setText(f.getItem() + ""); // item number
        t2.setText(f.getStock() + ""); // item quantity
        t3.setText(nf.format(f.getPrice())); // item price

        // Problem here
        /**
         * Exception in thread "main" java.lang.ClassCastException: inventoryProgram3.DVD cannot be
         * cast to inventoryProgram3.MovieTitle at
         * inventoryProgram3.Inventory.myRedraw(Inventory.java:204) at
         * inventoryProgram3.Inventory.<init>(Inventory.java:149) at
         * inventoryProgram3.Inventory.main(Inventory.java:156)
         **/

        MovieTitle t = (MovieTitle) f;

        t4.setText(nf.format(t.getRestockingFee())); // item re-stocking fee

        // up above

        t5.setText(nf.format(inventoryValue));

        // up above

        // total value of inventory
        totalInvValue.setText(nf.format(calculateEntireInventory(DVD)));
    }// end method

    // action handler for button presses
    public void actionPerformed(ActionEvent event) {
        int last = rb.length - 1;

        // get command string assigned to the pressed button.
        String action = event.getActionCommand();

        // set index based on which button was pressed.
        if (action.equals("prev")) { // previous pressed
            if (index == 0) {
                index = last; // at first item, go to last item
            } else {
                --index; // go to previous item
            }
        } else {// next pressed
            if (index == last) {
                index = 0; // at last item, go to first time
            } else {
                ++index; // go to next item
            }
        }
        myRedraw();

    }// end method

} // end program

这是DVD类:

package inventoryProgram3;

class DVD {
    // Create local variable to capture data from parameter list of the constructor

    private String thisItem;
    private String thisTitle;
    private double thisStock;
    private double thisPrice;

    // Create constructor to call this class from external classes
    public DVD(String item, String title, double stock, double price) {
        // Set local variables to values passed in via a class call
        thisItem = item;
        thisTitle = title;
        thisStock = stock;
        thisPrice = price;
    } // end constructor

    // getInventoryValue: calculates the total value of the inventory for the item
    public double getInventoryValue() {
        return getPrice() * getStock();
    }

    // set name
    public void setTitle(String title) {
        thisTitle = title;
    }// end method setTitle

    // return Title
    public String getTitle() {
        return thisTitle;
    }// end method getTitle

    // set Stock
    public void setStock(double stock) {
        thisStock = stock;
    }// end method setStock

    // return Stock
    public double getStock() {
        return thisStock;
    }// end method get Stock

    public void setPrice(double price) {
        thisPrice = price;
    }// end method setPrice

    // return Price
    public double getPrice() {
        return thisPrice;
    }// end method getPrice

    public void setItem(String item) {
        thisItem = item;
    }// end method setItem

    // return Item
    public String getItem() {
        return thisItem;
    }// end method getItem

    // calculate the inventory value
    public double value() {
        return thisPrice * thisStock;
    }// end method value
}// end class

这是MovieTitle类:

package inventoryProgram3;

public class MovieTitle extends DVD {
    private final double restockingFee = 0.05;

    public MovieTitle(String item, String title, double stock, double price) {
        super(item, title, stock, price);
    }

    public double getRestockingFee() {
        return getPrice() * restockingFee;
    }
}

5 个答案:

答案 0 :(得分:3)

您不能将超类对象强制转换为其子类之一,只允许反向。它看起来最简单的方法来修复你现在拥有的是将数组声明为类型为child并在主程序中使用子对象填充它,然后你可以访问子类和超类方法。

答案 1 :(得分:3)

异常表示出了什么问题。您正在尝试将DVD投射到MovieTitle。尝试绘制自己的维恩图。所有MovieTitles都是DVD,但不是所有的DVD都是MovieTitles。例外情况表明您正在尝试处理其中一个DVD - 这些不是电影的标题,就像它是一个MovieTitle一样。

最初的猜测是您直接实例化DVD。您可以通过阅读代码来确认这一点,以查看实例化对象的位置。您需要将对象实例化为MovieTitle而不是DVD,或者您需要使用DVD方法来获取DVD的标题。

答案 2 :(得分:0)

显示错误是因为您正在将DVD投射到MovieTitle。 DVD不是MovieTtitle对象,因此您无法像这样投射它。

restockFee是MovieTitle的更具体的价格。

试试这个,看它是否有效:

在MovieTitle类中:

@Override
public double getPrice { 
    return super.getPrice() * restockingFee;
}

在库存类:

//MovieTitle t = (MovieTitle) f;
//t4.setText(nf.format(t.getRestockingFee())); // item re-stocking fee
t4.setText(nf.format(f.getPrice()); // item re-stocking fee

答案 3 :(得分:0)

您应该采用naming convention,像DVD = new DVD[5]这样的代码很难阅读。

关于你的问题,将超类实例强制转换为它的子类是没有意义的。

让我们假设演员成功了。由于超类不具有子类中定义的状态,因此在调用子类方法时,结果与子类中定义的字段一起使用会产生什么结果?这些字段不存在于您执行强制转换的超类对象中。在您的示例中,restockingFee实例中没有DVD,那么您会得到什么?

在允许使用此语言的语言中,如C语言系列,您将获得DVD对象边界之后的任何内存内容(换句话说,您将有一个错误)。 Java会保护您免受此错误的影响并抛出ClassCastException

您的问题有很多可能的解决方案:

1)将您需要的状态/方法移动到超类。在您的示例中,如果您始终在restockingFee上使用DVD,请将其移至DVD类。

2)如果restockingFee仅在子类中有意义(似乎是您的用例),并且您同时使用超类和子类实例,那么只有在使用子类实例时才需要读取它:

if (f instanceof MovieTitle) {
   MovieTitle t = (MovieTitle) f;
   t4.setText(nf.format(t.getRestockingFee()));
}

3)如果您只使用子类实例,那么将相关字段声明为子类类型并完全避免转换(以这种方式获得编译时安全性,避免您遇到的运行时错误):

static private MovieTitle rb[];

4)使用不兼容接口时,更复杂设计的一般解决方案是Adapter模式。

答案 4 :(得分:0)

我终于找到了答案,即使我真的不明白,我正在查看其他代码并尝试了不同的东西。我在带有数组的主类中的原始代码:

    public Inventory() { // constructor
    super("DVD1");    
    DVD = new DVD[7];
    DVD[0] = new DVD ( "1", " Fast and Furious 6", 10, 15 );
    DVD[1] = new DVD ( "2", " The Matrix Reloaded", 8, 5 );
    DVD[2] = new DVD ( "3", " In Pursuit of Happiness", 8, 5 );
    DVD[3] = new DVD ( "4", " Darknet", 8, 5 );
    DVD[4] = new DVD ( "5", " Goonies", 8, 5 );

public Inventory() { // constructor super("DVD1"); DVD = new DVD[7]; DVD[0] = new DVD ( "1", " Fast and Furious 6", 10, 15 ); DVD[1] = new DVD ( "2", " The Matrix Reloaded", 8, 5 ); DVD[2] = new DVD ( "3", " In Pursuit of Happiness", 8, 5 ); DVD[3] = new DVD ( "4", " Darknet", 8, 5 ); DVD[4] = new DVD ( "5", " Goonies", 8, 5 );

现在更改为并且工作原理是:     

     public Inventory() { // constructor
     super("DVD1");
     DVD = new DVD[7];
     DVD[0] = new MovieTitle ( "1", " Fast and Furious 6", 10, 15 );
     DVD[1] = new MovieTitle ( "2", " The Matrix Reloaded", 8, 5 );
     DVD[2] = new MovieTitle ( "3", " In Pursuit of Happiness", 8, 5 );
     DVD[3] = new MovieTitle ( "4", " Darknet", 8, 5 );
     DVD[4] = new MovieTitle ( "5", " Goonies", 8, 5 );
     DVD[5] = new MovieTitle ( "6", " zzzz", 8, 5 );
     DVD[6] = new MovieTitle ( "7", " AAaaaa", 15, 19.99 );
 </code>

I added in the last two to the array and added two more buttons (first and last) to make sure the buttons worked. With changing the new DVD to new MovieTitle, the restockFee does show up in GUI. Yes, I also needed: