英文:
Is there a way to not have to write the variables and the constructor for every child class
问题
以下是您要翻译的内容:
创建一个管理广告的程序。每个广告都有2个共同属性:1:ID,2:描述。
根据广告是用于网页还是报纸等,它将具有不同的每页成本、字数或显示持续时间。
我有3个文件
- Main.java
- Advertisement.java
- PrintedAd.java
- WebpageAd.java
Advertisement.java
public class Advertisement{
private int ID;
private String description;
// 构造函数
public Advertisement(int ID, String description){
this.ID = ID;
this.description = description;
}
public int getID() {
return ID;
}
PrintedAd.java
public class PrintedAd extends Advertisement{
private int First; //第一页成本
private int Middle; //中间页成本
private int Last; //最后一页成本
public PrintedAd(int First, int Middle, int Last){
this.First = First;
this.Middle = Middle;
this.Last = Last;
}
public int getFirst() {
return First;
}
Main.java
public class Main{
public static void main(String[] args) {
Advertisement ad = new Advertisement(34567, "test");
System.out.println(ad.getID());
PrintedAd ad2 = new PrintedAd(10,20,30);
System.out.println(ad2);
}
}
(为了更易读,我不得不更改变量名称,所以如果出现任何“愚蠢”的错误,请理解)
从这两个类创建2个不同的变量是有效的。
尽管变量ad2是一则广告,需要有一个ID号和一个描述,但我无法同时拥有Advertisement和PrintedAd属性。
我正在询问的是是否有办法不必为每个子类编写变量和构造函数。
如果我要为每种类型的广告都添加这个,我认为这将解决问题,但还是要问是否有办法:
private int ID;
private String description;
// 构造函数
public Advertisement(int ID, String description){
this.ID = ID;
this.description = description;
}
英文:
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
- Main.java
- Advertisement.java
- PrintedAd.java
- WebpageAd.java
Advertisement.java
public class Advertisement{
private int ID;
private String description;
// Constructor
public Advertisement(int ID, String description){
this.ID = ID;
this.description = description;
}
public int getID() {
return ID;
}
PrintedAd.java
public class PrintedAd extends Advertisement{
private int First; //first page cost
private int Middle; //middle page cost
private int Last; //last page cost
public PrintedAd(int First, int Middle, int Last){
this.First = First;
this.Middle = Middle;
this.Last = Last;
}
public int getFirst() {
return First;
}
Main.java
public class Main{
public static void main(String[] args) {
Advertisement ad = new Advertisement(34567, "test");
System.out.println(ad.getID());
PrintedAdd ad2 = new PrintedAdd(10,20,30);
System.out.println(ad2);
}
}
(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:
private int ID;
private String description;
// Constructor
public Advertisement(int ID, String description){
this.ID = ID;
this.description = description;
}
答案1
得分: 3
在你的代码中:
PrintedAdd ad2 = new PrintedAdd(10,20,30);
这个新的 PrintedAdd
对象(也是一个 Advertisement
)在其两个继承成员字段 ID
和 description
中都有 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和描述传递给每个构造函数是有意义的,因为没有其他方法来确定这些字段的值应该是什么。
超类:
// 在这里是你的超类代码
每个子类,还有一个额外的 RadioAd
:
// 在这里是你的子类代码
一个应用程序来使用这些业务逻辑类:
// 在这里是你的应用程序代码
运行时:
// 在这里是运行时输出
要了解更多信息,请查看Oracle提供的免费的 Java 教程:
- 控制类的成员访问
- 继承
<details>
<summary>英文:</summary>
In your code:
PrintedAdd ad2 = new PrintedAdd(10,20,30);
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`.
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`.
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. 👉 You should write the subclass to have a constructor taking 5 arguments, for the 2 inherited fields and the 3 subclass-specific fields.
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).
Here is some example code, and some notes.
- 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).
- 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.)
- 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].
- For simplicity, I replaced your multiple member fields on `PrintAd` to a single `LocalDate`.
- 👉 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.
The superclass:
```java
package work.basil.example.advertising;
import java.util.Objects;
import java.util.UUID;
public abstract sealed class Advertisement
permits PrintAd, WebAd, RadioAd
{
// Member fields. Read-only, via getter methods.
private final UUID id;
private final String description;
// Constructors
public Advertisement ( final UUID id ,
final String description )
{
this.id = id;
this.description = description;
}
// Getters
public UUID getId ( )
{
return id;
}
public String getDescription ( )
{
return description;
}
// `Object` overrides
@Override
public boolean equals ( Object o )
{
if ( this == o ) return true;
if ( o == null || getClass ( ) != o.getClass ( ) ) return false;
Advertisement that = ( Advertisement ) o;
return Objects.equals ( id , that.id );
}
@Override
public int hashCode ( )
{
return Objects.hash ( id );
}
@Override
public String toString ( )
{
return "Advertisement[" +
"id=" + id + ", " +
"description=" + description + ']';
}
}
Each of the subclasses, with a third one RadioAd
just for fun:
package work.basil.example.advertising;
import java.time.LocalDate;
import java.util.UUID;
public final class PrintAd extends Advertisement
{
private final LocalDate runDate;
public PrintAd ( final UUID id , final String description , final LocalDate runDate )
{
super ( id , description );
this.runDate = runDate;
}
public LocalDate getRunDate ( )
{
return runDate;
}
}
package work.basil.example.advertising;
import java.net.URL;
import java.util.UUID;
public final class WebAd extends Advertisement
{
private final URL url;
public WebAd ( final UUID id , final String description , final URL url )
{
super ( id , description );
this.url = url;
}
public URL getUrl ( )
{
return url;
}
}
package work.basil.example.advertising;
import java.time.LocalTime;
import java.util.UUID;
public final class RadioAd extends Advertisement
{
private final LocalTime airTime;
public RadioAd ( final UUID id , final String description , final LocalTime airTime )
{
super ( id , description );
this.airTime = airTime;
}
public LocalTime getAirTime ( )
{
return this.airTime;
}
}
And an app to exercise those business logic classes.
package work.basil.example.advertising;
import java.net.MalformedURLException;
import java.net.URI;
import java.time.LocalDate;
import java.time.LocalTime;
import java.util.List;
import java.util.UUID;
public class App
{
public static void main ( String[] args )
{
App app = new App ( );
app.demo ( );
}
private void demo ( )
{
List < Advertisement > ads = null;
try
{
ads =
List.of (
new PrintAd (
UUID.fromString ( "a71330e7-131f-4d10-beac-4e8ffc21887f" ) ,
"Example print ad." ,
LocalDate.now ( )
) ,
new WebAd (
UUID.fromString ( "8aafa2cf-03dc-452b-a84d-c61d75964955" ) ,
"Example web ad." ,
URI.create ( "https://www.DailyBugle.com/ads" ).toURL ( )
) ,
new RadioAd (
UUID.fromString ( "e21b187c-01e2-44da-9a26-5debb9146cf6" ) ,
"Example radio ad." ,
LocalTime.NOON
)
);
}
catch ( MalformedURLException e ) { throw new RuntimeException ( e ); }
System.out.println ( "ads = " + ads );
}
}
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
字段。
考虑以下代码:
public class Advertisement {
private static int universalId = 0;
private int ID;
private String description;
protected Advertisement() {
ID = universalId++;
}
public Advertisement(String description) {
this();
this.description = description;
}
public int getID() {
return ID;
}
}
然后,对于您的子类,在其构造函数内调用超类构造函数,如下所示:
public class PrintedAdd extends Advertisement {
private int First; //first page cost
private int Middle; //middle page cost
private int Last; //last page cost
public PrintedAdd(int First, int Middle, int Last) {
super();
this.First = First;
this.Middle = Middle;
this.Last = Last;
}
public int getFirst() {
return First;
}
}
因此,调用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.
public class Advertisement {
private static int universalId = 0;
private int ID;
private String description;
protected Advertisement() {
ID = universalId++;
}
public Advertisement(String description) {
this();
this.description = description;
}
public int getID() {
return ID;
}
}
Then, for your sub-classes, within their constructors', make a call to the super constructor, as follows.
public class PrintedAdd extends Advertisement {
private int First; //first page cost
private int Middle; //middle page cost
private int Last; //last page cost
public PrintedAdd(int First, int Middle, int Last) {
super();
this.First = First;
this.Middle = Middle;
this.Last = Last;
}
public int getFirst() {
return First;
}
}
Thus, making a call to ad.getID()
should produce 0
, and making a call to ad2.getID()
should produce 1
.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论