Путь относительного идентификатора пакета в Java - PullRequest
0 голосов
/ 04 июля 2018

Введение

Переходя от C ++, одним из больших отличий было различие в области видимости: в C ++ каждый идентификатор относится к текущей области (class или namespace), и вы можете написать абсолютный путь с помощью оператора разрешения области :: в начале.

Однако в Java я не смог найти способ получить доступ к идентификатору из другого пакета, не импортировав его в текущую область или не записав полный путь.

Это может быть проблемой, если у меня есть несколько классов с одинаковыми именами (тогда в C ++ я бы назвал их как Module1 :: Foo и Module2 :: Foo, что невозможно в Java, если я хочу сохрани мое здравомыслие, так как com.company.project.module1.Foo слишком долго, на мой вкус).

Код!

Вот пример доступа к классу Tools.Useless.Foo из Java и C ++ (без import или using)

Tools/Useless/Foo.hpp

namespace Tools {
namespace Useless {
class Foo {         
};
}
}

Tools/Bar.hpp

namespace Tools {
...
// Use Foo with a relative identifier
Useless::Foo foo;
// Use Foo with an absolute identifier.
::Tools::Useless::Foo bar;
...
} 

И вот как это будет выглядеть в Java:

com/company/project/Tools/Useless/Foo.java

package com.company.project.Tools.Useless;

public class Foo { }

com/company/project/Tools/Bar.java

...
// Use Foo with a relative identifier
???
// Use Foo with an absolute identifier.
com.company.project.Tools.Useless.Foo foo;
...

Вопрос (ы)

  1. Есть ли способ получить доступ к Foo из пакета Tools.Useless без указания Tools.Useless полного имени пакета (и импорта его; поскольку при импорте он будет привязан к текущей области)?
  2. Я правильно делаю? Как мне использовать несколько классов с одинаковыми именами? Должен ли я просто избежать этого или просто импортировать их с помощью "package. *", Чтобы обойти это?

Решения

  1. Использование большего количества описательных имен классов (например, ToolsUselessFoo вместо просто Foo).
  2. Импортируйте все с помощью import path.to.module.* вместо import path.to.module.Foo и затем получите доступ к Foo нужным пакетам для устранения любой неопределенности. Проблема в том, что иногда имена пакетов имеют значение (например, Tools.Useless.Foo и Tools.Useful.Foo).

1 Ответ

0 голосов
/ 06 июля 2018

Java-пакеты не являются вложенными. Хотя их имена могут иметь общие префиксы, это не имеет значения в языке программирования Java.

Также тот факт, что их файлы классов хранятся во вложенных каталогах, когда хранилище является файловой системой, не имеет никакого дополнительного значения. Когда классы хранятся в jar-файле, они хранятся с именами записей, соответствующими их квалифицированным именам, без фактического формирования каталогов вообще (хотя многие инструменты предпочитают представлять их как будто они находятся в иерархической структуре для имитации файловой системы).

Таким образом, пакеты com.company.project.tools.useless и com.company.project.tools не имеют никакого отношения вообще. В то время как мы, люди, склонны организовывать код таким образом, что здесь можно предположить семантические отношения (что хорошо), на техническом уровне их нет. Между ними нет относительной адресации, и нет никаких дополнительных прав доступа по сравнению с любыми двумя другими пакетами. Фактически, оба пакета могут быть частью двух разных модулей (начиная с Java 9) с еще меньшими правами доступа по сравнению с двумя другими пакетами с менее похожими именами.

Стандартный подход к использованию класса из другого пакета заключается в использовании com.company.project.Tools.Useless.Foo; с последующим использованием Foo в классе.

Не совсем ясно, какую проблему вы видите с этим, то есть, что, как предполагается, должно означать «поскольку импорт связывает его с текущей областью действия». Само существование оператора import не влияет на код. Все, что он говорит компилятору, - это как разрешить вхождения простого имени Foo, если в области видимости нет другого Foo.

Другими словами, локальные области все еще имеют приоритет, даже включая унаследованные элементы. Кроме того, в местах, где могут появляться переменные и типы, переменные имеют приоритет. Например. для вхождения Foo.bar() переменная с именем Foo будет иметь приоритет, локальная переменная перед переменными-членами того же типа, внешний класс или унаследованные. В противном случае будут использоваться типы элементов, внешние типы или унаследованные типы элементов. Только если ни один из них не существует, оператор import будет использоваться для разрешения Foo.

Само собой разумеется, вам следует избегать иметь так много предметов с одинаковым простым именем, что вам придется подумать о деталях процесса разрешения. Вот почему соглашения об именах предлагают начинать имена переменных со строчной буквы, а имена классов - с заглавной.

И да, избегайте давать классам одно и то же простое имя. Как только вы столкнетесь с обоими классами в пределах одного модуля компиляции, вы не сможете получить доступ к одному из них с его (полностью) квалифицированным именем во всем модуле компиляции. (Использование * в импорте никак не поможет при таком сценарии)


Как объяснено, термин «полностью» в Java устарел, поскольку квалифицированные имена всегда полны.

...