有没有办法不必为每个子类都编写变量和构造函数?

huangapple go评论95阅读模式
英文:

Is there a way to not have to write the variables and the constructor for every child class

问题

以下是您要翻译的内容:

创建一个管理广告的程序。每个广告都有2个共同属性:1:ID,2:描述。
根据广告是用于网页还是报纸等,它将具有不同的每页成本、字数或显示持续时间。

我有3个文件

  1. Main.java
  2. Advertisement.java
  3. PrintedAd.java
  4. WebpageAd.java

Advertisement.java

  1. public class Advertisement{
  2. private int ID;
  3. private String description;
  4. // 构造函数
  5. public Advertisement(int ID, String description){
  6. this.ID = ID;
  7. this.description = description;
  8. }
  9. public int getID() {
  10. return ID;
  11. }

PrintedAd.java

  1. public class PrintedAd extends Advertisement{
  2. private int First; //第一页成本
  3. private int Middle; //中间页成本
  4. private int Last; //最后一页成本
  5. public PrintedAd(int First, int Middle, int Last){
  6. this.First = First;
  7. this.Middle = Middle;
  8. this.Last = Last;
  9. }
  10. public int getFirst() {
  11. return First;
  12. }

Main.java

  1. public class Main{
  2. public static void main(String[] args) {
  3. Advertisement ad = new Advertisement(34567, "test");
  4. System.out.println(ad.getID());
  5. PrintedAd ad2 = new PrintedAd(10,20,30);
  6. System.out.println(ad2);
  7. }
  8. }

(为了更易读,我不得不更改变量名称,所以如果出现任何“愚蠢”的错误,请理解)
从这两个类创建2个不同的变量是有效的。

尽管变量ad2是一则广告,需要有一个ID号和一个描述,但我无法同时拥有Advertisement和PrintedAd属性。

我正在询问的是是否有办法不必为每个子类编写变量和构造函数。
如果我要为每种类型的广告都添加这个,我认为这将解决问题,但还是要问是否有办法:

  1. private int ID;
  2. private String description;
  3. // 构造函数
  4. public Advertisement(int ID, String description){
  5. this.ID = ID;
  6. this.description = description;
  7. }
英文:

Creating a program that manages advertisements. Every ad will have 2 common attributes 1: ID, 2: Description.
Depending if the ad is for a webpage or for a newspaper for example it will have different costs per page, words or duration it is shown.

I have 3 files

  1. Main.java
  2. Advertisement.java
  3. PrintedAd.java
  4. WebpageAd.java

Advertisement.java

  1. public class Advertisement{
  2. private int ID;
  3. private String description;
  4. // Constructor
  5. public Advertisement(int ID, String description){
  6. this.ID = ID;
  7. this.description = description;
  8. }
  9. public int getID() {
  10. return ID;
  11. }

PrintedAd.java

  1. public class PrintedAd extends Advertisement{
  2. private int First; //first page cost
  3. private int Middle; //middle page cost
  4. private int Last; //last page cost
  5. public PrintedAd(int First, int Middle, int Last){
  6. this.First = First;
  7. this.Middle = Middle;
  8. this.Last = Last;
  9. }
  10. public int getFirst() {
  11. return First;
  12. }

Main.java

  1. public class Main{
  2. public static void main(String[] args) {
  3. Advertisement ad = new Advertisement(34567, "test");
  4. System.out.println(ad.getID());
  5. PrintedAdd ad2 = new PrintedAdd(10,20,30);
  6. System.out.println(ad2);
  7. }
  8. }

(had to change var names to make it more readable so if any "dumb" errors appear please understand)
Creating 2 different variables from these 2 classes works fine.

Even though the variable ad2 is an ad and needs to have an ID number and a description I am unable to do both the Advertisement and PrintedAd attributes.

What I am asking is if there a way for me to not have to write the variables and the constructor for every child class.
If I were to add to every type of ad this it would solve the issue I believe but still asking if there is a way:

  1. private int ID;
  2. private String description;
  3. // Constructor
  4. public Advertisement(int ID, String description){
  5. this.ID = ID;
  6. this.description = description;
  7. }

答案1

得分: 3

在你的代码中:

  1. PrintedAdd ad2 = new PrintedAdd(10,20,30);

这个新的 PrintedAdd 对象(也是一个 Advertisement)在其两个继承成员字段 IDdescription 中都有 null 值。你忘了调用构造函数(或者设置器)来指定这些值,所以它们默认为 null

所以,如果你希望子类在运行时具有5个字段,其中2个是继承的,3个在子类自身定义,你需要传递5个值(原始类型或对象引用)。你可以通过构造函数传递,和/或者通过设置器方法传递。或者你可以使用依赖注入框架,比如 Jakarta Contexts and Dependency Injection,Google Guice,或者 Spring。否则,成员字段将使用默认值;对于对象引用,这意味着 null

在你的特定情况下,你的对象是只读的,有获取器但没有设置器。所以这就排除了设置器的选项。而且在你的情况下,依赖注入框架不适用,因为它是用来提供资源和服务的,而不是用来提供单个值,比如ID或描述。所以,只剩下构造函数的选项。你应该编写子类以接受5个参数的构造函数,包括2个继承字段和3个子类特定字段。

请注意,子类的构造函数可以调用父类的构造函数。可以参考现有的问题,比如 "在Java中从子类构造函数调用父类"。

以下是一些示例代码和注释。

  • 你的超类应该被标记为 abstract,因为你只打算实例化子类,而不是超类。你可能想阅读由 baeldung 提供的 "Java抽象类中的构造函数"。还可以阅读问题, "抽象类可以有构造函数吗?"。
  • 由于你在编译时知道所有的子类,并且不希望在运行时动态添加新的子类,你可以封闭超类。封闭的类和接口限制了哪些其他类或接口可以扩展或实现它们。(对于你的问题不重要,只是现代Java编程的一些注意事项。)
  • 在Java的命名约定中,成员字段应该以小写字母开头命名。所以,应该是 first,而不是 First。应该是 id,而不是 ID。按照约定,全部大写表示一个常量。
  • 为了简化,我将 PrintAd 上的多个成员字段替换为一个 LocalDate
  • 注意,将id和描述传递给每个构造函数是有意义的,因为没有其他方法来确定这些字段的值应该是什么。

超类:

  1. // 在这里是你的超类代码

每个子类,还有一个额外的 RadioAd

  1. // 在这里是你的子类代码

一个应用程序来使用这些业务逻辑类:

  1. // 在这里是你的应用程序代码

运行时:

  1. // 在这里是运行时输出

要了解更多信息,请查看Oracle提供的免费的 Java 教程:

  • 控制类的成员访问
  • 继承
  1. <details>
  2. <summary>英文:</summary>
  3. In your code:
  4. PrintedAdd ad2 = new PrintedAdd(10,20,30);
  5. This new `PrintedAdd` object (also an `Advertisement`) has `null` in its two inherited member fields, `ID` and `description`. You neglected to invoke a constructor (or setters) to specify those values, so they default to `null`.
  6. So yes, if you want a subclass to have 5 fields, 2 inherited, and 3 defined on the subclass itself, at run time you need to pass 5 values (primitives or object references). You can pass to a constructor, and/or you can pass via setter methods. Or you could use a [dependency injection][1] framework such as [*Jakarta Contexts and Dependency Injection*][2], [*Google Guice*][3], or [*Spring*][4]. Otherwise, you get default values in member field; for object references that means `null`.
  7. In your particular case, your objects are read-only, with getters but no setters. So that eliminates the setters option. And in your case, a dependency injection framework is not appropriate, as that is for providing resources and services, not for individual values such as an ID or description. So, that leaves the constructor option. &#128073; You should write the subclass to have a constructor taking 5 arguments, for the 2 inherited fields and the 3 subclass-specific fields.
  8. Be aware that a subclass’ constructor can call a superclass’ constructor. See existing Question such as [*Calling superclass from a subclass constructor in Java*](https://stackoverflow.com/q/19326229/642706).
  9. Here is some example code, and some notes.
  10. - Your superclass should be marked `abstract` as you intend only to instantiate the subclasses, never the superclass. You may want to read [*Constructors in Java Abstract Classes*](https://www.baeldung.com/java-abstract-classes-constructors) by [baeldung][5]. And read Question, [*Can an abstract class have a constructor?*](https://stackoverflow.com/q/260666/642706).
  11. - Since you know all subclasses at compile time, and do not expect new ones to be dynamically added at runtime, you can [seal the superclass][6]. Sealed classes and interfaces restrict which other classes or interfaces may extend or implement them. (Not important for your Question, just a note for modern Java programming.)
  12. - In Java naming conventions, a member field should be name with an initial lowercase letter. So, `first`, not `First`. And `id`, not `ID`. All uppercase by convention means a [constant][7].
  13. - For simplicity, I replaced your multiple member fields on `PrintAd` to a single `LocalDate`.
  14. - &#128073; Note how it makes sense to pass the id and description in each constructor — there is no other way to discern what the value should be for those fields.
  15. The superclass:
  16. ```java
  17. package work.basil.example.advertising;
  18. import java.util.Objects;
  19. import java.util.UUID;
  20. public abstract sealed class Advertisement
  21. permits PrintAd, WebAd, RadioAd
  22. {
  23. // Member fields. Read-only, via getter methods.
  24. private final UUID id;
  25. private final String description;
  26. // Constructors
  27. public Advertisement ( final UUID id ,
  28. final String description )
  29. {
  30. this.id = id;
  31. this.description = description;
  32. }
  33. // Getters
  34. public UUID getId ( )
  35. {
  36. return id;
  37. }
  38. public String getDescription ( )
  39. {
  40. return description;
  41. }
  42. // `Object` overrides
  43. @Override
  44. public boolean equals ( Object o )
  45. {
  46. if ( this == o ) return true;
  47. if ( o == null || getClass ( ) != o.getClass ( ) ) return false;
  48. Advertisement that = ( Advertisement ) o;
  49. return Objects.equals ( id , that.id );
  50. }
  51. @Override
  52. public int hashCode ( )
  53. {
  54. return Objects.hash ( id );
  55. }
  56. @Override
  57. public String toString ( )
  58. {
  59. return &quot;Advertisement[&quot; +
  60. &quot;id=&quot; + id + &quot;, &quot; +
  61. &quot;description=&quot; + description + &#39;]&#39;;
  62. }
  63. }

Each of the subclasses, with a third one RadioAd just for fun:

  1. package work.basil.example.advertising;
  2. import java.time.LocalDate;
  3. import java.util.UUID;
  4. public final class PrintAd extends Advertisement
  5. {
  6. private final LocalDate runDate;
  7. public PrintAd ( final UUID id , final String description , final LocalDate runDate )
  8. {
  9. super ( id , description );
  10. this.runDate = runDate;
  11. }
  12. public LocalDate getRunDate ( )
  13. {
  14. return runDate;
  15. }
  16. }
  1. package work.basil.example.advertising;
  2. import java.net.URL;
  3. import java.util.UUID;
  4. public final class WebAd extends Advertisement
  5. {
  6. private final URL url;
  7. public WebAd ( final UUID id , final String description , final URL url )
  8. {
  9. super ( id , description );
  10. this.url = url;
  11. }
  12. public URL getUrl ( )
  13. {
  14. return url;
  15. }
  16. }
  1. package work.basil.example.advertising;
  2. import java.time.LocalTime;
  3. import java.util.UUID;
  4. public final class RadioAd extends Advertisement
  5. {
  6. private final LocalTime airTime;
  7. public RadioAd ( final UUID id , final String description , final LocalTime airTime )
  8. {
  9. super ( id , description );
  10. this.airTime = airTime;
  11. }
  12. public LocalTime getAirTime ( )
  13. {
  14. return this.airTime;
  15. }
  16. }

And an app to exercise those business logic classes.

  1. package work.basil.example.advertising;
  2. import java.net.MalformedURLException;
  3. import java.net.URI;
  4. import java.time.LocalDate;
  5. import java.time.LocalTime;
  6. import java.util.List;
  7. import java.util.UUID;
  8. public class App
  9. {
  10. public static void main ( String[] args )
  11. {
  12. App app = new App ( );
  13. app.demo ( );
  14. }
  15. private void demo ( )
  16. {
  17. List &lt; Advertisement &gt; ads = null;
  18. try
  19. {
  20. ads =
  21. List.of (
  22. new PrintAd (
  23. UUID.fromString ( &quot;a71330e7-131f-4d10-beac-4e8ffc21887f&quot; ) ,
  24. &quot;Example print ad.&quot; ,
  25. LocalDate.now ( )
  26. ) ,
  27. new WebAd (
  28. UUID.fromString ( &quot;8aafa2cf-03dc-452b-a84d-c61d75964955&quot; ) ,
  29. &quot;Example web ad.&quot; ,
  30. URI.create ( &quot;https://www.DailyBugle.com/ads&quot; ).toURL ( )
  31. ) ,
  32. new RadioAd (
  33. UUID.fromString ( &quot;e21b187c-01e2-44da-9a26-5debb9146cf6&quot; ) ,
  34. &quot;Example radio ad.&quot; ,
  35. LocalTime.NOON
  36. )
  37. );
  38. }
  39. catch ( MalformedURLException e ) { throw new RuntimeException ( e ); }
  40. System.out.println ( &quot;ads = &quot; + ads );
  41. }
  42. }

When run:

>ads = [Advertisement[id=a71330e7-131f-4d10-beac-4e8ffc21887f, description=Example print ad.], Advertisement[id=8aafa2cf-03dc-452b-a84d-c61d75964955, description=Example web ad.], Advertisement[id=e21b187c-01e2-44da-9a26-5debb9146cf6, description=Example radio ad.]]


To learn more, see the The Java Tutorials provided by Oracle Corp free of cost:

答案2

得分: -1

以下是您要翻译的内容:

在完成此任务的一种方法是在Advertisement类内创建一个静态字段。

然后,在您的Advertisement构造函数中,将此字段递增1,并将其赋值给您的ID字段。

考虑以下代码:

  1. public class Advertisement {
  2. private static int universalId = 0;
  3. private int ID;
  4. private String description;
  5. protected Advertisement() {
  6. ID = universalId++;
  7. }
  8. public Advertisement(String description) {
  9. this();
  10. this.description = description;
  11. }
  12. public int getID() {
  13. return ID;
  14. }
  15. }

然后,对于您的子类,在其构造函数内调用超类构造函数,如下所示:

  1. public class PrintedAdd extends Advertisement {
  2. private int First; //first page cost
  3. private int Middle; //middle page cost
  4. private int Last; //last page cost
  5. public PrintedAdd(int First, int Middle, int Last) {
  6. super();
  7. this.First = First;
  8. this.Middle = Middle;
  9. this.Last = Last;
  10. }
  11. public int getFirst() {
  12. return First;
  13. }
  14. }

因此,调用ad.getID()应该产生0,调用ad2.getID()应该产生1

英文:

One way to complete this task is to create a static field within the Advertisement class.

Then, within your Advertisement constructor, increment this field by 1, and assign it to your ID field.

Consider the following.

  1. public class Advertisement {
  2. private static int universalId = 0;
  3. private int ID;
  4. private String description;
  5. protected Advertisement() {
  6. ID = universalId++;
  7. }
  8. public Advertisement(String description) {
  9. this();
  10. this.description = description;
  11. }
  12. public int getID() {
  13. return ID;
  14. }
  15. }

Then, for your sub-classes, within their constructors', make a call to the super constructor, as follows.

  1. public class PrintedAdd extends Advertisement {
  2. private int First; //first page cost
  3. private int Middle; //middle page cost
  4. private int Last; //last page cost
  5. public PrintedAdd(int First, int Middle, int Last) {
  6. super();
  7. this.First = First;
  8. this.Middle = Middle;
  9. this.Last = Last;
  10. }
  11. public int getFirst() {
  12. return First;
  13. }
  14. }

Thus, making a call to ad.getID() should produce 0, and making a call to ad2.getID() should produce 1.

huangapple
  • 本文由 发表于 2023年5月18日 03:44:59
  • 转载请务必保留本文链接:https://go.coder-hub.com/76275687.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定