что такое виртуальная функция и используются ли они в java

Как работают виртуальные функции в C # и Java?

Как виртуальные функции работают на С# и Java?

Использует ли он такую ​​же концепцию vtable и vpointer, что и для С++, или это нечто совершенно другое?

6 ответов

Как виртуальные функции работают в Java?

Кодирующие интервьюеры любят этот вопрос. Да. Хотя Java не имеет виртуального ключевого слова, Java имеет виртуальные функции, и вы можете их записать.

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

Направьте интервьюера на конкретный пример виртуальной функции.

Да, вы можете писать виртуальные функции в Java с интерфейсами.

Да, вы можете писать виртуальные функции в Java с абстрактными классами.

Java Абстрактные классы содержат неявно «виртуальные» методы, реализуемые классами, расширяющими его. Например:

Вы можете заставить функцию НЕ быть виртуальной в родовом классе, сделав ее final

В Java нет виртуального ключевого слова.

Он просто решает самую производную версию любого метода, который вы вызываете.

В ответ на ваш комментарий, Naveen:

Если вы сказали A a = new A(); a.sayhi(); он будет печатать «A».

Терминология java является динамической. Вы можете считать это виртуальным, но это может смутить некоторых разработчиков Java. те, кто не знает С++, по крайней мере. В Java нет явных указателей, поэтому нам не нужно беспокоиться о виртуальном/не виртуальном. Нет VTables, вы просто возвращаетесь к классу и его предкам, пока не найдете реализацию метода, который вы хотите. Там только одно наследование, поэтому вам не нужно беспокоиться о порядке конструкторов (он всегда снизу вверх).

В С++ вы получаете другое поведение, если у вас есть виртуальные методы и что-то вроде

где a было A *, указывающим на экземпляр B вместо

Источник

Что такое виртуальная функция в Java?

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

Что это такое?

Поведение виртуальной функции может быть переопределено наследующей функцией класса с тем же именем. Она в основном определяется в базовом классе и переопределяется в унаследованном классе.

Ожидается, что виртуальная функция будет определена в производном классе. Мы можем вызвать виртуальную функцию, ссылаясь на объект производного класса, используя ссылку или указатель базового класса.

Каждый нестатический метод по умолчанию является виртуальным методом. В Java нет виртуального ключевого слова, такого как C ++, но мы можем определить его и использовать для таких понятий, как полиморфизм во время выполнения.

Пример

Каждый нестатический метод является виртуальной функцией, кроме финальных и закрытых методов. Методы, которые нельзя использовать для полиморфизма, не рассматриваются как виртуальные функции.

Статическая функция не считается виртуальной функцией, потому что статический метод связан с самим классом. Поэтому мы не можем вызвать статический метод из имени объекта или класса для полиморфизма. Даже когда мы переопределяем статический метод, он не резонирует с концепцией полиморфизма.

С интерфейсами

Все интерфейсы Java являются виртуальными, они полагаются на реализующие классы для обеспечения реализации методов. Код для выполнения выбирается во время выполнения. Вот простой пример для лучшего понимания.

Здесь applyBreaks() является виртуальным, потому что функции в интерфейсах предназначены для переопределения.

Чистая

Чистая виртуальная функция – это виртуальная функция, для которой у нас нет реализаций. Абстрактный метод можно рассматривать как чисто виртуальную функцию. Давайте рассмотрим пример, чтобы лучше это понять.

Полиморфизм

Полиморфизм во время выполнения – это когда вызов переопределенного метода разрешается во время выполнения, а не во время компиляции. Переопределенный метод вызывается через ссылочную переменную базового класса.

Источник

Можете ли вы написать виртуальные функции / методы на Java?

можно писать виртуальный методы в Java, как это было бы в C++?

или, есть ли правильный подход Java, который вы можете реализовать, который производит подобное поведение? Могу я привести несколько примеров?

6 ответов

с Википедия

на Java, все нестатические методы по по умолчанию «виртуальные функции.» только методы, отмеченные ключевое слово final, который нельзя отменить, вместе с частные методы, которые не в наследство, являются non-virtual.

можете ли вы писать виртуальные функции на Java?

да. Фактически, все методы экземпляра в Java являются виртуальными по умолчанию. Только некоторые методы не являются виртуальными:

вот несколько примеров:

«нормальные» виртуальные функции

следующий пример из старая версия страницы Википедии, упомянутой в другом ответе.

пример с интерфейсами

Java методы интерфейса все виртуальный. Они!—33—>должны быть виртуальными, потому что они полагаются на классы реализации для предоставления реализаций метода. Код для выполнения будет выбран только во время выполнения.

