Урок 8

Переопределение методов


1. Что такое переопределение методов?

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

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

Пример 1. Переопределение методов

public class M {
    public int i;
    public int j;

    public M(int i, int j) {
        this.i = i;
        this.j = j;
    }

    public void print() {
        System.out.println("Print in M");
        System.out.println("i = " + i);
        System.out.println("j = " + j);
    }
}

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

public class N extends M {
    public int k;

    public N(int i, int j, int k) {
        super(i, j);
        this.k = k;
    }

    public void print() {
        System.out.println("Print in N");
        System.out.println("k = " + k);
    }

    public void someMethod() {
        print();
    }
}
public class OverrideDemo {
    public static void main(String[] args) {
        M obj1 = new M(7, 8);
        obj1.print();

        N obj2 = new N(4, 5, 6);
        obj2.print();

        M obj3 = new N(1, 2, 3);
        obj3.print();
    }
}

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

M obj3 = new N(1, 2, 3);
obj3.print();

Переопределение методов это одна из форм реализации полиморфизма.

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

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

Пример 2. Переопределение методов

public class Figure {
    double dim1;
    double dim2;

    public Figure(double dim1, double dim2) {
        this.dim1 = dim1;
        this.dim2 = dim2;
    }

    public double area() {
        System.out.println("Площадь фигуры не определена.");
        return 0;
    }
}
public class Rectangle extends Figure {
    public Rectangle(double dim1, double dim2) {
        super(dim1, dim2);
    }

    public double area() {
        System.out.println("B области четырехугольника.");
        return dim1 * dim2;
    }
}
public class Triangle extends Figure {
    public Triangle(double dim1, double dim2) {
        super(dim1, dim2);
    }

    public double area() {
        System.out.println("B области треугольника.");
        return dim1 * dim2 / 2;
    }
}
public class FindAreas {
    public static void main(String[] args) {
        Figure[] figures = new Figure[3];
        figures[0] = new Figure(10, 10);
        figures[1] = new Rectangle(10, 10);
        figures[2] = new Triangle(10, 10);
        for (Figure figure : figures) {
            figure.area();
        }
    }
}

2. Методы подставки

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

Пример 3. Подставка

public class R {
    Box6 getInstance() {
        return new Box6();
    }
}
public class S extends R {
    @Override
    HeavyBox getInstance() {
        return new HeavyBox();
    }
}

3. Переопределение и статические методы

Динамический полиморфизм к статическим методам класса неприменим, так как обращение к статическому атрибуту или методу осуществляется по типу ссылки, а не по типу объекта, через который производится обращение.

Версия вызываемого статического метода всегда определяется на этапе компиляции.

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

Пример 4. “Переопределение” статических методов

public class Base {
    public static void go() {
        System.out.println("метод из Base");
    }
}
public class Sub extends Base {
    public static void go() {
        System.out.println("метод из Sub");
    }
}
public class Runner {
    public static void main(String[] args) {
        Base ob = new Sub();
        ob.go();
        Sub.go();
    }
}

4. Переопределение методов в классах наследниках

private методы никто, кроме самого класса не видит. Поэтому их наличие/отсутствие никак не отражается на классах-наследниках.

Они с легкостью могут объявлять методы с такой же сигнатурой и любыми модификаторами. Но это плохой тон!

Также класс наследник может расширить видимость protected-метода.

Сузить видимость класс-наследник не может.  

5. Аннотация @Override

Используйте аннотацию @Override при переопределении метода. Если метод переопределен неверно, код не скомпилируется.



0 comments
Leave your comment: