如何将派生类名称分配为基类构造函数中的参数?

问题描述 投票:0回答:2

假设我有一个基类

Fruit

public class Fruit {

  String name;

  public Fruit(String name) {
    this.name = name
  }
}

我有类

Apple()
,它扩展了
Fruit()
,并且我给了该类两个构造函数。

public class Apple extends Fruit {
    
    // constructor one
    public Apple() {
      this("Apple");
    }

    // constructor two
    public Apple(String name) {
        super(name);
    }
}

这让我可以拨打

new Apple()
以及
new Apple("Red Apple")

与其必须将

constructor one
添加到
Fruit
的每个派生类,我更希望
Fruit
类似于以下内容:

public class Fruit {

  String name;

  // Automatically assign the classname from the derived class
  public Fruit() {
    this(this.getClass().getSimpleName());
  }

  public Fruit(String name) {
    this.name = name
  }
}

然后我可以从

constructor one
中删除
Apple
,因为它将继承自
Fruit

理想情况下,这会让我拨打

new Apple()
并自动将
Apple.name
设置为
Apple

不幸的是,

this(this.getClass().getSimpleName());
抛出了

错误
java cannot refer to 'this' nor 'super' while explicitly invoking a constructor

我在其他语言中使用类似的模式,没有任何问题。 如何将派生类名称分配为基类构造函数中的参数? 在 Java 中这样的事情可能吗?

java inheritance
2个回答
0
投票

您始终可以按照您喜欢的方式实现该方法

getName()
。 (并确保在您的代码中没有人直接访问成员变量
name
)。但无论如何,如果您希望构造函数
new Apple()
new Apple(String name)
一起可用,那么您需要实现两者,以及
Fruit()
Fruit(String)

但是,当然,还有其他更简单的方法:

public class Constructoriz0r {



    public static void main(final String... args) {
        {
            final Apple a = new Apple();
            System.out.println("a1 name: " + a.getName());
        }
        {
            final Apple a = new Apple().setName("iThink");
            System.out.println("a2 name: " + a.getName());
        }
        {
            final Banana b = new Banana();
            System.out.println("b1 name: " + b.getName());
        }
        {
            final Banana b = new Banana().setName("YouDo");
            System.out.println("b2 name: " + b.getName());
        }
    }



    static public class Fruit<T> {
        private String mName = null;
        public T setName(final String pName) {
            mName = pName;
            @SuppressWarnings("unchecked") final T ret = (T) this;
            return ret;
        }
        public String getName() {
            if (mName == null) mName = getClass().getSimpleName();
            return mName;
        }
    }

    static public class Apple extends Fruit<Apple> { /* apple stuff */ }
    static public class Banana extends Fruit<Banana> { /* banana stuff */ }



}

0
投票

然后我可以从 Apple 中删除构造函数一,因为它将继承自 Fruit

不,你不会。 java不是这样工作的。简单的例子:

class Parent {
  private final String name;

  public Parent() {
    this("Jane");
  }

  public Parent(String name) {
    this.name = name;
  }
}

class Example extends Parent {
  public Example(String name) {
    super(name);
  }

  static void test() {
    new Example(); // compiler error
  }
}

在java中,构造函数不继承。方法继承 - 如果您

class Y extends X
其中 X 包含某个方法,那么 Y 也自动包含该方法(事实上,您不能“删除它”,最多只能覆盖它)。但构造函数根本不这样做。您可以使用 super 语法来
调用
它们。到这里就结束了。

但是,这可能会令人困惑!有 2 个不相关的 Java 语言特性使其看起来像是构造函数继承,但实际上并非如此:

  1. 如果你的类根本没有构造函数,那么java会假设你打算写public YourClassName() {}

     - 就像这样,java将表现得好像你有一个公共的无参数不做任何事的构造函数。

  2. 所有构造函数都

    需要来调用this

    super
    ,他们不能不调用。如果你没有这样做,编译器会假设你打算用 
    super()
     来启动你的构造函数。此规则也适用于上一个项目符号。

所以,鉴于:

class Example { Example() { System.out.println("In example constructor"); } } class Child extends Example { } class Main { public static void main(String[] args) { new Child(); // prints 'In example constructor' } }
但是,请不要误会,这与 Child “继承”构造函数无关。事实并非如此。没有定义构造函数,所以 java 玩了一个相信的游戏,就像你写的那样 

public Child() { super(); }

因此,你的问题现在几乎完全被排除了。

但是,为了争论:

你根本做不到。不是java的工作原理。然而,解决方案通常是与哨兵合作。字段应该是

private

,而不是包私有或受保护。这使我们能够完全控制它。如果您希望其他人访问该“字段”,请创建一个吸气剂。因为你可以控制它。

现在它是私有的,我们可以规定,如果字符串是某个值,则

意味着只继承该名称。因此:

public class Fruit { private final String name; public Fruit() { this.name = null; } public Fruit(String name) { if (name == null) throw new NullPointerException("name"); this.name = name; } public String getName() { return this.name != null ? name : this.getClass().getName(); } }
在这里,只要名称相关,我们就检查该字段:如果它为空,我们返回类名。否则我们返回该字段。

© www.soinside.com 2019 - 2024. All rights reserved.