пример с виртуальными функциями с абстрактными классами.

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

все функции в Java являются виртуальными по умолчанию.

вы должны сделать все возможное, чтобы написать не виртуальные функции, добавив ключевое слово «final».

Это противоположность C++/C# по умолчанию. По умолчанию функции класса не являются виртуальными; вы делаете их так, добавляя модификатор «virtual».

все non-private методы экземпляра являются виртуальными по умолчанию в Java.

В C++, частные методы могут быть виртуальными. Это можно использовать для идиомы non-virtual-interface (NVI). В Java вам нужно будет защитить переопределяемые методы NVI.

из спецификации языка Java, v3:

8.4.8.1 переопределение (методами экземпляра) метода экземпляра m1 объявленные в классе C может другой метод экземпляра, м2, объявленный в классе A iff все следующие верны:

Да, вы можете писать виртуальные «функции» на Java.

Источник

Java. Абстрактные, виртуальные, конечные и статические методы.

Статические методы и поля

Для того чтобы не надо было создавать объект класса Math (и других аналогичных классов) каждый раз, когда надо вызвать sin (и другие подобные функции), введено понятие статических методов (static method; иногда в русском языке они называются статичными). Статический метод (отмечаемый словом static в описании) можно вызвать, не создавая объекта его класса. Поэтому можно писать

double x = Math.sin(1);

Math m = new Math(); double x = m.sin(1);

Ограничение, накладываемое на статические методы, заключается в том, что в объекте this они могут обращаться только к статическим полям и методам. Статические поля имеют тот же смысл, что и в C++: каждое существует только в одном экземпляре.

В Java все методы являются виртуальными в терминологии C++: при вызове метода, по-разному определённого в базовом и наследующем классах, всегда производится проверка времени выполнения. Абстрактным методом (описатель abstract) в Java называется метод, для которого заданы параметры и тип возвращаемого значения, но не тело. Абстрактный метод определяется в классах-наследниках. В C++ то же самое называется чисто виртуальной функцией. Для того чтобы в классе можно было описывать абстрактные методы, сам класс тоже должен быть описан как абстрактный. Объекты абстрактного класса создавать нельзя.

При описании класса Pet мы не можем задать в методе voice () никакой полезный алгоритм, поскольку у всех животных совершенно разные голоса.

Как же использовать абстрактные классы? Только порождая от них подклассы, в которых переопределены абстрактные методы.

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

Кстати, можно задать пустую реализацию метода, просто поставив пару фигурных скобок, ничего не написав между ними, например:

Получится полноценный метод. Но это искусственное решение, запутывающее структуру класса.

Замкнуть же иерархию можно окончательными классами.

В языке Java определение метода включает его объявление и реализацию. Определение метода всегда указывается в теле класса.

Метод может иметь модификаторы доступа, возвращать значение и получать параметры.

Метод может иметь следующие модификаторы:

abstract, final, native или synchronized.

Для модификаторов доступа метода определены следующие правила:

public указывает, что данный метод будет доступен везде, где доступен класс, в котором он определен;

protected указывает, что данный метод будет доступен как внутри пакета, содержащего объявление класса, в котором он определен, так и внутри любого подкласса данного класса;

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

По умолчанию метод считается доступным везде внутри пакета, содержащего класс, в котором он определен, и недоступным ни в каком другом подклассе указанного класса в том случае, если подкласс содержится в другом пакете.

Метод, не имеющий модификатора static, называется методом экземпляра. Метод экземпляра может быть вызван только для созданного экземпляра класса или подкласса. Такой метод нельзя вызывать непосредственно, квалифицируя его именем класса.

Метод, объявленный с модификатором static, называется статическим методом (или методом класса) и может быть вызван без создания экземпляра класса. Этот метод всегда вызывается непосредственно из класса. Статический метод имеет доступ к другим статическим переменным и методам данного класса.

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

public class A implements B <

public static int Metod2()<

return 0;> //Статический метод

final public static int a=1;

public class C extends A <

public static int Metod2()

public static void main(String[] args) <

При переопределении методов их модификаторы доступа должны совпадать. Так, нельзя переопределить метод, имеющий модификатор доступа public, методом с модификатором доступа private.

Абстрактный метод указывается модификатором abstract. Такой метод никогда не имеет тела метода: вместо фигурных скобок, ограничивающих тело метода, объявление метода завершается точкой с запятой.

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

public class A extends AA implements B <

public static int Metod2()

abstract int Metod4();

abstract int Metod3();

