back/Java

KH 13일차

devel0per 2022. 7. 18. 17:14

13일차인 오늘은 오버라이딩, 접근지정자, Final, 객체 형변환에 대해서 학습했다.

 

(1) 오버라이딩

package ja_0718;


class AA_2{
	
	int aa = 55;
	int bb = 77;
	
	void display() {
		System.out.println("AA_2 클래스의 display() 메소드");
	}
}

class BB_2 extends AA_2{
	
	int bb = 478;
	int cc = 888;
	
	void display() {
		System.out.println("BB_2 클래스의 display() @@@ 메소드");
	}
}


public class Overriding_1 {
	public static void main(String[] args) {
		
//		AA_2 obj_1 = new AA_2();
//		BB_2 obj_1 = new BB_2();
		AA_2 obj_1 = new BB_2();
		
		//멤버 변수는 AA_2 것이 나오고 메소드는 BB_2 클래스에서 나온다.
		//멤버 변수는 쉐도잉 되고 메소드는 오버라이딩 된다.
		
		obj_1.display();
		System.out.println(obj_1.bb);
		
	}
		

}

저번 시간에 이어 복습겸으로 오버라이딩에 대해서 학습했다. 오버라이딩이란 부모 클래스에서 상속된 자식클래스가 부모 클래스가 가지고 있는 메소드를 재 정의 하여 같은 이름의 메소드를 갖는것이다.

AA_2를 상속받은 BB_2가 AA_2의 메소드인 display()를 그대로 재 정의하여 사용하는 것을 알 수 있다.

AA_2 obj_1 = new BB_2(); 를 통해서 멤버변수는 쉐도잉 하고, 메소드는 오버라이딩 처리를 해주는 것이라고 한다.

쉐도잉의 개념을 이해하지 못하겠다.. 


섀도윙 (shadowing)

 

변수, 메소드, 클래스, 인터페이스의 이름을 같은 영역에서 동일하게 사용하면 이름이 겹쳐 섀도윙이 발생한다. 예를 들어, 인스턴스 변수의 이름과 인스턴스 메소드 내부의 지역변수 이름이 같은 경우이다. 어떤 대상이 섀도윙되면 해당 대상을 이름으로 접근할 수 없다. 다양한 방법을 사용하면 접근할 수 있겠지만, 전히 접근 불가능한 경우도 있다.

일반적으로 섀도윙은 사용하지 않는 것이 좋다. 하지만 많은 개발자들이 생성자에서 인스턴스 변수의 초기화를 할 때 일반적으로 섀도윙을 사용한다.

 

출처: https://soy.me/5 

 

Java 이름 재사용 - 오버라이딩 / 하이딩 / 섀도윙 / 모호화

오버라이딩 (overriding) 자식 클래스에 있는 인스턴스 메서드가 부모 클래스의 접근 가능한 메서드와 동일한 이름과 매개변수를 가지는 것. 오버라이딩 되면 동적 바인딩이 가능해짐. 따라서 JVM은

soy.me

 

(2) 접근지정자

 

package ja_0718;

// show 메소드가 현재 private 이므로, 다른 클래스에서는 사용하지 못함.
// 따라서 사용하기 위해서 클래스 내부에서 사용하게 코드를 짜야됨.
class Super_1{
	
	public void display() {
		System.out.println("Super_1 class display Method ~~~~");
		// private된 show()를 사용하기 위해선 메소드 속에서 사용해야 된다. 
		show();
	}
	
	protected void message() {
		System.out.println("Super_1 class message Method ~~~~");
	}
	
	void print() {
		System.out.println("Super_1 class print Method ~~~~");
	}
	
	
	// err  :  color red!!
	private void show() {
		System.err.println("Super_1 class show Method ~~~~");
	}
	

}
public class Method_1 extends Super_1{
	public static void main(String[] args) {
		
		Method_1 obj_1 = new Method_1();
		
		obj_1.display();
		obj_1.message();
		obj_1.print();
//		obj_1.show();
	
	}
		
}

현재 부모클래스에서 public, protected, default, private 접근 지정자를 이용하여 메소드를 정의했다.

그 결과 private 메소드는 자식 메소드에서 사용할 수 없음을 볼 수 있다. 

