Notice
Recent Posts
Recent Comments
Link
관리 메뉴

브래의 슬기로운 코딩 생활

JAVA 프로그래밍 7주차 정리 본문

2-1/JAVA 프로그래밍

JAVA 프로그래밍 7주차 정리

김브래 2023. 4. 17. 20:04

상속과 다형성


Inheritance(상속)

what

• 기존의 클래스가 가지고 있는 변수와 메소드를 기반으로 필요한 변수와 메소드를 추가하거나

기존 메소드를 수정하여 새로운 클래스를 정의하는 것
• 기존 메소드의 수정을 재정의(overriding)라고 함.

why or benefits

• 비슷한 유형의 코드를 재사용하여 생산성이 높고 클래스 구조가 간소해진다
• 코드를 복사하는 방식이 아니기 때문에 효율적이다
• 검증된 코드를 사용하기 때문에 안정성이 증대된다.
• 오류를 줄일 수 있다.
• 재정의, 중첩으로 유연성과 확장성이 증대된다.


상속 관계


접근 수정자(access modifier)

필드, 메소드에 대한 접근 권한을 제어함

private은 선언된 클래스나 그 클래스로부터 직접 생성된 객체만 접근 가능함


private 필드는 상속 시 오류가 발생함
- private ➔ public으로 변경해서 해결
- 재정의해서 해결
- 접근 메소드(setter, getter) 제공을 통한 해결


private으로 정의되지 않은 인스턴스 변수와 메소드는 하위 클래스에서 사용할 수 있음
- 생성자의 경우 private으로 정의되지 않았지만 하위 클래스에서 사용할 수 없음


super vs. this

공통점

- 객체 생성 후 사용할 수 있는 예약어

super

수퍼 클래스의 메소드나 데이터를 접근할 때 사용되는 예약어
- 상위 클래스의 메소드 접근 : super.MethodName([ArgumentList]);

this

- 클래스로부터 생성되는 객체 자신을 나타내는 예약어
- 예)
public Integer(int value) { // 생성자
    this.value = value; // 객체의 value 값을 배정
}


재정의와 중첩


시그니쳐(signature)

- 메소드 이름, 매개변수 개수, 매개변수 유형


재정의(overriding)

수퍼 클래스의 메소드와 시그니쳐가 같은 메소드를 만드는 것
- 서브 클래스로부터 생성된 객체는 재정의한 수퍼 클래스의 메소드를 접근할 수 없음

 

중첩(overloading)

메소드 이름은 같고 나머지 시그니쳐가 다른 메소드를 만드는 것
- 메소드 선언과 동일할 작업이고, 
- 시그니쳐가 다른 경우, 반환 유형이 달라져도 됨


재정의하는 메소드는 기존 메소드와 같거나 더 넓은 접근 범위를

나타내는 접근 수정자로 재정의 되어야 함
- private -> private, default, protected, public
- default -> default, protected, public
- protected -> protected, public
- public -> public

예외 처리시 같은 예외 형식이거나 같은 종류의 예외 형식이어야 함


Object 클래스

모든 클래스의 상위 클래스, 즉 모든 클래스는 Object 클래스로부터 파생된다.

toString() : 데이터형과 객체의 해시 정보를 출력
- <package>.<className>@<hashcodeUsingHex>


equals() : 객체 참조변수의 비트 패턴이 같은 지만을 판별


상속받는 클래스에서 재정의 해서 사용함

String의 equals() : 문자열의 내용이 같은 지를 비교하도록 재정의 하여 사용함



final

final 메소드는 재정의가 불가함
- 재정의를 시도하는 경우 오류가 발생함


final 클래스의 모든 메소드는 묵시적으로 final 메소드임
- public class FinalClass extends String {
  } 
  // Error : cannot inherit from final java.lang.String


static

- 클래스가 사용되는 시점에서 메모리에 적재되어 메소드 사용이 가능함.

객체마다 존재하지 않고, 클래스 단위로 존재함


- static 메소드 내부에서는 non-static 메소드와 필드를 참조할 수 없음
- static 메소드 내부에서는 this, super 예약어를 사용할 수 없음


상속과 생성자


상속 관계가 있는 두 클래스에서 서브 클래스로부터 객체를 생성할 경우

실행 순서

- 클래스 변수, 클래스 메소드 적재
- 수퍼 클래스의 인스턴스 변수 초기화 실행
- 수퍼 클래스의 생성자 실행
- 서브 클래스의 인스턴스 변수 초기화 실행
- 서브 클래스의 생성자 실행

 

호출된 생성자의 첫 줄에는 상위 클래스가 있는 경우 상위 클래스의 디폴트 생성자 호출이 생략되어 있는 것으로 처리함