Методы, объявленные с модификатором private, не могут быть абстрактными методами, так как они недоступны вне тела класса. Статические методы также не могут выступать в качестве абстрактных методов, так как считаются конечными и не могут быть переопределены.

Объявление метода с модификатором final запрещает его последующее переопределение. Такие методы называются конечными методами, и по умолчанию считается, что private-метод всегда является конечным методом.

Методы, объявленные с модификатором native, могут иметь реализацию на другом языке программирования. Эти методы используются для написания машинно-зависимого кода. native-методы в Java-программе не имеют тела метода.

Synchronized-методы выполняются с блокировкой:

для метода класса выполняется блокировка класса,

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

Метод может возвращать значение заданного типа. В этом случае:

перед именем метода указывается тип возвращаемого значения;

в теле метода присутствует оператор return, определяющий возвращаемое значение.

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

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

C# и Java. Интерфейсы.

Интерфейс определяет набор методов, которые будут реализованы классом. Сам

интерфейс не реализует методы. Таким образом, интерфейс — это логическая конст-

рукция, которая описывает методы, не устанавливая жестко способ их реализации. В

этой главе рассматриваются еще два типа данных С#: структуры и перечисления.

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

значений, а не как ссылочные типы. Перечисления — это списки именованных цело-

численных констант. Структуры и перечисления вносят существенный вклад в общую

копилку средств и инструментов, составляющих среду программирования С#.

Интерфейсы

В объектно-ориентированном программировании иногда требуется определить,

что класс должен делать, а не как он будет это делать. Вы уже видели такой подход на

примере абстрактного метода. Абстрактный метод определяет сигнатуру для метода,

но не обеспечивает его реализации. В производном классе каждый абстрактный ме-

тод, определенный базовым классом, реализуется по-своему. Таким образом, абст-

рактный метод задает интерфейс для метода, но не способ его реализации. Несмотря

на всю полезность абстрактных классов и методов, эту идею можно развить. В С#

предусмотрена возможность полностью отделить интерфейс класса от его реализации

с помощью ключевого слова interface.

Интерфейсы синтаксически подобны абстрактным классам. Однако в интерфейсе

ни один метод не может включать тело, т.е. интерфейс в принципе не предусматрива-

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

уточняет, как. Коль скоро интерфейс определен, его может реализовать любое коли-

чество классов. При этом один класс может реализовать любое число интерфейсов.

Для реализации интерфейса класс должен обеспечить теля (способы реализации)

методов, описанных в интерфейсе. Каждый класс может определить собственную реа-

лизацию. Таким образом, два класса могут реализовать один и тот же интерфейс раз-

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

вательно, код, «осведомленный» о наличии интерфейса, может использовать объекты

любого класса, поскольку интерфейс для всех объектов одинаков. Предоставляя про-

граммистам возможность применения такого средства программирования, как интер-

фейс, С# позволяет в полной мере использовать аспект полиморфизма, выражаемый

как «один интерфейс — много методов».

дит упрощенная форма объявления интерфейса:

i n t e r f a c e имя<

Имя интерфейса задается элементом имя. Методы объявляются с использованием

лишь типа возвращаемого ими значения и сигнатуры. Все эти методы, по сути, — аб-

страктные. Как упоминалось выше, для методов в интерфейсе не предусмотрены спо-

собы реализации. Следовательно, каждый класс, который включает интерфейс, дол-

жен реализовать все его методы. В интерфейсе методы неявно являются открытыми

(public-методами), при этом не разрешается явным образом указывать спецификатор

Рассмотрим пример интерфейса для класса, который генерирует ряд чисел.

public interface ISeries <

int getNext(); // Возвращает следующее число ряда,

void reset (); // Выполняет перезапуск,

void setStart(int x) ; // Устанавливает начальное

Этот интерфейс имеет имя ISeries. Хотя префикс » I » необязателен, • многие

программисты его используют, чтобы отличать интерфейсы от классов. Интерфейс

ISeries объявлен открытым, поэтому он может быть реализован любым классом в

Помимо сигнатур методов интерфейсы могут объявлять сигнатуры свойств, индек-

саторов и событий. События рассматриваются в главе 15, поэтому здесь мы остано-

вимся на методах, индексаторах и свойствах. Интерфейсы не могут иметь членов дан-

ных. Они не могут определять конструкторы, деструкторы или операторные методы.

Кроме того, ни один член интерфейса не может быть объявлен статическим.

Реализация интерфейсов

Итак, если интерфейс определен, один или несколько классов могут его реализо-

вать. Чтобы реализовать интерфейс, нужно указать его имя после имени класса по-

добно тому, как при создании производного указывается базовый класс. Формат запи-

