使用两个不同的构造函数创建一个对象[重复]

Posted

技术标签:

【中文标题】使用两个不同的构造函数创建一个对象[重复]【英文标题】:Create a single object using two different constructors [duplicate] 【发布时间】:2017-09-19 11:44:32 【问题描述】:

我有一个 Card 类,它包含两个构造函数,如下面的代码所示。问题是每个 Card 对象都包含 2 个字符串和 2 个图像,因为我想保存这些对象,所以我必须将图像的路径保存为字符串,然后检索它们,因此有 2 个构造函数。但是,使用一些打印语句,我发现每当检索一张卡片时,都会创建 2 个单独的对象:一个正常的对象和另一个为空的对象。我知道这是因为我使用第二个构造函数中的第一个构造函数创建了一个新卡。有没有办法可以避免这种情况,这样我就没有 2 个单独的对象?如果可能的话,我想找到一种只使用一个构造函数的方法。这是我的类:

Card.java:

package com.spdesigns.dokkancardspreview.model;

import javafx.scene.image.Image;

public class Card 

private String mName;
private String mDescription;
private Image mMainImage;
private Image mSecondaryImage;
private String mMainImagePath;
private String mSecondaryImagePath;

public Card(String name, String description, Image mainImage, Image secondaryImage) 
    mName = name;
    mDescription = description;
    mMainImage = mainImage;
    mSecondaryImage = secondaryImage;


public Card(String name, String description , String mainImagePath, String secondaryImagePath) 
   Card newCardToAdd =  new Card(name,description,new Image(mainImagePath),new Image(secondaryImagePath));


@Override
public String toString() 
    return mName + " | " + mDescription;


public Image getmMainImage() 
    return mMainImage;


public Image getmSecondaryImage() 
    return mSecondaryImage;


public String getName() 
    return mName;


public String getDescription() 
    return mDescription;


home.java:

package com.spdesigns.dokkancardspreview.controllers;

import com.spdesigns.dokkancardspreview.model.Card;

import javafx.beans.property.ListProperty;
import javafx.beans.property.SimpleListProperty;
import javafx.collections.FXCollections;
import javafx.event.ActionEvent;
import javafx.fxml.FXML;
import javafx.fxml.Initializable;
import javafx.scene.control.Button;
import javafx.scene.control.ListView;
import javafx.scene.image.Image;
import javafx.scene.image.ImageView;

import java.io.*;
import java.util.List;
import java.net.URL;
import java.util.ArrayList;
import java.util.ResourceBundle;

public class home implements Initializable 

private Card hit = new Card("Hit","Expanding Possibility",
        new Image("/images/hit_main.jpg") , new Image("/images/hit_secondary.jpg"));

private Card goku = new Card("Goku SSJ3","Everlasting legend",
        new Image("/images/gokussj3_main.jpg") , new Image("/images/gokussj3_secondary.jpg"));

private boolean clickedAgain = false;

@FXML
private Button arrowButton;
@FXML
private ImageView imageView;

@FXML
private ImageView arrow;

@FXML
private ListView listView;

protected List<Card> testingList = new ArrayList<Card>();

    protected ListProperty<Card> listProperty = new SimpleListProperty<Card>();


@Override
public void initialize(URL location, ResourceBundle resources) 
    addCard(hit);
    addCard(goku);
    //testingList.add("test2");

    listView.itemsProperty().bind(listProperty);
    // wrapping our list in an observable list and then pass that observableList to the ListProperty isntance
    listProperty.set(FXCollections.observableArrayList(testingList));

    // Handle listView selection changes
    listView.getSelectionModel().selectedItemProperty().addListener(((observable, oldValue, newValue) -> 
        Card currentlySelectedCard = listProperty.get(listView.getSelectionModel().getSelectedIndex());
        System.out.printf("ListView item clicked! Value retrieved: %s\n", currentlySelectedCard);
        imageView.setImage(new Image(currentlySelectedCard.getmMainImage().impl_getUrl()));
        arrow.setVisible(true);
        arrowButton.setVisible(true);
    ));

    arrow.translateYProperty().set(283f);
    arrowButton.translateYProperty().set(283f);
    arrow.setRotate(180);
    arrow.setVisible(false);
    arrowButton.setVisible(false);


public void handleShowDetails(ActionEvent actionEvent) 
    System.out.println("Button Clicked!");
    Card currentlySelectedCard = listProperty.get(listView.getSelectionModel().getSelectedIndex());
    if(clickedAgain) 
        imageView.setImage(new Image(currentlySelectedCard.getmMainImage().impl_getUrl()));
        arrow.setRotate(180);
        clickedAgain = false;
     else 
        imageView.setImage(new Image(currentlySelectedCard.getmSecondaryImage().impl_getUrl()));
        arrow.setRotate(360);
        clickedAgain = true;
    


