子类和超类
Sublass and superclass
我需要有关创建子类的帮助,子类不会覆盖父类方法。我使用注册表对象来收集所有项目。
public class Registry {
private final Item[] items = new Item[100];
private int pos =0;
public Item[] getItems(){
return items;
}
public void addItem(Item item) {
items[pos] = item;
pos ++;
}
public void addItem(Item item, int nrTimes) {
for(int i = 0; i<nrTimes;i++){
items[pos] = item;
pos++;
}
}
public double totPrice(){
double total = 0.0;
for(int i = 0; i < items.length; i ++){
if(items[i] == null) break;
total += items[i].getNr(this);
}
return total;
}
public String toString() {
String result = "";
for(int i= 0; i < items.length;i++){
if (items[i] == null) break;
result = result + items[i].getName()+" $" + items[i].getNr(this) + " Sold by " + items[i].getName2()+ "\n";
}
return result;
}
}
public class Item {
private final String name;
private final String name2;
private final double nr1;
public Item (String name, String name2, double nr1) {
this.name = name; this.name2 = name2; this.nr1 = nr1;
}
public Item (Item obj) {
name = obj.name; name2 = obj.name2; nr1 = obj.nr1;
}
public double getNr(Registry reg) { return nr1;}
public final String getName() { return name;}
public final String getName2() { return name2;}
}
子类
public class ReducedItem extends Item {
private final Item obj = this;
private final double reduce; // in %
public ReducedItem (Item obj, double reduce) {
super(obj);
this.reduce = reduce/100;
}
public double getNr(Registry reg){
double nr;
nr = super.getNr(reg) - (super.getNr(reg)*reduce);
return nr;
}
}
这里是我创建对象的主要地方
import java.util.*;
public class Main {
static Scanner scan = new Scanner(System.in);
public static void registerItems(Registry reg){
String name,seller;
double price;
int nrprod,discount;
scan.nextLine();
System.out.print("Product name: ");
name = scan.nextLine();
System.out.print("Seller: ");
seller = scan.nextLine();
System.out.print("Price: ");
price = scan.nextDouble();
System.out.print("How many: ");
nrprod = scan.nextInt();
System.out.print("Discount (enter 0 if no discount applies): ");
discount = scan.nextInt();
Item item = new Item(name,seller,price);
if(discount >0) {
ReducedItem redItem = new ReducedItem(item, discount);
if(nrprod == 1){
reg.addItem(redItem);
}else{
reg.addItem(redItem, nrprod);
}
}else{
if(nrprod == 1){
reg.addItem(item);
}else{
reg.addItem(item, nrprod);
}
}
}
public static void main(String[] args) {
System.out.println("Welcome");
System.out.println("What's your name?");
String customer = scan.nextLine();
System.out.println("Hi "+customer+". Please choose one of the following options:");
System.out.print("buy product (1) or checkout (0)");
Registry reg = new Registry();
int input = scan.nextInt();
while(input == 1){
registerItems(reg);
System.out.println("buy product (1) or checkout (0)");
input = scan.nextInt();
}
System.out.println(reg.toString());
System.out.println("Your total is " + reg.totPrice());
}
}
在registerItems中输入
Product name = Car
Seller = Jack
Price = 10000
how many =1
discount = 20
checkout = 0
输出
Car 00 Sold by jack
Your total is 8000.0
现车优惠20%
这是我认为您正在寻找的工作示例。
public class J_crow {
public static void main(String... args) {
Item item = new Item("Name One", "Second Name", 42);
System.out.println(item);
Item reducedItem = new ReducedItem(item, 20);
System.out.println(reducedItem);
}
}
class Item {
private final String name;
private final String name2;
private final double nr1;
public Item(String name, String name2, double nr1) {
this.name = name;
this.name2 = name2;
this.nr1 = nr1;
}
public Item(Item obj) {
this(obj.getName(), obj.getName2(), obj.getNr());
}
public double getNr() {
return nr1;
}
@Override
public String toString() {
return String.format("I am an [%s], I cost [%f]", getClass().getCanonicalName(), getNr());
}
public String getName2() {
return name2;
}
public String getName() {
return name;
}
}
class ReducedItem extends Item {
private final double reduce; // in %
public ReducedItem(Item obj, double reduce) {
super(obj);
this.reduce = reduce;
}
@Override
public double getNr() {
return super.getNr() * (1 - (reduce / 100d));
}
}
输出:
I am an [Item], I cost [42.000000]
I am an [ReducedItem], I cost [33.600000]
错误解释
您的错误出现在 Registry
class 中的以下几行中。 (我得到了你之前发布的源代码。)
public void addItem(Item item) {
items[pos] = new Item(item);
pos ++;
}
您无缘无故地创建了一个全新的 Item
,即使客户想要添加一个 ReducedItem
,所以您实际上是在 删除 通过将 ReducedItem
s 替换为 Item
s 并导致 ReducedItem.getNr
过载到 never 来进行折扣。如果您 运行 在调试器中逐步执行代码,您应该能够看到。
这一行应该只是 items[pos++] = item;
.
另请注意,您的 Registry
class 存在一些问题和隐藏的错误。例如,
- 这个错误也出现在不必要的
addItem(Item, int)
方法重载中;
- 错误命名的
getNr
方法期望 Registry
的实例然后不将其用于任何事情;
- 向您的注册表添加足够的项目,当
pos
大于 items.length
; 时,您将遇到索引超出范围异常
Registry
效率非常低,浪费了很多 space(例如 new Item[100]
),然后每次都循环所有 100 个,即使很少或没有项目已添加。
还有其他几个问题我不会讨论,所以我建议您将您的代码与我在下面的建议进行比较,然后了解它们为何不同。
代码重新设计
您提供的代码有几个编译错误并且难以使用。相反,我试图了解您正在尝试做什么,并重构了代码,希望能澄清一些事情,同时向您展示一些您应该考虑改进和简化代码的事情。
请注意,您需要改编我在这里写的内容。
总结
我创建了一个 Example
class 来表示应用程序。它使用 ItemRegistry
来注册 Item
s。 Item
接口由RegularItem
(即没有折扣的Item
)和ItemDiscount
实现,这是一个例子Decorator Design Pattern.
Item
接口:
public interface Item {
String getName();
double getCost();
}
这应该很简单:基本上已经声明了一个类型。通常,您应该优先使用接口来指定新类型,因为它允许应用程序的其余部分依赖 合同协议 (即规范)而不是 实现细节(即class)。这就是接口的用途。
警告:您真的不应该在实际应用程序中使用浮点类型来处理金钱。基本上是由于舍入误差的累积会慢慢导致你的结果不正确。有关详细信息,请参阅 this post。我在这里使用它是因为这是一个简单的玩具示例。
RegularItem
Class:
public class RegularItem implements Item {
private String name;
private double cost;
public RegularItem(String name, double cost) {
this.name = name;
this.cost = cost;
}
@Override
public String getName() {
return name;
}
@Override
public double getCost() {
return cost;
}
}
这应该是不言自明的:具有名称及其相关成本的项目的简单实现。常规项目没有应用折扣。 ItemDiscount
class.
事情开始变得更有趣
ItemDiscount
Class(装饰器)
// Decorator class
public class ItemDiscount implements Item {
private Item item;
private double discount;
public ItemDiscount(Item it, double amount) {
item = it;
discount = amount / 100.0; // e.g. 15/100 = 15%
}
@Override
public String getName() {
return item.getName();
}
@Override
public double getCost() {
return item.getCost() - (item.getCost() * discount);
}
}
它基本上包装了任何 Item
需要应用折扣的东西,以及 returns 客户请求 Item
的成本时的折扣成本。这有几个优点:
- 客户只看到
Item
s,不知道哪些有折扣,哪些没有。没必要。
- 您可以对同一商品应用任意数量的折扣(例如,客户有 5 张折扣券?没问题!)
- 您的应用程序更易于理解和维护
还有更多,但我现在不去那里。让我们跟进下面的ItemRegistry
:
ItemRegistry
Class
import java.util.ArrayList;
import java.util.List;
public class ItemRegistry {
private List<Item> items = new ArrayList<Item>();
public ItemRegistry() {}
void registerItem(Item i) {
items.add(i);
}
double getTotalCost() {
double total = 0.0;
for(Item i : items)
total += i.getCost();
return total;
}
List<Item> getItems() {
return items;
}
}
注意这个简化版本中的几件事。
- class不需要处理折扣或非折扣的“特殊情况”。 (还记得有 5 张优惠券的顾客吗?这里不需要更改!)
- class 使用 接口 而不是 classes 进行通信,后者是应该保持封装的实现细节。
请注意,注册表不需要了解它拥有的项目的具体类型——只需要知道它们是项目即可。 (您不希望每次定义一种新的项目时都必须更新整个应用程序,或者更糟的是,强迫那些需要维护您的代码的人这样做,做你?)
使用注册表的客户端也不需要知道它使用的是 ArrayList
还是其他东西——只需要知道它是 List
。这使其更 space 高效,并修复了您的代码在添加 100 多个项目后会遇到的错误。
您可以在下面的 Example
class 中看到它,因为它使用了 ItemRegistry
:
Example
Class(申请)
public class Example {
public static void main(String[] args) {
ItemRegistry reg = new ItemRegistry();
reg.registerItem(new RegularItem("Toy Gun", 10));
reg.registerItem(new ItemDiscount(new RegularItem("Toy Car", 100), 10)); // apply 10% discount to Toy Car item
for(Item item : reg.getItems()) {
System.out.println("Name: " + item.getName());
System.out.println("Cost: " + item.getCost());
}
System.out.println("Total: " + reg.getTotalCost());
}
}
此示例应该可以让您更轻松地在调试器中逐步执行代码,以便您可以了解如何调用方法以及覆盖的实际工作方式。
程序输出:
Name: Toy Gun
Cost: 10.0
Name: Toy Car
Cost: 90.0
Total: 100.0
而且是正确的:)
我太笨了!我解决了我的问题
public void addItem(Item item) {
items[pos] = new Item(item);
pos ++;
}
public void addItem(Item item, int nrTimes) {
for(int i = 0; i<nrTimes;i++){
items[pos] = new Item(item);
pos++;
}
}
我每次都创建一个新的Item,我需要使用传递的参数来代替
public void addItem(Item item) {
items[pos] = item;
pos ++;
}
public void addItem(Item item, int nrTimes) {
for(int i = 0; i<nrTimes;i++){
items[pos] = item;
pos++;
}
}
谢谢,看了你的回答和评论我学到了很多东西
我需要有关创建子类的帮助,子类不会覆盖父类方法。我使用注册表对象来收集所有项目。
public class Registry {
private final Item[] items = new Item[100];
private int pos =0;
public Item[] getItems(){
return items;
}
public void addItem(Item item) {
items[pos] = item;
pos ++;
}
public void addItem(Item item, int nrTimes) {
for(int i = 0; i<nrTimes;i++){
items[pos] = item;
pos++;
}
}
public double totPrice(){
double total = 0.0;
for(int i = 0; i < items.length; i ++){
if(items[i] == null) break;
total += items[i].getNr(this);
}
return total;
}
public String toString() {
String result = "";
for(int i= 0; i < items.length;i++){
if (items[i] == null) break;
result = result + items[i].getName()+" $" + items[i].getNr(this) + " Sold by " + items[i].getName2()+ "\n";
}
return result;
}
}
public class Item {
private final String name;
private final String name2;
private final double nr1;
public Item (String name, String name2, double nr1) {
this.name = name; this.name2 = name2; this.nr1 = nr1;
}
public Item (Item obj) {
name = obj.name; name2 = obj.name2; nr1 = obj.nr1;
}
public double getNr(Registry reg) { return nr1;}
public final String getName() { return name;}
public final String getName2() { return name2;}
}
子类
public class ReducedItem extends Item {
private final Item obj = this;
private final double reduce; // in %
public ReducedItem (Item obj, double reduce) {
super(obj);
this.reduce = reduce/100;
}
public double getNr(Registry reg){
double nr;
nr = super.getNr(reg) - (super.getNr(reg)*reduce);
return nr;
}
}
这里是我创建对象的主要地方
import java.util.*;
public class Main {
static Scanner scan = new Scanner(System.in);
public static void registerItems(Registry reg){
String name,seller;
double price;
int nrprod,discount;
scan.nextLine();
System.out.print("Product name: ");
name = scan.nextLine();
System.out.print("Seller: ");
seller = scan.nextLine();
System.out.print("Price: ");
price = scan.nextDouble();
System.out.print("How many: ");
nrprod = scan.nextInt();
System.out.print("Discount (enter 0 if no discount applies): ");
discount = scan.nextInt();
Item item = new Item(name,seller,price);
if(discount >0) {
ReducedItem redItem = new ReducedItem(item, discount);
if(nrprod == 1){
reg.addItem(redItem);
}else{
reg.addItem(redItem, nrprod);
}
}else{
if(nrprod == 1){
reg.addItem(item);
}else{
reg.addItem(item, nrprod);
}
}
}
public static void main(String[] args) {
System.out.println("Welcome");
System.out.println("What's your name?");
String customer = scan.nextLine();
System.out.println("Hi "+customer+". Please choose one of the following options:");
System.out.print("buy product (1) or checkout (0)");
Registry reg = new Registry();
int input = scan.nextInt();
while(input == 1){
registerItems(reg);
System.out.println("buy product (1) or checkout (0)");
input = scan.nextInt();
}
System.out.println(reg.toString());
System.out.println("Your total is " + reg.totPrice());
}
}
在registerItems中输入
Product name = Car
Seller = Jack
Price = 10000
how many =1
discount = 20
checkout = 0
输出
Car 00 Sold by jack
Your total is 8000.0
现车优惠20%
这是我认为您正在寻找的工作示例。
public class J_crow {
public static void main(String... args) {
Item item = new Item("Name One", "Second Name", 42);
System.out.println(item);
Item reducedItem = new ReducedItem(item, 20);
System.out.println(reducedItem);
}
}
class Item {
private final String name;
private final String name2;
private final double nr1;
public Item(String name, String name2, double nr1) {
this.name = name;
this.name2 = name2;
this.nr1 = nr1;
}
public Item(Item obj) {
this(obj.getName(), obj.getName2(), obj.getNr());
}
public double getNr() {
return nr1;
}
@Override
public String toString() {
return String.format("I am an [%s], I cost [%f]", getClass().getCanonicalName(), getNr());
}
public String getName2() {
return name2;
}
public String getName() {
return name;
}
}
class ReducedItem extends Item {
private final double reduce; // in %
public ReducedItem(Item obj, double reduce) {
super(obj);
this.reduce = reduce;
}
@Override
public double getNr() {
return super.getNr() * (1 - (reduce / 100d));
}
}
输出:
I am an [Item], I cost [42.000000]
I am an [ReducedItem], I cost [33.600000]
错误解释
您的错误出现在 Registry
class 中的以下几行中。 (我得到了你之前发布的源代码。)
public void addItem(Item item) {
items[pos] = new Item(item);
pos ++;
}
您无缘无故地创建了一个全新的 Item
,即使客户想要添加一个 ReducedItem
,所以您实际上是在 删除 通过将 ReducedItem
s 替换为 Item
s 并导致 ReducedItem.getNr
过载到 never 来进行折扣。如果您 运行 在调试器中逐步执行代码,您应该能够看到。
这一行应该只是 items[pos++] = item;
.
另请注意,您的 Registry
class 存在一些问题和隐藏的错误。例如,
- 这个错误也出现在不必要的
addItem(Item, int)
方法重载中; - 错误命名的
getNr
方法期望Registry
的实例然后不将其用于任何事情; - 向您的注册表添加足够的项目,当
pos
大于items.length
; 时,您将遇到索引超出范围异常
Registry
效率非常低,浪费了很多 space(例如new Item[100]
),然后每次都循环所有 100 个,即使很少或没有项目已添加。
还有其他几个问题我不会讨论,所以我建议您将您的代码与我在下面的建议进行比较,然后了解它们为何不同。
代码重新设计
您提供的代码有几个编译错误并且难以使用。相反,我试图了解您正在尝试做什么,并重构了代码,希望能澄清一些事情,同时向您展示一些您应该考虑改进和简化代码的事情。
请注意,您需要改编我在这里写的内容。
总结
我创建了一个 Example
class 来表示应用程序。它使用 ItemRegistry
来注册 Item
s。 Item
接口由RegularItem
(即没有折扣的Item
)和ItemDiscount
实现,这是一个例子Decorator Design Pattern.
Item
接口:
public interface Item {
String getName();
double getCost();
}
这应该很简单:基本上已经声明了一个类型。通常,您应该优先使用接口来指定新类型,因为它允许应用程序的其余部分依赖 合同协议 (即规范)而不是 实现细节(即class)。这就是接口的用途。
警告:您真的不应该在实际应用程序中使用浮点类型来处理金钱。基本上是由于舍入误差的累积会慢慢导致你的结果不正确。有关详细信息,请参阅 this post。我在这里使用它是因为这是一个简单的玩具示例。
RegularItem
Class:
public class RegularItem implements Item {
private String name;
private double cost;
public RegularItem(String name, double cost) {
this.name = name;
this.cost = cost;
}
@Override
public String getName() {
return name;
}
@Override
public double getCost() {
return cost;
}
}
这应该是不言自明的:具有名称及其相关成本的项目的简单实现。常规项目没有应用折扣。 ItemDiscount
class.
ItemDiscount
Class(装饰器)
// Decorator class
public class ItemDiscount implements Item {
private Item item;
private double discount;
public ItemDiscount(Item it, double amount) {
item = it;
discount = amount / 100.0; // e.g. 15/100 = 15%
}
@Override
public String getName() {
return item.getName();
}
@Override
public double getCost() {
return item.getCost() - (item.getCost() * discount);
}
}
它基本上包装了任何 Item
需要应用折扣的东西,以及 returns 客户请求 Item
的成本时的折扣成本。这有几个优点:
- 客户只看到
Item
s,不知道哪些有折扣,哪些没有。没必要。 - 您可以对同一商品应用任意数量的折扣(例如,客户有 5 张折扣券?没问题!)
- 您的应用程序更易于理解和维护
还有更多,但我现在不去那里。让我们跟进下面的ItemRegistry
:
ItemRegistry
Class
import java.util.ArrayList;
import java.util.List;
public class ItemRegistry {
private List<Item> items = new ArrayList<Item>();
public ItemRegistry() {}
void registerItem(Item i) {
items.add(i);
}
double getTotalCost() {
double total = 0.0;
for(Item i : items)
total += i.getCost();
return total;
}
List<Item> getItems() {
return items;
}
}
注意这个简化版本中的几件事。
- class不需要处理折扣或非折扣的“特殊情况”。 (还记得有 5 张优惠券的顾客吗?这里不需要更改!)
- class 使用 接口 而不是 classes 进行通信,后者是应该保持封装的实现细节。
请注意,注册表不需要了解它拥有的项目的具体类型——只需要知道它们是项目即可。 (您不希望每次定义一种新的项目时都必须更新整个应用程序,或者更糟的是,强迫那些需要维护您的代码的人这样做,做你?)
使用注册表的客户端也不需要知道它使用的是 ArrayList
还是其他东西——只需要知道它是 List
。这使其更 space 高效,并修复了您的代码在添加 100 多个项目后会遇到的错误。
您可以在下面的 Example
class 中看到它,因为它使用了 ItemRegistry
:
Example
Class(申请)
public class Example {
public static void main(String[] args) {
ItemRegistry reg = new ItemRegistry();
reg.registerItem(new RegularItem("Toy Gun", 10));
reg.registerItem(new ItemDiscount(new RegularItem("Toy Car", 100), 10)); // apply 10% discount to Toy Car item
for(Item item : reg.getItems()) {
System.out.println("Name: " + item.getName());
System.out.println("Cost: " + item.getCost());
}
System.out.println("Total: " + reg.getTotalCost());
}
}
此示例应该可以让您更轻松地在调试器中逐步执行代码,以便您可以了解如何调用方法以及覆盖的实际工作方式。
程序输出:
Name: Toy Gun
Cost: 10.0
Name: Toy Car
Cost: 90.0
Total: 100.0
而且是正确的:)
我太笨了!我解决了我的问题
public void addItem(Item item) {
items[pos] = new Item(item);
pos ++;
}
public void addItem(Item item, int nrTimes) {
for(int i = 0; i<nrTimes;i++){
items[pos] = new Item(item);
pos++;
}
}
我每次都创建一个新的Item,我需要使用传递的参数来代替
public void addItem(Item item) {
items[pos] = item;
pos ++;
}
public void addItem(Item item, int nrTimes) {
for(int i = 0; i<nrTimes;i++){
items[pos] = item;
pos++;
}
}
谢谢,看了你的回答和评论我学到了很多东西