왜냐하면 private는 같은 class내에서만 공유할 수 있기 때문이다.

따라서 private로 지정한 메소드를 사용하고 싶으면, 부모 클래스에 존재하는 다른 메소드 속에 메소드를 정의해서 출력해야한다.

 

(3) Final

package ja_0718;

// 변수에 final이 붙으면 상수처리
// 메소드에 final이 붙으면 오버라이딩 하지못함.
// 클래스에 final이 붙으면 상속처리 하지 못함.

class WordProcess{
	
	int a = 0;
	int b = 0;
	
	final void Input() {
		
	}
	
//	void Input(int a, int b) {
//		this.a = a;
//		this.b = b;
//	}
	
	void Edit() {
		
	}
	
	void Print() {
		
	}
	
	void About() {
		System.out.println("a company developer");
	}
}

class NewWordProcess extends WordProcess{
	void About() {
		System.out.println("b company developer");
	}
}

public class Final_1 {
	public static void main(String[] args) {
		
		NewWordProcess obj = new NewWordProcess ();
		
		obj.About();
		
	}

}

어제 변수를 final로 지정하여 상수처리를 해봤다. 오늘은 메소드와 클래스에 까지 final 처리를 해봤는데, 메소드에 final이 붙게되면 더 이상 오버라이딩 할 수 없고, 클래스에 final이 붙게 되면 더 이상 상속처리를 할 수 없게 된다.

 

(4) 객체 형변환

 

package ja_0718;

class Con_11{
	
	int a = 33;
	
	void display() {
		System.out.println("con_11 method display()~~~~~");
	}
}

class Con_22 extends Con_11{
	int b = 77;
	
}

class Con_33 extends Con_11{
	
	int a = 45;
	int c = 99;


	void display() {
		System.out.println("con_33 method display ##");
	}
	
	void show() {
		System.out.println("con_33 method show ^^^^^");
	}
}

public class Convert_1 {
	public static void main(String[] args) {
		
		//객체 형변환 
		
		Con_33 obj_1 = new Con_33();
		Con_22 obj_2 = new Con_22();
		Con_11 obj_3 = new Con_11();
//	
//		Con_11 objj33 = obj_1;
//		Con_22 objj22 = (Con_22) obj_2;
		
		
		
		obj_2.display();
		System.out.println("Con_22 a, b : " + obj_2.a + ", " + obj_2.b);
		
		obj_1.display();
		System.out.println("Con_33 a, c : " + obj_1.a + ", " + obj_1.c);	
		
		
		// 오른쪽이 커야한다.
			
	}

}

오늘의 하이라이트 객체 형변환... 솔직히 완벽하게 이해가 가지 않는다.. 헷갈려죽겠음...

예전에 int로 형태를 지정한 변수를 int 보다 범위가 큰 double로 변환했을떄, 자동으로 형이 변환되는 것을 볼 수 있었다.

그러나 double로 지정된 변수를 int로 변환하려면 캐스팅 작업을 해줬어야했다.

 

예를 들어서 

 

int a = 0;

double b = a; 

라고 지정하면 알아서 casting 되지만

 

double a = 0;

int b = a; 

라고 지정하면 오류가 발생한다 범위가 넓은 a가 b에 들어갈 수 없다는 것이다.

이럴땐,

 

double a = 0;

int b =(int)a;

이런식으로 casting 변환을 해줬어야했다.

 

객체 형변환도 똑같이 생각하면 (쉽게 생각해서) " = " 기준으로 오른쪽에 존재하는 변수가 범위가 작아야(?) 한다는 것이다.

예를 들어서, AA_1이라는 부모클래스를 가진 BB_1이 있고 , BB_1을 부모클래스로 가진 CC_1이 있다고 가정하자.

 

AA_1 a = new AA_1();   라고 지정하고

 

BB_1 b = a; 라고 지정하면 오류가 발생한다는 것이다.

 

이때도 똑같이 BB_1 b = (BB_1)a; 라고 casting 해줘야한다.

 

아직은 완벽히 이해가 안되지만, 후에 interface를 이해하기 위해선 꼭 학습해야되는 부분이니 공부하도록 하자!