Вътрешни класове

В: И така, за какво са полезни вътрешните класове?

О: Вътрешните класове гнездят в рамките на други класове. Нормалният клас е директен член на пакет, клас от най-високо ниво. Вътрешните класове, които станаха достъпни с Java 1.1, се предлагат в четири вида:

  • Статични класове на членове
  • Членски класове
  • Местни класове
  • Анонимни класове

Нека да разгледаме набързо всеки поред.

Накратко, статичният член-член е статичен член на клас. Подобно на всеки друг статичен метод, статичният член-член има достъп до всички статични методи на родителския или най-високо ниво клас.

Подобно на статичен клас член, член член също се дефинира като член на клас. За разлика от статичното разнообразие, класът член е специфичен за екземпляр и има достъп до всички методи и членове, дори до thisреференцията на родителя .

Локалните класове се декларират в рамките на блок от код и са видими само в рамките на този блок, точно както всяка друга променлива на метода.

И накрая, анонимният клас е локален клас, който няма име.

За да отговоря на конкретния ви въпрос, ще се съсредоточа върху вътрешните класове за членове и анонимни, тъй като те най-вероятно ще срещнете и използвате. За мен предимствата на вътрешните класове могат да бъдат разделени на три категории: обектно-ориентирано предимство, организационно предимство и предимство за обратно връщане.

Обектно-ориентираното предимство

Според моето скромно мнение най-важната характеристика на вътрешния клас е, че ви позволява да превръщате нещата в обекти, които обикновено не бихте превърнали в обекти. Това позволява вашият код да бъде още по-обектно-ориентиран, отколкото би бил без вътрешни класове.

Нека да разгледаме класа на членовете. Тъй като неговият екземпляр е член на своя родителски екземпляр, той има достъп до всеки член и метод в родителския. На пръв поглед това може да не изглежда много; ние вече имаме такъв достъп от един метод в родителския клас. Класът член обаче ни позволява да извадим логиката от родителя и да я обективираме. Например, дървесен клас може да има метод и много помощни методи, които извършват търсене или разходка по дървото. От обектно-ориентирана гледна точка дървото е дърво, а не алгоритъм за търсене. За да извършите търсене обаче, се нуждаете от интимни познания за структурите от данни на дървото.

Вътрешен клас ни позволява да премахнем тази логика и да я поставим в своя клас. Така че от обектно-ориентирана гледна точка извадихме функционалността от мястото, където тя не принадлежи и я поставихме в свой собствен клас. Чрез използването на вътрешен клас успешно отделихме алгоритъма за търсене от дървото. Сега, за да променим алгоритъма за търсене, можем просто да разменяме в нов клас. Бих могъл да продължа, но това отваря нашия код за много от предимствата, предоставени от обектно-ориентираните техники.

Организационно предимство

Обектно-ориентираният дизайн не е нещо на всеки, но за щастие вътрешните класове осигуряват повече. От организационна гледна точка вътрешните класове ни позволяват да организираме по-нататък нашата структура на пакета чрез използване на пространства от имена. Вместо да изхвърлят всичко в плосък пакет, класовете могат да бъдат допълнително вложени в класове. Изрично, без вътрешни класове, бяхме ограничени до следната йерархична структура:

пакет1 клас 1 клас 2 ... клас n ... пакет n 

С вътрешните класове можем да направим следното:

пакет 1 клас 1 клас 2 клас 1 клас 2 ... клас n 

Използвани внимателно, вътрешните класове могат да осигурят структурна йерархия, която по-естествено отговаря на вашите класове.

Предимството на обратното обаждане

Класовете на вътрешните членове и анонимните класове предоставят удобен метод за дефиниране на обратно извикване. Най-очевидният пример се отнася до GUI код. Приложението на обратното обаждане обаче може да се разпростира върху много домейни.

Повечето графични интерфейси на Java имат някакъв компонент, който предизвиква actionPerformed()извикване на метод. За съжаление, повечето разработчици просто разполагат с основния си прозорец ActionListener. В резултат на това всички компоненти споделят един и същ actionPerformed()метод. За да разберете кой компонент е извършил действието, обикновено има гигантски, грозен превключвател в actionPerformed()метода.