수퍼, 서브 클래스 모두 생성자가 없는 경우

- 컴파일러가 디폴트 생성자를 수퍼 클래스와 서브 클래스에 삽입

생성자가 있는 경우

- 디폴트 생성자는 삽입되지 않기 때문에 명시적으로 디폴트 생성자를 삽입해야 함.
- super([ArgumentList]);를 삽입해서 다른 생성자를 호출해야 함

상위 클래스 생성자 호출

- super([ArgumentList]);

클래스 내 다른 생성자 호출

- this([ArgumentList]);


생성자 관련 상속 관계

- 생성자가 정의된 경우 하위 클래스 생성자는 상위 클래스의 디폴트 생성자를 자동으로 호출함
- 생성자가 정의되지 않은 경우 하위 생성자 첫 줄에 호출하려는 상위 생성자와 

같은 인자정보를 가진 super(매개변수);를 삽입해야 함

 

- 상위 클래스, 하위 클래스 모두 생성자를 정의하지 않은 경우 오류 발생하지 않음
- 상위 클래스에 생성자가 존재하는 경우, 하위 클래스에서는 명시적으로 호출해야 함


다형성(polymorphism)


정의

객체의 종류에 따라 동일한 메시지(대상 객체 이름, 메소드, 매개변수)가 다른 연산을 수행하도록 하는 것

 

예) 
- 에어컨.동작한다() / 온풍기.동작한다()
- 요금을 낸다(성인객체) / 요금을 낸다(청소년객체)

 

다형성이 있는 메시지는 컴파일 시가 아니라, 실행 시에 구체적으로 호출되는 연산을 결정됨

 

장점

코드의 중복을 줄여주고, 프로그램 변경을 최소화하면서 프로그램 확장 및 유지보수가 가능하도록 함


클래스(객체참조형) 형변환

업캐스팅 (묵시적인 형변환 가능)

- 메소드 감추기 또는 기능 감추기(invisible)
- 서브 클래스 형 객체를 수퍼 클래스 형으로 변환
  - 서브 클래스의 멤버 변수와 메소드 중 수퍼 클래스에 구현된 부분만 사용이
    가능하도록 제한함
  - Object obj = new StringBuffer("UpCasting");
    • obj는 다운캐스팅이 되기전까지 Object 클래스에 구현된 부문만 사용이 가능하다. 
    • obj.length()를 호출하는 경우 오류가 발생함

 

다운캐스팅 (명시적인 형변환이 필수적으로 필요함)

- 업캐스팅된 상위 클래스 형의 객체를 상속관계가 있는 하위 클래스 형으로 변환
    ▪ String str = (String) obj;
    ▪ obj가 참조하는 객체는 본래 StringBuffer 클래스를 업캐스팅한 객체라면 String 클래스로 형변환을 할 수 없다.


- 참고 : instanceof 연산자를 이용하여 참조하는 객체의 유형 확인
    ▪ if(obj instanceof StringBuffer) : ture를 반환함
    ▪ if(obj instanceof String) : false를 반환함


추상클래스와 인터페이스 (Abstract Class & Interface)


추상 클래스(abstract class)

What

서브 클래스를 정의하는 기준을 제시하기 위해 하나 이상의 추상 메소드를 갖는 클래스
- 추상 메소드 : 구현 코드가 없이 선언만으로 구성된 메소드


Why or Benefits

- 높은 유연성과 확장성을 제공하기 위한 방법
- 일관성 있는 설계가 가능함

 

추상 클래스 선언

Syntax

[public] abstract class <className> {
                        <fieldDeclarations>
                        <methodDeclarations>
                       [<abstractMothod>]

        }


- private, final 예약어는 사용할 수 없음


특징

추상 메소드가 존재하기 때문에 인스턴스를 생성할 수 없음

 

단일 상속만을 가능함
- 하나의 추상 클래스만을 상속받을 수 있음. 즉 extends 예약어 뒤에는 하나의 추상 클래스만 가능함

 

추상 메소드를 구현할 때 접근 수정자는 항상 일치해야 함


상속을 통해 서브 클래스를 정의하는 경우 모든 추상 메소드가 구현되어야 함


상속을 통해 서브 추상 클래스를 정의하는 경우
- 상속받은 추상 메소드를 구현하거나 새로운 추상 메소드를 삽입할 수 있음
- 추상 메소드가 존재하여도 됨


자바 인터프리터가 실행시간에 해당 메소드를 적절하게 선택하여 동작 시킴(동적 바인딩)
- 재정의된 메소드를 호출하는 경우 객체 참조 변수가 참조하는 객체의 유형을 고려해서 메소드가 호출
    ▪ 컴파일 시에는 참조 변수의 유형을 고려함


