Java: видимость подпакета?

У меня есть два пакета в моем проекте: odp.proj и odp.proj.test. Существуют определенные методы, которые я хочу видеть только для классов в этих двух пакетах. Как я могу это сделать?

РЕДАКТИРОВАТЬ: Если в Java нет концепции субпакета, существует ли какой-либо способ этого? У меня есть определенные методы, которые я хочу получить только для тестировщиков и других членов этого пакета. Должен ли я просто выбросить все в один пакет? Использовать обширное отражение?

Ответ 1

Вы не можете. В Java нет понятия подпакета, поэтому odp.proj и odp.proj.test являются полностью отдельными пакетами.

Ответ 2

Имена ваших пакетов подсказывают, что приложение предназначено для модульного тестирования. Типичный шаблон используется для размещения классов, которые вы хотите протестировать, и кода unit test в том же пакете (в вашем случае odp.proj), но в разных источниках. Поэтому вы ставите свои классы в src/odp/proj и ваш тестовый код в test/odp/proj.

У Java есть модификатор доступа "пакет", который является модификатором доступа по умолчанию, когда ни один не указан (т.е. вы не указываете public, private или protected). С модификатором доступа "пакет" доступ к методам будет иметь только классы в odp.proj. Но имейте в виду, что в Java нельзя использовать модификаторы доступа для обеспечения соблюдения правил доступа, потому что с отражением возможен любой доступ. Модификаторы доступа просто наводящие на размышления (если только не существует ограничивающий диспетчер безопасности).

Ответ 3

Это не имеет особого отношения между odp.proj и odp.proj.test - они просто называются как связанные.

Если пакет odp.proj.test просто предоставляет тесты, вы можете использовать одно и то же имя пакета (odp.proj). IDE, такие как Eclipse и Netbeans, будут создавать отдельные папки (src/main/java/odp/proj и src/test/java/odp/proj) с тем же именем пакета, но с семантикой JUnit.

Обратите внимание, что эти IDE будут генерировать тесты для методов в odp.proj и создать соответствующую папку для методов тестирования, которых она не существует.

Ответ 4

Когда я делаю это в IntelliJ, мое исходное дерево выглядит так:

src         // source root
- odp
   - proj   // .java source here
- test      // test root
  - odp
     - proj // JUnit or TestNG source here

Ответ 5

EDIT: если нет понятия subpackage в Java, есть ли способ вокруг этого? У меня есть определенные методы что я хочу быть доступным только для тестеров и других членов этого пакет.

Вероятно, это немного зависит от ваших мотивов, чтобы не отображать их, но если единственная причина в том, что вы не хотите загрязнять публичный интерфейс вещами, предназначенными только для тестирования (или какой-либо другой внутренней вещи), я бы поставил методы в отдельном публичном интерфейсе, и потребители "скрытых" методов используют этот интерфейс. Это не остановит других от использования интерфейса, но я не вижу причин, почему вы должны.

Для модульных тестов, и если это возможно без перезаписи партии, следуйте рекомендациям по использованию того же пакета.

Ответ 6

Как объясняли другие, в Java нет такого понятия, как "подпакет": все пакеты изолированы и ничего не наследуют от своих родителей.

Простой способ получить доступ к защищенным членам класса из другого пакета - расширить класс и переопределить члены.

Например, чтобы получить доступ к ClassInA в пакете ab:

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(); }
}

сделайте класс в этом пакете, который переопределяет методы, которые вам нужны в ClassInA:

package a.b;

import a.ClassInA;

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

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

Это позволяет вам использовать переопределяющий класс вместо класса в другом пакете:

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()));
    }
}

Обратите внимание, что это работает только для защищенных членов, которые видимы для расширяющих классов (наследование), а не для закрытых для пакета членов, которые видимы только для подчиненных/расширяющих классов в одном и том же пакете. Надеюсь, это кому-нибудь поможет!

Ответ 7

Не помещая модификатор доступа перед этим методом, вы говорите, что он закрыт.
Посмотрите на следующий пример.

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
    }
}

Ответ 8

С классом PackageVisibleHelper и сохраняйте его закрытым до того, как заморожен пакет PackageVisibleHelperFactory, мы можем вызвать метод launchA (by PackageVisibleHelper) в любом месте:)

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); 
    }
}