나는 내 프로젝트에서 두 패키지를 가지고 odp.proj
와 odp.proj.test
. 이 두 패키지의 클래스에만 표시하려는 특정 메소드가 있습니다. 어떻게해야합니까?
편집 : Java에 하위 패키지 개념이 없으면이 방법이 있습니까? 테스터 및 해당 패키지의 다른 멤버에게만 제공되는 특정 방법이 있습니다. 모든 것을 동일한 패키지에 넣어야합니까? 광범위한 반사를 사용하십니까?
나는 내 프로젝트에서 두 패키지를 가지고 odp.proj
와 odp.proj.test
. 이 두 패키지의 클래스에만 표시하려는 특정 메소드가 있습니다. 어떻게해야합니까?
편집 : Java에 하위 패키지 개념이 없으면이 방법이 있습니까? 테스터 및 해당 패키지의 다른 멤버에게만 제공되는 특정 방법이 있습니다. 모든 것을 동일한 패키지에 넣어야합니까? 광범위한 반사를 사용하십니까?
답변:
당신은 할 수 없습니다. Java에는 하위 패키지의 개념이 없으므로odp.proj
와 odp.proj.test
완전히 분리 된 패키지입니다.
패키지 이름은 여기에서 응용 프로그램이 단위 테스트 용임을 암시합니다. 일반적으로 사용되는 패턴은 테스트하려는 클래스와 단위 테스트 코드를 동일한 패키지 (경우에 따라 odp.proj
)이지만 다른 소스 트리에 배치하는 것입니다. 따라서 클래스를 넣고 src/odp/proj
테스트 코드를에 넣으십시오 test/odp/proj
.
Java에는 "패키지"액세스 수정자가 있습니다.이 수정자는 지정되지 않은 경우 기본 액세스 수정 자입니다 (즉, 공개, 개인 또는 보호를 지정하지 않음). "패키지"액세스 수정자를 사용하면 클래스의 클래스 만 odp.proj
메소드에 액세스 할 수 있습니다. 그러나 Java에서는 액세스 수정자가 모든 액세스가 가능하므로 액세스 규칙을 적용하는 데 의존 할 수 없음을 명심하십시오. 제한적 보안 관리자가없는 경우 액세스 수정자는 단지 암시 적입니다.
이 사이에 특별한 관계 없다 odp.proj
하고 odp.proj.test
- 그들은 단지 분명히 관련라는 이름으로 일이.
odp.proj.test 패키지가 단순히 테스트를 제공하는 경우 동일한 패키지 이름 ( odp.proj
)을 사용할 수 있습니다 . Eclipse 및 Netbeans와 같은 IDE는 패키지 이름은 동일하지만 JUnit 시맨틱 을 사용하여 별도의 폴더 ( src/main/java/odp/proj
및 src/test/java/odp/proj
)를 작성합니다.
이 IDE는 메소드에 대한 테스트를 odp.proj
생성하고 존재하지 않는 테스트 메소드에 대한 적절한 폴더를 작성합니다.
편집 : Java에 하위 패키지 개념이 없으면이 방법이 있습니까? 테스터 및 해당 패키지의 다른 멤버에게만 제공되는 특정 방법이 있습니다.
아마도 그것들을 표시하지 않는 동기에 약간 의존하지만 유일한 이유는 테스트를위한 것 (또는 다른 내부적 인 것)으로 공용 인터페이스를 오염시키고 싶지 않다면 메소드를 별도의 공용 인터페이스를 사용하고 "숨겨진"메서드 소비자가 해당 인터페이스를 사용하도록합니다. 다른 사람들이 인터페이스를 사용하는 것을 막지는 않지만 당신이 그럴 이유가 없습니다.
단위 테스트의 경우, 로트를 다시 쓰지 않고 가능하다면 제안에 따라 동일한 패키지를 사용하십시오.
다른 사람들이 설명했듯이 Java에는 "하위 패키지"와 같은 것이 없습니다. 모든 패키지가 격리되어 부모로부터 아무것도 상속받지 않습니다.
다른 패키지에서 보호 된 클래스 멤버에 액세스하는 쉬운 방법은 클래스를 확장하고 멤버를 재정의하는 것입니다.
예를 들어 ClassInA
패키지 에서 액세스하려면 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(); }
}
해당 패키지에서 필요한 메소드를 대체하는 클래스를 작성하십시오 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()));
}
}
이것은 확장 된 클래스 (상속)에 보이는 보호 된 멤버에 대해서만 작동하며 동일한 패키지 내의 하위 / 확장 클래스에만 보이는 패키지 전용 멤버에는 적용되지 않습니다. 잘만되면 이것은 누군가를 돕는다!
여기에있는 대부분의 답변에 따르면 Java에는 하위 패키지와 같은 것은 없지만 정확히 정확하지는 않습니다. 이 용어는 Java 6에 이르기까지 Java 언어 사양에 있었으며 아마도 더 뒤로 돌아 왔습니다 (이전 버전의 Java에 대해서는 자유롭게 액세스 할 수있는 JLS 버전이 아닌 것 같습니다). Java 6부터 JLS에서 하위 패키지 관련 언어가 크게 변경되지 않았습니다.
패키지의 멤버는 하위 패키지와 패키지의 모든 컴파일 단위에 선언 된 모든 최상위 클래스 유형 및 최상위 인터페이스 유형입니다.
예를 들어, Java SE Platform API에서 :
- 이 패키지에는
java
하위 패키지가awt
,applet
,io
,lang
,net
,와util
,하지만 컴파일 단위를.- 이 패키지
java.awt
에는image
클래스 및 인터페이스 유형의 선언을 포함하는 여러 컴파일 단위뿐만 아니라 라는 하위 패키지 가 있습니다.
서브 패키지 개념은 패키지와 클래스 / 인터페이스 간의 이름 지정 제약 조건을 적용하는 것과 관련이 있습니다.
패키지에는 동일한 이름의 두 멤버가 포함되어 있지 않거나 컴파일 타임 오류가 발생할 수 있습니다.
여기 몇 가지 예가 있어요.
- 패키지
java.awt
에는 서브 패키지 가 있으므로image
, 클래스 또는 인터페이스 유형의 선언을 포함 할 수 없으며 포함하지도 않습니다image
.- 해당 패키지에 이름이 지정된 패키지
mouse
와 멤버 유형Button
(이후이라고도 함mouse.Button
)이 있으면 정규화 된 이름mouse.Button
또는을 가진 패키지가있을 수 없습니다mouse.Button.Click
.- 경우
com.nighthacks.java.jag
유형의 완전한 이름은 다음 누구의 정규화 된 이름 중 어떤 패키지가있을 수 없다com.nighthacks.java.jag
거나com.nighthacks.java.jag.scrabble
.
그러나이 이름 제한은 언어별로 하위 패키지에 제공 되는 유일한 의미입니다.
패키지의 계층 적 이름 지정 구조는 일반적인 방식으로 관련 패키지를 구성하는 데 편리하도록 만들어졌지만 해당 패키지에 선언 된 최상위 유형과 이름이 같은 하위 패키지를 갖는 패키지에 대한 금지 외에는 그다지 의미가 없습니다. .
예를 들어,라는 이름의 패키지 사이에 특별한 접근 관계가없는
oliver
명명 된 다른 패키지oliver.twist
, 또는 명명 된 패키지 사이에evelyn.wood
하고evelyn.waugh
. 즉, 이름oliver.twist
이 지정된 패키지의oliver
코드는 다른 패키지의 코드보다 패키지 내에 선언 된 유형에 더 잘 액세스 할 수 없습니다 .
이러한 맥락에서 질문 자체에 답할 수 있습니다. 패키지와 해당 서브 패키지 또는 상위 패키지의 두 개의 서로 다른 서브 패키지 사이에는 명시 적으로 특별한 액세스 관계가 없으므로 요청 된 방식으로 두 개의 서로 다른 패키지에 메소드를 표시 할 수있는 방법이 없습니다. 이것은 문서화 된 의도적 인 디자인 결정입니다.
메소드를 공개하고 모든 패키지 ( odp.proj
및 포함 odp.proj.test
)가 지정된 메소드에 액세스 할 수 있거나 메소드를 패키지 전용 (기본 가시성)으로 만들 수 있으며 메소드에 직접 액세스해야하는 모든 코드를 입력해야합니다. 방법과 동일한 (하위) 패키지.
즉, Java의 매우 표준 사례는 테스트 코드를 소스 코드와 동일한 패키지에 배치하지만 파일 시스템의 다른 위치에 배치하는 것입니다. 예를 들어,에 메이븐 빌드 도구,이 협약은 이러한 소스 및 테스트 파일을 배치하는 것 src/main/java/odp/proj
과
src/test/java/odp/proj
각각. 빌드 도구가이를 컴파일하면 두 파일 세트가 모두 odp.proj
패키지에 포함되지만 src
파일 만 프로덕션 아티팩트에 포함됩니다. 테스트 파일은 빌드시에만 프로덕션 파일을 확인하는 데 사용됩니다. 이 설정을 통해 테스트 코드는 테스트중인 코드의 패키지 개인 코드 또는 보호 된 코드가 동일한 패키지에 있으므로 자유롭게 액세스 할 수 있습니다.
테스트 / 제작 사례가 아닌 하위 패키지 또는 형제 패키지에서 코드 공유를 원하는 경우 일부 라이브러리에서 사용하는 한 가지 해결책은 공유 코드를 공개로 설정하는 것이지만 내부 라이브러리 용으로 작성되었다는 것을 문서화하는 것입니다 사용하십시오.
메소드 앞에 액세스 수정자를 넣지 않으면 개인용 패키지라고합니다.
다음 예를보십시오.
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
}
}
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);
}
}