Как продлить окончательный класс в Java
Вот моя проблема, с которой я сейчас сталкиваюсь.
У меня есть класс, скажем Foo
, и этот класс определяет метод с именем getBar
, который возвращает экземпляр Bar
. Класс Bar
определяется внутри Foo
и объявляется public static final
. Я хочу, чтобы определить класс MyFoo
, который расширяет Foo
, но я также хочу расширить Bar
с помощью MyBar
, добавив свои собственные функции (методы, свойства и т.д.).
Я также хочу, чтобы getBar
возвращал MyBar
.
Задача Bar
является окончательной. Вот иллюстрация того, что я хочу сделать:
public class Foo {
Bar bar = new Bar();
public Bar getBar(){
return bar;
}
....
public static final class Bar {
}
}
Что я хочу сделать:
public class MyFoo extends Foo {
public MyBar getBar(){ // here I want to return an instance of MyBar
}
public static final class MyBar extends Bar { // That impossible since Bar is final
}
}
Как я могу это достичь?
[EDIT] Я добавляю более подробные сведения к моему вопросу.
Я действительно разрабатываю плагин для Jenkins и после поиска, я понимаю, что есть плагин, который предлагает базовые функции, которые я хочу сделать, Foo
и Bar
. Я хочу настроить Foo
и Bar
, чтобы он соответствовал моим потребностям.
Foo является основным классом плагина и расширяет класс Builder. Foo определяет метод под названием perform
, который содержит все операции для выполнения сборки.
Bar
содержит операции для целей конфигурирования, а Foo - это Bar для получения этих сведений.
Итак, что я хочу сделать, это расширить Foo с помощью MyFoo
и добавить некоторые конфигурации с помощью MyBar
. И, как вы видите, MyFoo
нужно будет получить эти конфигурации, вызвав getBar();
Во-вторых, я не контролирую instanciation MyFoo
и MyBar
Что блокирует меня, я не могу расширить Bar. Как я могу это достичь?
Ответы
Ответ 1
Вы не можете, в принципе. Похоже, разработчик, который разработал Bar
, предназначенный для его расширения, поэтому вы не можете его расширять. Вам нужно будет искать другой дизайн - возможно, тот, который не использует наследование так много... если вы не можете изменить существующий код, конечно.
(Трудно дать более конкретный совет, не зная больше о реальной цели здесь - разработке общей системы.)
Ответ 2
Вы не можете расширить класс, объявленный final
. Однако вы можете создать промежуточный класс, называемый Wrapper
. Этот Wrapper будет в основном содержать экземпляр исходного класса и предоставляет альтернативные методы для изменения состояния объекта в соответствии с тем, что вы хотите сделать.
Конечно, это не даст доступ к закрытым и защищенным полям класса final
, но вы можете использовать его методы getters и seters в сочетании с новыми методами и полями, которые вы объявили в классе Wrapper
, чтобы получить результат, который вы хотите или что-то относительно близко.
Другим решением является не объявлять final
класс, если для этого нет веской причины.
Ответ 3
Вы не можете расширить класс final
- цель ключевого слова final
.
Однако существуют (по крайней мере) два рабочих процесса:
- Класс находится в проекте Jenkins, который является открытым исходным кодом, поэтому вы можете просто загрузить проект, внести изменения, которые вы хотите в класс, и перестроить банку
- Отчасти из-за взлома, но вы можете использовать библиотеку, например Javassist, чтобы заменить реализацию класса в памяти
Ответ 4
Вы не можете расширять заключительные классы, то есть точку объявления классов final. Вы можете определить интерфейс, который наследуется как для окончательного класса, так и для класса-оболочки, который делегирует вызовы завершенному окончательному классу. Поэтому возникает вопрос, почему сделать класс окончательным на первом месте.
Ответ 5
Возможно, что вы хотите, это прокси. Это легко реализовать. Это отличная статья: http://java.dzone.com/articles/power-proxies-java
Ответ 6
Например, мы не можем добавить StringBuffer в Collection TreeSet, потому что
TreeSet не является дочерним элементом интерфейса Comparable:
public class Main(){
public static void main(String[] args){
TreeSet treeSetSB = new TreeSet();
treeSetSB.add(new StringBuffer("A")); //error, Comparable is not implemented
}
Но мы можем использовать оболочку для реализации Comparable:
class myWrap implements Comparable{
TreeSet treeset;
public myWrap() {
this.treeset=new TreeSet<>();
}
public TreeSet getTreeset() {
return treeset;
}
public void setTreeset(TreeSet treeset) {
this.treeset = treeset;
}
}
public class Main(){
public static void main(String[] args){
myWrap myWrap =new myWrap();
TreeSet myTrs =myWrap.getTreeset();
myTrs.add("b"); // no error anymore
myTrs.add("a");
myTrs.add("A");
System.out.println(myTrs);
}