Pergunta

Suponha que eu tenho uma classe base B, e uma classe derivada D. I desejo de ter um foo () método dentro de minha classe base que retorna um novo objeto de qualquer tipo a instância é. Assim, por exemplo, se eu chamar B.foo () ele retorna um objecto do tipo B, enquanto se chamo D.foo () ele retorna um objecto de tipo D; Enquanto isso, reside a implementação apenas na classe base B.

Isso é possível?

Foi útil?

Solução

Não faça isso. Faça o "foo" método abstrato.

abstract class B {
    public abstract B foo();
}

ou receber uma fábrica abstrata através do construtor da classe base:

abstract class B {
    private final BFactory factory;
    protected B(BFactory factory) {
        this.factory = factory;
    }
    public B foo() {
        return factory.create();
    }
}
interface BFactory {
    B create();
}

Adicionar tipos de retorno covariantes e genéricos a gosto.

Outras dicas

Enquanto cada classe tem um construtor padrão:

    public B instance() throws Exception {
        return getClass().newInstance();
    }

Bem, eu poderia estar fora, mas eu diria que desde que "isto" sempre se refere ao objeto atual, você poderia fazer algo como

public B foo() {
    return this.getClass().newInstance();
}

ou algo nesse sentido? Se você criar uma instância de D e, em seguida, d.foo call () você deve obter uma instância de D retornado como um B. Você poderia devolvê-lo como um objeto simples, mas você deve ser o mais específico possível, neste caso, eu acho.

Além do fato de que eu acho que provavelmente é uma falha de projeto, se você quiser fazer isso, você pode tentar a seguinte abordagem.

Em sua pergunta, você está usando métodos (classe) estáticos, B.foo (), D.foo (), isso não pode ser feito usando herança, porque os métodos estáticos não têm uma natureza dinâmica, eles não participam no sistema de pesquisa. Então você não tem informações de tipo suficiente.

Se você estiver usando uma função membro foo () você poderia ter a seguinte construção:

public class B {
    public B foo()
    throws IllegalAccessException, InstantiationException {
        return this.getClass().newInstance();
    }
}

public class D  extends B{    
}

public class Test {
    public static final void main(String[] args)
    {
        try {
            System.out.println((new B()).foo());
            System.out.println((new D()).foo());
        } catch (IllegalAccessException e) {
            e.printStackTrace();  
        } catch (InstantiationException e) {
            e.printStackTrace();  
        }
    }
}

Como as outras respostas dizer, você pode usar getClass (). NewInstance () se houver um construtor sem argumento em cada subclasse (certifique-se de pegar InstantiationException e IllegalAccessException).

Se algum dos construtores necessitam de argumentos, você pode usar a reflexão ou (preferível, na minha opinião) definir um método como getNewInstance (), que você pode substituir na subclasse somente se necessário.

por exemplo.

Thing foo() {
    Thing th = getNewInstance();
    // do some stuff with th
    return th;
}

Thing getNewInstance() {
    return getClass().newInstance();
}

Então getNewInstance () pode ser substituído somente se você realmente precisa, por subclasses que não têm o construtor padrão.

Thing getNewInstance() {
    return new BigThing(10, ThingSize.METRES);
}

Eu acho que isso pode ser possível fazer usando a reflexão, ou seja, na sua superclasse você tem:

public ClassName getFoo() throws InstantiationException, IllegalAccessException
{
    return getClass().newInstance();
}

Onde ClassName é o nome da sua classe base.

Você terá que lançá-lo onde quer que você usá-lo embora ... Eu não tenho certeza que esta é realmente uma grande solução!

Editar:. newInstance () métodos de tipo são normalmente estático, e, claro, você não terá uma idéia do que o tipo da sua subclasse é com um método estático

Eu não acho que há alguma maneira de obter um estática para (dinamicamente) criar uma instância de uma subclasse.

@Rik

Bem, o verdadeiro problema é que eu tenho uma coisa abstrata classe base. E coisa tem um método chamado getNextThing () que retorna uma nova instância de coisa.

Então, eu tenho um número de subclasses como BigThing, LittleThing, SomethingThing, e eu não quero manter reescrever o método getNextThing () para cada um deles. Parece um desperdício, uma vez que todos eles fazem a mesma coisa ....

Am I incorreta na minha abordagem?

Eu não sei por que você está tentando fazer o que você está realmente tentando fazer. Fornecendo mais de um contexto pode vamos dar-lhe mais ajuda.

public class B <X extends B>{

public X foo() throws InstantiationException, IllegalAccessException{
    return (X)this.getClass().newInstance();
}
}        
public class C extends B<C>{        

}

Deixe-me oferecer-lhe este conselho. A forma como as classes CS tendem a ser ensinado é que os professores são apaixonados com a herança, mas ainda não descobri composição. Eu acho que você pode estar procurando composição é. Então, em vez de chamar getNextThing na própria coisa, talvez você deve pensar em fazer coisa implementar Iterable

Isto significa que você só precisa escrever um Iterator que podem encapsular a lógica de obter a próxima coisa, uma vez que não parecem se encaixar em seu modelo de herança. Outra vantagem é que você obtenha alguns dispositivos sintáticos agradáveis ??fora deste (reforçada para a compreensão loop).

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top