Java

[Final] Abstract Classes

ssungni 2024. 5. 7. 11:21

Abstract Classes

  • Classes are more general as we move up the in heritance hierarchy
    // 클래스는 상속 계층 구조를 통해 위로 올라갈수록 더 일반적임
  • Inheritance is useful to definecommonattributes/behaviour
    // 상속은 공통 속성이나 동작을 정의하는 데 유용
  • ex) Animal Class
    추상 클래스는 일반적인 동작이나 속성을 정의하고, 이 클래스를 상속받아 구체적인 클래스를 만들 때 사용됨.
    추상 클래스는 abstract 키워드를 사용하여 정의되며, 추상 메서드(abstract method)를 포함할 수 있음.
    여기서 makeSound() 메서드는 추상 메서드로 선언되었기 때문에, 이 클래스를 상속받는 실제 동물 클래스에서는 makeSound() 메서드를 반드시 구현해야 함.
    // 추상 클래스 Animal
    abstract class Animal {
        private String name;
        private int age;
    
        // 생성자
        public Animal(String name, int age) {
            this.name = name;
            this.age = age;
        }
    
        // 추상 메서드 - 각 동물마다 구현해야 할 메서드
        public abstract void makeSound();
    
        // 일반 메서드
        public void eat() {
            System.out.println(name + "이(가) 먹이를 먹습니다.");
        }
    
        // 일반 메서드
        public void sleep() {
            System.out.println(name + "이(가) 잠을 잡니다.");
        }
    }

    이제 실제 동물 클래스를 상속받아 구현해보면 
    // 실제 동물 클래스 - Cat
    class Cat extends Animal {
        public Cat(String name, int age) {
            super(name, age);
        }
    
        // 추상 메서드 구현
        @Override
        public void makeSound() {
            System.out.println("야옹");
        }
    }
    
    // 실제 동물 클래스 - Dog
    class Dog extends Animal {
        public Dog(String name, int age) {
            super(name, age);
        }
    
        // 추상 메서드 구현
        @Override
        public void makeSound() {
            System.out.println("멍멍");
        }
    }

    Cat 클래스와 Dog 클래스는 Animal 추상 클래스를 상속받아 구현된 실제 동물 클래스임.
    각각의 동물 클래스는
    makeSound() 메서드를 재정의(override)하여 각 동물의 소리를 표현하는 것을 볼 수 있음

Motivation (계기)

  • A common method can't bedefinedinthesuper class
    // super class에서 common method를 정의할 수 없는 경우
  • abstract 키워드를 사용하여 abstract classes와 methods 선언
  • ex) Person super class, Employee and Stdent sub classes
    // 추상 클래스 Person
    public abstract class Person {
        private String name;
        private int age;
    
        // 생성자
        public Person(String name, int age) {
            this.name = name;
            this.age = age;
        }
    
        // 추상 메서드 - 구현이 없는 메서드
        public abstract void introduce();
    }​
    // Employee 클래스 - Person을 상속받음
    public class Employee extends Person {
        private String employeeId;
    
        // 생성자
        public Employee(String name, int age, String employeeId) {
            super(name, age);
            this.employeeId = employeeId;
        }
    
        // 추상 메서드 구현
        @Override
        public void introduce() {
            System.out.println("저는 직원입니다.");
        }
    }
    
    // Student 클래스 - Person을 상속받음
    public class Student extends Person {
        private String studentId;
    
        // 생성자
        public Student(String name, int age, String studentId) {
            super(name, age);
            this.studentId = studentId;
        }
    
        // 추상 메서드 구현
        @Override
        public void introduce() {
            System.out.println("저는 학생입니다.");
        }
    }​
  • Instance를 생성할 수는 없음.
    public class Main {
        public static void main(String[] args) {
            // Person person = new Person("John", 30); // 추상 클래스이므로 인스턴스 생성 불가능
    
            Person employee = new Employee("Jane", 25, "E123"); // Employee 클래스의 인스턴스 생성
            employee.introduce(); // "저는 직원입니다." 출력
    
            Person student = new Student("Mike", 20, "S456"); // Student 클래스의 인스턴스 생성
            student.introduce(); // "저는 학생입니다." 출력
        }
    }
     위의 Main 클래스에서는 Person 추상 클래스의 인스턴스를 직접 생성할 수 없음. 대신 EmployeeStudent 클래스의 인스턴스를 생성하여 Person 타입의 참조 변수로 참조할 수 있음.