// Saving
public void exportTo(String fileName) 
    try(
            FileOutputStream fos = new FileOutputStream(fileName);
            PrintWriter writer = new PrintWriter(fos);
    )
        for(int i =0;i<testingList.size()-1;i++) 
            writer.printf("%s|%s|%s|%s\n",testingList.get(i).getName(),testingList.get(i).getDescription(),
                    testingList.get(i).getmMainImage().impl_getUrl(),testingList.get(i).getmSecondaryImage().impl_getUrl());
            System.out.println(testingList.get(i).toString());
        
     catch (IOException ioe) 
        System.out.printf("Problem saving: %s/n", fileName);
        ioe.printStackTrace();
    


// Loading
public void importFrom(String fileName) 
    try(
            FileInputStream fis = new FileInputStream(fileName);
            BufferedReader reader = new BufferedReader(new InputStreamReader(fis));
    )
        String line;
        while((line = reader.readLine()) != null) 
            String[] args = line.split("\\|");
            this.addCard(new Card(args[0],args[1],args[2],args[3]));
        
     catch (IOException ioe) 
        System.out.printf("Problem loading: %S\n" , fileName);
        ioe.printStackTrace();
    
    int i = 0;
    for (Card card : testingList) 
        System.out.printf("%s loaded\n",testingList.get(i).toString());
        i++;
    
    System.out.println("Loading Successful!");


public void addCard(Card card) 
    testingList.add(card);


// DEBUG purposes
public void printTestingList() 
    for (Card card : testingList) 
        System.out.println(card.toString());
    


MAIN.JAVA:

package com.spdesigns.dokkancardspreview;

import com.spdesigns.dokkancardspreview.controllers.home;
import javafx.application.Application;
import javafx.fxml.FXMLLoader;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.stage.Stage;

import java.io.File;

public class Main extends Application 

private home controller;
private File file = new File("CardsCollection.txt");

@Override
public void start(Stage primaryStage) throws Exception
    FXMLLoader loader = new FXMLLoader(getClass().getResource("/fxml/home.fxml"));
    Parent root = loader.load();
    controller = loader.getController();
    primaryStage.setTitle("Dokkan Battle Card Preview");
    primaryStage.setScene(new Scene(root, 900, 700));
    primaryStage.setResizable(false);
    // Loading cards
    primaryStage.show();
    try 
        if(!file.exists()) 
            file.createNewFile();
        
        controller.importFrom("CardsCollection.txt");
     catch (NullPointerException npe) 
        System.out.println("Error loading file!");
        npe.printStackTrace();
    


@Override
public void stop() 
    System.out.println("App is closing!");
    // Saving before exiting
    try 
        controller.exportTo("CardsCollection.txt");
     catch (NullPointerException npe) 
        System.out.println("Problem saving file!");
        npe.printStackTrace();
    
   // controller.printTestingList();


public static void main(String[] args) 
    launch(args);


【问题讨论】:

【参考方案1】:

改变

public Card(String name, String description , String mainImagePath, String secondaryImagePath) 
   Card newCardToAdd =  new Card(name,description,new Image(mainImagePath),new Image(secondaryImagePath));

public Card(String name, String description , String mainImagePath, String secondaryImagePath) 
   this(name,description,new Image(mainImagePath),new Image(secondaryImagePath));

【讨论】:

请注意,此解决方案未初始化 mMainImagePathmSecondaryImagePath 字段。 @MickMnemonic 是的,但是这些字段是私有的并且不可访问,也许这些字段应该被删除或者如果要使用它们应该有一个 getter?【参考方案2】:

你的代码的问题在于这个构造函数:

public Card(String name, String description , String mainImagePath, String secondaryImagePath) 
   Card newCardToAdd =  new Card(name,description,new Image(mainImagePath),new Image(secondaryImagePath));

如您所见,您在其中创建了一张新卡 newCardToAdd,导致新实例的初始化完全错误...

在这种情况下,您所做的是从另一个构造函数中调用一个构造函数...在您的情况下,您的 2 个构造函数应该如下所示:

public Card(String name, String description, Image mainImage, Image secondaryImage) 
    mName = name;
    mDescription = description;
    mMainImage = mainImage;
    mSecondaryImage = secondaryImage;


public Card(String name, String description, String mainImagePath, String secondaryImagePath) 
    this(name, description, new Image(mainImagePath), new Image(secondaryImagePath));

【讨论】:

【参考方案3】:

如果您永远不需要将Images 直接传递给类(仅图像路径),则单个构造函数就足够了:

public Card(String name, String description, 
               String mainImagePath, String secondaryImagePath) 
    mName = name;
    mDescription = description;
    mMainImagePath = mainImagePath;
    mSecondaryImagePath = secondaryImagePath;
    mMainImage = new Image(mainImagePath);
    mSecondaryImage = new Image(secondaryImagePath);

【讨论】:

以上是关于使用两个不同的构造函数创建一个对象[重复]的主要内容,如果未能解决你的问题,请参考以下文章

创建单个对象时如何执行多个构造函数[重复]

即使使用复制构造函数,克隆对象也会更改原始对象[重复]

对象的构造与析构

在java中从另一个调用一个构造函数[重复]

将对象数组传递给构造函数[重复]

golang语言构造函数