-
[자바기초] 객체지향 프로그래밍 특징(상속성) 정리노트º Language º/Java 2023. 3. 23. 00:05
* 값에 의한 호출(Call by Value) / 참조에 의한 호출(Call by reference)
- 메소드 호출에는 값에 의한 호출과 참조에 의한 호출이 있습니다.
- 값에 의한 호출 : 메소드 호출시에 "기본자료형"이 전달되는 경우를 말하며 메소드 안에서 변경되어 전달한 값이 메소드 호출쪽에서는 지속적으로 적용이 되지 않아요.class CallByValueTest { public static void add(int n){ n = n + 1; System.out.println(n); //return 생략 } public static void main(String[] args) { int data; data = 20; System.out.println(data); //20 add(data); //21 System.out.println(data); //20 }
> 값에 의한 호출(Call by Value) 은 int , double..등의 8가지 기본 자료형의 값이 있는 메소드를 호출하는 것을 의미합니다.스택 메모리 저장 공간에만 여러 개 메모리로 따로 저장이 되기 때문에 메소드를 호출하여 main에 불러오더라도 이후 출력문에 값에 영향을 주지 않게 됩니다.메소드를 복사해서 사용하는 개념이기 때문에 불러오는 호출문에만 적용 되고 이후의 출력문에는 영향을 주지 않게 되는 것입니다.- 참조에 의한 호출 : 메소드 호출시에 배열이나 객체변수가 전달되는 경우를 참조에 의한 호출이라 하며 메소드 호출시에 전달한 데이터 값이 메소드에 의해 변경될 때에 호출한 쪽에서도 변경이 내용이 지속적으로 적용 됩니다.
class Person{ String name; int age; public Person(String name, int age){ this.name = name; this.age = age; } } class CallByReferenceObject{ public static void add( Person p ){ // 클래스를 매개변수로 받음. p.age = p.age + 1 ; } public static void main(String[] args) { Person kim = new Person("김유신", 20); add(kim); //21 System.out.println(kim.age); //김유신,21 } }
> 객체나 배열은 힙데이터에 저장이 되고 클래스를 매개변수로 받아 같은 힙메모리의 저장공간을 사용하기에 이후에 호출 값에도 영향을 주어 변경된 값이 고정됩니다.
* 클래스의 상속
- 현실세계의 부모의 상속과 같은 상속의 개념이 있듯이 클래스의 세상에도 상속이 있습니다.
이미 있는 클래스를 확장하여 새로운 클래스를 만들 수 있는데 이것을 "상속"이라고 합니다.
class A{ --- } class B extends A{ <-- A클래스를 확장하여 B를 만들겠다. }
> 기본적으로 사용되는 상속문입니다. A 부모 클래스를 B 자식클래스가 상속 받는 모습입니다.
상속을 받을 때에는 extends 를 사용합니다.
- 이렇게 함으로 해서 B는 자동으로 A의 모든 것을 물려받게 됩니다. A클래스의 코드라인의 수가 수백줄이라고 할 때에 자동으로 B가 이것을 물려받게 됩니다. 새로 추가되는 내용에 대해서만 B안에 써 주면 됩니다.
* 상속의 장점
1. "코드의 재사용"을 높일 수 있다.
2. 개발속도를 향상시킨다.
3. 비용을 절감할 수 있다.
* 객체 지향 프로그래밍의 특징- 객체 지향 프로그래밍의 특징 중 은닉성에 대해 먼저 알아보았었습니다.
은닉성(Encapsulation)이란 : private 를 사용하여 외부의 다른 클래스로 부터 맴버변수들을 보호하는 것입니다.
이번에는 상속성에 대해 알아보도록 하겠습니다.* 상속성 (Inheritance)
- 상속성이란 이미 있는 클래스를 확장하여 코드를 재사용 하는 것을 말합니다.
class A{ --- } class B extends A{ <-- A클래스를 확장하여 B를 만들겠다. }
> A를 부모 클래스라고 하고, B를 자식 클래스라고 합니다.자식클래스는 부모의 모든 속성과 동작을 자동으로 물려받게 됩니다. 그러나 부모의 private영역에는 아무리 자식클래스라 하더라도 접근할 수 없어요!
그렇기 때문에 외부의 클래스로 부터 보호는 하고 싶고, 자식 클래스에서만 맴버변수를 사용하게끔 하기 위해 protected 를 사용합니다.
* protected
- 외부의 다른 클래스로 부터는 보호하되 상속한 자식클래스들 에게는 접근을 허용하기 위하여 protected를 사용합니다.- 따라서, 클래스를 만들 때에 상속을 염두해 두고 있다면 속성(맴버변수)들을 procted에 둡니다.자바가 제공하는 대부분의 클래스들도 그렇게 만들어져 있습니다.* 상속과 생성자- 생성자는 객체 생성시에 자동수행하여 맴버변수들의 값을 초기화 할 목적으로 사용합니다.또, 사용자가 생성자를 만들지 않아도 기본생성자가 제공됩니다.
그런데 만약 사용자가 생성자를 하나라도 만들기 시작하면 기본생성자를 제공하지 않습니다.
필요하다면 만들어야 해요!
class A{ public A(){ //부모생성자 } } class B extends A{ public B(){ //자식생성자 } }
> 상속관계에 있을때에 부모클래스와 자식클래스에 생성자를 하나도만들지 않으면 각각 기본생성자가 제공되어 부모의 생성자가 먼저 수행되고 자식의 생성자가 동작합니다.- 그런데 만약!알고 있듯이 사용자가 생성자를 하나라도 만들기 시작하면 기본생성자를 제공하지 않습니다.
만약 부모클래스에 매개변수를 갖는 생성자를 만들고 기본생성자를 따로 만들지 않았다고 합시다.
그리고 자식클래스에서는 생성자를 하나도 만들지 않았어요.
class A{ protected String name; public A(String name){ this.name = name; } } class B extends A{ } B ob = new B(); // B클래스 객체는 기본 생성자가 없어서 오류발생
> 이때, 자식클래스의 객체를 생성하면 자동으로 (묵시적으로) 부모의 기본생성자를 요구하기 때문에 오류가 발생합니다!
만약, 부모의 매개변수를 갖는 생성자를 동작시키고자 한다면 super()를 이용합니다.
class A{ protected String name; public A(String name){ this.name = name; } } class B extends A{ public B(String name){ super(name); // super을 이용 } } B ob = new B(); // 객체 생성 가능
> super()는 생성자의 첫번째 문장에 와야합니다.
* 메소드 오버라이딩 (method overriding)
상속관계에 있을때에 자식클래스는 부모클래스의 모든 속성(맴버변수)과 동작(맴버메소드)을 물려 받게 됩니다.
즉, 자식클래스 안에서 부모의 메소드를 자유롭게 내 것 처럼 사용할 수 있어요!
- 그런데 만약 부모의 어떠한 메소드가 자식클래스에게는 맞지 않거나 마음에 들지 않을 때 다시 재정의 하는 것을 "메소드 오버라이딩"이라고 합니다.
- 메소드 오버라이딩을 위해서 메소드 이름뿐 아니라 매개변수의 개수와 자료형이 일치되게 재정의 하여야 합니다.
(* 메소드 오버로딩과의 차이점 : 메소드 오버로딩은 메소드 중복이며 같은 클래스 안에서 메소드를 여러개 만들 고 싶을 때 사용됩니다. 자료형이 서로 다르거나 매개변수의 개수가 다른 경우 여러개의 중복 메소드를 사용 할 수 있습니다.)
class Person{ String name; String addr; public Person(String name, String addr){ this.name = name; this.addr = addr; } public void info(){ //부모 클래스의 메소드 System.out.println(name+","+addr); } } class Customer extends Person{ int no; public Customer(String name, String addr, int no){ super(name, addr); this.no = no; } public void info(){ //자식 클래스의 메소드 System.out.println(no+","+name+","+addr); } } class MethodOverridingTest02 { public static void main(String[] args) { Customer c = new Customer("홍길동","서울", 100); c.info(); } }
> 메소드 이름뿐 아니라 매개변수의 개수와 자료형이 똑같은 모습으로 재정의 된 것을 확인할 수 있습니다.
하지만 자식 클래스에서는 기존 클래스를 확장하여 맴버 변수 하나를 추가하였기에 메소드의 변화를 주고 싶습니다.
그러므로 맴버 변수의 값을 추가하여 오버라이딩 해줍니다.
* 추상 클래스와 추상 메소드
- 미래에 만들어질 클래스들의 공통적인 속성들과 동작들을 뽑아서 부모클래스를 만들 수 있어요. 이것을 "일반화"라고 합니다.- 이때에 미래의 자식클래스들이 반드시 가져야 할 메소드가 있다고 합시다. 이것을 일반화 하는 시점에서는 그 메소드의 body를 구체화 할 수 없을때에 메소드의 선언문만 써요. 이러한 메소드를 "추상메소드"라고 합니다.
- "추상메소드"임을 나타내기 위하여 메소드이름 왼쪽에 abstract 키워드를 써 줍니다.
abstract class Employee{ //추상클래스 //부모클래스 protected String name; // 추상클래스인 Employee는 객체를 가질 수 없음. protected String no; protected int salary; public abstract void computeSalary(); //추상메소드 } class SalariedEmployee extends Employee{ //자식클래스 private int level; private int base; private int sudang; public void computeSalary(){ //추상메소드를 구체화 하는 메소드 switch(level){ case 1:base=2000000;sudang=200000;break; case 2:base=3500000;sudang=350000;break; case 3:base=5000000;sudang=500000;break; } salary = base + sudang; } } class HourlyEmployee extends Employee{ //자식클래스 private int base; private int hours; public void computeSalary(){ //추상메소드를 구체화 하는 메소드 salary = base * hours; }
> 추상 메소드를 사용하면 자식클래스에서는 이를 구체화 해주는 메소드를 꼭 작성해야 합니다.
그렇지 않으면 오류가 납니다.
*** 추상클래스의 객체는 생성할 수 없어요!!! 어떻게 동작해야 하는지 메소드의 body가 구체화 되지 않은 추상메소드를 갖고 있기 때문에 그 클래스의 객체는 생성할 수 없어요!!
그러나 배열을 사용하면 가능합니다.
class EmployeeTest05 { public static void main(String[] args) { String name,no; int type; int level, base, hours; Scanner sc = new Scanner(System.in); Employee []e = new Employee[3]; for(int i=0; i<e.length; i++){ System.out.print("사원이름==>"); name = sc.next(); System.out.print("사원번호==>"); no = sc.next(); System.out.print("급여의 종류 입력==>[1.월급, 2:시간]"); type = sc.nextInt(); switch(type){ case 1: System.out.print("호봉==>"); level = sc.nextInt(); e[i] = new SalariedEmployee(name,no,level); break; case 2: System.out.print("시간당 임금==>"); base= sc.nextInt(); System.out.print("작업시간==>"); hours= sc.nextInt(); e[i] = new HourlyEmployee(name,no,base,hours); break; } } //급여를 계산하고 출력 for(int i=0; i<e.length; i++){ e[i].computeSalary(); System.out.println(e[i].toString()); } /*public String toString(){ return "이름:"+name+",사원번호:"+no+",실수령액:"+salary; } public String toString(){ return super.toString()+",호봉:"+level+",기본금:"+base+",수당:"+sudang; } public String toString(){ return super.toString()+",시간당급여:"+base+",작업시간:"+hours; } */
Employee []e = new Employee[3]; e[i] = new SalariedEmployee(name,no,level); e[i] = new HourlyEmployee(name,no,base,hours);
> 배열을 사용하여 3명의 사용자의 값을 반복문을 통하여 각각의 자식클래스의 생성문으로 만들 수 있습니다.이때, 등장하는 개념이 is a 관계입니다.* is a 관계- 상속관계에 있는 것을 is a 관계라고 하고 부모의 참조변수가 자식클래스의 객체를 참조할 수 있어요!
Employee e1; e1 = new SalariedEmployee(); e1 = new HourlyEmployee();
> 부모클래스의 참조 변수가 자식 클래스의 객체를 참조하는 모습입니다.반대로 사용은 불가합니다.'º Language º > Java' 카테고리의 다른 글
[자바기초] String, StringBuffer, String Builder 정리노트 (0) 2023.03.29 [자바기초] 객체지향 프로그래밍 특징(다형성) 정리노트 (0) 2023.03.25 [자바기초] 객체지향 프로그래밍 정의 및 특징(은닉성) 정리노트 (0) 2023.03.20 [자바기초] 배열 정리노트 (0) 2023.03.17 [자바기초] 제어문(반복문) 정리노트 (0) 2023.03.15