[Java] Object 클래스, 다형성
Object 클래스
Object 클래스는 모든 자바 클래스의 최고 조상 클래스가 됩니다.
따라서 자바의 모든 클래스는 Object 클래스의 모든 메소드를 바로 사용할 수 있습니다.
이러한 Object 클래스는 필드를 가지지 않으며, 총 11개의 메소드만으로 구성되어 있습니다.
System.out.println(객체명); 만 입력해도 객체명.toString() 메소드가 호출된다.
toString()의 리턴 값이 String이어야 한다. System.out.println()을 toString 안에서 하면 안된다.
toString()은 문자열을 리턴해야 하는 메소드이므로!
http://www.tcpschool.com/java/java_api_object
객체지향 프로그래밍
- 캡슐화
- 객체의 실제 구현 내용을 감추어 필드와 메소드를 보호하는 것
- 외부의 잘못된 사용으로 객체가 손상되지 않게 함
- 접근제어자를 활용하여 객체의 필드와 메소드의 사용 범위 제한
- 상속
- 상위 객체의 필드와 메소드를 물려받아 재사용하는 것
- 코드의 중복을 줄일 수 있어 효율적임
- 다형성
- 하나의 타입으로 여러 객체를 생성하여 다양한 기능을 사용할 수 있도록 하는 특성
- 부모 클래스 타입으로 자식 객체의 생성 가능
- 인터페이스 타입으로 인터페이스 구현 객체 생성 가능
- 동일한 규격에 맞게 다양한 기능을 구현할 수 있어 유연하고 확장성 있는 프로그램 만들 수 있음
다형성
- 객체 지향 프로그래밍에서 가장 중요함!
- 부모 타입으로 다양한 형태의 자식 객체를 생성, 참조할 수 있는 것
- 슈퍼클래스 타입의 참조변수가 서브 클래스 타입의 객체를 참조할 수 있는 것
다형성이 왜 좋을까?
- 매개변수의 타입을 부모클래스로 했을 때, 해당 메소드의 매개변수로 부모 클래스를 상속받는 모든 자손 클래스의 참조변수를 매개변수로 받아들일 수 있게 되어서 자손 클래스별로 매개변수를 만들 필요가 없어진다. 동일한 내용의 메소드를 매개변수의 타입에 따라 만들 필요 없이 한 번만 만들면 되어서 효율적이다.
class Buyer { // 고객
int money = 1000; // 소유금액
void buy(Product p) {
// 매개 변수가 Product 타입의 참조변수. Product 클래스의 자손 클래스 Tv, Computer의 참조변수를 한번에 매개변수로 받아들일 수 있음.
// 앞으로 다른 제품 클래스를 추가할 때 Product클래스를 상속받기만 하면, buy(Product p)메서드의 매개변수로 받아들여질 수 있다.
if(money<p.price) {
System.out.println("잔액이 부족하여 물건을 살수 없습니다.");
return;
}
money -= p.price; // 가진 돈에서 구입한 제품의 가격을 뺀다.
}
}
- 자식 클래스로 생성한 객체에서 부모 클래스의 메소드를 사용할 거라면 여러 개의 객체를 따로 따로 생성해서 여러 개의 변수로 관리하는 게 아니라, 부모 클래스 타입의 배열을 하나의 변수로 관리하고 중복되는 메소드를 반복문으로 호출 가능
객체 타입 확인 (instanceof)
강제 타입 변환은 자식 타입이 부모 타입으로 변환 되어 있는 상태에서만 가능
부모 타입의 변수가 부모 객체를 참조할 경우 자식 타입으로 변환 할 수 없다.
부모 객체인지, 자식 객체인지 확인하는 방법 -> instanceof 연산자
주의할 점은 아예 부모 자식 관계에 해당되지 않는 것을 instanceof로 검사할 땐 true, false가 나오는 게 아니라
컴파일 시점에서 Error가 발생하게 되므로 적어도 부모 자식 관계에 있는 것들끼리 instanceof를 사용해야 함
좌항 객체, 우항 타입, 우항 인스턴스 이면 true
boolean result = 좌항(객체) instanceof 우항(타입)
instanceof 연산자는 매개값의 타입을 조사할 때 주로 사용
메소드 내에서 강제 타입 변환이 필요할 경우(자식 메소드에만 있는 메소드 사용 시) 반드시 매개값이 어떤 객체인지 instanceof 연산자로 확인하고 안전하게 강제 타입 변환 -> ClassCastException 예외 발생
public void method(Parent parent){
if(parent instanceof Child){ // 객체 타입 확인 후
Child child = (Child)parent // 강제 타입 변환
}
}
((Taxi)taxi).setMaxNum(4); // 반드시 ()로 바깥을 감싸야 함
((Truck)truck).setMaxWeight(100);
동적바인딩
결론부터 말하면 동적 바인딩은
Runtime 시점에 해당 메소드를 구현하고 있는 실제 객체 타입을 기준으로 찾아가서
실행될 함수를 호출하는 것을 의미한다.
바인딩
컴퓨터 프로그래밍에서 각종 값들이 확정되어 더 이상 변경할 수 없는 구속(bind) 상태가 되는 것. 프로그램 내에서 변수, 배열, 라벨, 절차 등의 명칭, 즉 식별자(identifier)가 그 대상인 메모리 주소, 데이터형 또는 실제값으로 배정되는 것이 이에 해당되며, 원시 프로그램의 컴파일링 또는 링크 시에 확정되는 바인딩을 정적 바인딩(static binding)이라 하고, 프로그램의 실행되는 과정에서 바인딩되는 것을 동적 바인딩(dynamic binding)이라고 한다. 프로그래밍에서는 바인딩을 가급적 뒤로 미루도록 권고하고 있다.
[네이버 지식백과] 바인딩 [binding] (IT용어사전, 한국정보통신기술협회)
정적 바인딩
실행 이전에 값이 확정되면 정적 바인딩이라고 한다.
컴파일 타임에 호출될 함수가 결정되는 것.
컴파일러는 선언되어있는 자료형을 보고 바인딩을 하기 때문에 실제로 가리키는 객체가 무엇이든 포인터의 자료형을 기반으로 호출의 대상을 결정한다.
* 빌드 중에 이루어진다
동적 바인딩
실행 이후에 값이 확정되면 동적 바인딩이라고 한다.
런타임에 호출될 함수가 결정되는 것으로, virtual 키워드를 통해 동적 바인딩하는 함수를 가상 함수라고 한다.
함수가 가상 함수로 선언이 되면, 포인터 변수가 실제로 가리키는 객체에 따라 호출의 대상이 결정된다.
* 실행 파일을 만들 때 바인딩 되지 않고 보류 상태 둔다.
* 실행 시간에 실제로 사용된 객체의 클래스형에 의해 호출될 함수가 결정됩니다.
* 점프할 메모리 번지를 저장하기 위한 메모리 공간(4 byte)을 가지고 있다가 런타임에 결정.
Java에서 동적 바인딩
메소드를 기본적으로 동적 바인딩 하기 때문에 메소드 오버라이딩이 가능하다!
또한 static으로 선언하는 것은 메모리를 한 번밖에 할당하지 않기 때문에 컴파일 시에 메모리에 할당된다.
따라서 static으로 선언된 것은 모두 정적 바인딩이다.
동적바인딩이 가능하기에 다형성 및 상속이 모두 가능한 것이다.
https://todayscoding.tistory.com/16
https://sorjfkrh5078.tistory.com/87
컴파일 vs. 런타임
컴파일
일반적으로 컴파일은 고급 언어로 작성된 프로그램을 기계어로 번역하는 것
소스코드를 기계가 이해할 수 있는 기계어로 바꿔주는 것
자바에서 컴파일은 컴퓨터가 이해할 수는 없지만 JVM이라는 기계가 이해할 수 있는 바이트 코드를 생성해주는 것
코드를 작성하다가 저장했을 경우에 컴파일 처리가 된다.
컴파일 시에는 참조데이터타입(스택 공간)에 따라서 메소드가 결정됨
다형성으로 자식 객체 생성 시, 부모 객체에 없는 메소드를 호출하고자 할 때 컴파일 에러 발생
(다형성으로 자식 객체 생성 시 참조 데이터 타입은 부모 클래스임.
부모 클래스에 자식 객체에만 있는 메소드가 없기 때문에 컴파일 에러 발생하는 것)
런타임
컴파일 과정을 마친 컴퓨터 프로그램이 실행되고 있는 환경 또는 동작되는 동안의 시간을 말한다.
실행될 때는 실제 객체가 저장된 곳(힙 공간)에 따라서 실행되는 메소드가 결정됨 == 동적 바인딩
자바 파일이 컴파일러와 JVM을 만나고 기계어코드로 변환되기까지의 과정을 정리하면,
1. 자바소스코드가 개발자에 의해 작성된다.
2. 컴파일타임을 거쳐 (javac) , java.class 바이트코드 파일로 변환된다.
3. 변환된 파일을 JVM의 클래스 로더에게 전달한다.
4. 동적 로딩을 거쳐 필요한 클래스를 런타임 메모리영역에 올린다.
5. 실행 엔진을 통해 코드가 해석과 실행과정을 거친다.