Java의 정석 제 7 장 객체지향개념 II-2 Java 정석 2008. 8. 8 남궁성 강의 Chapter 7. 객체지향개념 II http://www.javachobo.com Java의 정석 제 7 장 객체지향개념 II-2 안녕하십니까? 자바의 정석의 저자 남궁성입니다. 지금부터 제7장 객체지향개념2의 두 번째 강의를 시작하겠습니다. 2008. 8. 8 남궁성 강의 castello@naver.com
객체지향개념 II-1 객체지향개념 II-2 객체지향개념 II-3 Java 1. 상속 2. 오버라이딩 의 정석 Chapter 7. 객체지향개념 II http://www.javachobo.com 1. 상속 객체지향개념 II-1 2. 오버라이딩 3. package와 import 4. 제어자 객체지향개념 II-2 5. 다형성 7장도 분량이 많기 때문에 이와 같이 3개의 부분으로 나누어서 강좌를 제작하였습니다. 이번엔 두번째 부분인 제어자와 다형성에 대해서 설명드리겠습니다. 특히 다형성은 아주 중요하니까 반복을 통해 완전히 이해하셔야 합니다. 6. 추상클래스 객체지향개념 II-3 7. 인터페이스
Java 4. 제어자(modifiers) 4.1 제어자란? 4.7 접근 제어자를 이용한 캡슐화 4.2 static 의 정석 Chapter 7. 객체지향개념 II http://www.javachobo.com 4. 제어자(modifiers) 4.1 제어자란? 4.7 접근 제어자를 이용한 캡슐화 4.2 static 4.8 생성자의 접근 제어자 4.3 final 4.9 제어자의 조합 4.4 생성자를 이용한 final 멤버변수 초기화 4.5 abstract 4.6 접근 제어자 5. 다형성(polymorphism) 5.1 다형성이란? 세부목차인데요. 이 강의는 이와 같은 순서로 진행될 것입니다. 5.2 참조변수의 형변환 5.3 instanceof연산자 5.4 참조변수와 인스턴스변수의 연결 5.5 매개변수의 다형성 5.6 여러 종류의 객체를 하나의 배열로 다루기
4. 제어자(modifiers) Java 정석 의 Chapter 7. 객체지향개념 II http://www.javachobo.com 4. 제어자(modifiers)
Java 4.1 제어자(modifier)란? 정석 - 클래스, 변수, 메서드의 선언부에 사용되어 부가적인 의미를 부여한다. Chapter 7. 객체지향개념 II http://www.javachobo.com 4.1 제어자(modifier)란? - 클래스, 변수, 메서드의 선언부에 사용되어 부가적인 의미를 부여한다. - 제어자는 크게 접근 제어자와 그 외의 제어자로 나뉜다. - 하나의 대상에 여러 개의 제어자를 조합해서 사용할 수 있으나, 접근제어자는 단 하나만 사용할 수 있다. 제어자는... 클래스나 변수, 메서드의 선언부에 사용되어 부가적인 의미를 부여하는 것을 말합니다. 명사 앞에 붙어서.. 명사를 수식하는 형용사하고 비슷하다고 볼 수 있습니다. modifier라는 이름 역시 변경하다라는 뜻의 동사 modify에서 나온 것으로... 어떤 대상의 성격을 바꿔주는 것이라고 이해하시면 됩니다. 제어자는 접근제어자와... 그 외의 제어자로 ... 크게 두 가지 부류로 나눌 수 있습니다. 접근제어자에는 public, protected, default, private 모두 4개가 있는데요. 이 중에서 default를 실제로 사용하지 않습니다. 이에 대해서는 나중에 다시 설명하겠습니다. 접근제어자를 제외한 나머지 제어자는 ... 이러한 것들이 있는데요. static, final. abstract가 중요하고요... 나머지는 자주 사용되지 않습니다. 참고로 간단히 설명하면... native는 자바가 아닌 다른 언어로 작성된 메서드를 자바에서 호출하기 위해 사용하는 것이고요. transient는 14장에서 배울 직렬화에서 자세히 다룹니다. synchronized와 volatile은 쓰레드의 동기화와 관련된 것이고요. strictfp는 float나 double과 같은 부동소수점, 즉 fp(floating-point)의 정확성을 보장하기 위한 것인데... strictfp를 사용하면, 어떤 JVM이나 어떤 하드웨어에서도... 동일한 부동소수점 계산결과를 얻을 수 있습니다. 하나의 대상에 여러 개의 제어자를 조합해서 사용할 수도 있습니다. 다만... 접근제어자는 한번에 하나만 사용할 수 있습니다. 예를 들면... 접근제어자 public과 protected를 동시에 사용할 수 는 없다는 것입니다. 앞으로 제어자를 하나하나 배워나갈 것인데요... 그 때마다... 제어자를 사용할 수 있는 대상과... 대상에 따라 제어자가 어떤 의미를 갖게 되는지 잘 눈여겨 보시기 바랍니다. 5 5
Java 4.2 static – 클래스의, 공통적인 정석 의 Chapter 7. 객체지향개념 II http://www.javachobo.com 4.2 static – 클래스의, 공통적인 static은 클래스의, 공통적인...이라는 의미의 제어자입니다. 이미 앞서 배웠기 때문에 잘 알고 계실테니... 간단히 정리하고 넘어가겠습니다. static이 사용될 수 있는 곳은... 멤버변수와 메서드... 그리고 초기화 블럭입니다. 멤버변수 앞에 static이 붙으면... 클래스변수가 되고... 모든 인스턴스가 공유하게 됩니다. 그리고 static이 붙은 변수나 메서드는 모두 클래스가 메모리에 로드될 때 자동적으로 생성되므로 인스턴스 생성없이 사용가능합니다. static메서드에서는 인스턴스 멤버를 사용할 수 없다는 점 다시한번 확인해 두시기 바랍니다. 6 6
Java 4.3 final – 마지막의, 변경될 수 없는 정석 의 Chapter 7. 객체지향개념 II http://www.javachobo.com 4.3 final – 마지막의, 변경될 수 없는 final은 마지막의, 변경될 수 없는...이라는 의미의 제어자입니다. final을 사용할 수 있는 곳은.... 클래스, 메서드, 멤버변수, 지역변수... 거의 모든 대상에 사용할 수 있는데요. 각 대상에 따라 final이 붙었을 때 어떤 의미가 되는 지 잘이해하셔야합니다. 변수 앞에 final이 붙으면 값을 변경할 수 없는 상수가 된다는 것은 이미 배웠고요. 클래스 앞에 final이 붙으면... 확장될 수 없는 클래스가 되어서 다른 클래스의 조상이 될 수 없습니다. 즉, 상속계층도의 마지막이라는 의미죠. 메서드 앞에 final이 붙으면... 변경될 수 없는 메서드... 즉, 오버라이딩을 할 수 없는 메서드가 됩니다. 그래서 이와 같이... FinalTest클래스의 getMaxSize메서드에 제어자 final이 붙어 있으면... 자손클래스에서 이 메서드를 재정의 할 수 없습니다. 7 7
Java 4.4 생성자를 이용한 final 멤버변수 초기화 정석 의 정석 Chapter 7. 객체지향개념 II http://www.javachobo.com 4.4 생성자를 이용한 final 멤버변수 초기화 - final이 붙은 변수는 상수이므로 보통은 선언과 초기화를 동시에 하지만, 인스턴스변수의 경우 생성자에서 초기화 할 수 있다. final이 붙은 변수는 보통... 선언과 동시에 초기화를 해주지만... 인스턴스변수의 경우에는 생성자에서 초기화 해주는 것이 가능합니다. 예를 들어 아래와 같이 Card클래스를 정의할 때... 카드의 속성인 NUMBER와 KIND는 한번 값이 지정되면 바뀌지 않아야 하는 값입니다. 카드의 숫자와 무늬가 게임도중에 마음대로 바뀌어서는 안되겠죠. 그래서 제어자 final을 붙였습니다. 그런데... 만일 final이 붙은 변수는 반드시 선언과 동시에 초기화를 해야한다면... 모든 Card인스턴스는 같은 NUMBER와 KIND값을 갖게 되겠죠... 이러한 문제를 해결하기 위해서... 멤버변수의 경우, final이 붙었어도... 선언과 동시에 초기화 하지않고... 생성자에서 단 한번만 초기화 할 수 있도록 허용했습니다. Card인스턴스를 생성한 다음에는... 이와같이... 다른 값을 저장하려고 하면... 에러가 발생합니다. 8 8
Java 4.5 abstract – 추상의, 미완성의 정석 의 Chapter 7. 객체지향개념 II http://www.javachobo.com 4.5 abstract – 추상의, 미완성의 abstract는 추상의, 미완성의...라는 의미의 제어자입니다. abstract가 사용될 수 있는 곳은 클래스와 메서드이고요... 메서드 앞에 abstract가 붙으면 추상메서드가 되고, 클래스 앞에 abstract가 붙으면 추상클래스가 됩니다. 추상메서드는... 선언부만 있고 구현부가 없는 미완성 메서드입니다. 추상메서드가 정의된 클래스 역시 미완성 클래스이기 때문에... 클래스 앞에 abstract를 붙여서 이 클래스가 추상메서드를 포함하고 있고... 미완성 클래스이기 때문에 인스턴스를 생성할 수 없다라는 것을 알려줘야합니다. 추상클래스는 상속을 통해서 자손클래스에서 완성되어야만 인스턴스를 생성할 수 있습니다. 추상메서드와 추상클래스에 대해서는 다음 강의에서 자세히 다룰 것이니까... 간단히 이 정도만 설명하고 넘어가겠습니다. 9 9
4.6 접근 제어자(access modifier) Java 의 정석 Chapter 7. 객체지향개념 II http://www.javachobo.com 4.6 접근 제어자(access modifier) - 멤버 또는 클래스에 사용되어, 외부로부터의 접근을 제한한다. 접근 제어자는 멤버 또는 클래스에 대한 접근범위를 제한하는 역할을 합니다. 비밀번호와 같은 중요한 데이터가 아무런 제약없이 쉽게 접근되어서는 안되겠죠... 접근제어자는 private, default, protected, public 모두 4개가 있고요. 클래스, 멤버변수, 메서드... 생성자에 사용될 수 있습니다. 각 접근제어자마다 접근할 수 있는 범위가 다른데요... private이 붙은 멤버는 같은 클래스 이외에서는 접근할 수 없습니다. 가장 제한이 높은 접근 제어자이고요. default는 같은 패키지 내의 클래스에서만 접근할 수 있습니다. protected는 자손클래스에서만 접근이 가능합니다. 그리고 같은 패키지 내의 클래스에서도 접근이 가능합니다. public은 접근 제한이 전혀 없습니다. 접근 범위가 제일 넓은 것 부터 순서대로 나열하면... public, protected, default, private이 되겠습니다. 별로 외우기 어렵지 않습니다, private은 같은 클래스, default는 같은 패키지, protected는 같은 패키지 플러스 자손클래스, public은 전혀 제한 없음. 쉽죠? ^^; 클래스에는 public과 default만 사용할 수 있고요. 멤버변수와 메서드에는 접근제어자 4개를 모두 사용할 수 있습니다. 접근제어자 default를 실제로 사용하지는 않습니다. 어떤 접근제어자도 사용하지 않으면 그게 바로 default접근제어자가 사용된 것입니다. 그래서 여기에 괄호를 쳐놓은 것이고요... 10 10
Java 4.7 접근 제어자를 이용한 캡슐화 정석 의 Chapter 7. 객체지향개념 II http://www.javachobo.com 4.7 접근 제어자를 이용한 캡슐화 접근제어자를 사용하는 주된 이유는... 외부로 부터 데이터를 보호하기 위해서입니다. 그리고, 외부에는 불필요한 내부적으로만 사용되는 부분을 감춰서 복잡성을 줄이기 위한 것입니다. 그래서 Java API문서를 보면... 접근제어자가 public이나 protected인 것들만 나와 있는 것을 알 수 있습니다. 여기 Time클래스를 보면.... 멤버변수들은 모두 접근제어자를 private으로 해서 클래스 외부에서 접근하지 못하도록 하고... 접근제어자가 public인 한 쌍의 메서드를 통해서만 읽거나 변경할 수 있도록 되어 있습니다. getHour메서드는 멤버변수 hour의 값을 반환하고... setHour메서드는 넘겨받은 값을 체크해서 유효한 값일 경우에만 hour의 값을 변경하도록 코드가 작성되어 있습니다. 이처럼... 멤버변수의 값을 읽어오는 메서드는 멤버변수 이름앞에 get을 붙이고... 변경하는 메서드는 set을 붙이는 것이 일반적이기는 하지만 꼭 지켜야 하는 규칙은 아닙니다. Time인스턴스 t를 생성하고... 화면에 출력하면...12:35:30라는 시간이 출력됩니다. 참조변수를 출력하면... 참조변수가 가리키는 인스턴스의 toString()메서드를 호출하기 때문에... 참조변수 t를 출력하는 것은... 참조변수 t가 가리키는 인스턴스의 toString메서드를 호출하는 것과 같습니다. 그래서... Time클래스의 toString메서드가 호출되어... 시분초가 화면에 출력된 것입니다. 이처럼 참조변수를 이용해서 멤버변수에 직접 접근하려고 하면... 에러가 발생합니다. 이와 같이... 메서드를 이용해서... 멤버변수에 접근해야합니다. t.getHour메서드를 통해 인스턴스 t의 멤버변수 hour의 값 12를 얻어서 1을 더한 값을 setHour메서드에 넘겨주면... 멤버변수 hour의 값이 13이 됩니다. 인스턴스 t를 화면에 다시 출력하면... 멤버변수 hour의 값이 12에서 1증가된 13이 되어 있는 것을 알 수 있습니다. 객체지향개념 책들을 보다보면... 이와 같은 그림을 볼 수 있는데요. 이게 바로 객체입니다. 안에 있는 원들이... 멤버변수고요... 멤버변수들을 둘러싸고 있는 것이 메서드입니다. 접근제어자를 이용해서 멤버변수들은 private으로 해서 내부에 감추고... 메서드들은 public으로 해서 외부에 노출시킴으로써... 같은 클래스에 정의된 멤버들끼리는 서로 자유롭게 접근하고... 외부에서는 메서드를 통해서만 멤버변수에 접근할 수 있는 구조로 만드는 것입니다. 외부에서는... 객체의 노출된 public 메서드만을 호출할 수만 있을 뿐... 실제 내부가 어떻게 되어 있는지 알 수 없습니다. 이 것이 바로 캡슐화죠. private은 가장 높은 접근제한이기 때문에... 상속을 통해 확장될 목적으로 작성되는 클래스에서는 멤버변수의 접근제어자를 private대신 protected를 사용해야 자손클래스에서 조상클래스의 멤버를 쉽게 접근할 수 있습니다. 11 11
Java 4.8 생성자의 접근 제어자 정석 - 일반적으로 생성자의 접근 제어자는 클래스의 접근 제어자와 일치한다. Chapter 7. 객체지향개념 II http://www.javachobo.com 4.8 생성자의 접근 제어자 - 일반적으로 생성자의 접근 제어자는 클래스의 접근 제어자와 일치한다. - 생성자에 접근 제어자를 사용함으로써 인스턴스의 생성을 제한할 수 있다. getInstance()에서 사용될 수 있도록 인스턴스가 미리 생성되어야 하므로 static이어야 한다. 생성자에도... 접근제어자를 사용할 수 있습니다. 일반적으로 생성자는 클래스와 같은 접근제어자를 사용하지만... 생성자에 접근제어자를 사용해서 인스턴스의 생성을 제한할 수 있습니다. 연산자 new를 통해서 인스턴스를 생성하려면... 생성자를 호출해야하는데... 생성자의 접근제어자를 private으로 하면... 연산자 new를 통해서 인스턴스를 생성할 수 없습니다. 대신... 이처럼... 내부적으로 객체를 생성해서 접근제어자를 private으로 해서 감추고 public 메서드를 호출해서 생성된 객체에 접근할 수 있도록 해야 합니다. getInstance메서드가 하는 일은 생성된 객체의 참조를 반환하는 것 뿐입니다. 만일을 대비해서...참조가 null인 경우에는 새로운 객체를 생성하도록 했고요. 외부에서 객체를 생성할 수 없기 때문에... 객체생성없이 호출할 수 있도록 static메서드이어야 하고요. static메서드에서 참조할 수 있어야하기 때문에... 객체에 대한 참조도 static이어야 합니다. 그리고... 이처럼 생성자의 접근제어자가 private인 경우에는... 다른 클래스의 조상이 될 수 없습니다. 전에 배운 것과 같이... 자손클래스의 인스턴스를 생성하면... 조상의 생성자를 호출하는데... 조상의 생성자가 private이라서... 호출할 수 없기 때문입니다. 그래서... 클래스 앞에 final을 붙여줘서... 상속을 통해 확장할 수 없는 클래스라는 것을 알려주는 것이 좋습니다. Singleton클래스는 생성자의 접근제어자가 private이라서... 이처럼 new연산자를 사용해서 인스턴스를 생성할 수 없고... 아래의 코드와 같이... 메서드를 통해서 이미 생성되어 있는 인스턴스의 참조를 얻어와야 합니다. 12 12
Java 4.9 제어자의 조합 정석 1. 메서드에 static과 abstract를 함께 사용할 수 없다. Chapter 7. 객체지향개념 II http://www.javachobo.com 4.9 제어자의 조합 1. 메서드에 static과 abstract를 함께 사용할 수 없다. - static메서드는 몸통(구현부)이 있는 메서드에만 사용할 수 있기 때문이다. 2. 클래스에 abstract와 final을 동시에 사용할 수 없다. - 클래스에 사용되는 final은 클래스를 확장할 수 없다는 의미이고, abstract는 상속을 통해서 완성되어야 한다는 의미이므로 서로 모순되기 때문이다. 지금 까지 배운 제어자를.... 사용대상을 중심으로 정리해봤습니다. 어떤 대상에 어떤 제어자를 사용할 수 있는지 다시한번 확인해 보시고요... 제어자를 조합해서 사용할 때, 몇가지 생각해봐야할 것들을 적어보았는데요... 별로 중요한 내용은 아닙니다... 그동안 학습한 제어자를 다시한번 정리하는 의미에서 같이 가볍게 읽어보고 제어자에 대한 강의를 마무리할 까 합니다. 3. abstract메서드의 접근제어자가 private일 수 없다. - abstract메서드는 자손클래스에서 구현해주어야 하는데 접근 제어자가 private이면, 자손클래스에서 접근할 수 없기 때문이다. 4. 메서드에 private과 final을 같이 사용할 필요는 없다. - 접근 제어자가 private인 메서드는 오버라이딩될 수 없기 때문이다. 이 둘 중 하나만 사용해도 의미가 충분하다. 13 13
5. 다형성(polymorphism) Java 정석 의 Chapter 7. 객체지향개념 II 14 http://www.javachobo.com 5. 다형성(polymorphism) 14
5.1 다형성(polymorphism)이란?(1/3) Java 의 정석 Chapter 7. 객체지향개념 II http://www.javachobo.com 5.1 다형성(polymorphism)이란?(1/3) -“여러 가지 형태를 가질 수 있는 능력” -“하나의 참조변수로 여러 타입의 객체를 참조할 수 있는 것” 즉, 조상타입의 참조변수로 자손타입의 객체를 다룰 수 있는 것이 다형성. 다형성이란... 여러가지 형태를 가질 수 있는 능력...입니다. 무슨 얘긴지 잘 감이 안오시죠... ^^; 이건 어디까지나... 순수하게 객체지향이론적인 다형성의 정의고요... 프로그래밍에서의 다형성은... 하나의 참조변수로 여러타입의 객체를 참조할 수 있는 것을 말합니다. 즉, 조상타입의 참조변수로 자손타입의 객체를 다룰 수 있는 것이 다형성입니다. 누가 다형성이 뭐냐?고 물어보면... 조상타입의 참조변수로 자손타입의 객체를 다룰 수 있는 것’이라고 바로 대답이 나올 수 있으셔야 합니다. 이와 같이... Tv클래스와 Tv클래스를 조상으로 하는 CaptionTv클래스가 정의되어 있을 때... 각 클래스의 인스턴스를 생성할 때... 이렇게 하죠? Tv인스턴스는 Tv타입의 참조변수로... CaptonTv인스턴스는 CaptionTv타입의 참조변수로... 그런데... 이렇게... CaptionTv인스턴스를 Tv타입의 참조변수로 다루는 것도 가능합니다. 이 것이 바로 다형성인 것이죠... 그러면... CaptionTv인스턴스를... CaptionTv타입의 참조변수로 다루는 것과 Tv타입의 참조변수로 다루는 것의 차이는 뭘까요? 다음 페이지에서 설명하겠습니다. ^^; 15 15
5.1 다형성(polymorphism)이란?(2/3) Java 의 정석 Chapter 7. 객체지향개념 II http://www.javachobo.com 5.1 다형성(polymorphism)이란?(2/3) “하나의 참조변수로 여러 타입의 객체를 참조할 수 있는 것” 즉, 조상타입의 참조변수로 자손타입의 객체를 다룰 수 있는 것이 다형성. + - | power caption 앞에서 CaptionTv인스턴스를 CaptionTv타입의 참조변수 외에도 조상인 Tv클래스 타입의 참조변수로도 다룰 수 있다고 했는데요. 이 둘의 차이는 사용할 수 있는 멤버의 개수입니다. CaptinoTv타입의 참조변수로는 CaptionTv인스턴스의 모든 멤버를 사용할 수 있지만... Tv타입의 참조변수로는 CaptionTv인스턴스의 모든 멤버를 사용할 수 없습니다. 단지, Tv클래스에 정의된 멤버만 사용할 수 있습니다. 실제 인스턴스가 CaptionTv인스턴스임에도 불구 하고... Tv타입의 참조변수로는... Tv클래스에 정의된 5개의 멤버만 사용할 수 있다는 것입니다. CaptionTv에 정의된 멤버변수 text와 caption메서드는 Tv타입의 참조변수로는 사용할 수 없습니다. 전에 참조변수를 리모콘에 비유해서 얘기했는데요... 실제로 참조변수는 리모콘과 유사한 점이 많습니다. 예를 들어서... Tv를 하나 샀습니다. 그런데 금새 고장나서... 새로나온 Caption기능이 있는 새로운 Tv를 샀습니다. 전에 샀던 Tv와 같은 회사 제품이라서... 옛날에 쓰던 Tv리모콘도 새로산 Tv에 쓸 수 있습니다. 그런데... 옛날 리모콘으로는 새로운 기능인 Caption기능을 사용할 수 없겠죠. 아무리 Tv가 Caption기능을 가지고 있어도요... 옛날 리모콘에는 캡션기능 관련된 버튼이 아예 없잖아요... 그래서 Tv타입의 참조변수로는 Tv클래스에 정의된 멤버들만 사용할 수 있는 겁니다. 참조변수의 타입에 따라... 사용할 수 있는 멤버의 개수가 달라진다는 것 이해하셨죠? 그러면 왜 이렇게 할까요? CaptionTv타입의 참조변수로 CaptionTv인스턴스를 사용하면 될텐데 굳이 Tv타입의 참조변수로 CaptionTv인스턴스를 다룰 까요... Tv타입의 참조변수로는 CaptionTv인스턴스의 일부밖에 사용못하는데 말이죠. 그 이유는 나중에 자세히 설명드릴 것이고요. 지금은 참조변수의 타입에 따라 사용할 수 있는 멤버의 개수가 달라진다는 점만 확실히 이해하시면 됩니다. + - | power 16 16
5.1 다형성(polymorphism)이란?(3/3) Java 의 정석 Chapter 7. 객체지향개념 II http://www.javachobo.com 5.1 다형성(polymorphism)이란?(3/3) “조상타입의 참조변수로 자손타입의 인스턴스를 참조할 수 있지만, 반대로 자손타입의 참조변수로 조상타입의 인스턴스를 참조할 수는 없다.” + - | power 이처럼... 자손타입의 인스턴스를 조상타입의 참조변수로 가리키는게 가능하다고 했죠... 그러면 반대로 조상타입의 인스턴스를 자손타입의 참조변수로 가리키는게 가능할까요? 결론부터 말씀드리면... 가능하지 않습니다. 사람들은 리모콘만가지고 Tv를 조작하기 때문에... 이처럼... CaptionTv를 가지고도... Tv리모콘을 사용하면... 아무런 불평없이 잘 사용합니다. caption가능이 있는지도 모르고요... 그러나.. CaptionTv리모콘을 가지고 Caption기능이 없는 Tv를 사용하면... 난리가 납니다. 분명히 리모콘에는 caption 기능 버튼이 있는데... 아무리 눌러도 작동을 안하거든요. Tv회사 서비스센터에 전화하고... 난리나죠... 결론은... 자손타입의 참조변수로는 조상타입의 인스턴스를 참조할 수 없다. 입니다. 리모콘에 정의된 기능이 실제 제품의 기능보다 많아서는 안되기 때문이죠... + - | power caption 17 17
Java 5.2 참조변수의 형변환 정석 - 서로 상속관계에 있는 타입간의 형변환만 가능하다. Chapter 7. 객체지향개념 II http://www.javachobo.com 5.2 참조변수의 형변환 - 서로 상속관계에 있는 타입간의 형변환만 가능하다. - 자손 타입에서 조상타입으로 형변환하는 경우, 형변환 생략가능 기본형 변수뿐만 아니라 참조형 변수도 형변환이 가능합니다. 다만 조상자손관계에 있을 때만 형변환이 가능하죠. 자손타입을 조상타입으로 형변환 하는 것을 업캐스팅이라고 하고요. 조상타입을 자손타입으로 형변환 하는 것을 다운캐스팅이라고 합니다. 상속계층도에서 봤을 때 조상으로 가면 올라가는 거니까 up이고 반대는 내려가는 거니까 down입니다. 형변환할 때는 클래스간의 상속계층도를 간단히 그려보면 쉽게 해결됩니다. 형변환 방법은 간단합니다. 기본형 변수의 형변환과 똑같이... 괄호 안에다 변환하고자 하는 타입을 적어주기만 하면 됩니다. 참조형변수의 형변환도... 경우에 따라서 형변환을 생략할 수 있는데요... 자손타입에서 조상타입으로 형변환 하는 경우에는 생략이 가능합니다. 자손타입에서 조상타입으로 형변환된다는 것은 리모콘의 버튼 개수가 줄어든다는 것을 의미하는데요. 리모콘의 버튼 개수가 많아지는 것은 문제가 되도, 적어지는 것은 문제가 되지 않기 때문에... 형변환을 생략할 수 있도록 한 것입니다. 참조변수의 형변환은... 단지 참조할 수 있는 멤버의 개수가 달라질 뿐 다른 변화는 아무것도 없습니다. 참조변수가 저장하고 있는 객체의 주소값이 바뀌는 것도 아니고... 인스턴스에 영향을 주지도 않습니다. 코드를 보면... Car클래스와 Car클래스를 조상으로 하는 FireEngine클래스와 Ambulance클래스가 정의되어 있는데요. 이 클래스들의 상속관계를 그려보면 이와 같습니다... FireEngine타입의 참조변수를 Car타입으로 형변환하려면... 괄호안에 Car를 적어주면 됩니다. 여기서는 자손타입에서 조상타입으로... 즉 리모콘의 버튼개수가 줄어드는 쪽으로 형변환을 하는 것이기 때문에... 형변환을 생략할 수 있습니다. 바로 아래에... 그 반대의 경우인... car타입의 참조변수를 자손인 FireEngine타입으로 변환하는 경우에는 형변환을 생략할 수 없습니다. FireEngine클래스와 Ambulance클래스는 둘다 Car를 조상으로 하고 있지만... 두 클래스 사이에는 어떠한 관계도 성립하지 않기 때문에... 형변환이 불가능합니다. 18 18
Java 5.2 참조변수의 형변환 - 예제설명 정석 의 Chapter 7. 객체지향개념 II http://www.javachobo.com 5.2 참조변수의 형변환 - 예제설명 Car타입의 참조변수 car를 선언하고요... 그러면 이렇게 참조변수 car가 만들어집니다. 그 다음에... FireEngine인스턴스를 생성하고 이 인스턴스를 참조변수 fe가 가리키게 합니다. 그러면 이런 그림이 되겠죠... 그리고 FireEngine타입의 참조변수 fe2를 선언했습니다. 그 다음에...참조변수 fe에 대해서 메서드 water()를 호출합니다. 그러면... FireEngine인스턴스의 water메서드가 호출되어... 화면에 water!!!라는 글자가 출력됩니다. 그 다음에... 참조변수 fe의 값을 참조변수 car에 저장합니다. 자손의 타입에서 조상의 타입으로의 형변환... 즉, 리모콘 버튼의 개수를 줄이는 형변환...이기 때문에 형변환을 생략할 수 있었습니다. 참조변수가 저장하고 있는 값은 인스턴서의 주소값이니까.. 참조변수 fe에 저장되어 있는 주소 100번지가 참조변수 car에 저장되겠죠. 그래서... 참조변수 car역시 FireEngine인스턴스를 가리기게 됩니다. 하지만... 참조변수 fe와는 달리 참조변수 car로는 water()를 호출할 수 없습니다. Car클래스에 정의된 멤버가 아니기 때문입니다. 그 다음에... 참조변수 car에 저장된 값을 참조변수 fe2에 저장합니다. 이 두 변수는 타입이 다르기 때문에... 형변환 연산자를 사용해줘야겠죠... 조상타입의 참조변수의 값을 자손타입의 참조변수에 저장하는 것이기 때문에... 형변환을 생략할 수 없습니다. 이제 참조변수 fe2에도 100번지가 저장되어서... 참조변수 fe2로도 FireEngine인스턴스를 다룰 수 있습니다. 참조변수 car와는 달리... 참조변수와 실제 인스턴스의 타입이 같기 때문에... 참조변수 fe2로는 인스턴스의 모든 멤버를 다룰 수 있습니다. 참조변수의 형변환은... 참조변수의 타입만을 변경할 뿐... 변수의 값이나 인스턴스에는 아무런 영향을 주지 않는다는 점... 확인하시기 바랍니다. 19 19
Java 5.3 instanceof연산자 정석 - 참조변수가 참조하는 인스턴스의 실제 타입을 체크하는데 사용. Chapter 7. 객체지향개념 II http://www.javachobo.com 5.3 instanceof연산자 - 참조변수가 참조하는 인스턴스의 실제 타입을 체크하는데 사용. - 이항연산자이며 피연산자는 참조형 변수와 타입. 연산결과는 true, false. - instanceof의 연산결과가 true이면, 해당 타입으로 형변환이 가능하다. instanceof연산자는 참조변수가 참조하고 있는 인스턴스의 타입을 체크하는데 사용됩니다. 다형성을 통해 조상타입의 참조변수로 자손타입의 인스턴스를 가리킬 수 있게 되었기 때문에... 참조변수의 타입과 참조변수가 가리키는 인스턴스의 타입이 항상 같지는 않습니다. 그래서... 참조변수가 가리키는 인스턴스의 타입이 어떤 것인지 확인하기 위해서 instanceof연산자를 사용하는 것입니다. 예제를 보시면... FireEngine인스턴스를 생성해서 참조변수 fe가 가리키도록 했습니다. 그리고... instanceof연산자를 이용해서... 참조변수 fe가 가리키는 인스턴스의 타입이 FireEngine타입인지 확인합니다. 인스턴스의 타입이 FireEngine이면 instanceof의 결과는 true가 되고, 그렇지 않으면 false가 됩니다. 여기서는 참조변수 fe가 가리키는 인스턴스의 타입이 FireEngine이 맞으므로 instanceof의 결과가 true가 되어 이 문장이 화면에 출력됩니다. 그 다음에도 Car타입인지, Object타입인지... 확인을 하는데요... 실행결과를 보면... 실제인스턴스가 FireEngine임에도 불구하고, Car타입과 Object타입에 대한 instanceof검사도 결과가 true라는 것을 알 수 있습니다. 참조변수를 어떤 타입에 instanceof연산을 했을 때 결과가 true라는 것은... 참조변수를 검사한 타입으로 형변환하는 것이 가능하다는 의미 입니다. 그래서... instanceof연산자가 실제인스턴스의 타입을 알려준다기 보다는... 형변환이 가능한지를 알려준다고 하는 것이 더 옳다고 생각합니다. 예들들어... 이와 같은 method가 있을 때... 매개변수의 타입이 Object지만... 이 참조변수가 가리키고 있는 인스턴스의 타입은 무엇인지 확신할 수 없습니다. 이럴 때는 반드시... instanceof로 체크를 한 후에 형변환을 해야 안전합니다. 20 20
Java 5.4 참조변수와 인스턴스변수의 연결 정석 Chapter 7. 객체지향개념 II http://www.javachobo.com 5.4 참조변수와 인스턴스변수의 연결 - 멤버변수가 중복정의된 경우, 참조변수의 타입에 따라 연결되는 멤버변수가 달라진다. (참조변수타입에 영향받음) - 메서드가 중복정의된 경우, 참조변수의 타입에 관계없이 항상 실제 인스턴스의 타입에 정의된 메서드가 호출된다.(참조변수타입에 영향받지 않음) 앞에서... 참조변수의 타입에 따라 사용할 수 있는 인스턴스의 멤버가 달라진다고 배웠습니다. 그 외에도 한가지 더 차이점이 있는데요. 멤버변수가 중복정의된 경우에는...참조변수의 타입에 따라 연결되는 멤버가 달라진다는 것입니다. 왼쪽과 같이 Parent클래스와 이를 조상으로 하는 Child클래스가 정의되어 있을 때... 멤버변수 x가 중복되어 있습니다. 메서드 역시... 오버라이딩되어 있고요. main메서드에서... Child인스턴스를 생성해서 Parent타입의 참조변수로 참조하게 하고, 또하나의 Child인스턴스를 생성해서 Child타입의 참조변수로 참조하게 합니다. 그리고 참조변수 p로 멤버변수 x를 출력하고 메서드를 호출합니다. 그 다음에는 참조변수 c로 멤버변수 x를 출력하고 메서드를 호출합니다. 이 코드가 실행되면 이와 같은 결과를 얻는데요. 참조변수 p로 읽어온 멤버변수x의 값과 참조변수 c로 읽어온 멤버변수 x의 값이 다르다는 것을 알 수 있습니다. 메서드의 경우 참조변수의 타입에 관계 없이 실제 인스턴스인 Child인스턴스의 메서드가 호출되었고요... 이런 결과가 나오는 이유는... Parent타입의 참조변수 p로 멤버변수 x를 접근하면... Parent클래스에 정의된 멤버변수 x와 연결되고... Child타입의 참조변수 c로 멤버변수 x를 접근하면... Child클래스에 정의된 멤버변수 x와 연결되기 때문입니다. 이를 통해서 알 수 있는 것은... 멤버변수가 중복된 경우에는 참조변수의 타입에 따라 연결되는 멤버변수가 달라진다는 것입니다. 메서드는 참조변수의 타입에 관계없이 항상 실제 인스턴스의 타입에 정의된 것이 호출되고요. 여기서는 Child인스턴스니까... Child클래스에 정의된 메서드가 호출되고요. 일반적으로는 이처럼 외부에서 멤버변수에 직접 접근하는 경우는 드물고... 메서드를 이용해서 접근하므로... 별문제는 안되기는 합니다. 만일 오른쪽 코드와 같이... 멤버변수나 메서드가 중복되어 정의되지 않은 경우에는 선택의 여지가 없기 때문에... 참조변수의 타입에 따라 결과가 달라지지 않습니다. 같은 이름의 멤버변수가 중복정의되어 있는 경우에만 참조변수의 타입에 따른 차이가 있다는 것 잘 기억해 두시기 바랍니다. 21 21
Java 5.5 매개변수의 다형성 정석 - 참조형 매개변수는 메서드 호출시, 자신과 같은 타입 또는 자손타입의 Chapter 7. 객체지향개념 II http://www.javachobo.com 5.5 매개변수의 다형성 - 참조형 매개변수는 메서드 호출시, 자신과 같은 타입 또는 자손타입의 인스턴스를 넘겨줄 수 있다. 제품가격과 보너스점수를 멤버로 정의한 Product클래스를 정의하고... 모든 제품은... Product클래스를 상속받도록 하였습니다. 그래서 Tv, Computer, Audio클래스는 Product클래스를 상속받았습니다. Buyer클래스는 물건을 사는 사람... 구매자를 클래스로 정의한 것이고요. 멤버변수로 가진돈과 보너스점수를 정의하였습니다. Buyer클래스에... 제품을 구입하는 기능의 buy메서드를 추가하려고 합니다. 그래서... Tv를 구입할 수 있는 buy메서드를 이와 같이 구현하였습니다. 매개변수로 Tv타입의 참조변수를 선언하고... Tv의 가격인 price의 금액을 buyer가 가진 돈인 money에서 빼고... Tv의 보너스점수를 buyer의 bonusPoint에 더해줍니다. 그런데... 이 buy메서드로는 Tv밖에 살 수 없습니다. 그래서 Computer를 사기 위해서는 Computer타입의 참조변수를 매개변수로 하는 메서드를 하나 더 정의해야합니다. 이런식이면... 새로운 제품이 추가될 때마다... buy메서드를 새로 만들어줘야 합니다. 그래서... buy메서드의 매개변수를 Tv타입이 아닌... 이들의 공통 조상인 Product타입으로 정의해야합니다. Product클래스는 모든 제품 클래스의 조상이라서... Tv인스턴스, Computer인스턴스, Audio인스턴스를 참조할 수 있기 때문이죠. 이렇게 하면... 새로운 제품클래스가 추가되어도... 새로운 buy메서드를 추가할 필요없이... Product타입의 참조변수를 매개변수로 하는 buy메서드 하나면 끝납니다. 이처럼... 매개변수의 타입을 공통조상타입으로 정의하면 여러종류의 자손인스턴스를 넘겨 받을 수 있는데요. 이것을 ... 매개변수의 다형성이라고 합니다. 자손인스턴스를 조상타입의 참조변수로 다루면... 이러한 장점이 있는 것입니다. 22 22
5.6 여러 종류의 객체를 하나의 배열로 다루기(1/3) Java 의 정석 Chapter 7. 객체지향개념 II http://www.javachobo.com 5.6 여러 종류의 객체를 하나의 배열로 다루기(1/3) - 조상타입의 배열에 자손들의 객체를 담을 수 있다. 앞서 정의된 바와 같이... Tv, Computer, Audio클래스는 Product클래스의 자손이므로... 이와 같이 조상타입의 참조변수로 자손인스턴스를 참조할 수 있습니다. 이 문장들을 배열로 변경하면... 이와 같습니다. 먼저... 3개의 객체를 담을 수 있는 객체배열을 생성하고... 배열의 각 요소에 객체를 생성해서 저장합니다. 사실 이 배열은 실제 객체를 저장하는 것이 아니라... 참조변수를 저장하기 위한 것이고요. 배열의 각 요소에는 인스턴스의 주소값이 저장되겠죠. 이처럼... 조상타입의 객체배열을 이용하면... 여러 종류의 자손인스턴스를 하나의 배열에 담아서 다룰 수 있습니다. 그래서... 이전의 Buyer클래스를 발전 시켜서... 구입한 제품을 담을 수 있는 Product배열을 새로 추가했습니다. 배열은 생성할 때 크기를 정해주어야하기 때문에 일단 크기를 10으로 하였습니다. 그리고 buy메서드도 변경해서... 물건을 사고나면... Product배열에 저장하도록 하였습니다. 23 23
5.6 여러 종류의 객체를 하나의 배열로 다루기(2/3) Java 의 정석 Chapter 7. 객체지향개념 II http://www.javachobo.com 5.6 여러 종류의 객체를 하나의 배열로 다루기(2/3) ▶ java.util.Vector – 모든 종류의 객체들을 저장할 수 있는 클래스 좀전에는 크기가 10인 Product배열을 사용했는데요... 저장할 객체의 수가 10이 넘으면... 배열은 한번 만들면 크기변경이 안되니까... 새로운 배열을 생성하고 복사하고... 해야할 일이 많습니다. 그렇다고 해서... 너무 큰 배열을 생성하면 메모리 낭비가 되니까 안되겠죠. 그래서... 이럴 때는 Product배열 대신에 java.util패키지의 Vector클래스를 사용하면 됩니다. Vector클래스는 이와 같이... 내부적으로 Object타입의 객체배열을 가지고 있어서... 어떠한 종류의 객체도 담을 수 있습니다. Object가 모든 클래스의 조상이고 조상의 타입으로 자손인스턴스를 참조할 수 있으니까요... 게다가 이 Object배열을 자동적으로 관리해주기 때문에... 배열을 직접관리해줄 필요없이... 객체를 Vector에 저장하고 읽어오는 메서드만 사용하기만 하면 됩니다. Vector클래스의 주요 메서드를 몇 개 골라봤습니다. Vector클래스의 기본 생성자 인데요... 이 생성자를 이용하면 기본적으로 10개의 객체를 저장할 수 있는 인스턴스가 생성되고요. Vector에 10개 이상의 객체를 저장하면 자동적으로 크기가 증가됩니다. add메서드는 Vector에 객체를 저장하는 메서드인데요... 매개변수가 Object타입의 참조변수라서... 어떤 객체도 매개변수로 쓸 수 있습니다. 리턴값은 boolean으로.. 저장에 성공하면 true, 실패하면 false를 리턴합니다. remove메서드는 Vector에 저장된 객체를 삭제하는 메서드입니다. 그 외에는 add메서드와 똑같고요... isEmpty()메서드는 Vector가 비어있는지 알려줍니다. get메서드는 지정된 위치, index에 저장되어 있는 객체를 반환합니다. Vector는 객체를 배열에 순서대로 저장하기 때문에... index의 값은 0부터 시작합니다. 만일 index의 값을 3으로 하면 4번째로 저장한 객체가 반환되겠죠. size()메서드는 Vector에 실제로 저장된 객체의 개수를 정수로 반환합니다. 24 24
5.6 여러 종류의 객체를 하나의 배열로 다루기(3/3) Java 의 정석 Chapter 7. 객체지향개념 II http://www.javachobo.com 5.6 여러 종류의 객체를 하나의 배열로 다루기(3/3) 전에 Product배열을 사용했던 코드를 Vector클래스를 이용해서 바꾸면... 이렇게 됩니다. Product배열 대신에 Vector를 생성하고... add메서드만 호출하도록 바꾸는 거죠. 책에 Vector클래스를 이용한 예제가 나와있고요... 그 중에서 구입한 제품의 목록을 출력해주는 summary메서드만 자세히 설명해 드리겠습니다. 변수 sum은 구입한 물건가격의 총합을 저장하기 위한 것이고요. cartList는 구입한 제품의 목록을 저장할 문자열입니다. isEmpty메서드는 Vector인스턴스인 cart에 저장된 객체가 있는지를 확인하는 것이죠. 반환값이 boolean이기 때문에 if문의 조건문으로 사용할 수 있습니다. cart가 비어있으면... 바로 메서드의 수행을 종료하고요. 그렇지 않으면... 반복문을 이용해서 cart에 저장된 제품의 목록을 만들어서 화면에 출력합니다. size메서드를 호출해서 Vector인스턴스 cart에 저장된 객체의 개수를 얻어내서... 그 개수만큼 반복하게 됩니다. cart에 저장된 객체를 읽어오기 위해서 get메서드를 사용했는데요... get메서드의 리턴타입이... Object이기 때문에... Product타입으로 형변환 해주어야 합니다. 원래는 형변환 하기전에 instanceof연산자를 이용해서 타입체크를 해야하지만... 여기서는 cart에 저장된 객체가 모두 Product클래스의 자손이기 때문에... instanceof를 사용하지 않았습니다. get메서드를 호출해서 얻은 결과가 Object타입의 참조이기 때문에... Product타입으로 형변환 해주어야만 Product클래스에 정의된 멤버변수 price에 접근할 수 있습니다. 만일 이처럼... Object타입의 참조변수로 price에 접근하려고 하면... 에러가 발생합니다. 전에 배운 것과 같이... 아무리 실제 인스턴스가 멤버변수 price를 가지고 있어도... Object클래스에는 멤버변수 price가 정의되어 있지 않기 때문에... Object타입의 참조변수로는 price에 접근할 수 없는 것입니다. 문자열과 참조변수를 덧셈연산하면... 참조변수에 toString메서드가 호출되어 문자열을 얻어서 결합합니다. 그래서 빈문자열과 참조변수 p를 덧셈연산하면... 참조변수 p가 가리키는 객체의 toString메서드가 호출됩니다. 만일 참조변수 p가 가리키고 있는 객체가 Tv였다면... Tv클래스에 정의된 toString메서드가 호출되어서... 문자열 “Tv”를 얻습니다. 빈문자열과 문자열 “Tv”를 결합하면 그 결과는 문자열 “Tv”가 되겠죠. 이 예제를 이해하는데 별 어려움이 없었다면... 다형성을 잘 이해하고 계신겁니다. 다형성은 매우 중요하니까... 반복을 통해서 완전히 이해하도록 하세요. 25 25
감사합니다. http://www.javachobo.com Java 정석 의 정석 Chapter 7. 객체지향개념 II http://www.javachobo.com 감사합니다. 더 많은 동영상강좌를 아래의 사이트에서 구하실 수 있습니다. http://www.javachobo.com 이것으로 제 7장 객체지향개념II-2에 대한 강의를 모두 마치겠습니다. 감사합니다. 이 동영상강좌는 비상업적 용도일 경우에 한해서 저자의 허가없이 배포하실 수 있습니다. 그러나 일부 무단전제 및 변경은 금지합니다. 관련문의 : 남궁성 castello@naver.com