Как получить доступ к пакету Private Class из класса в каком-то другом пакете? - PullRequest
8 голосов
/ 25 ноября 2011

У меня есть следующие классы

Hello.java

package speak.hello;

import java.util.Map;

import speak.hi.CustomMap;
import speak.hi.Hi;

public class Hello {

    private Hi hi;

    Hello(Hi hi) {
        this.hi = hi;
    }

    public String sayHello() {
        return "Hello";
    }

    public String sayHi() {
        return hi.sayHi();
    }

    public Map<String, Object> getMap() {
        return hi.getMap();
    }

    public void clearMap() {
        hi.getMap().clear();
    }

    public void discardMap() {
        CustomMap map = (CustomMap) hi.getMap();
        map.discard();
    }

    public static void main(String[] args) {
        Hello hello = new Hello(new Hi());
        System.out.println(hello.sayHello());
        System.out.println(hello.sayHi());
        System.out.println(hello.getMap());
        hello.clearMap();
        System.out.println("--");
        hello.discardMap();
    }

}

Hi.java

package speak.hi;

import java.util.HashMap;
import java.util.Map;

public class Hi {
    public String sayHi() {
        return "Hi";
    }

    public Map<String, Object> getMap() {
        return new CustomMap<String, Object>();
    }
}

CustomMap.java

package speak.hi;

import java.util.HashMap;

public class CustomMap<K, V> extends HashMap<K, V> {
    private static final long serialVersionUID = -7979398843650044928L;

    public void discard() {
        System.out.println("Discarding Map");
        this.clearCache();
        this.clear();
    }

    @Override
    public void clear() {
        System.out.println("Clearing Map");
        super.clear();
    }

    private void clearCache() {
        System.out.println("Clearing Map");
    }
}

Это работает нормально, пока я не удалю public спецификатор доступа из CustomMap

package speak.hi;

import java.util.HashMap;

class CustomMap<K, V> extends HashMap<K, V> {
    private static final long serialVersionUID = -7979398843650044928L;

    public void discard() {
        System.out.println("Discarding Map");
        this.clearCache();
        this.clear();
    }

    @Override
    public void clear() {
        System.out.println("Clearing Map");
        super.clear();
    }

    private void clearCache() {
        System.out.println("Clearing Map");
    }
}

Компилятор выкрикивает, что

Тип speak.hi.CustomMap не видимый

Теперь, если у меня нет опций для изменения speak.hi.CustomMap (баночка стороннего производителя и т. Д.)есть ли какой-нибудь способ, которым я все еще мог бы использовать CustomMap из speak.hello.Hello?


Один из известных мне вариантов - переместить speak.hello.Hello в speak.hi.Hello, так как теперь Hello находится в пакете speak.hi, это можетпакет доступа private Класс Hi


Есть ли другой способ сделать это?Возможно, вы используете отражение?


РЕДАКТИРОВАТЬ : Обновлено с дополнительными сведениями в соответствии с запросом @ StephenC

Ответы [ 10 ]

10 голосов
/ 25 ноября 2011

Есть ли другой способ сделать это? Возможно, с помощью отражения?

Да. Отражение можно использовать для обхода правил доступа к Java, если ваше приложение обладает полными правами.

Например, чтобы получить доступ к полю private объекта из другого класса, вам необходимо:

  • Получить объект Class объекта.
  • Используйте метод Class.getDeclaredField(...), чтобы получить объект Field для поля.
  • Позвоните Field.setAccessible(true), чтобы отключить проверку доступа.
  • Вызовите Class.getField(object, Field), чтобы получить значение поля (или коробочное значение, если это тип примитива).

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


Как вы можете себе представить, это утомительно и подвержено ошибкам. Вам бы посоветовали найти лучший способ, например:

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

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


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

6 голосов
/ 17 января 2012

Следующий метод Вызывает default метод классов с использованием отражения

public void discardMap() {
    //CustomMap map = (CustomMap) hi.getMap();
    //map.discard();
    try {
        Object o =hi.getClass().getMethod("getMap").invoke(hi);
        Method m = o.getClass().getMethod("discard");
        m.setAccessible(true);
        m.invoke(o);
    } catch (Exception e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    }
}
1 голос
/ 25 ноября 2011

Добавление этого решения для полноты картины.

Один вариант, который я знаю, это переместить speak.hello.Hello к speak.hi.Hello as Now Hello находится в пакете speak.hi, он может получить доступ к закрытому пакету Class Hi

package speak.hi;

public class Hello {

    private Hi hi;

    Hello(Hi hi) {
        this.hi = hi;
    }

    public String sayHello() {
        return "Hello";
    }

    public String sayHi() {
        return hi.sayHi();
    }

    public static void main(String[] args) {
        Hello hello = new Hello(new Hi());
        System.out.println(hello.sayHello());
        System.out.println(hello.sayHi());
    }

}
1 голос
/ 25 ноября 2011

Это может быть невозможно, потому что:

Класс:

Доступно для класса из того же пакета?

  • общедоступный: да
  • защищен: да
  • по умолчанию: да
  • частный: нет

Доступно длякласс из другого пакета?

  • общедоступный: да
  • защищен: нет
  • по умолчанию: если это не подкласс
  • частный: нет
1 голос
/ 25 ноября 2011

Я не рекомендую использовать не-API классы, так как они могут измениться в любой будущей версии и могут испортить ваш код.

Как вы узнали об этом классе? Это библиотека с открытым исходным кодом?

Попробуйте связаться с авторами библиотеки, рассказать им о своем сценарии использования и найти способ предложить им публичный API. Если это библиотека с открытым исходным кодом, вы можете помочь им, предоставив патч.

1 голос
/ 25 ноября 2011

Не возможно. Модель безопасности такова: модель для обеспечения безопасности :) Если вы разработали класс Hi и доставили его клиентам с частным доступом, вы бы не хотели, чтобы они могли обойти ваши ограничения, не так ли?

0 голосов
/ 26 февраля 2015

1-й класс находится в пакете a.b.c.class1, но class1 является как личным, так и абстрактным 2-й класс находится в пакете a.b.c.class2 расширяет class1, но class2 является общедоступным

3-й класс в пакете x.y.z.class3

Чтобы получить доступ к class1 в классе 3, вы можете написать что-то вроде: -

Класс baseClass = (новый class2 ()). GetClass (); и используйте экземпляр его суперкласса, затем используйте: baseClass.getSuperClass (); и используй его где хочешь.

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

0 голосов
/ 25 ноября 2011

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

0 голосов
/ 25 ноября 2011

Я думаю, что по умолчанию класс будет "default" (пакет можно сказать приватным), а не "private".Так что к нему можно получить доступ в одном пакете.

Более того, вы НЕ МОЖЕТЕ сделать любой * класс верхнего уровня Приватным в Java.

И если вы хотите сделать класс по умолчанию и при этом иметь доступ к нему в другом пакететогда какова цель наличия спецификаторов доступа (модификаторов) ??

, вам нужно либо сделать класс общедоступным, либо перейти в тот же пакет.

0 голосов
/ 25 ноября 2011

Не возможно, вы не можете создать свой класс Hi как частный.

...