使用继承时使用类的实际类型

时间:2015-02-04 20:03:50

标签: java inheritance types casting

我们假设我们有一个课程,其中包含以下方法:

public class Entry {
    private String name;

    public static Entry getOrCreate(String name) {
        // ...
        return new Entry(name);
    }
}

这个类可以是子类(例如SubEntry),以及" getOrCreate"不会改变。但是子类不应该返回类型为Entry的新对象,而是返回相应子类的类型(例如return SubEntry(name)

如果不为getOrCreate的每个子类重新实现方法Entry,我怎样才能实现这一点?是否有这种技术的术语?

3 个答案:

答案 0 :(得分:1)

子类化Entry不会影响getOrCreate方法,因为静态方法不是类实例的一部分;他们在逻辑上不属于任何阶级。

如果您将getOrCreate移动到非静态Factory类中,则可以使用一些Generics魔术来确定返回的类型:

public class Entry {
    private String name;
}

abstract class AbstractEntryFactory<T extends Entry>
    public abstract T getOrCreate(String name);
}

public class EntryFactory extends AbstractEntryFactory<Entry>
    @Override
    public Entry getOrCreate(String name) {
        // ...
        return new Entry(name);
    }
}

public class SubEntryFactory extends AbstractEntryFactory<SubEntry>
    @Override
    public SubEntry getOrCreate(String name) {
        // ...
        return new SubEntry(name);
    }
}

实际上调用getOrCreate看起来与您的代码看起来有所不同。而不是:

Entry myEntry = Entry.getOrCreate("my name");

它看起来像这样:

Entry myEntry = new EntryFactory().getOrCreate("my name");

或者这个:

SubEntry myEntry = new SubEntryFactory().getOrCreate("my name");

答案 1 :(得分:0)

假设您希望能够调用Entry.getOrCreate()来创建一种SubEntry,则必须传递一些额外的信息。原因是getOrCreate()方法不会继承SubEntry方法,因为它是static方法。因此,如果您想按照我提到的方式调用它,则必须传递要创建的类名。在下面的代码中,没有用于验证Class clazzEntry还是子类型的检查,但这可以帮助您开始。

import java.lang.reflect.Constructor;

public class TestClass {
    public static void main(String[] args) {
        Entry entry = (Entry)Entry.getOrCreate("entry", Entry.class);
        SubEntry subEntry = (SubEntry)SubEntry.getOrCreate("subEntry", SubEntry.class);

        System.out.println("entry class: " + entry.getClass().getName());
        System.out.println("subEntry class: " + subEntry.getClass().getName());
    }
}

class Entry {
    private String name;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public static Object getOrCreate(String name, Class clazz) {
        // If a constructor is created that takes a String, such as "public Entry(String name)",
        // then each sub class will need to implement that method. Instead I used a getter and
        // setter for the name attribute.
        try {
            Entry entry = (Entry)clazz.newInstance();
            entry.setName(name);
            return entry;
        }
        catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }
}

class SubEntry extends Entry {
}

最终结果是这个输出:

entry class: Entry
subEntry class: SubEntry

答案 2 :(得分:0)

您提出两个问题:

  1. 我该怎么做?
  2. 这种技术叫做什么?
  3. 第二个比第一个重要得多。

    在我看来,您尝试实现的内容类似于克隆link)或虚拟构造函数的概念。但是你希望这是一个静态方法,它提出了为什么这样的问题?由于静态方法与某个类相关联,而不是实例,因此您应该通过该类调用它,在这种情况下,您可以明确地调用new。但是,在搜索“静态上下文中的反向类”时,我会说不可能完全按照你在问题中写的那样做。

    如果将静态方法转换为普通方法,可以使用反射来完成:

    class Entry {
        private String name;
        public Entry(String name) {
            this.name = name;
        }
        public Entry() {
            this.name = null;
        }
        public Entry getOrCreate(String name) {
            try {
                return getClass().getConstructor(String.class).newInstance(name);
            } catch (Exception e) {
                return new Entry(name);
            }
        }
    }
    
    class BetterEntry extends Entry {
        public BetterEntry(String name) {
            super(name);
        }
        public BetterEntry() {
            super();
        }
    }
    

    然后你将从一个实例调用该函数,如下所示:

    Entry a = new Entry().getOrCreate("First");
    Entry b = new BetterEntry().getOrCreate("Second");
    Entry c = b.getOrCreate("Third");
    

    a,b,c的动态类型是Entry,BetterEntry和BetterEntry。您可以省略默认构造函数,但我添加了它们以使调用getOrCreate更像静态方法。

    如果你真的希望这个方法是静态的,最简单的方法就是在每个子类中重新实现这个函数。