Какой смысл "финального класса" в Java?

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

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

Если Java объектно ориентирована и вы объявляете класс final, не останавливает ли она идею класса, имеющего характеристики объектов?

+463
источник поделиться
23 ответа

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

Класс final - это просто класс, который не может быть расширен.

(Это не означает, что все ссылки на объекты класса будут действовать так, как если бы они были объявлены как final.)

Когда полезно объявить класс как окончательный, он будет рассмотрен в ответах на этот вопрос:

Если Java объектно ориентирована и вы объявляете класс final, не останавливает ли она идею класса, имеющего характеристики объектов?

В некотором смысле да.

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


Связанная статья: Java: когда создавать окончательный класс

+443
источник

В Java элементы с модификатором final не могут быть изменены!

Это включает в себя финальные классы, финальные переменные и финальные методы:

  • Последний класс не может быть расширен ни одним другим классом
  • Окончательная переменная не может быть переназначена другое значение
  • Последний метод не может быть переопределен
+164
источник
другие ответы

Связанные вопросы


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

Один сценарий, в котором конечный параметр важен, если вы хотите предотвратить наследование класса по соображениям безопасности. Это позволяет вам убедиться, что код, который вы используете, не может быть переопределен кем-то.

Другой сценарий для оптимизации: я, кажется, помню, что компилятор Java строит некоторые вызовы функций из конечных классов. Итак, если вы вызываете a.x(), а a объявляется final, во время компиляции мы знаем, что такое код, и может встроить в вызывающую функцию. Я понятия не имею, действительно ли это сделано, но с окончательным - это возможность.

+27
источник

Лучшим примером является

публичный конечный класс String

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

+19
источник

Если вы представляете иерархию классов как дерево (как в Java), абстрактными классами могут быть только ветки, а конечные классы - это те, которые могут быть только листьями. Классы, которые не входят ни в одну из этих категорий, могут быть как ветвями, так и листьями.

Там нет нарушения принципов OO, окончательный просто обеспечивает приятную симметрию.

На практике вы хотите использовать final, если хотите, чтобы ваши объекты были неизменными или вы пишете API, чтобы сигнализировать пользователям API о том, что класс просто не предназначен для расширения.

+15
источник

Соответствующее чтение: принцип Открытого и закрытого Боба Мартина.

Ключевая цитата:

Программные объекты (классы, модули, функции и т.д.) Должны быть открыты для расширения, но закрыты для модификации.

Ключевое слово final - это средство для реализации этого в Java независимо от того, используется ли оно в методах или классах.

+15
источник

Ключевое слово final само по себе означает, что что-то является окончательным и не должно быть каким-либо образом изменено. Если класс, помеченный final, то он не может быть расширен или подклассифицирован. Но возникает вопрос, почему мы отмечаем класс final? ИМО есть разные причины:

  • Стандартизация: Некоторые классы выполняют стандартные функции, и они не предназначены для модификации, например. классы, выполняющие различные функции, связанные с строковыми манипуляциями или математическими функциями и т.д.
  • Причины безопасности. Иногда мы пишем классы, которые выполняют различные функции аутентификации и пароля, и мы не хотим, чтобы они были изменены кем-либо еще.

Я слышал, что класс маркировки final повышает эффективность, но, откровенно говоря, я не мог найти этот аргумент для переноса большого веса.

Если Java ориентирована на объекты, и вы объявляете окончательный класс, не так ли? остановить идею класса, имеющего характеристики объектов?

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

На стороне примечания мы должны предпочесть состав над наследованием и final ключевое слово действительно помогает в соблюдении этого принципа.

+9
источник

Если класс помечен как final, это означает, что структура класса не может быть изменена ничем внешним. Где это наиболее заметно, когда вы выполняете традиционное полиморфное наследование, в основном class B extends A просто не будет работать. Это в основном способ защиты некоторых частей вашего кода (до степени).

Чтобы уточнить, класс mark final не помечает свои поля как final и, таким образом, не защищает свойства объекта, а не фактическую структуру класса.

+5
источник

Будьте осторожны, когда вы делаете класс "final". Потому что, если вы хотите написать unit test для окончательного класса, вы не можете подклассифицировать этот последний класс, чтобы использовать технику взлома зависимостей "Подкласс и метод переопределения", описанный в книге Майкла C. Перья "Эффективная работа с устаревшим кодом" ". В этой книге Перус сказал:" Серьезно, нетрудно поверить, что запечатанные и окончательные ошибочно ошибочны, что их никогда не следует добавлять к языкам программирования. Но настоящая ошибка лежит на нас. Когда мы напрямую зависим от библиотеки, которые находятся вне нашего контроля, мы просто просим о проблемах ".

+5
источник

ДЛЯ АДРЕСА ЗАДАЧИ ЗАКЛЮЧИТЕЛЬНОГО КЛАССА:

Есть два способа сделать окончательный класс. Во-первых, использовать ключевое слово final в объявлении класса:

public final class SomeClass {
  //  . . . Class contents
}

Второй способ сделать окончательный класс - объявить все его конструкторы как частные:

public class SomeClass {
  public final static SOME_INSTANCE = new SomeClass(5);
  private SomeClass(final int value) {
  }

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

public class Test{
  private Test(Class beanClass, Class stopClass, int flags)
    throws Exception{
    //  . . . snip . . . 
  }
}

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

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

+5
источник

final class может избежать взлома открытого API при добавлении новых методов.

Предположим, что в версии 1 вашего Base класса вы делаете:

public class Base {}

и клиент делает:

class Derived extends Base {
    public int method() { return 1; }
}

Затем, если в версии 2 вы хотите добавить method метода в Base:

class Base {
    public String method() { return null; }
}

это сломало бы код клиента.

Если бы вместо этого мы использовали final class Base, клиент не смог бы наследовать, а добавление метода не нарушило бы API.

+4
источник

Да, иногда вам может понадобиться это, хотя или по соображениям безопасности или скорости. Это было сделано и на С++. Возможно, это не применимо для программ, но, скорее, для фреймворков. http://www.glenmccl.com/perfj_025.htm

+3
источник

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

Предотвращение подкласса класса может быть особенно полезно, если вы пишете API или библиотеки и хотите избежать расширения для изменения поведения базы.

+3
источник

Одно из преимуществ сохранения класса как окончательного: -

Класс String остается окончательным, так что никто не может переопределять его методы и изменять функциональность. например, никто не может изменить функциональность метода length(). Он всегда будет возвращать длину строки.

Разработчик этого класса не хотел менять функциональность этого класса, поэтому он сохранил его как окончательный.

+3
источник

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

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

+1
источник

Как сказано выше, если вы хотите, чтобы никто не мог изменить функциональность метода, вы можете объявить его окончательным.

Пример: путь к файлу сервера приложений для загрузки/выгрузки, разделение строки на основе смещения, такие методы, которые вы можете объявить в Final, чтобы эти функции методов не были изменены. И если вы хотите, чтобы такие конечные методы были в отдельном классе, определите этот класс как Final. Таким образом, у конечного класса будут все конечные методы, где в качестве конечного метода можно объявить и определить в нечетном классе.

+1
источник

подумайте о FINAL как о "конце линии" - этот парень больше не может производить потомство. Поэтому, когда вы это видите, есть много реальных сценариев, которые вы столкнетесь с этим, и вам нужно отметить маркер "конец строки" для класса. Это Domain Driven Design - если ваш домен требует, чтобы данный ENTITY (класс) не мог создавать подклассы, тогда отметьте его как FINAL.

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

Лучший подход - посмотреть на домен и позволить ему диктовать ваши проектные решения.

+1
источник

Класс Android Looper - хороший практический пример этого. http://developer.android.com/reference/android/os/Looper.html

Класс Looper предоставляет определенные функции, которые НЕ предназначены для переопределения любым другим классом. Следовательно, здесь нет подкласса.

+1
источник

Допустим, у вас есть класс Employee с методом greet. Когда вызывается метод greet он просто печатает Hello everyone! , Так что это ожидаемое поведение метода greet

public class Employee {

    void greet() {
        System.out.println("Hello everyone!");
    }
}

Теперь позвольте GrumpyEmployee Employee и переопределить метод greet как показано ниже.

public class GrumpyEmployee extends Employee {

    @Override
    void greet() {
        System.out.println("Get lost!");
    }
}

Теперь в приведенном ниже коде взгляните на метод sayHello. Он принимает экземпляр Employee в качестве параметра и вызывает метод greet, надеясь, что он скажет Hello everyone! Но то, что мы получаем, это Get lost! , Это изменение в поведении происходит из-за Employee grumpyEmployee = new GrumpyEmployee();

public class TestFinal {
    static Employee grumpyEmployee = new GrumpyEmployee();

    public static void main(String[] args) {
        TestFinal testFinal = new TestFinal();
        testFinal.sayHello(grumpyEmployee);
    }

    private void sayHello(Employee employee) {
        employee.greet(); //Here you would expect a warm greeting, but what you get is "Get lost!"
    }
}

Этой ситуации можно избежать, если класс Employee был final. Представьте, сколько хаоса может вызвать дерзкий программист, если String Class не будет объявлен как final.

+1
источник

Если вы сделаете какой-либо класс окончательным, вы не сможете его продлить.

final class Bike{}  

class Honda1 extends Bike{  
 void run(){System.out.println("running safely with 100kmph");}  

public static void main(String args[]){  
 Honda1 honda= new Honda();  
honda.run();  
  }  
}  

    Output:Compile Time Error
0
источник

Вкратце, класс, переменная или метод, объявленные как final, не могут быть изменены.

Что важнее мое мнение:

Честно говоря, я считаю, что ключевое слово final является ошибкой, поскольку его существование позволяет пользователю определить нечто не final. Все в Java должно быть final по умолчанию, кроме методов интерфейса (по определению). Было неудачным выбором, чтобы все методы экземпляров были virtual по умолчанию (в терминах ). Ключ состоит в том, чтобы заставить пользователя сначала подумать и явно опозорить метод как virtual - это заставило бы его задаться вопросом, должен ли этот метод позволить другим переопределить его, really ли это необходимо или убедить его изменить свой код.

0
источник

Финальный класс не может быть продлен дальше. Если нам не нужно делать класс наследуемым в Java, мы можем использовать этот подход.

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

0
источник

Ориентация объектов не касается наследования, это касается инкапсуляции. И наследование прерывает инкапсуляцию.

Объявление окончательного класса имеет смысл во многих случаях. Любой объект, представляющий "ценность", как цвет или сумма денег, может быть окончательным. Они стоят самостоятельно.

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

Джошуа Блох в "Эффективной Java" рекомендует явно разрабатывать для наследования или запрещать его, и он отмечает, что проектирование для наследования не так просто.

-2
источник

Посмотрите другие вопросы по меткам или Задайте вопрос