Окончательный класс
Когда класс определяется как окончательный класс, это означает, что класс не может быть унаследован другими классами, то есть его нельзя использовать после расширения. В противном случае вы получите ошибку во время компиляции.
пакет com.iderzheng.finalkeyword; Public Final Class FinalClass {} // Ошибка: не может наследовать от FinalClass PackAgeClass Extends FinalClass {} Java поддерживает определение класса как окончательный, который, по-видимому, нарушает основные принципы объектно-ориентированного программирования. Однако, с другой стороны, закрытый класс также гарантирует, что все методы класса были фиксированными, и не будет никаких переопределений подкласса для динамической загрузки. Это дает больше возможностей для оптимизации компилятора. Лучший пример - String, который является последним классом. Компилятор Java может напрямую поворачивать константы строк (те, которые содержатся в двойных кавычках) в строковые объекты, и в то же время непосредственно оптимизировать работу оператора + в новые константы, поскольку окончательная модификация гарантирует, что ни один подклассы не возвращают различные значения для операций сплайсинга.
Для всех различных определений класса - классы верхнего уровня (глобальный или видимый пакет), вложенные классы (внутренние или статические вложенные классы) могут быть изменены с помощью окончательного. Однако, в целом, финал в основном используется для изменения классов, определенных как публичные, потому что для неглобальных классов модификаторы доступа ограничили свою видимость, и уже трудно унаследовать эти классы, поэтому нет необходимости добавлять уровень окончательных ограничений.
Также упоминается, что, хотя анонимные классы не могут быть унаследованы, компилятор не ограничивается окончательным.
импортировать java.lang.reflect.modifier; открытый класс main {public static void main (string [] args) {runnable anonymous = new Runnable () {@Override public void run () {}}; System.out.println (modifier.isfinal (anonymous.getClass (). GetModifiers ())); }}Выход:
ЛОЖЬ
Окончательный метод
Тщательно связан с концепцией наследования, который тесно связан с полиморфизмом, который включает в себя разницу между концепциями переоценки и укрытия (для удобства, следующее в совокупности называется «переписывание»). Однако, в отличие от определения метода в C ++, является ли виртуальное ключевое слово добавлено в подкласс, независимо от того, использует ли метод подписи подкласса или скрыт, в Java подклассы используют одну и ту же подпись метода, чтобы перезаписать метод родительского класса, который будет сформировать скрытый метод класса (статический метод), в то время как объектный метод (не статический метод), который будет обращать в действие. Поскольку Java допускает прямой доступ к методам класса с помощью объектов, Java не позволяет методам класса и методам объектов иметь одинаковую подпись в одном и том же классе.
Последний класс определяет, что весь класс не может быть унаследован, и это также означает, что все методы в классе не могут быть покрыты и скрыты подклассами. Когда класс не модифицируется окончательным, некоторые методы все еще могут быть изменены, используя окончательный, чтобы предотвратить переписываемые эти методы на подклассах.
Точно так же такая конструкция разрушает объектно-ориентированный полиморфизм, но окончательный метод может обеспечить детерминизм его выполнения, обеспечивая таким образом стабильность вызовов методов. В некоторых структурах разработки некоторые реализованные методы абстрактных классов часто считаются ограниченными, поскольку некоторые коды драйвера в структуре будут зависеть от этих методов для достижения установленных целей, поэтому нет подклассов, которые охватывают его.
В следующем примере показана роль окончательной модификации в различных типах методов:
пакет com.iderzheng.other; открытый класс FinalMethods {public static void publicstaticMethod () {} public final void publicfinalMethod () {} public Static final void publicstaticfinalmethod () {} Защищенный void protectedfinalmethod () {} protected static final protectaticficf void staticfinalmethod () {} private static final void privatestaticfinalmethod () {} private final void privatefinalmethod () {}} пакет com.iderzheng.finalkeyword; импорт com.iderzheng.other.finalmethods; Методы публичного класса расширяют finalmethods {public static void publicstaticmethod () {} // Ошибка: невозможно переопределить публичный окончательный void publicfinalmethod () {} // Ошибка: невозможно переопределить публичный Static final void publicstaticfinalmethod () {} // ошибка: невозможно переопределить public static vicalstaticfinalmethod () {} // ошибка: невозможно переопределить public static vicalstaticfinalmethod () {} // ошибка: невозможно переопределить public static vicalstaticfinalmethod () {} // ошибка. void publicstaticfinalmethod () {} // Ошибка: невозможно переопределить защищенную конечную void protectionfinalmethod () {} // Ошибка: невозможно переопределить защищенную статическую конечную void staticfinalmethod () {} final void finalmethod () {} static final staticfinalmethod () {} private private staticeStatis privateSTATINGEDTATIN {} private final void privatefinalmethod () {}} Прежде всего, обратите внимание, что в приведенном выше примере окончательныеметоды и методы определяются в разных пакетах. Для первого PublicstaticMethod подкласс успешно переписывает статический метод родительского класса, но поскольку это статический метод, то, что происходит, на самом деле «скрыто». В частности, вызов методов.publicStaticMethod () выполнит реализацию в классе методов. При вызове FinalMethods.publicStaticMethod () реализация не будет происходить с полиморфной нагрузкой подкласса, но будет напрямую использовать реализацию FinalMethods. Следовательно, при использовании подклассов для доступа к методам видимость методов, подписанных родительским классом, скрыта.
Для глобального метода PublicfinalMethod, как описано в окончательном методе модификации, подкласс запрещено перезаписать его, и исключение будет брошено во время компиляции. Тем не менее, имя метода одинаково в подклассе, но оно имеет параметр, такой как: publicfinalmethod (String x) в порядке, потому что это синхронная подпись метода.
В Intellij IDE показывает предупреждение для PublicstaticfinalMethod: «статический», объявленный «окончательным». Это кажется излишним для этого, но из примера можно увидеть, что окончательный также запрещает определения подкласса от статических методов, чтобы скрыть его. В фактическом развитии поведение определения тех же статических методов подклассов и родительских классов чрезвычайно желательно, поскольку скрытые методы требуют, чтобы разработчики обращали внимание на использование различных имен классов для определения различных эффектов, которые легко вызывать ошибки. Более того, в классе вы можете напрямую вызвать статические методы, не используя имя класса. Когда разработчик снова наследует, он может не заметить скрытое существование. По умолчанию при использовании метода родительского класса он обнаружит, что это не ожидаемый результат. Следовательно, статические методы должны быть окончательными по умолчанию и не должны быть скрыты, поэтому IDE считает, что это ненужная модификация.
Защищенные методы модификации и публичных изменений в родительском классе видны подклассу, поэтому ситуация окончательной модификации защищенных методов совпадает с общественными методами. Следует отметить, что в реальном развитии защищенные статические методы обычно определяются редко, потому что такие методы слишком практичны.
Для метода пакета родительского класса подклассы в разных пакетах невидимы. Частный метод был настроен, и только к нему может получить доступ только родительский класс. Таким образом, компилятор позволяет подклассам определять тот же метод. Но это не образует переопределения и не скрывает, потому что родительский класс скрыл эти методы с помощью модификаторов, не вызванных переписыванием подклассов. Конечно, если подкласс и родительский класс находятся в том же пакете, то ситуация будет такой же, как и предыдущая публика и защищена.
Почему конечный метод эффективен?
Последний метод будет использовать встроенный механизм для оптимизации inline во время компиляции. Встроенная оптимизация относится к замене кода функции вызова непосредственно во время компиляции, а не вызова функций во время выполнения. Встроенный должен знать, какую функцию использовать в конце при составлении. Очевидно, это невозможно использовать его без окончательного. Нефильные методы могут быть переписаны на подклассах. Из -за возможного полиморфизма компилятор не может определить истинный тип объекта, чтобы вызвать метод в будущем на стадии компиляции, и он не может определить, какой метод вызовать.
Окончательная переменная
Проще говоря, окончательная переменная в Java может и должна быть инициализирована один раз, а затем переменная связана со значением. Однако это назначение не обязательно должно быть инициализировано немедленно, когда переменная определена. Java также поддерживает различные результаты для окончательных переменных с помощью условных операторов, но переменная может быть назначена только один раз в любом случае.
Тем не менее, конечная переменная Java не является абсолютной постоянной, потому что переменные объекта Java являются только эталонными значениями, поэтому окончательная просто означает, что ссылка не может быть изменена, а содержание объекта все еще может быть изменено. По сравнению с указателями C/C ++, это больше похоже на переменную типа * const, чем переменная Type Const *.
Переменные Java можно разделить на две категории: локальные переменные (локальная переменная) и переменные члена класса (поле класса). Ниже приведен код для введения их ситуации инициализации отдельно.
Локальная переменная
Локальные переменные в основном относятся к переменным, определенным в методах. Они исчезнут и станут недоступными после метода. Существует особый случай, который можно разделить на: параметры функции. Для этого случая его инициализация связана с параметрами, передаваемыми при вызове функции.
Для других локальных переменных они определены в методе, и их значения могут быть условно инициализированы:
Метод публичной строки (Final Boolean FinalParam) {// Ошибка: окончательный параметр finalParam не может быть назначен // finalParam = true; Final Object Finallocal = FinalParam? новый объект (): null; Final Int Finalvar; if (finallocal! = null) {finalvar = 21; } else {finalvar = 7; } // Ошибка: переменная FinalVar уже может быть назначена // finalvar = 80; Final String Finalret; Switch (finalvar) {case 21: finalret = "me"; перерыв; Случай 7: finalret = "Она"; перерыв; по умолчанию: finalret = null; } return finalret;} Из приведенного выше примера можно увидеть, что параметрам функции, измененные в конечном итоге, не может быть присвоено новое значение, но другим конечным локальным переменным можно присвоить значение в условном операторе. Это также обеспечивает определенную гибкость для финала.
Конечно, все условия в условном утверждении должны содержать назначения для окончательных локальных переменных, в противном случае вы получите ошибку, что переменная может не быть инициализирована.
Public String Method (Final Object FinalParam) {final int finalvar; if (finalparam! = null) {finalvar = 21; } final String finalret; // Ошибка: переменная FinalVar, возможно, не было инициализированным Switch (finalVar) {case 21: finalret = "me"; перерыв; Случай 7: finalret = "Она"; перерыв; } // Ошибка: переменная Finalret, возможно, не была инициализирована return finalret;} Теоретически, локальные переменные не необходимы для определения как окончательного, и разумный метод проектирования должен хорошо поддерживать локальные переменные. Просто при использовании анонимных функций для закрытия методов Java Java требует, чтобы указанная локальная переменная должна была быть определена как окончательная:
Public Runnable Method (String String) {int integer = 12; return new Runnable () {@Override public void run () {// Ошибка: необходимо объявить окончательный System.out.println (String); // ошибка: необходимо объявить окончательную систему.out.println (Integer); }};}Поле класса
Переменные члена класса могут быть фактически разделены на два типа: статический и нестатический. Для статических переменных членов класса, поскольку они связаны с классами, в дополнение к тому, что они непосредственно инициализированы во время определения, они также могут быть помещены в статический блок, и использование последних может выполнять более сложные операторы:
пакет com.iderzheng.finalkeyword; import java.util.hashset; import java.util.linkedhashset; импорт java.util.set; открытый класс staticfinalfields {static final int static_final_init_inline = 7; Статический окончательный набор <integer> static_final_init_static_block; / ** Статический блок **/ static {if (system.currenttimemillis () % 2 == 0) {static_final_init_static_block = new Hashset <> (); } else {static_final_init_static_block = new LinkedHashset <> (); } Static_final_init_static_block.add (7); Static_final_init_static_block.add (21); }}В Java также существуют нестатические блоки, которые могут инициализировать нестатические переменные-члены, но для этих переменных они часто помещаются в конструктор для инициализации. Конечно, необходимо убедиться, что каждая конечная переменная инициализируется один раз в конструкторе. Если другие конструкторы вызываются через это (), эти конечные переменные больше не могут быть назначены в конструкторе.
пакет com.iderzheng.finalkeyword; public class finalfields {final long final_init_inline = system.currenttimemillis (); final long final_init_block; final long final_init_constructor; / ** Начальный блок **/ {final_init_block = System.nanotime (); } Finalfields () {this (217); } Finalfields (boolean bool) {final_init_constructor = 721; } Finalfields (long init) {final_init_constructor = init; }}Когда окончательный используется для изменения классов (класса) и методов (метод), это в основном влияет на объектно-ориентированное наследование. Без наследства не будет никакой зависимости от кода подкласса на родительском классе. Следовательно, при изменении кода во время технического обслуживания не нужно учитывать, будет ли разрушена реализация подкласса, что делает его более удобным. Когда он используется на переменной, Java гарантирует, что значение переменной не будет изменено. Если дальнейший дизайн гарантирует, что члены класса не могут быть изменены, то вся переменная может быть превращена в постоянную, что очень полезно для многопоточного программирования. Поэтому окончательный оказывает очень хорошее влияние на обслуживание кода.