생성자 역시 메서드의 한 종류이므로 Overload가 가능하다.
생성자를 Overload할 경우, 해당 클래스에 대해 '객체를 생성하는 방법'을 다양하게 준비할 수 있게 된다.
this(); <- 생성자를 선언
army.attack();
naver.attack();
airforce.attack();
java 기본 유형의 데이터들처럼 객체 참조변수의 경우에도 형변환(Casting)이 이루어진다.
서로 다른 클래스 유형으로부터 나온 객체 참조변수들 간의 대입에는 일정한 규칙이 있다.
Parent parent = new Child();
위의 대입연산에서 왼쪽 항(Parent)와 오른쪽항(Child)의 객체 유형이 서로 다른 경우, 두 유형이 서로 상속 관계에 있고 왼쪽 객체(Parent)가 오른쪽 객체(Child)의 상위 클래스인 경우에만 암묵적인 형 변환이 이루어진다.
하위 클래스에서 상위클래스 유형으로 할당하는 것은 가능하나 그 반대의 경우에는 명시적 형 변환을 해야한다.
다음 알고리즘을 통한 형변환 예시)
A a1 = new B();
A a2 = new X();
----------------
A a3 = new C();
A a4 = new Y();
-----------------
B b1 = new C();
X x1 = new Y();
------------------
C c = new C();
B b2 = c;
------------------
Y y = new Y();
X x2 = y;
5개의 예제는 형변환 예시를 나타내며 모두 가능한 선언문이다.
암묵적 형 변환은 부모를 상속받은 자식 객체의 기능을 부모에게 물려받은 기능만 사용하도록 제한한다.
그러므로 암묵적 형변환이 발생하면 오버라이드된 기능만 사용가능하고 추가적으로 구현한 기능은 사용할 수 없다.
주의할 점은 기능의 제한이지, 기능의 변경은 아니다.
해당 클래스의 기능(메소드)을 쓰지 못할뿐 없어지거나 수정된게 아니란 뜻이다.
상속관계의 객체를 부모 형태로 변환하면 클래스 종류를 구분하지 않고,일괄된 기능을 호출 할 수 있다.
객체가 상위클래스 형태로 형변환 되더라도 Override된 자신의 기능은 잃지않는다
Unit u1 = army;
Unit u2 = Navy;
Unit u3 = Airforce;
u1.attcak();
u2.attcak();
u3.attcak();
// Unit이라는 상위 클래스에 하위 클래스를 불러들인 뒤, attack 메소드 호출
하지만, 추가적으로 구현한 기능(하위 클래스에 없는)은 사용할 수 없게 되므로 원래의 기능을 다시 사용할 수 있는 방법이 필요해 졌다.
부모 클래스의 객체를 자식 클래스 형태로 변환하는것.
형변환을 위해서는 다음과 같이 변환할 클래스 이름을 명시적으로 지정해 주어야한다.
ChhildClass child = (Childclass) Parent;
객체가 최초 생성될 때 자식 클래스 형태로 생성되고, 부모 형태로 암묵적 형변환이 된 상태를 다시 원래의 자식 클래스 형태로 되돌릴 경우에만 가능하다.
ChildClass child1 = new ChildClass();
ParentClass Parent = child1; //암묵적 형변환
ChildClass child2 = (ChildClass)Parrent; //명시적 형변환
- 가능한 경우
Army army1 = new Army();
Unit u = army1;
Army army2 = (Army)u;
- 가능한 경우
Unit u = new Navy();
Navy navy = (Navy)u;
- 최초 객체 생성이 부모 형태로 만들어진 경우 불가능하다.
Unit u = new Unit();
Army army = (Army)u;
- 최초 생성된 것과 다른 형식으로 변환하는 것은 불가능 하다.
Army army = new Army();
Unit u = army;
Navy navy = (Navy)u;
위의 두 경우(불가능한 경우) 모두 문법적인 오류는 없기 때문에, 이클립스에서는 에러를 검출하지 못한다. 하지만 프로그램을 실행시켰을 경우에는 에러가 발생한다.
일반 데이터 타입의 배열과 동일한 개념으로, 같은 클래스의 객체 여러개를 그룹화 할 수 있다.
int[] data = new int[3]; //int 타입의 값을 배열에 저장
Army[] data = new army[3]; // army타입의 객체를 저장
각 경우에 대한 배열의 요소 할당 처리
-> 일반 데이터 형은 단순히 값을 대입하지만, 객체 배열은 'new'를 사용하여 객체를 할당한다.
// 일반적인 int타입 값 선언
data[0] = 1;
data[1] = 2;
...
--------------------------
// 객체 배열 선언
data[0] = new Army();
data[1] = new Army();
...
객체 형변환
-> 같은 부모 클래스에서 파생된 서로 다른 자식 클래스의 객체들은
부모 형태로 암묵적 형변환 되어 일관된 형식으로 사용 가능하다.
객체 배열
-> 동일한 클래스의 객체는 배열로 묶어서 여러 개를 한꺼번에 제어할
수 있다.
배열의 생성이 부모 클래스로 지정되었을 경우, 모든 자식 클래스의 객체들은 그 배열에 포함될 수 있다.
Unit[] unit = new Unit[3];
// 배열의 요소 할당 과정에서 암묵적 형변환이 이루어진다.
Unit[0] = new Army();
Unit[1] = new Navy();
Unit[2] = new Airforce();
일괄 처리가 가능하다.
서로 다른 객체를 부모 형태의 배열에 담기게 되면, 반복문으로 일괄처리가 가능하다.
이 때 배열의 각 요소를 통해 사용하는 메서드가 Override 되어 있을 경우, 부모의 메서드가 아니라 자신이 재정의한 기능을 뜻한다.
for(int i = 0; i<unit.length; i++){
unit[i].attack();
}
//배정된 Unit객채의 배열 길이만큼 attack실행
배열의 각 요소가 확장한 기능을 사용하기 위해서는 원래의 클래스 형태로 명시적 형변환이 이루어 져야한다.
하지만 반복적으로 처리되는 과정에서 몇 번째 요소가 어떤 클래스에서 최초 생성 되었는지를 판단하기란 쉽지않다.
instanceof 연산자
-> 어떤 객체에 대한 출저를 판단하여 boolean형태로 결과를
반환한다.
if( unnit[0] instanceof Army){
Army temp = (Army)uint[0];
} // 배열란에 Army란 글이 들어간다면, temp에 형변환하여 저장
상속성은 객체간의 공통적인 기능을 관리하기 위한 기법으로, 코드의 재사용을 통하여 프로그램의 유지보수를 편리하게 한다.
다형성(Override, Overload)은 서로 다른 기능이지만 메서드의 이름을 공통되게 처리함으로서 전체 프로그램의 일관성을 유지하게 한다.
면접시 잘 물어보는것중 하나라고 한다.
추상화 기법은 특정 클래스를 상속받은 경우, 부모의 특정 메서드들을 무조건 재정의하도록 강제하는 기법이다.
특정 메서드를 재정의하도록 강제함으로써, 자식 클래스들을 작성하기 위한 가이드의 역할을 할 수 있다.
즉, 추상화 기법은 Java 클래스를 작성하기 위한 설계도를 소스코드 형태로 제시하는 역할을 한다.
이클립스 source란에 Override 자동생성을 잘 사용하자
추상 메서드를 정의하기 위해서는 'abstract' 키워드를 사용하여 메서드를 정의한다.
추상 메서드는 자식 클래스가 구현해야 하는 메서드의 가이드라인만 제시하기 위한 목적으로 사용되기 때문에, 선언만 가능하고 구현부가 없다.
//선언만 가능하고, 구현무를 위한 블록이 존재하지 않는다.
public abstract void sayHello();
추상 메서드를 포함한 클래스
추상 메서드를 하나 이상 포함하고 있는 클래스는 반드시 '추상 클래스'로 정의되어야 한다.
추상 클래스는 abstract키워드를 사용하여 할 수 있다.
예시
public abstract class Hello{
public abstract void sayHello();
}
추상 클래스는 객체를 생성할 수 없고, 반드시 상속을 통해서만 사용될 수 있다. 즉, 추상 클래스는 다른 자식클래스를 위한 '가이드라인'의 역할을한다.
추상 클래스는 생성자, 멤버변수, 일반 메서드등을 포함할 수 있다.
즉 공통 기능과 가이드라인을 모두 정의하여 다른 클래스에게 상속된다.
public abstract class Unit{
public abstract void attack(); // 공격
public abstract void shild(); // 방어
public abstract void walk(); // 걷다
public abstract void run(); // 뛰다
public abstract void jump(); // 점프
public abstract void pickup(); // 아이템 줍기
}
위와 같은 알고리즘을 만들려하는데 기존 추상(abstract)방식으로는 하나의 객체만 override할 수 있기에 다른 방식이 필요하다
자바 클래스간에 상속에서 하나의 부모만 존재할 수 있기 때문에, 앞의 상황에서 요구하는 다중 상속의 구현은 불가능하다.
완벽한 추상화를 구현하기 위한 Java Class의 한 종류(다중 상속을 하기위한 Class)
다중 상속이 가능하기 때문에 용도별로 세분화 하여 필요한 요소만 상속할 수 있다.
- 추상 클래스
-> 멤버변수, 생성자, 추상메서드를 포함할 수 있다.
-> 이 클래스를 상속받은 자식 클래스는 다른 클래스를 상속받을 수 없다.
- 인터페이스
-> 추상메서드만 포함할 수 있다.
-> 인터페이스는 다중 상속이 가능하다.
- 공통점 : 객체의 생성이 불가능하다.
interface는 상속에 abstract처럼 implements를 사용한다.
public class Article{
private -static- int count; // 전체 글 수
private -static- String category;// 카테고리
private int num; // 글 번호
private String title; // 글 제목
private String regDate; // 날짜
}
전체 글 수와 카테고리부분에 static을 선언하면서 고정값으로 바꾼다
객체간의 공유 자원을 표현하는 static키워드
클래스를 설계할때, 멤버변수 중 모든 객체에서 공통적으로 사용해야 하는 값에 static을 붙인다.
static이 붙은 멤버변수는 객체의 개수에 상관 없이 단 하나만 사용디며, 이를 모든 객체를 공유하기 때문에 메모리를 효율적으로 사용할 수 있다.
- 코드영역(고정영역)
->프로그램의 코드가 저장되는 영역
-> 이 영역에 저장된 명령어들은 cpu가 하나씩 가져가 실행한다.
- 데이터영역(고정영역)
-> 전역변수와 static으로 선언되는 변수가 할당된다.
-> 이 영역에 할당되는 변수들은 프로그램 시작과 동시에 메모리 공간이 할당되어 종료될 때 까지 남아있게 된다.
- 힙 영역(동적영역)
-> 프로그래머가 원하는 시점에 변수를 할당하고 소멸시키는 영역
-> 메모리 동적 할당시 사용된다. 객체가 생성되는 영역이다.
-스택 영역(동적영역)
-> 함수가 실행될 때 사용되는 파라미터와 지역변수에 대한 메모리 공간
-> 함수의 종료와 함께 소멸된다.
- 고점영역
-> 프로그램이 실행되면 실행파일이 메모리에 로드되면서,
실행파일의 용량만큼 RAM을 사용한다.
-> 실행 파일의 크기는 변할 수 없으므로 이 영역의 크기는
고정 크기를 갖는다.
- 동적영역
-> 프로그래머가 new키워드를 사용해서 객체나 배열을 생성하면
사용된다.
-> 또 다른 경우는 매서드가 호출되는 동안 사용될 파라미터와
지역변수가 생성된다.
-> 메서드가 종료되거나 객체가 더이상 사용되지 않으면 생성된
변수나 객체는 메모리에서 사라지므로, 이 영역은 유동적인 크기를
갖게된다.
static 데이터는 메모리의 고정영역중 데이터 영역에 생성되고, 일반 멤버 변수나 객체는 동적 영역중 Heap 메모리 영역에 생성된다.
최초 실행시 고정 영역에 실행파일 만큼에 메모리를 점유한다.
프로그램이 각종 동작을 수행하는 동안 동적영역을 사용한다.