си класса, который реализует интерфейс, таков:

class имя_класса : имя__интерфейса <

Нетрудно догадаться, что имя реализуемого интерфейса задается с помощью эле-

Если класс реализует интерфейс, он должен это сделать в полном объеме, т.е. реа-

лизация интерфейса не может быть выполнена частично.

Классы могут реализовать несколько интерфейсов. В этом случае имена интерфей-

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

или несколько интерфейсов. В этом случае список интерфейсов должно возглавлять

имя базового класса.

Методы, которые реализуют интерфейс, должны быть объявлены открытыми. Дело

в том, что методы внутри интерфейса неявно объявляются открытыми, поэтому их

реализации также должны быть открытыми. Кроме того, сигнатура типа в реализации

метода должна в точности совпадать с сигнатурой типа, заданной в определении ин-

Рассмотрим пример реализации интерфейса ISeries, объявление которого приве-

дено выше. Здесь создается класс с именем ByTwos, генерирующий ряд чисел, в кото-

эом каждое следующее число больше предыдущего на два.

// Реализация интерфейса ISeries,

class ByTwos : ISeries <

public int getNext() <

public void setStart(int x) <

Как видите, класс ByTwos реализует все три метода, определенные интерфейсом

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

ную реализацию интерфейса.

Рассмотрим пример, демонстрирующий использование класса ByTwos. Вот его код:

// Демонстрация использования интерфейса,

// реализованного классом ByTwos.

public static void Main() <

ByTwos ob = new ByTwos() ;