Abstract Methods

  • abstract classes를 사용하여
    • 클래스는 추상 및 구체적인 메서드를 모두 포함할 수 있음
  • 구체적인 하위 클래스에서 반드시 재정의되어야 함. 그렇지 않으면 하위 클래스도 추상 클래스여야 함
    public class Dog extends Animal ...
    
    public abstract class Cat extends Animal {
        public Cat(String name) {
            super(name);
        }
        // Cat 클래스는 추상 메서드를 재정의하지 않으므로 추상 클래스가 됨
    }
  • Abstract classes and Polymorphism
    • Polymorphism(다형성)
      • 같은 코드를 사용하여 다양한 객체를 다룰 수 있는 기능을 말함.
      • 상속과 관련하여 부모 클래스 타입의 참조 변수가 자식 클래스의 객체를 참조할 수 있는 성질을 의미함.
      • 메서드 오버라이딩(재정의)을 통해 다형성을 구현할 수 있음
    • ex)
      public class Dog extends Animal
          public void makeSound() {
              System.out.println(getName() + "이(가) 멍멍 짖습니다.");
      
      public class Cat extends Animal
          public void makeSound() {
              System.out.println(getName() + "이(가) 야옹 웁니다.");
      
      public class Main {
          public static void main(String[] args) {
              Animal dog = new Dog("멍멍이");
              Animal cat = new Cat("야옹이");
      
              animalMakesSound(dog);
              animalMakesSound(cat);
          }
      
          // 다형성을 이용한 동물 소리 출력 메서드
          public static void animalMakesSound(Animal animal) {
              animal.makeSound();
          }
      }

Object Class

  • 모든 Java 클래스의 부모 클래스
  • 다른 클래스들은 암시적으로 이 클래스를 상속받음
  • 일부 메서드
    • equals(): 객체의 동등성을 비교하는 메서드
      더보기
      public class Person {
          private String name;
          private int age;
      
          public Person(String name, int age) {
              this.name = name;
              this.age = age;
          }
      
          // equals() 메서드 재정의
          @Override
          public boolean equals(Object obj) {
              if (this == obj) {
                  return true; // 같은 객체인 경우 true 반환
              }
              if (obj == null || getClass() != obj.getClass()) {
                  return false; // null이거나 클래스가 다른 경우 false 반환
              }
              Person other = (Person) obj; // obj를 Person으로 형변환
              return age == other.age && name.equals(other.name); // 필드 값 비교
          }
      
          public static void main(String[] args) {
              Person person1 = new Person("John", 30);
              Person person2 = new Person("John", 30);
      
              System.out.println(person1.equals(person2)); // true 출력 (내용 비교)
          }
      }
    • hashCode(): 객체의 해시 코드를 반환하는 메서드
      더보기
      public class Person {
          private String name;
          private int age;
      
          public Person(String name, int age) {
              this.name = name;
              this.age = age;
          }
      
          @Override
          public int hashCode() {
              return Objects.hash(name, age); // 필드 값들을 이용하여 해시 코드 생성
          }
      
          public static void main(String[] args) {
              Person person = new Person("Alice", 25);
              System.out.println(person.hashCode()); // 객체의 해시 코드 출력
          }
      }
    • toString(): 객체를 문자열로 표현하는 메서드
      더보기
      public class Person {
          private String name;
          private int age;
      
          public Person(String name, int age) {
              this.name = name;
              this.age = age;
          }
      
          @Override
          public String toString() {
              return "Person{" +
                      "name='" + name + '\'' +
                      ", age=" + age +
                      '}';
          }
      
          public static void main(String[] args) {
              Person person = new Person("Bob", 35);
              System.out.println(person.toString()); // 객체의 문자열 표현 출력
          }
      }

Downcasting

  • 부모 클래스에서 실제 자식 클래스 타입으로의 형변환
  • Example
  • Using "instanceof"