Java: вызов super.getClass () из подкласса - PullRequest
0 голосов
/ 06 сентября 2018

Я знаю, что этот вопрос уже задавался здесь , но я не понимаю части "Почему".

Давайте возьмем следующий пример:

public class First {
    First() {
       System.out.println(super.getClass());
    }
}

public class Second extends First {
    Second() {
       System.out.println(super.getClass());
    }
}

public class Third extends Second {
    Third() {
       System.out.println(super.getClass());
    }
}  

Когда я создаю экземпляр объекта типа Third:

public class Main {
    public static void main(String[] args) {
        Third third = new Third();
    }
}

Вывод:

class Third
class Third
class Third  

И я ожидал, что (думая, что super.getClass () должен вернуть имя родительского класса):

class java.lang.Object
class First
class Second

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

РЕДАКТИРОВАТЬ

Мое истинное намерение состояло в том, чтобы понять, как на самом деле работает наследование (что очень хорошо объяснил Джефф), вместо получения ожидаемого результата.
Это сомнение возникло, когда я пытался понять, почему работает следующий код (более конкретно, почему super.equals (point3d) работал, поскольку ему был передан объект типа Point3D)

public class Main {
    public static void main(String[] args) {
        Point3D p1 = new Point3D(1, 2, 3);
        Point3D p2 = new Point3D(1, 2, 3);
        System.out.println(p1.equals(p2));  // Output: true
    }
}

public class Point {
    private int x;
    private int y;

    public Point() {
        this.x = 0;
        this.y = 0;
    }

    public Point(int x, int y) {
        this.x = x;
        this.y = y;
    }

    @Override
    public boolean equals(Object object) {
        if (object != null && object.getClass() == this.getClass()) {
            Point point = (Point) object;
            return point.x == this.x && point.y == this.y;
        } else {
            return false;
        }
    }
}

public class Point3D extends Point {
    private int z;

    public Point3D() {
        this.z = 0;
    }

    public Point3D(int x, int y, int z) {
        super(x, y);
        this.z = z;
    }

    @Override
    public boolean equals(Object object) {
        if (object != null && object.getClass() == this.getClass()) {
            Point3D point3D = (Point3D) object;
            return super.equals(point3D) && point3D.z == this.z;  // Had doubt here
        } else {
            return false;
        }
    }
}

Ответы [ 2 ]

0 голосов
/ 06 сентября 2018

Важно признать, что здесь точно один объект с одной ссылкой . Может быть заманчиво представить его так, как будто суперкласс является отдельным экземпляром Second, находящимся в вашем экземпляре Third, но это не так; нет способа сослаться на этот экземпляр, потому что он не существует.

Для ясности: Дело не в том, что в Третьем есть скрытый экземпляр Second, на который ссылается super, а во Втором есть First, а в First есть Объект. Вместо этого есть один объект, который может вести себя как Объект, Первый, Второй или Третий. Независимо от типа локальной переменной или ссылки («статический тип»), сам экземпляр имеет «тип времени выполнения», который является третьим.

Единственное, что super может сделать для вас, это преднамеренно вызвать члена, который принадлежит суперклассу (JLS 15.11.2) , который может быть скрыт переопределением или именованием. Здесь это ничего не делает, потому что getClass() - это метод final, объявленный в Object. getClass имеет документацию о том, что он «возвращает класс времени выполнения этого объекта» ( docs ). Не может быть различной реализации, поэтому вы всегда получите тип Third, как и в своем вопросе.


ОБНОВЛЕНИЕ: В отличие от getClass, equals не является final и может быть переопределено. Point.equals гарантирует, что класс, возвращаемый getClass, равен и x и y равны. Вместо того, чтобы писать совершенно другую реализацию equals, Point3D использует определение Point для equals и дополнительно проверяет, что поле z равно, что работает, потому что Point проверяет, что object.getClass() == this.getClass(), а не object.getClass() == Point.class. Он не мог сделать это просто, вызывая equals, потому что это использовало бы реализацию Point3D.equals; вместо этого он должен вызвать super.equals, чтобы увидеть, как Point будет вычислять equals.

Однако я надеюсь, что это пример в уроке, потому что полиморфизм утверждает, что Point3D является-Point и может делать все, что может делать Point (см. Принцип замены Лискова ). Для Point и Point3D это может ввести в заблуждение: вы можете написать метод double distanceBetween(Point a, Point b), который работает, как ожидается, с использованием 2D-точек, но дает неверный результат при использовании 3D-точек. В реальных условиях вам нужно быть осторожным в отношении того, что ваша иерархия классов и что они подразумевают.

0 голосов
/ 06 сентября 2018

getClass() - это метод для Object. Там нет отдельного для каждого из ваших подклассов. Если вы хотите пойти по такой цепочке, позвоните getSuperclass() по результату getClass().

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