저를 포함한 초보자분들에게 도움이 됐으면 좋겠습니다.
초보자분들은 수박 겉핥기 식으로 알고 넘어가지 마시고, 조금이라도 왜 이렇게 프로그램이 돌아가는지 알고 가시는 시간이 됐으면 좋겠습니다.

오늘은 상속 편에서 잠깐 언급했던 오버 라디오에 관련한 내용을 적어볼까 합니다.
오버라이딩, 오버라이드, 하이딩은 서로서로 관련이 많기에 같이 설명해 보고자 합니다.
자 그럼 오버라이딩(Overriding)부터 설명해 보겠습니다.

오버라이딩(Overriding)이란 부모 클래스에서 정의한 메소드를 자손 클래스에서 재정의하여 사용하는 것입니다. 재정의하여 사용하니 메소드의 return, 이름, 매개변수는 같아야 합니다.
예시를 봅시다.

(1) public class parent {
	  public void say() {
		  System.out.println("부모");
	  }
  }
(2) public class son extends parent{
	  public void say() {
		  System.out.println("자손");
	  }
	  public static void main(String[] args) {
		  son myson = new son(); // 객체생성
		  myson.say(); //자손 출력
	  }
  }

(2) 코드를 보시면, son 클래스는 (1) 클래스인 parent를 상속받고 있습니다. 
그럼 생성한 myson 객체는 son, parent의 변수,메소드를 사용할 수 있죠.
하지만 son과 parent 클래스에 이름, 매개변수가 같은 메소드인 say을 두 클래스 모두 가지고 있습니다. 이러한 경우에 오버라이딩(Overriding)이 적용이 되는 것이죠.
이와 같은 경우에 say 메소드를 수행 시켜보면, son에 있는 say가 실행되는 것을 볼 수 있죠.
오버라이딩은 이와 같이 이름,매개변수가 같은 메소드가 부모, 자손 클래스에 모두 있으면 상속을 받는 자손메소드로 사용하는 것이죠.
이유는 간단합니다. 저번에도 말씀드렸듯 상속은 자손 클래스 - 부모 클래스 순서로 엮어주는 것입니다.
say라는 메소드를 실행하면, 자손 클래스 - 부모 클래스 순으로 처음 발견한 곳의 메소드를 수행합니다.
부모 클래스에만 있는 메소드를 사용할 수 있는 이유도 이와 같습니다. 자손 클래스에서 찾고 없으니 부모 클래스로 넘어가 찾아 사용하기 때문이죠.

그다음은 하이딩(hidding / 은닉)입니다.
하이딩은 static으로 정의된 메소드에 수행이 됩니다. 오버라이딩과 하는 일은 같습니다. 
하지만 다른 점이 하나 있습니다. 오버라이딩은 한번 되는 순간 형 변환을 통하여 부모메소드를 실행시켜도 오버라이딩된 메소드가 실행되는 것을 볼 수 있습니다. 예를 보시죠.

(3)public class son extends parent{
	public void say() {
        super.say(); //부모
		System.out.println("자손");
	}

	public static void main(String[] args) {
		son myson = new son(); // son 객체생성
		parent myparent = (parent)myson; // parent객체 생성  --- myson의 형변환
		myparent.say(); //자손
	}
}  최종출력: 부모 자손

(3) 코드와 같이 son 객체를 생성하여 부모의 형태로 변환하여 myparent에 저장을 해주었습니다.
이 상태에서 say()를 실행해 보면, 접근은 parent에 있는 메소드에 접근을 하지만, 결과는 "자손"이라는 출력이 나옵니다. myson.say()와 같죠. 이처럼 오버라이딩이 되면 형 변환으론 부모 메소드에 접근할 수 없습니다. 그럼 어떻게 접근할까요? 3번째 줄에 적혀있는 super라는 키워드가 부모의 재산(변수/메소드)에 접근 가능하도록 해줍니다. 
결국 (3) 코드의 결과는 "부모 자손"이라는 결과를 뽑게 되죠.

하이딩은 다릅니다! 형 변환으로 접근이 가능하죠. 이유는 단순히 숨기기 때문입니다.
예를 보시죠. 달라진 것은 say()메소드 앞에 static 키워드가 붙은 것뿐입니다.(부모/자손 say 둘 다)


(4)public class son extends parent{
	public static void say() {
		System.out.println("자손");
	}

	public static void main(String[] args) {
		son myson = new son(); // son 객체생성
		parent myparent = (parent)myson; // parent객체 생성
		myparent.say(); //부모
	}

(4) 번 코드를 수행하면 어떻게 될까요? 설명드렸듯 static으로 설정된 메소드는 오버라이딩이 되는 것이 아닌 하이딩이 되는 것이기에 "부모"라는 출력이 나옵니다. 부모 메소드 say()에 접근했단 것이죠.
그럼 왜 하이딩(hidding)을 하는 것일까요?? 이 부분은 static에 대해서 알아야 합니다. 여기선 간단하게 설명한 후 끝내도록 하죠. 
static 키워드는 하나만 쓰겠다는 것입니다. 무슨 말인고 하니..
A 클래스 안에 static int a =3; 이 되어있다고 합시다.
A newA = new A(); ,  A newA2 = new A();를 이용해 2개의 객체를 만들었다고 했을 때, 이 객체 안에 들어있는 int a는  A, A2 객체가 공유하고 있는 겁니다. 그래서 A.a=5로 변경을 하면, A2.a는 5가 되듯 공유하고 있는 것이죠. 이렇게 static 키워드는 하나를 공유하여 사용한다는 개념이기에 객체가 생성되기도 전에 미리 만들어져 있죠. 이와 같은 특성 때문에 객체를 만들지 않아도 static은 클래스명.~~로 접근이 가능합니다. 오늘은 이 정도만 설명하겠습니다.

언제든지 접근 가능해야 하는 static의 특성 때문에 hidding(은닉)으로써 super 키워드를 사용하지 않고 접근이 가능하도록 해준 것이죠. 하지만 static은 C의 전역변수 역할을 하기에 객체지향 언어인 java에선 사용을 자제하는 편입니다.

마지막으로 오버 로딩(Overloading)입니다. 오버라이딩은 상속관계 메소드의 이름, 매개변수가 같을 때 일어나지만, 오버 로딩은 메소드 이름이 같고 매개변수가 '다를 때' 일어납니다. 예제를 보시면 명확히 이해하실 수 있습니다.

(5)public class son {	
	public void say() {
		System.out.println("void say");
	}
	public void say(int k) {
		System.out.println("int say");
	}
	public void say(char a) {
		System.out.println("char say");
	}

	public static void main(String[] args) {
		son myson = new son(); // son 객체생성
		myson.say(); //void say
		myson.say('d'); //char say
		myson.say(4); //int say
	}
}

(5) 코드를 보시면 say메소드가 3개 존재합니다. 하지만 각각 매개변수 받는 형태가 다르죠.
이렇게 메소드 이름이 같고 매개변수를 받는 형태가 다른 것을 오버 로딩이라고 합니다.
오버 로딩을 하여 메소드를 수행하게 되면, 매개변수에 맞게 알맞은 메소드를 수행시켜 줍니다.
say()를 했을 땐 알아서 void say를 출력해주고, say('d')를 했을 땐 char say를 출력해 주듯 말이죠.

오늘도 코드적으로 뜯어보기보단 이론적인 설명이었습니다. 개념들 잘 익히시고 static 메소드는 왜 hiding이 되는지 정도만 알아두시면 될 것 같습니다.

다음은.. this, super 와 같은 키워드에 대해서 이야기해 보겠습니다.

저를 포함한 초보자분들에게 도움이 됐으면 좋겠습니다.
초보자분들은 수박 겉핥기 식으로 알고 넘어가지 마시고, 조금이라도 왜 이렇게 프로그램이 돌아가는지 알고 가시는 시간이 됐으면 좋겠습니다.

자바 뜯어보기 - 클래스 편 보셨는지요? 상속은 클래스 편을 반드시 보고 오시는 게 좋습니다.
http://sims-solve.tistory.com/5?category=747624


오늘은 클래스 편에 이어 '상속'에 대해서 이야기해보도록 하겠습니다.
대개 일상생활에서는 '상속' 하면 '재산 상속'이 생각나네요.
'재산 상속'이라 하면 가지고 있는 재산을 물려준다.라는 의미가 되는데요.
클래스에서도 이 의미가 통하게 됩니다.

일단 자바에서 어떻게 상속을 받는지 살펴보도록 합시다. 

(1)public class parent {
	public void say() {
		System.out.println("부모의 유산");
	}
}
(2)public class son extends parent{  }

(1)은 parent(부모)가 되는 클래스를 정의해 주었습니다. 
(2)는 son(자손)이 parent를 상속받은 클래스입니다.
(2)에서 보듯 상속은 extends를 사용합니다. 이렇게 parent를 상속해주면 어떻게 될까요?
상속은 '재산 상속'과 같다고 말씀드렸습니다. parent의 재산은 무엇일까요?
재산은 parent가 가지고 있는 변수 / 메소드라고 생각하시면 됩니다.
즉 parent가 가지고 있는 모든 것을 son에게 물려줍니다.

이렇게 되면 son은 무슨 이득이 있을까요? (3) 코드를 보시죠.

(3)public class son extends parent{
	 public static void main(String[] args) {
	 	 son myson = new son(); // 객체생성
	 	 myson.say(); // "부모의 유산" 출력
	 }
 }

say()라는 메소드는 (1) 소스에서 보듯이 parent에서 선언한 메소드입니다.
하지만 son은 parent를 상속받고 있으므로 son 형태로 만든 myson 객체가 say 메소드를 사용할 수 있습니다. 마치 myson 객체 안에 선언된 메소드처럼 사용할 수 있게 되는 것이죠.
이게 바로 상속입니다. 다시 정의를 하지 않아도 부모에게서 물려받은 변수 / 메소드를 재사용 할 수 있습니다.
물론 myson 안에 say가 생성되는 것은 아닙니다. 상속을 받게 되면 son - parent 순으로 연결이 된다고 생각하시면 됩니다. 그래서 myson.say()를 하게 되면, 처음은 son 클래스에 say()메소드가 있는지 찾습니다. 없으면 다음 순서인 parent로 넘어가 say()가 있나 찾습니다. 이렇게 상속받은 쪽으로 올라가면서 해당 메소드,변수가 있는지 찾아 찾으면 실행시켜 주는 것이죠.

증명을 하고 넘어가 보죠. 만약 son에서도 say()가 있다면 어떻게 될까요?


(4)public class son extends parent{
	
	public void say() {
		System.out.println("자손의 유산");
	}

	public static void main(String[] args) {
		son myson = new son(); // 객체생성
		myson.say(); // "자손의 유산" 출력
	}
}

(4) 코드를 해보시면, son에 있는 say 메소드가 실행되는 것을 보실 수 있을 겁니다.
이처럼 생성한 자손의 클래스에서 먼저 say()가 있는지 찾기 때문에 son에 있는 say()가 출력되는 것을 볼 수 있습니다. 이것을 바로 '오버라이딩'이라고 합니다.
지금은 간단히 설명하고 넘어가겠습니다. '오버라이딩'은 부모가 물려준 재산 중 중복된 재산이 있다면 
부모의 재산을 사용하지 않고 내가 가지고 있는 재산을 사용하겠다는 겁니다.
즉, 부모 건 필요 없다는 소리죠. '오버라이딩'에 관한 내용은 추후에 쓰겠습니다.

오늘도 코드적으로 뜯어보기보단 이론적인 설명이었습니다. 자바에서 Class를 사용하는데 상속은  약방에 감초같이 빠질 수 없는 역할을 하죠. 상속은 그렇게 어려운 개념은 아니므로 잘 이해하시고 넘어가시길 바랍니다.

다음은 오버라이딩,은닉 등등.. 추가적인 부분을 올리도록 하겠습니다.

저를 포함한 초보자 분들에게 도움이 됐으면 좋겠습니다.
초보자 분들은 수박 겉핥기 식으로 알고 넘어가지 마시고, 조금이라도 왜 이렇게 프로그램이 돌아가는지알고 가시는 시간이 됐으면 좋겠습니다.

자바 뜯어보기 - 입력편(BufferedReader) 보셨는지요?
안보고 오셨다면 한번 보고 오시는 것도 좋습니다.  
http://sims-solve.tistory.com/3?category=747624

블로그 키워드를 보니 '입력'으로 유입하시는 분들이 많더라구요. 
입력방법을 크게 Scanner, BufferedReader 두가지 뜯어봤는데요. 대게 BufferReader를 많이 사용해요. 왜냐면 입력편에서 말했듯 속도를 무시 할 수 없습니다.
그래서 이번편은! 입력을 받은 걸 어떻게 처리 할 수 있는지 알아보도록 합시다.

1. 혹시 1993-05-02를 입력으로 받아 년/월/일로 나눈다면 어떻게 하실 건가요? 

(1)	public static void main(String[] args) throws IOException {
		String k = "1993-05-02";
		System.out.println(k.substring(0,4)+" "+k.substring(5,7)+" "+k.substring(8,10));
	}

혹시나 (1)코드처럼 처리 하실껀가요?
그럼 만약에 1993-5-2로 입력이 들어오면 어떻게 할껀가요?
또 다시 다르게 처리를 해줘야 합니다. 이렇게 특정 문자로 구분되어있는 문자열을 아주 쉽게 처리할 수 있는 방법을 제시하는 클래스가 있습니다. StringTokenizer라는 아주 유용할 클래스가 존재합니다.
String은 문자열을 나타내며 Tokenizer는 낱말분석이라는 뜻입니다. 즉 문자열을 분석한다는 소리죠.

StringTokenizer는 사용자가 설정한 구분문자를 기준으로 나누어 출력을 할 수 있도록 도와줍니다.
예시를 봅시다.


(2)	public static void main(String[] args) throws IOException {
		BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
		StringTokenizer st = new StringTokenizer(br.readLine(),"-");
		while(st.hasMoreTokens()) {
			System.out.print(st.nextToken());
		}
	}//최종출력 : 19930502

(2)코드와같이 사용 가능합니다. 일단 입력 BufferedReader는 우리가 일반적으로 사용하듯 만들어 주면 됩니다. new StringTokenizer(String , delim(구분문자))로 구성이 되는데 우리는 입력을 받은 것을 처리 하므로 br.readLine()을 넣어 주고 "1993-05-02"에서 "-"구분문자를 기준으로 자르고 싶으니 
구분문자를 "-"로 설정해 주면 됩니다.
자 설정은 끝났습니다. 이제 문자열을 분석해 보죠.


 (3)  public boolean hasMoreTokens() {
        newPosition = skipDelimiters(currentPosition);
        return (newPosition < maxPosition);
    }

일단은 .hasMoreTokens()입니다. (3)코드에서 보듯이 아주 간단합니다. 여기서 newPositio은 뽑아야될 문자의 위치입니다. maxPosition은 문자의 길이 - 1(0부터시작)를 뜻하구요.
즉, 뽑아야 할 문자가 있다면 true를 반환하게 됩니다. 예시로 설명드리죠.
1993-05-02가 있다면 처음 newPosition은 0입니다. nextToken()을 하게되면 구분문자"-"의 다음을 가리키게 되죠.
그럼 두번째 newPosition은 5, 같은 방법으로 하면 세번째 newPosition은 7, 네번째는 9가 됩니다.
9가되면 maxPosition과 같기에 false를 리턴하여 마무리합니다.

그 다음은 nextToken()메소드 입니다.
nextToken은 설정된 구분문자의 위치를 알아내어 문자을 처리하는 역할을 하죠.
조금 더 자세히 StringTokenizer를 뜯어볼까요?


(4)class StringTokenizer implements Enumeration

기본적으로 StringTokenizer클래스 안에는 (4)코드처럼  문자들을 쪼개기위해 여러가지 변수들이 있습니다. 이 변수들을 적절하게 사용하여 문자를 출력해주는 것이죠.
변수가 어떤 역할을 하는지는 주석으로 처리해 놓았으니 참고하시길 바랍니다.

(5)  public String nextToken() {

        currentPosition = (newPosition >= 0 && !delimsChanged) ?
            newPosition : skipDelimiters(currentPosition);

        delimsChanged = false;
        newPosition = -1;

        if (currentPosition >= maxPosition)
            throw new NoSuchElementException();
        int start = currentPosition;
        currentPosition = scanToken(currentPosition);
        return str.substring(start, currentPosition);
    }

(5)코드가 nextToken 메소드인데요. scanToken을 통하여 설정한 구분자 위치를 찾아내고 
String.substring를 사용하여 구분자 전까지 문자열을 리턴해 주네요. 

이처럼 StringTokenizer를 사용하게 된다면 손쉽게 구분자가 있는 문자열들은 처리 할 수 있습니다.
필자가 가장 많이 사용하는 경우는 생각보다 " "(띄어쓰기)로 문자열을 구분하여 처리해야 하는 경우가 많은데 이 경우 StringTokenizer로 많이 처리합니다.
여러분들도 StringTokenizer로 문자열을 현명하게 처리 할 수 있길 바랍니다.

+ Recent posts