인터페이스(interface)

What

- 모든 메소드는 추상 메소드이고, public static final 속성을 갖는 인스턴스 변수들로 구성된 프로그램 구성 요소
- 상수와 추상 메소드들로 구성된 설계의 표현


Why or Benefit

기능의 외부적 명시화에 유용
- 클래스의 정의를 알지 못해도, 구현된 객체의 사용법을 명료하게 알 수 있음


아주 높은 유연성을 제공함
- 서로 관련성이 떨어지는 클래스를 특별한 상속 관계 없이 연결하여 사용할 수 있음

 

하나 이상의 클래스를 통해서 구현해야 하는 메소드 선언 시 사용


인터페이스 선언

Syntax

[public] interface InterfaceName
                                  [extends ListOfSuperInterface] {
                       <constantDefinitions>
                      [<abstractMothod>]

}


수퍼 인터페이스 : 상속해주는 인터페이스
    ▪ 수퍼 인터페이스는 복수개가 나타날 수 있음
    ▪ interface MultiInheritInterface
                      extends SuperInterface1, SuperInterface2

 

서브 인터페이스 : 상속을 받는 인터페이스


특징

다중 상속이 가능함

 

모든 메소드는 묵시적으로 public

- static일 수 없음

 

모든 인스턴스 변수는 묵시적으로 public static final 속성을 가짐
- 초기화가 필요함

 

생성자는 없음 : 객체 생성이 아닌 설계가 목적임

 

private, protected, synchronized, volatile 사용 할 수 없음


인터페이스와 상속

- 메소드 상속 시 Signature가 같은 메소드는 반환유형도 같아야 함, 다른 경우 오류 발생
- 메소드 상속 시 Signature가 다른 경우 중첩
- 인터페이스 이름과 함께 인스턴스 변수를 기술하기 때문에 모호성이 발생하지 않음


다중 상속의 문제점

모호성(ambiguity) : 참조하는 필드나 메소드의 출처가 혼동되는 문제

- 예) 시그니쳐가 같은 메소드를 갖는 두 수퍼 클래스들을 다중상속한 경우 서브 클래스로부터 생성한 객체가

메소드를 호출하면 어느 수퍼 클래스의 메소드인지 혼동된다.

 

자바에서는 인터페이스 다중 상속을 지원하므로, 객체를 생성하기

위해서는 구현을 해야 하기 때문에 출처를 명확하게 알 수 있다. 


인터페이스 구현

• Syntax
[<classModifiers>] class <ClassName>
                                  implements <InterfaceName1>, …
{
                   // instance variable declarations
                   // methods declarations
        }


다이아몬드 상속

수퍼 클래스로부터 상속을 받고, 인터페이스로 부터 구현하는 상속 관계

 

• 예)
interface SuperInterface1 { }
interface SuperInterface2 { }
interface ExtendedInterface extends SuperInterface1 {}
abstract class SuperClass implements SuperInterface1{}
class DiamondInheritance extends SuperClass
implements ExtendedInterface


다이아모든 상속과 다중 구현

class DiamondMultiple extends SuperClass
  implements SuperIterface2, ExtendedInterface

 

비교


중첩 클래스(nested class) 

what

- 다른 클래스 내부나 블록 내부에 선언된 클래스
- inner class, static nested class, local class, anonymous class

 

why or benefits

- 클래스 참조 범위를 제한하여 이름 충돌(name conflicts) 문제를 해결할 수 있음
- 연관된 클래스들을 논리적으로 하나의 클래스에 모을 수 있기 때문에 가독성과 유지보수성이 향상됨
- 내부 클래스의 구현의 외부 노출을 방지함으로써 캡슐화가 더 향상됨

 

syntax

- class OuterClass {
           // outer class body
           class InnerClass {
                // inner class body
           }
           static class StaticNestedClass {
                // static nested class body
     }
}


지역 클래스(local class)

블록({ ~ }) 내부 또는 메소드 바디에 선언된 클래스


특징
- 유효 범위, 즉 참조 가능한 범위가 메소드 바디 또는 블록 내부로 한정됨
- 컴파일이 생성되면 LocalClassTest.class와
  LocalClassTest$1LocalClass.class 가 생성됨


익명 클래스(anonymous class)

선언과 동시에 인스턴스화를 수행하는 클래스

 

클래스 이름이 없는 클래스, 컴파일을 수행하면 <className>$1.class , 
<className>$2.class 등의 파일이 생성됨

 

syntax
<ClassName> <referenceVariable> = new <ClassConstructor>() {
                       //class body
}

 

why or benefits
코드 간소화됨