web-dev-qa-db-fra.com

Java: visibilité des sous-packages?

J'ai deux paquets dans mon projet: odp.proj et odp.proj.test. Il y a certaines méthodes que je veux voir uniquement pour les classes de ces deux packages. Comment puis-je faire ceci?

EDIT: S'il n'y a pas de concept de sous-paquet en Java, y a-t-il un moyen de contourner cela? J'ai certaines méthodes que je veux être disponible uniquement pour les testeurs et les autres membres de ce package. Devrais-je tout jeter dans le même paquet? Utiliser une réflexion approfondie?

136
Nick Heiner

Tu ne peux pas. Dans Java, il n’existe pas de concept de sous-package, ainsi odp.proj et odp.proj.test sont des packages complètement séparés.

152
starblue

Les noms de vos paquets suggèrent que l'application ici est destinée aux tests unitaires. Le modèle typique utilisé consiste à placer les classes que vous souhaitez tester et le code de test unitaire dans le même package (dans votre cas, odp.proj) mais dans des arbres sources différents. Donc, vous mettriez vos cours dans src/odp/proj et votre code de test dans test/odp/proj.

Java a le modificateur d'accès "package" qui est le modificateur d'accès par défaut lorsqu'aucun n'est spécifié (c'est-à-dire que vous ne spécifiez pas public, privé ou protégé). Avec le modificateur d'accès "package", seules les classes de odp.proj aura accès aux méthodes. Mais gardez à l'esprit qu'en Java, on ne peut pas compter sur les modificateurs d'accès pour appliquer les règles d'accès car, avec la réflexion, tout accès est possible. Les modificateurs d'accès sont simplement suggestifs (sauf si un gestionnaire de sécurité restrictif est présent).

57
Asaph

Ce n'est pas une relation particulière entre odp.proj et odp.proj.test _ - ils se trouvent juste nommés comme étant apparemment liés.

Si le paquet odp.proj.test fournit simplement des tests, vous pouvez utiliser le même nom de paquet (odp.proj). Des IDE comme Eclipse et Netbeans créeront des dossiers séparés (src/main/Java/odp/proj et src/test/Java/odp/proj) avec le même nom de package mais avec la sémantique JUnit.

Notez que ces IDE généreront des tests pour les méthodes dans odp.proj et créez le dossier approprié pour les méthodes de test qui n'existent pas.

11
peter.murray.rust

Lorsque je fais cela dans IntelliJ, mon arbre source ressemble à ceci:

src         // source root
- odp
   - proj   // .Java source here
- test      // test root
  - odp
     - proj // JUnit or TestNG source here
5
duffymo

EDIT: S'il n'y a pas de concept de sous-paquet en Java, y a-t-il un moyen de contourner cela? J'ai certaines méthodes que je veux être disponible uniquement pour les testeurs et les autres membres de ce package.

Cela dépend probablement un peu des raisons pour lesquelles vous ne les affichez pas, mais si la seule raison en est que vous ne voulez pas polluer l'interface publique avec des éléments destinés uniquement à des tests (ou à une autre opération interne), je mettrais les méthodes dans un séparer l'interface publique et demander aux consommateurs des méthodes "cachées" d'utiliser cette interface. Cela n'empêchera pas les autres d'utiliser l'interface, mais je ne vois aucune raison de le faire.

Pour les tests unitaires, et si cela est possible sans réécrire le lot, suivez les suggestions pour utiliser le même package.

4
Fredrik

Comme d'autres l'ont expliqué, il n'existe pas de "sous-paquet" en Java: tous les paquets sont isolés et n'héritent pas de leurs parents.

Un moyen facile d'accéder aux membres de classe protégés à partir d'un autre package consiste à étendre la classe et à remplacer les membres.

Par exemple, pour accéder à ClassInA dans le package a.b:

package a;

public class ClassInA{
    private final String data;

    public ClassInA(String data){ this.data = data; }

    public String getData(){ return data; }

    protected byte[] getDataAsBytes(){ return data.getBytes(); }

    protected char[] getDataAsChars(){ return data.toCharArray(); }
}

créez une classe dans ce paquet qui remplace les méthodes dont vous avez besoin dans ClassInA:

package a.b;

import a.ClassInA;

public class ClassInAInB extends ClassInA{
    ClassInAInB(String data){ super(data); }

    @Override
    protected byte[] getDataAsBytes(){ return super.getDataAsBytes(); }
}

Cela vous permet d'utiliser la classe de remplacement à la place de la classe dans l'autre paquet:

package a.b;

import Java.util.Arrays;

import a.ClassInA;

public class Driver{
    public static void main(String[] args){
        ClassInA classInA = new ClassInA("string");
        System.out.println(classInA.getData());
        // Will fail: getDataAsBytes() has protected access in a.ClassInA
        System.out.println(Arrays.toString(classInA.getDataAsBytes()));

        ClassInAInB classInAInB = new ClassInAInB("string");
        System.out.println(classInAInB.getData());
        // Works: getDataAsBytes() is now accessible
        System.out.println(Arrays.toString(classInAInB.getDataAsBytes()));
    }
}

Notez que cela ne fonctionne que pour les membres protégés, qui sont visibles pour les classes d'extension (héritage), et non pour les membres de package privés qui ne sont visibles que pour les classes sous/d'extension dans le même package. Espérons que cela aide quelqu'un!

2
ndm13

Avec la classe PackageVisibleHelper et gardez-la privée avant que PackageVisibleHelperFactory ne soit gelé, nous pouvons invoquer la méthode launchA (par PackageVisibleHelper) n'importe où :)

package odp.proj;
public class A
 {
    void launchA() { }
}

public class PackageVisibleHelper {

    private final PackageVisibleHelperFactory factory;

    public PackageVisibleHelper(PackageVisibleHelperFactory factory) {
        super();
        this.factory = factory;
    }

    public void launchA(A a) {
        if (factory == PackageVisibleHelperFactory.INSTNACNE && !factory.isSampleHelper(this)) {
            throw new IllegalAccessError("wrong PackageVisibleHelper ");
        }
        a.launchA();
    }
}


public class PackageVisibleHelperFactory {

    public static final PackageVisibleHelperFactory INSTNACNE = new PackageVisibleHelperFactory();

    private static final PackageVisibleHelper HELPER = new PackageVisibleHelper(INSTNACNE);

    private PackageVisibleHelperFactory() {
        super();
    }

    private boolean frozened;

    public PackageVisibleHelper getHelperBeforeFrozen() {
        if (frozened) {
            throw new IllegalAccessError("please invoke before frozen!");
        }
        return HELPER;
    }

    public void frozen() {
        frozened = true;
    }

    public boolean isSampleHelper(PackageVisibleHelper helper) {
        return HELPER.equals(helper);
    }
}
package odp.proj.test;

import odp.proj.A;
import odp.proj.PackageVisibleHelper;
import odp.proj.PackageVisibleHelperFactory;

public class Test {

    public static void main(String[] args) {

        final PackageVisibleHelper helper = PackageVisibleHelperFactory.INSTNACNE.getHelperBeforeFrozen();
        PackageVisibleHelperFactory.INSTNACNE.frozen();


        A a = new A();
        helper.launchA(a);

        // illegal access       
        new PackageVisibleHelper(PackageVisibleHelperFactory.INSTNACNE).launchA(a); 
    }
}
0
qxo

Sans mettre le modificateur d'accès devant la méthode, vous dites qu'il s'agit d'un paquet privé.
Regardez l'exemple suivant.

package odp.proj;
public class A
{
    void launchA() { }
}

package odp.proj.test;
public class B
{
    void launchB() { }
}

public class Test
{
    public void test()
    {
        A a = new A();
        a.launchA()    // cannot call launchA because it is not visible
    }
}
0
Alberto Zaccagni