Каково различие между переопределением и перегрузкой?
Перегрузка: выбор метода сигнатуры во время компиляции на основе количества и типа указанных аргументов
Перегрузка: выбор метода реализации во время выполнения на основе фактического типа целевого объекта (в отличие от типа выражения во время компиляции)
Например:
class Base
{
void foo(int x)
{
System.out.println("Base.foo(int)");
}
void foo(double d)
{
System.out.println("Base.foo(double)");
}
}
class Child extends Base
{
@Override void foo (int x)
{
System.out.println("Child.foo(int)");
}
}
...
Base b = new Child();
b.foo(10); // Prints Child.foo(int)
b.foo(5.0); // Prints Base.foo(double)
Оба вызова являются примерами перегрузки. Есть два метода с именем foo
, и компилятор определяет, какую сигнатуру вызывать.
Первый вызов является примером переопределения . Компилятор выбирает сигнатуру "foo(int)", но затем во время выполнения тип целевого объекта определяет, что используемая реализация должна быть той же, что и в Child
.
Перегрузка методов - это компилятор, позволяющий использовать то же имя для выполнения разных действий в зависимости от параметров.
Переопределение способа означает, что его целая функциональность заменяется. Переопределение - это что-то в детском классе к методу, определенному в родительском классе.
Перегрузка:
public Bar foo(int some);
public Bar foo(int some, boolean x); // Same method name, different signature.
Перегружается:
public Bar foo(int some); // Defined in some class A
public Bar foo(int some); // Same method name and signature. Defined in subclass of A.
Если второй метод не был определен, он унаследовал бы первый метод. Теперь он будет заменен вторым методом в подклассе A.
Перегрузка - аналогичная подпись - одно имя, разные параметры
void foo() {
/** overload */
}
void foo( int a ) {
/** overload */
}
int foo() {
/** this is NOT overloading, signature is for compiler SAME like void foo() */
}
Переопределить - вы можете переопределить тело метода, когда вы наследуете его.
class A {
void foo() {
/** definition A */
}
}
class B extends A {
void foo() {
/** definition B, this definition will be used when you have instance of B */
}
}
Посмотрите через галерею MatPlotlib , все графики там имеются свой исходный код. Найти тот, который вам нравится, вырезать и вставить, рассекать!
-121--4746540-- это когда способ, который унаследован подклассом из суперкласса, является , заменен (переопределен) в подклассе.
class A {
void foo() {
/** definition A of foo */
}
}
class B extends A {
void foo() {
/** definition B of foo */
}
}
Теперь, если вы звоните foo
, используя:
A a = new B();
a.foo();
B
определение FOO
. Это не так интуитивно понятно, поскольку вы получите ошибку компиляции, если класс A
не имеет метода FOO
. Таким образом, тип объекта A
, который является A
должен иметь метод foo
, то вы можете его вызвать, и метод foo
экземпляра будет выполнено, что является классом B
, отсюда «время выполнения».
Когда вы создаете метод с тем же именем, что и существующий метод. Чтобы избежать ошибки времени компиляции, вы имеют , чтобы определить новый метод с разными параметрами, чем существующий. Таким образом, методы будут различимыми. Имейте метод с тем же именем и параметрами, но другой тип возврата по-прежнему расплывшится и поэтому приведет к ошибке компиляции. Пример перегрузки:
class A {
void bar(int i) {}
// The following method is overloading the method bar
void bar(Object a) {}
// The following will cause a compile error.
// Parameters should differ for valid overload
boolean bar(int i) {
return true;
}
}
Об интересном моменте, о котором стоит упомянуть:
public static doSomething(Collection<?> c) {
// do something
}
public static doSomething(ArrayList<?> l) {
// do something
}
public static void main(String[] args) {
Collection<String> c = new ArrayList<String> ();
doSomething(c); // which method get's called?
}
Можно было бы предположить, что метод с аргументом ArrayList будет вызван, но это не так. Первый метод вызывается, поскольку правильный метод выбирается во время компиляции.