Ето пример за монолитно изпълнение:

публичен клас SomeGUI разширява JFrame реализира ActionListener {защитен JButton button1; защитен бутон JButton2; ... защитен бутон JButtonN; public void actionPerformed (ActionEvent e) {if (e.getSource () == button1) {// направи нещо} друго, ако (e.getSource () == button2) {... получавате картината

Винаги, когато видите превключватели или големи if/ if elseблокове, силните алармени камбани трябва да започнат да бият в съзнанието ви. По принцип такива конструкции са лошо обектно-ориентиран дизайн, тъй като промяната в един раздел на кода може да изисква съответна промяна в оператора за превключване. Вътрешните членове и анонимните класове ни позволяват да се измъкнем от превключения actionPerformed()метод.

Вместо това можем да дефинираме вътрешен клас, който да изпълнява ActionListenerза всеки компонент, който искаме да слушаме. Това може да доведе до много вътрешни класове. Въпреки това можем да избегнем големи оператори за превключване и да имаме допълнителен бонус от капсулиране на нашата логика на действие. Освен това този подход може да подобри ефективността. В превключвател, където има n сравнения, можем да очакваме n / 2 сравнения в средния случай. Вътрешните класове ни позволяват да установим съответствие 1: 1 между изпълнителя на действието и слушателя на действието. В голям графичен интерфейс подобни оптимизации могат да окажат значително влияние върху производителността. Анонимен подход може да изглежда така:

публичен клас SomeGUI разширява JFrame {... декларации за членове на бутони ... защитени невалидни buildGUI () {button1 = нов JButton (); button2 = нов JButton (); ... button1.addActionListener (new java.awt.event.ActionListener () {public void actionPerformed (java.awt.event.ActionEvent e) {// направи нещо}})); .. повторете за всеки бутон

Използвайки класове за вътрешни членове, същата програма ще изглежда така:

публичен клас SomeGUI разширява JFrame {... декларации за членове на бутони // клас на дефиниции на вътрешен клас Button1Handler реализира ActionListener {public void actionPerformed (ActionEvent e) {// направи нещо}} ... дефинира клас на вътрешен член за всеки бутон защитен void buildGUI () {// инициализираме бутоните button1 = new JButton (); button2 = нов JButton (); ... // регистрираме екземпляр на слушател на действия от вътрешен клас // за всеки бутон button1.addActionListener (нов Button1Handler ()); .. повторете за всеки бутон

Тъй като вътрешните класове имат достъп до всичко в родителя, можем да преместим всяка логика, която би се появила в монолитна actionPerformed()реализация, във вътрешен клас.

Предпочитам да използвам класове на членове като обратно извикване. Това обаче е въпрос на лични предпочитания. Просто чувствам, че твърде много анонимни класове бъркат в кода. Също така чувствам, че анонимните класове могат да станат тромави, ако са по-големи от един или два реда.

Недостатъци?

As with anything else, you have to take the good with the bad. Inner classes have their disadvantages. From a maintenance point of view, inexperienced Java developers may find the inner class difficult to understand. The use of inner classes will also increase the total number of classes in your code. Moreover, from a development point of view, most Java tools come up a bit short on their support of inner classes. For example, I use IBM's VisualAge for Java for my day-to-day coding. While inner classes will compile within VisualAge, there is no inner class browser or template. Instead, you must simply type the inner class directly into the class definition. That unfortunately makes browsing the inner class difficult. It is also difficult to type since you lose many of VisualAge's code completion aids when you type into the class definition or use an inner class.

Тони Синтес е старши консултант в ObjectWave, специализиран в телекомуникациите. Sintes, сертифициран от Sun софтуер за Java 1.1 и разработчик на Java 2, работи с Java от 1997 г.

Научете повече за тази тема

  • "Спецификация на вътрешните класове" от Sun, осигурява задълбочен поглед върху вътрешните класове

    //java.sun.com/products/jdk/1.1/docs/guide/innerclasses/spec/innerclasses.doc.html

Тази история „Вътрешни класове“ първоначално е публикувана от JavaWorld.