for(int i=0; i csc SeriesDemo.cs ISeries.cs ByTwos.cs

В классах, которые реализуют интерфейсы, можно определять дополнительные

члены. Например, в представленную ниже версию класса ByTwos добавлен метод

getPrevious (), который возвращает предыдущее значение ряда.

// Реализация интерфейса ISeries с дополнительно

// определяемым методом getPrevious().

class ByTwos : ISeries <

public int getNextO <

public void setStart(int x) <

// Метод, не объявленный в интерфейсе ISeries,

public int getPrevious() <

Обратите внимание на то, что добавление метода getPrevious () потребовало

внесения изменений в реализацию методов, определенных интерфейсом ISeries. Но

поскольку интерфейс для этих методов остается прежним, при изменении не разру-

шается код, написанный ранее. В этом и заключается одно из достоинств использова-

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

Рассмотрим, например, класс Primes, который генерирует ряд простых чисел. Обра-

тите внимание на то, что его способ реализации интерфейса ISeries в корне отлича-

ется от используемого классом ByTwos.

// Использование интерфейса ISeries для реализации

Источник

Как полиморфизм реализован внутри JVM

Перевод данной статьи подготовлен специально для студентов курса «Разработчик Java».

что такое виртуальная функция и используются ли они в java. Смотреть фото что такое виртуальная функция и используются ли они в java. Смотреть картинку что такое виртуальная функция и используются ли они в java. Картинка про что такое виртуальная функция и используются ли они в java. Фото что такое виртуальная функция и используются ли они в java

В моей предыдущей статье Everything About Method Overloading vs Method Overriding (“Все о перегрузке и переопределении методов”) были рассмотрены правила и различия перегрузки и переопределения методов. В этой статье мы посмотрим, как обрабатывается перегрузка и переопределение методов внутри JVM.

Для примера возьмем классы из предыдущей статьи: родительский Mammal (млекопитающее) и дочерний Human (человек).

На вопрос о полиморфизме мы можем посмотреть с двух сторон: с “логической” и “физической”. Давайте сначала рассмотрим логическую сторону вопроса.

Логическая точка зрения

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

Это все довольно просто, пока мы остаемся на концептуальном уровне. Но как же JVM обрабатывает это все внутри? Как JVM вычисляет, какой метод должен быть вызван?

Также мы знаем, что перегруженные методы (overload) не называются полиморфными и резолвятся во время компиляции. Хотя иногда перегрузку методов называют полиморфизмом времени компиляции или ранним/статическим связыванием.

Переопределенные методы (override) резолвятся во время выполнения, так как компилятор не знает, есть ли переопределенные методы в объекте, который присваивается ссылке.

Физическая точка зрения

Команда выше покажет две секции байткода.

1. Пул констант. Содержит почти все, что необходимо для выполнения программы. Например, ссылки на методы ( #Methodref ), классы ( #Class ), литералы строк ( #String ).

что такое виртуальная функция и используются ли они в java. Смотреть фото что такое виртуальная функция и используются ли они в java. Смотреть картинку что такое виртуальная функция и используются ли они в java. Картинка про что такое виртуальная функция и используются ли они в java. Фото что такое виртуальная функция и используются ли они в java

2. Байткод программы. Выполняемые инструкции байткода.

что такое виртуальная функция и используются ли они в java. Смотреть фото что такое виртуальная функция и используются ли они в java. Смотреть картинку что такое виртуальная функция и используются ли они в java. Картинка про что такое виртуальная функция и используются ли они в java. Фото что такое виртуальная функция и используются ли они в java

Почему перегрузка методов называется статическим связыванием

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

Почему переопределение методов называется динамическим связыванием

Для вызова методов anyMammal.speak() и humanMammal.speak() байткод одинаковый, так как с точки зрения компилятора оба метода вызываются для класса Mammal :

Итак, теперь возникает вопрос, если у обоих вызовов одинаковый байткод, как JVM узнает, какой метод вызвать?

Инструкция invokevirtual вызывает метод экземпляра через диспетчеризацию по (виртуальному) типу объекта. Это нормальная диспетчеризация методов в языке программирования Java.

JVM использует инструкцию invokevirtual для вызова в Java методов, эквивалентных виртуальным методам C++. В C++ для переопределения метода в другом классе, метод должен быть объявлен как виртуальный (virtual). Но в Java по умолчанию все методы виртуальные (кроме final и static методов), поэтому в дочернем классе мы можем переопределить любой метод.

Инструкция invokevirtual принимает указатель на метод, который нужно вызвать ( #4 — индекс в пуле констант).

Но ссылка #4 ссылается дальше на другой метод и Class.

Все эти ссылки используются совместно для получения ссылки на метод и класс, в котором находится нужный метод. Это также упоминается в спецификации JVM (прим. переводчика: ссылка на JVM spec 2.7):

Java Virtual Machine не требует какой-либо определённой внутренней структуры объектов.

В некоторых реализациях Java Virtual Machine, выполненных компанией Oracle, ссылка на экземпляр класса представляет собой ссылку на обработчик, который сам по себе состоит из пары ссылок: одна указывает на таблицу методов объекта и указатель на объект Class, представляющий тип объекта, а другая на область данных в куче, содержащую данные объекта.

Это означает, что каждая ссылочная переменная содержит два скрытых указателя:

Из приведенных выше рассуждений можно сделать вывод, что ссылка на объект косвенно содержит ссылку/указатель на таблицу, которая содержит все ссылки на методы этого объекта. Java позаимствовала эту концепцию из C ++. Эта таблица известна под различными именами, такими как таблица виртуальных методов (VMT), таблица виртуальных функций (vftable), виртуальная таблица (vtable), таблица диспетчеризации.

Мы не можем быть уверены в том, как vtable реализован в Java, потому что это зависит от конкретной JVM. Но мы можем ожидать, что стратегия будет примерно такая же, как и в C ++, где vtable — это структура, похожая на массив, которая содержит имена методов и их ссылки. Всякий раз, когда JVM пытается выполнить виртуальный метод, она запрашивает его адрес в vtable.

Для каждого класса существует только одна vtable, это означает, что таблица уникальна и одинакова для всех объектов класса, аналогично объекту Class. Объекты Class подробнее рассмотрены в статьях Why an outer Java class can’t be static и Why Java is Purely Object-Oriented Language Or Why Not.

что такое виртуальная функция и используются ли они в java. Смотреть фото что такое виртуальная функция и используются ли они в java. Смотреть картинку что такое виртуальная функция и используются ли они в java. Картинка про что такое виртуальная функция и используются ли они в java. Фото что такое виртуальная функция и используются ли они в java

что такое виртуальная функция и используются ли они в java. Смотреть фото что такое виртуальная функция и используются ли они в java. Смотреть картинку что такое виртуальная функция и используются ли они в java. Картинка про что такое виртуальная функция и используются ли они в java. Фото что такое виртуальная функция и используются ли они в java

что такое виртуальная функция и используются ли они в java. Смотреть фото что такое виртуальная функция и используются ли они в java. Смотреть картинку что такое виртуальная функция и используются ли они в java. Картинка про что такое виртуальная функция и используются ли они в java. Фото что такое виртуальная функция и используются ли они в java

Инструкция invokevirtual заставляет JVM обрабатывать значение в ссылке на метод # 4 не как адрес, а как имя метода, которое нужно искать в vtable для текущего объекта.
Я надеюсь, теперь стало более понятно то, как JVM использует пул констант и таблицу виртуальных методов для определения того, какой метод вызывать.
Код примера вы можете найти в репозитории Github.

Источник

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *