Search
Duplicate

자바를 자바 10 (inheritance, class object, 상속, 객체)

간단소개
팔만코딩경 컨트리뷰터
ContributorNotionAccount
주제 / 분류
Java
Scrap
태그
9 more properties

Inheritance(계속)

Creating a subclass

constructor 문제 -> 객체를 생성하면 constructor이 호출됨 마치 C++에서의 initializer과 동일함
만약 constructor가 없다면 default constructor가 호출됨, 이건 superclass의 constructor을 호출하게 됨
class Employee{ private String name; private int salary; public Employee(){ name="NoName"; salary=50000; } public String getname() {return this.name;} public int getSalary() {return this.salary;} } class Manager extends Employee{ private int bonus; public void setBonus(int bonus) {this.bonus=bonus;} public int getSalary() {return super.getSalary() +this.bonus;} }
Java
복사
만약 subclass에서 constructor을 호출하였다면 superclass의 constructor가 호출된다음 subclass의 constructor가 실행된다. 따라서 정리하자면 superclass constructor은 무조건 호출되게 되어 있음.
class Employee { private String name; private int salary; public Employee() { this.name = "NoName"; this.salary = 50000; } public void setName(String name) { this.name = name; } public String getName() { return this.name; } public int getSalary() { return this.salary; } } class Manager extends Employee { private int bonus; public Manager() { super.setName("NoName(Manager)"); bonus = 10000; } public void setBonus(int bonus) { this.bonus = bonus; } public int getSalary() { return super.getSalary() + this.bonus; } }
Java
복사
만약 superclass의 constructor가 매개변수를 받으면 어떻게 될까? 만약 subclass에서 superclass의 constructor을 호출하지 않으면 에러가 뜨게 된다. 왜냐하면 매개변수가 없는 constructor을 subclass에서 호출하려고 하기 때문이다. 그렇기 때문에 아래 코드와 같이 반드시 super(name, salary)를 호출하여야 한다.
class Employee { private String name; private int salary; public Employee(String name, int salary) { this.name = name; this.salary = salary; } public String getName() { return this.name; } public int getSalary() { return this.salary; } } class Manager extends Employee { private int bonus; public Manager(String name, int salary) { //필수적으로 superclass의 constructor을 호출하여 주어야 한다. super(name, salary); bonus = 10000; } public void setBonus(int bonus) { this.bonus = bonus; } public int getSalary() { return super.getSalary() + this.bonus; } }
Java
복사

Detour : Implicit Constructor(혹은 Default Constructor)

constructor을 포함하고 있지 않은 클래스라면 Implicit constructor라고 부른다. Implicit constructor은 매개변수가 없고 오직 superclass constructor을 호출하는 역활을 한다.
만약 constructor가 포함되었다면 explicit constructor라고 부르며 더 이상 Implicit constructor는 호출되지 않는다.
class Employee { private String name; private int salary; }
Java
복사
class Employee { private String name; private int salary; public Employee(String name, int salary) { this.name = name; this.salary = salary; } }
Java
복사
그렇기에 explicit constructor가 존재하는 클래스에 매개변수 값을 넘기지 않으면 에러가 생긴다.

Dynamic method lookup

Employee <- Manager 인 상태에서 다음과 같은 코드가 있다고 하자
Manager boss = new Manager(); Employee empl = boss; int salary = empl.getSalary(); // call getSalary which is defined in both Employee and Manager.
Java
복사
1.
superclass와 subclass 모두 같은 이름의 함수를 가질때 위와 같이 superclass 변수가 subclass 객체를 가지고 있을 때 getSalary() 함수가 오버라이딩 되어 있다면 어떻게 될 것인가? 이때 JVM에서는 Dynamic method lookup이라는 기능으로 인하여 객체를 따라가게 된다. 바로 이부분이 C++과 JAVA가 차이나는 부분 중 하나이다. C++은 부모 클래스에 virtual이 선언된 것이 아닌 이상은 무조건 변수를 따라가게 되어 있지만 JVM은 자동으로 객체를 따라가게끔 되어 있다.
2.
superclass에만 해당 함수를 가질때 물론 만약 subclass에 해당 method가 정의되어 있지 않다면 당연하게도 superclass의 method가 호출된다.
3.
subclass에만 해당 함수를 가질때 이경우에는 반대로 에러가 난다. 왜냐하면 변수는 super class 변수이기 때문에 우선적으로 변수를 따라가는데 superclass에 아예 존재하지 않는 함수이기 때문이다. 어떻게 보면 C++과 동일한 부분이라고 볼 수 있다.
Employee empl = new Manager("Donald", 100000); empl.setBonus(20000);
Java
복사
위와 같은 경우를 생각해 볼 수 있다.
Employee empl = new Manager("Donald", 100000); if(empl instanceof Manager) { Manager mgr = (Manager) empl; mgr.setBonus(20000); } System.out.println(empl.getSalary());
Java
복사
이러한 문제를 해결하기 위해 우리는 instanceof 키워드를 사용하여서
객체 instancof 클래스 객체가 클래스 타입으로 형변환 가능한지를 true, false로 알려주는 키워드이다. 그렇기 때문에 위와 같이 Manager 객체를 가지고 있는 Employee 변수는 Manager로 형변환이 가능하다. 반대로 다음의 사례를 보자 위와 같이 부모객체를 가진 부모 변수는 자식 변수로 바꿀 수 없다.

Final method

Final method는 함수 오버라이딩이 불가능하게 선언하는 방법이다.
class Employee { private String name; private int salary; public Employee(String name, int salary) { this.name = name; this.salary = salary; } public final String getName() { return this.name; } // subclass cannot override this method. public int getSalary() { return this.salary; } } class Manager extends Employee { private int bonus; public Manager(String name, int salary) { super(name, salary); bonus = 10000; } public void setBonus(int bonus) { this.bonus = bonus; } public String getName() { return "Sir " + super.getName(); } // Error: overriding a final method }
Java
복사

Fincal class

extends를 막는 방법이다.
final class Employee { private String name; private int salary; public Employee(String name, int salary) { this.name = name; this.salary = salary; } public String getName() { return this.name; } public int getSalary() { return this.salary; } } class Manager extends Employee { ... // Error: cannot inherit a final class }
Java
복사
대표적으로 String class는 Final class 이다.

Abstract method and abstract class

abstract class Person { private String name; public Person(String name) { this.name = name; } public final String getName() { return name; } public abstract int getId(); }
Java
복사
위와 같이 abstract method를 하나라도 가지고 있는 클래스는 반드시 abstract 선언해야만 한다.
이렇게 만들어진 abstract class를 받는 subclass는 반드시 getID()와 같은 abstract method를 그냥 method로 재정의하거나 혹은 subclass도 abstract 이어야 한다.
그런데 보면은 abstract class는 interface와 유사하여 보인다. 어떠한 차이점이 있을까? 바로 instance variable과 constructor을 가지고 있다는 차이점이 있다.

Abstract class

1.
Abstract class는 객체를 생성할 수 없다.
2.
Abstract class를 받았다면 반드시 abstract method를 재정의 하여야 한다.

Protected access

class Employee { private String name; protected int salary; public Employee(String name, int salary) { this.name = name; this.salary = salary; } public String getName() { return this.name; } public int getSalary() { return this.salary; } } class Manager extends Employee { private int bonus; public Manager(String name, int salary) { super(name, salary); bonus = 10000; } public void setBonus(int bonus) { this.bonus = bonus; } public int getSalary() { return salary + bonus; } // can access superclass protected variable }
Java
복사
protected는 다음 경우에 접근이 불가능하다.
1.
subclass가 아니면 접근 불가
2.
다른 패키지인 경우 접근 불가
반대로 subclass이면 protected 변수와 함수는 접근이 가능하다.

Superclass and Interface

interface는 다중 상속이 가능하지만 Superclass는 다중 상속이 불가능하다. 이는 C++과의 또 다른 차이점이다.
class Student extends Person, Animal { // Error: cannot extend multiple classes. ... }
Java
복사
interface와 superclass를 함께 받는 것은 가능하다.
interface Named { default String getName() { return "NoName"; } } abstract class Person { private String name; public Person(String name) { this.name = name; } public String getName() { return name; } public abstract int getId(); } class Student extends Person implements Named { private int id; public Student(String name, int id) { super(name); this.id = id; } public int getId() { return id; } }
Java
복사
만약 위와 같을때
Student s = new Student("Fred", 1729); System.out.println(s.getName());
Java
복사
다음과 같이 superclass와 interface 모두 가지고 있는 함수를 호출한다면 superclass가 우선권이 있다.

class Object : superclass of all classes

모든 클래스들은 Object라는 클래스를 상속 받고 있다.
class Student { ... } class Student extends Object { ... }
Java
복사
위의 두 클래스는 같은 클래스를 상속받은 상황인 것이다.
이때 Object 클래스는 위와 같은 기능을 포함하고 있다. 물론 이것만 있는 것은 아니다.

class Object: method toString

class Employee { private String name; protected int salary; public Employee(String name, int salary) { this.name = name; this.salary = salary; } public String getName() { return this.name; } public int getSalary() { return this.salary; } }
Java
복사
위와 같이 클래스가 있을때
Employee empl = new Employee("John", 50000); System.out.println(empl.getName() + " " + empl.getSalary()); System.out.println(empl.toString());
Java
복사
위와 같이 선언하면 객체의 정보를 String 값으로 반환해 준다.
Employee empl = new Employee("John", 50000); System.out.println(empl.getName() + " " + empl.getSalary()); System.out.println(empl); // this will print empl.toString()
Java
복사
하지만 구지 사용하지 않아도 toString()을 바로 출력할 수 있다.
또한 함수 자체를 오버라이딩하는 것도 가능하다.
class Manager extends Employee { private int bonus; public Manager(String name, int salary) { super(name, salary); bonus = 10000; } public String toString() { return super.toString() + "[bonus=" + bonus + "]"; } public void setBonus(int bonus) { this.bonus = bonus; } public int getSalary() { return salary + bonus; } }
Java
복사
위와 같이 superclass 함수를 호출하여서 사용할 수도 있다.