Сокрытие имени Java: трудный путь

У меня проблема со скрытием имен, которую очень сложно решить. Вот упрощенная версия, которая объясняет проблему:

Существует класс: 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.foo.X, потому что net скрыт унаследованным полем.

В моей базе кода только класс B; классы net.foo.X и org.A являются библиотечными классами поэтому я не могу их изменить!

Мое единственное решение выглядит так: Я мог бы вызвать другой класс, который в свою очередь вызывает X.doSomething(); но этот класс будет существовать только из-за столкновения имен, которое кажется очень грязным! Нет ли решения, в котором я могу напрямую вызвать X.doSomething() из B.doSomething()

На языке, который позволяет указывать глобальное пространство имен, например, global:: в C # или :: в C ++, я мог бы просто добавить префикс net к этому глобальному префиксу, но Java этого не делает разрешить это.

96 голосов | спросил gexicide 4 J000000Friday14 2014, 14:25:10

8 ответов


0

Вы можете привести null к типу и затем вызвать метод для этого (который будет работать, так как целевой объект не ' участвует в вызове статических методов).

((net.foo.X) null).doSomething();

Это имеет преимущества

  • не имеет побочных эффектов (проблема с созданием экземпляров net.foo.X),
  • не требует переименования чего-либо (поэтому вы можете дать методу в B имя, которое вы хотите, чтобы оно было, поэтому ---- +: = 4 =: + ---- не будет работать в вашем конкретном случае),
  • не требующий введения класса делегата (хотя это может быть хорошей идеей…), и
  • не требующий дополнительных затрат или сложности работы с API отражения.

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

import static

в подходящей (минимальной!) точке включения закроет компилятор.

ответил Donal Fellows 4 J000000Friday14 2014, 17:14:24
0

Вероятно, самый простой (не обязательно самый простой) способ справиться с этим - использовать класс делегата:

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

ответил blgt 4 J000000Friday14 2014, 15:09:33
0

Надлежащим способом выполнения действий будет статический импорт, но в самом худшем случае вы МОЖЕТЕ создать экземпляр класса, используя отражение, если знаете его полное имя.

Java: newInstance класса, у которого нет конструктора по умолчанию

А затем вызовите метод в экземпляре.

Или просто вызовите сам метод с отражением: Вызов статического метода с использованием отражения

Class<?> clazz = Class.forName("net.foo.X");
Method method = clazz.getMethod("doSomething");
Object o = method.invoke(null);

Конечно, это, очевидно, последние курорты.

ответил EpicPandaForce 4 J000000Friday14 2014, 14:58:26
0

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

(new net.foo.X()).doSomething();
ответил Michael Laffargue 4 J000000Friday14 2014, 14:43:01
0

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

Просто создайте такой класс

public final class XX extends X {
    private XX(){
    }
}

(Закрытый конструктор в этом последнем классе гарантирует, что никто не сможет случайно создать экземпляр этого класса.)

Тогда вы можете позвонить X.doSomething() через него:

    public class B extends A {

        public void doSomething() {
            XX.doSomething();
        }
ответил billc.cn 5 J000000Saturday14 2014, 21:24:45
0

Что если вы попытаетесь получить пространство имен gobal, если все файлы находятся в одной папке. ( http://www.beanshell.org/javadoc/bsh/class- использование /NameSpace.html )

    package com.bar;
      class B extends A {

       public void doSomething(){
         com.bar.getGlobal().net.foo.X.doSomething(); // drill down from the top...

         }
     }
ответил Vectoria 8 J000000Tuesday14 2014, 12:30:44
0

Это одна из причин, по которой композиция предпочтительнее наследования.

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();
    }
}
ответил emory 4 J000000Friday14 2014, 20:36:34
0

Я бы использовал шаблон Стратегии.

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

Теперь вы также развязали свою зависимость, поэтому ваши модульные тесты будут легче писать.

ответил Erik Madsen 15 J000000Tuesday14 2014, 15:02:58

Похожие вопросы

Популярные теги

security × 330linux × 316macos × 2827 × 268performance × 244command-line × 241sql-server × 235joomla-3.x × 222java × 189c++ × 186windows × 180cisco × 168bash × 158c# × 142gmail × 139arduino-uno × 139javascript × 134ssh × 133seo × 132mysql × 132