У меня эта проблема, и я застрял в ней часами. Я здесь новенький и надеюсь, что вы, ребята, сможете помочь.
Я думал, что проблема в объявлении массива или чего-то в этом роде, но я не могу это исправить.
Моя идея состояла в том, чтобы разделить коды на три разные части для построения, отображения и основного метода, но, видимо, в процессе возникла ошибка.
private static void constructArray(Customer [] c){
c = new Customer[3];
ArrayList<ItemInfo> cust1 = new ArrayList<>();
cust1.add(new ItemInfo("Mutton", 1, 19.85));
cust1.add(new ItemInfo("Stationery",2,17.66));
ArrayList<ItemInfo> cust2 = new ArrayList<>();
cust2.add(new ItemInfo("Fishball",1,12.07));
cust2.add(new ItemInfo("T Bone Steak",3, 19.20));
cust2.add(new ItemInfo("Stationery", 2, 12.25));
ArrayList<ItemInfo> cust3 = new ArrayList<>();
cust3.add(new ItemInfo("Crab", 2, 14.08));
c[0] = new Customer(cust1, "cheque");
c[1] = new Customer(cust2, "cash");
c[2] = new CustomerPlus(cust3, "Paynow", true);
}
private static void displayArray(Customer [] c){
c = new Customer[3];
for(Customer cust : c){
if(cust instanceof CustomerPlus){
CustomerPlus plus = (CustomerPlus) cust;
plus.addItem(new ItemInfo("Cigarette",2,12.96));
System.out.printf("Mode of payment:%s%nInvoice no:%04d%n%n", plus.getPaymentmode(), plus.getNumber());
System.out.printf("%s%19s%10s%13s%n","Item","Quantity","Price","Sub Total");
System.out.println(plus);
System.out.printf("Total payment: %.2f%n", plus.computePayment());
if(plus.getAdult())
System.out.println("Customer: adult");
System.out.println("-----------------------------------------");
}
else{
System.out.printf("Mode of payment:%s%nInvoice no:%04d%n%n", cust.getPaymentmode(), cust.getNumber());
System.out.printf("%s%19s%10s%13s%n","Item","Quantity","Price","Sub Total");
System.out.println(cust);
System.out.printf("Total payment: %.2f%n", cust.computePayment());
System.out.println("-----------------------------------------");
}
}
}
public static void main(String[] args){
main m = new main();
Customer [] c = new Customer[3];
constructArray(c);
displayArray(c);
}
Вот, в конечном счете, причина NPE:
private static void displayArray(Customer [] c){
c = new Customer[3];
for(Customer cust : c){
Вы инициализируете c как новый пустой массив клиентов. Все позиции в этом новом массиве будут иметь значение null.
Затем вы пытаетесь перебрать их и получить доступ к полям каждого клиента. Это не удастся, потому что значения равны нулю.
Вот отредактированная версия вашего кода:
public class Main {
// methods which create a value should preferably return
// their result rather than updating their input
// for reasons of code readability
private static Customer[] constructArray() {
Customer[] customers = new Customer[3];
// add the items directly to the customer instead of creating a list first
customers[0] = new BasicCustomer("cheque");
customers[0].addItem(new ItemInfo("Mutton", 1, 19.85));
customers[0].addItem(new ItemInfo("Stationery", 2, 17.66));
customers[1] = new BasicCustomer("cash");
customers[1].addItem(new ItemInfo("Fishball", 1, 12.07));
customers[1].addItem(new ItemInfo("T Bone Steak", 3, 19.20));
customers[1].addItem(new ItemInfo("Stationery", 2, 12.25));
customers[2] = new PlusCustomer("Paynow", true);
customers[2].addItem(new ItemInfo("Crab", 2, 14.08));
return customers;
}
private static void displayArray(Customer[] customers) {
for (Customer customer : customers) {
if (customer instanceof PlusCustomer) {
// why kill your plus customers? ;-)
customer.addItem(new ItemInfo("Cigarette", 2, 12.96));
}
// presentation logic moved into the Customer classes
// this keeps the Main class focused on the high level
// process and the Customer classes focused on doing
// customer logic (cohesion, information hiding)
// If you find yourself using instanceof always
// stop and think if you can solve the same issue
// using polymorphism
System.out.println(customer);
}
}
public static void main(String[] args) {
Customer[] customers = constructArray();
displayArray(customers);
}
}
Базовый класс Customer:
public class Customer {
private final List<ItemInfo> items = new ArrayList<>();
private final String paymentMode;
public Customer(String paymentMode) {
this.paymentMode = paymentMode;
}
public void addItem(ItemInfo item) {
items.add(item);
}
public double computePayment() {
double total = 0.0;
for (ItemInfo item : items) {
total += item.getTotal();
}
return total;
}
public int getNumber() {
return items.size();
}
public String getPaymentmode() {
return paymentMode;
}
@Override
public String toString() {
StringBuilder sb = new StringBuilder();
sb.append(String.format("Mode of payment:%s%n", getPaymentmode()));
sb.append(String.format("Invoice no:%04d%n%n", getNumber()));
String itemFormat = "%-20s %-10s %-10s %-10s %n";
sb.append(String.format(itemFormat, "Item", "Quantity", "Price", "Sub Total"));
sb.append(String.format("%n"));
for (ItemInfo item : items) {
sb.append(String.format(itemFormat, item.getName(), item.getAmount(), item.getPrice(), item.getTotal()));
}
sb.append(String.format("%n"));
sb.append(customPresentation());
sb.append(String.format("Total payment: %.2f%n", computePayment()));
return sb.toString();
}
/**
* Sub classes can override this method to provide their own custom part of the presentation logic
*
* @return
*/
String customPresentation() {
return "";
}
}
PlusCustomer должен вызвать суперконструктор, чтобы передать способ оплаты. Осталось реализовать только поле для взрослых.
public class PlusCustomer extends Customer {
private final boolean adult;
public PlusCustomer(String paymentMode, boolean adult) {
super(paymentMode);
this.adult = adult;
}
public boolean getAdult() {
return adult;
}
@Override
String customPresentation() {
return String.format("Customer: %s%n", getAdult() ? "adult" : "minor");
}
}
ItemInfo вычисляет свою сумму. Кстати, обычно вам следует избегать использованияdouble
для таких вычислений в Java это очень неточно. Лучше использовать BigDecimal.
public class ItemInfo {
private final String name;
private final int amount;
private final double price;
public ItemInfo(String name, int amount, double price) {
this.name = name;
this.amount = amount;
this.price = price;
}
public String getName() {
return name;
}
public int getAmount() {
return amount;
}
public double getPrice() {
return price;
}
public double getTotal() {
return price * amount;
}
}
Выход:
Mode of payment:cheque
Invoice no:0002
Item Quantity Price Sub Total
Mutton 1 19.85 19.85
Stationery 2 17.66 35.32
Total payment: 55.17
---------------------------------------
Mode of payment:cash
Invoice no:0003
Item Quantity Price Sub Total
Fishball 1 12.07 12.07
T Bone Steak 3 19.2 57.599999999999994
Stationery 2 12.25 24.5
Total payment: 94.17
---------------------------------------
Mode of payment:Paynow
Invoice no:0002
Item Quantity Price Sub Total
Crab 2 14.08 28.16
Cigarette 2 12.96 25.92
Total payment: 54.08
Customer: adult
---------------------------------------
Это сложно, но проблема в этой строке:
Customer [] c = new Customer[3];
Ваш код не создает три новыхCustomer
объекты. Это просто выделенное пространство памяти для массива, содержащего триCustomer
объекты. Вам нужно пройти через массив и создать экземпляры объектов вручную.
Customer [] c = new Customer[3];
for(int i = 0; i < c.length; ++i){
c[i] = new Customer();
}
c
новым пустым массивом. Вы делаете это как вdisplayArray()
и вconstructArray()
. Зачем ты это делаешь? Progmanc = new Customer[3];
. Nir Alfasi