Je souhaiterais pouvoir écrire une classe Java dans un package capable d'accéder à des méthodes non publiques d'une classe dans un autre package sans avoir à en faire une sous-classe de l'autre classe. Est-ce possible?
Réponses
Trop de publicités?Voici une petite astuce que j'utilise en JAVA pour répliquer C++ ami mécanisme.
Laisser dit que j'ai une classe Romeo
et une autre classe Juliet
. Il y a dans les paquets différents (famille), de la haine, des raisons.
Romeo
veut cuddle
Juliet
et Juliet
voulez seulement laissez - Romeo
cuddle
.
En C++, Juliet
déclarent Romeo
(amant) friend
, mais il n'y a pas de telles choses en java.
Voici les classes et le truc :
Ladies first :
package capulet;
import montague.Romeo;
public class Juliet {
public static void cuddle(Romeo.Love l) {
l.hashCode();
System.out.println("O Romeo, Romeo, wherefore art thou Romeo?");
}
}
Donc, la méthode de Juliet.cuddle
est public
, mais vous avez besoin d'un Romeo.Love
de l'appeler. Il utilise cette Romeo.Love
comme une "signature" de sécurité" pour s'assurer que seuls Romeo
peut appeler cette méthode et simplement les appels hashCode
sur elle de sorte que le moteur d'exécution jeter un NullPointerException
si il est null
.
Maintenant les garçons :
package montague;
import capulet.Juliet;
public class Romeo {
public static class Love { private Love() {} }
private static Love love = new Love();
public static void cuddleJuliet() {
Juliet.cuddle(love);
}
}
La classe Romeo.Love
est public, mais son constructeur private
. Donc tout le monde peut voir, mais seulement en Romeo
peut construire. Je utiliser un point de référence fixe donc l' Romeo.Love
qui n'est jamais utilisée est construit une fois et n'a pas d'impact de l'optimisation.
Par conséquent, Romeo
peut cuddle
Juliet
et que lui seul peut parce que seul il peut construire et d'accéder à un Romeo.Love
de l'instance, qui est requis par Juliet
de cuddle
(ou sinon elle va te frapper avec un NullPointerException
).
Les concepteurs de Java explicitement rejeté l'idée d'un ami car il fonctionne en C++. Vous mettez vos "amis" dans le même package. Privé, protégé et emballé sécurité est appliquée dans le cadre de la conception de langage.
James Gosling voulais Java C++ sans erreurs. Je crois qu'il a senti que l'ami était une erreur parce qu'elle viole les principes de la programmation orientée objet. Paquets fournissent un moyen raisonnable d'organiser les composants sans être trop puriste sur la POO.
NR a fait remarquer que vous pouvez tricher en utilisant la réflexion, mais même cela ne fonctionne que si vous n'utilisez pas le SecurityManager. Si vous activez Java standard de sécurité, vous ne serez pas en mesure de tricher avec la réflexion, à moins que vous écrivez de la politique de sécurité à autoriser expressément.
La " ami " concept est utile en Java, par exemple, pour séparer une API à partir de sa mise en œuvre. Il est commun pour les classes d'implémentation besoin d'accéder à la classe de l'API internes, mais ils ne devraient pas être exposés à des API clients. Ceci peut être réalisé à l'aide de la "Ami Accesseur' modèle comme détaillé ci-dessous:
La classe exposés par le biais de l'API:
package api;
public final class Exposed {
static {
// Declare classes in the implementation package as 'friends'
Accessor.setInstance(new AccessorImpl());
}
// Only accessible by 'friend' classes.
Exposed() {
}
// Only accessible by 'friend' classes.
void sayHello() {
System.out.println("Hello");
}
static final class AccessorImpl extends Accessor {
protected Exposed createExposed() {
return new Exposed();
}
protected void sayHello(Exposed exposed) {
exposed.sayHello();
}
}
}
La classe 'ami' de la fonctionnalité:
package impl;
public abstract class Accessor {
private static Accessor instance;
static Accessor getInstance() {
Accessor a = instance;
if (a != null) {
return a;
}
return createInstance();
}
private static Accessor createInstance() {
try {
Class.forName(Exposed.class.getName(), true,
Exposed.class.getClassLoader());
} catch (ClassNotFoundException e) {
throw new IllegalStateException(e);
}
return instance;
}
public static void setInstance(Accessor accessor) {
if (instance != null) {
throw new IllegalStateException(
"Accessor instance already set");
}
instance = accessor;
}
protected abstract Exposed createExposed();
protected abstract void sayHello(Exposed exposed);
}
Exemple d'accès d'une classe dans le " ami " de la mise en œuvre du paquet:
package impl;
public final class FriendlyAccessExample {
public static void main(String[] args) {
Accessor accessor = Accessor.getInstance();
Exposed exposed = accessor.createExposed();
accessor.sayHello(exposed);
}
}
Il y a deux solutions à votre question qui n'impliquent pas de garder toutes les classes du même package.
La première est d'utiliser l'Ami de l'Accesseur/Ami Package de modèle décrit dans (Pratique de Conception d'API, Tulach 2008).
La seconde est d'utiliser OSGi. Il y a un article ici d'expliquer comment OSGi accomplit ce.
Pour autant que je sache, ce n'est pas possible.
Peut-être que vous pourriez nous donner plus de détails sur votre conception. Des questions comme celles-ci sont probablement le résultat de défauts de conception.
Il suffit de considérer
- Pourquoi ces classes sont-elles dans des packages différents, si elles sont si étroitement liées?
- A doit-il accéder aux membres privés de B ou l'opération doit-elle être déplacée vers la classe B et déclenchée par A?
- Est-ce vraiment l'appel ou la gestion des événements est-elle meilleure?