2009-01-20 6 views
5

À titre d'exemple:En java, comment faire une classe avec un constructeur privé dont la superclasse a aussi un constructeur privé?

public class Foo { 
    private Foo() {} 
} 

public class Bar extends Foo { 
    private Bar() {} 

    static public doSomething() { 
    } 
} 

C'est une erreur de compilation là. Une classe doit, au moins, appeler implicitement le constructeur par défaut de sa superclasse, qui dans ce cas n'est pas visible dans Foo.

Puis-je appeler Constructeur de l'objet à partir de Barre à la place?

+0

Existe-t-il une raison pour que Foo() {} soit privé au lieu d'être protégé? –

+1

@svelil: Disons que c'est dans une bibliothèque tierce, ou en dehors de mon contrôle, et je veux la sous-classer. –

Répondre

10

Vous ne pouvez pas. Vous devez faire le privé paquet constructeur de Foo à tout le moins (Bien que je serais probablement juste le rendre protégé

(Edit -. Les commentaires dans ce poste un bon point)

+0

Package-private est suffisant, si les deux sont mis dans le même paquet. – starblue

+0

@starblue - Je crois que c'est pour ça qu'il a dit 'au moins'. –

+0

package est plus restrictive que protégé, donc «au moins» est faux. Si les deux étaient dans la même classe externe, je pense que la construction privée serait accessible. –

2

Vous ne serez pas en mesure de créer une instance de Bar tant que Foo a un constructeur privé.La seule façon de le faire est de savoir si Foo avait un constructeur protégé

+2

Si une super-classe a un constructeur privé, alors la sous-classe ne compilera même pas. –

1

Vous ne pouvez pas appeler le constructeur Object directement depuis Bar alors que c'est un sous-classe de Foo, il devrait passer par le constructeur de Foo, qui est privé dans ce cas

Lorsque vous déclarez Foo's c onstructor privé, il ne crée pas de constructeur public par défaut. Puisque Bar a pour invoquer le constructeur de Foo, il n'est pas possible de le laisser privé. Je suggérerais, comme d'autres l'ont fait, d'utiliser protégé au lieu de privé.

7

Ceci est en fait un symptôme d'une mauvaise forme d'héritage, appelé héritage d'implémentation. Soit la classe d'origine n'a pas été conçue pour être héritée, et donc a choisi d'utiliser un constructeur privé, ou que l'API entière est mal conçue. Le correctif pour cela n'est pas de trouver un moyen d'hériter, mais de voir si vous pouvez composer l'objet au lieu d'hériter, et ce via des interfaces. Par exemple, la classe Foo est maintenant l'interface Foo, avec un FooImpl. Alors la barre d'interface peut étendre Foo, avec un BarImpl, qui n'a aucun rapport avec FooImpl. À l'intérieur de BarImpl, vous pouvez si vous souhaitez réutiliser du code, avoir un FooImpl à l'intérieur en tant que membre, mais cela dépend entièrement de l'implémentation et ne sera pas exposé.

Questions connexes