解決するのが非常に難しい名前の非表示に問題があります。これは問題を説明する単純化されたバージョンです:
クラスがあります:_org.A
_
_package org;
public class A{
public class X{...}
...
protected int net;
}
_
次に、クラス_net.foo.X
_があります
_package net.foo;
public class X{
public static void doSomething();
}
_
そして今、これがA
を継承してnet.foo.X.doSomething()
を呼び出したい問題のあるクラスです
_package com.bar;
class B extends A {
public void doSomething(){
net.foo.X.doSomething(); // doesn't work; package net is hidden by inherited field
X.doSomething(); // doesn't work; type net.foo.X is hidden by inherited X
}
}
_
ご覧のとおり、これは不可能です。単純な名前X
は、継承された型によって隠されているため、使用できません。 net
は継承されたフィールドによって隠されているため、完全修飾名_net.foo.X
_を使用できません。
クラスB
のみが私のコードベースにあります。クラス_net.foo.X
_および_org.A
_はライブラリクラスなので、変更できません。
私の唯一の解決策は次のようになります。X.doSomething()
を呼び出す別のクラスを呼び出すことができます。しかし、このクラスは名前の衝突のためにのみ存在し、これは非常に厄介なようです! X.doSomething()
からB.doSomething()
を直接呼び出すことができる解決策はありませんか?
C#の_global::
_またはC++の_::
_などのグローバルネームスペースを指定できる言語では、net
にこのグローバルプレフィックスをプレフィックスとして付けることができますが、Javaはそれを許可しません。
null
を型にキャストし、その上でメソッドを呼び出すことができます(これは、ターゲットオブジェクトが静的メソッドの呼び出しに関与していないため機能します)。
((net.foo.X) null).doSomething();
これには次の利点があります
net.foo.X
のインスタンス化に関する問題)、B
のメソッドに希望の名前を付けることができます。そのため、import static
は正確に機能しません)。欠点は、このコードが本当に恐ろしいことです!私にとって、それは警告を生成し、それは一般的に良いことです。しかし、他の方法では完全に実用的でない問題を回避しているため、
@SuppressWarnings("static-access")
適切な(最小!)囲みポイントでコンパイラーをシャットダウンします。
おそらくこれを管理する最も簡単な(必ずしも最も簡単ではない)方法は、デリゲートクラスを使用することです。
import net.foo.X;
class C {
static void doSomething() {
X.doSomething();
}
}
その後 ...
class B extends A {
void doX(){
C.doSomething();
}
}
これはいくぶん冗長ですが、非常に柔軟です。好きなように動作させることができます。さらに、static
メソッドとインスタンス化されたオブジェクトの両方でほとんど同じように機能します
デリゲートオブジェクトの詳細はこちら http://en.wikipedia.org/wiki/Delegation_pattern
静的インポートを使用できます。
import static net.foo.X.doSomething;
class B extends A {
void doX(){
doSomething();
}
}
B
とA
にはdoSomething
という名前のメソッドが含まれていないことに注意してください
物事の適切な方法は静的インポートですが、完全な最悪のシナリオでは、完全修飾名がわかっている場合は、リフレクションを使用してクラスのインスタンスを構築できます。
Java:デフォルトのコンストラクタを持たないクラスのnewInstance
次に、インスタンスでメソッドを呼び出します。
または、リフレクションを使用してメソッド自体を呼び出すだけです。 リフレクションを使用して静的メソッドを呼び出す
Class<?> clazz = Class.forName("net.foo.X");
Method method = clazz.getMethod("doSomething");
Object o = method.invoke(null);
もちろん、これらは明らかに最後の手段です。
実際には答えではありませんが、Xのインスタンスを作成して静的メソッドを呼び出すことができます。それはあなたのメソッドを呼び出す方法です(私が認める汚い)。
(new net.foo.X()).doSomething();
キャストを行ったり、奇妙な警告を抑制したり、冗長なインスタンスを作成したりする必要はありません。親クラスの静的メソッドをサブクラス経由で呼び出すことができるという事実を利用したトリックです。 (私のハックなソリューションと同様 here 。)
このようなクラスを作成するだけです
_public final class XX extends X {
private XX(){
}
}
_
(この最終クラスのプライベートコンストラクターは、このクラスのインスタンスが誤って作成されないようにします。)
次に、それを介してX.doSomething()
を自由に呼び出すことができます。
_ public class B extends A {
public void doSomething() {
XX.doSomething();
}
_
すべてのファイルが同じフォルダーにある場合、gobalnamespaceを取得しようとするとどうなるでしょう。 ( http://www.beanshell.org/javadoc/bsh/class-use/NameSpace.html )
package com.bar;
class B extends A {
public void doSomething(){
com.bar.getGlobal().net.foo.X.doSomething(); // drill down from the top...
}
}
これが、相続よりも構成の方が望ましい理由の1つです。
package com.bar;
import Java.util.concurrent.Callable;
public class C implements Callable<org.A>
{
private class B extends org.A{
public void doSomething(){
C.this.doSomething();
}
}
private void doSomething(){
net.foo.X.doSomething();
}
public org.A call(){
return new B();
}
}
私は戦略パターンを使用します。
public interface SomethingStrategy {
void doSomething();
}
public class XSomethingStrategy implements SomethingStrategy {
import net.foo.X;
@Override
void doSomething(){
X.doSomething();
}
}
class B extends A {
private final SomethingStrategy strategy;
public B(final SomethingStrategy strategy){
this.strategy = strategy;
}
public void doSomething(){
strategy.doSomething();
}
}
これで依存関係も分離されたので、単体テストを簡単に記述できます。