package ex0723;

public class Ex04_ClassTypeCast {
	public static void main(String[] args) {
		Test4 t1 = new Test4();
		Sample4 s1 = new Sample4();
		
		System.out.println(t1.b+", "+s1.b);
		
		t1.print(); // Test4의 print() 호출
		
		// up-casting
		Test4 t2 = new Sample4();
		Test4 t3 = s1;
		Object o = new Sample4();
		
		System.out.println(t2.b); // 20, 필드는 무조건 자기 것
		// System.out.println(t3.c); 컴파일 오류. Test4클래스에 c 필드가 없으므로
		System.out.println( ((Sample4)t3).c ); // 200, 다운캐스팅
		// System.out.println (Sample4)t3.c ); // 컴오류. 연산자 우선순위가 . 이 높음.
		System.out.println( ((Sample4)o).c ); // 200, 다운캐스팅
		
		t2.print(); // 메소드는 재정의된 하위 클래스 메소드 호출(상위 메소드는 숨는다.)
		//t2.write(); // 컴파일오류. Test4에 없는 메소드 이므로.
		((Sample4)t2).write(); // 다운 캐스팅
		
		// down-casting
		// Sample4 s2 = (Sample4) t1; 런타임오류(ClassCastException) up한 것만 down가능
		if(t1 instanceof Sample4) { // instanceof 연산자 : 객체가 해당 클래스의 객체인지를 확인
			Sample4 s2 = (Sample4) t1;
			System.out.println(s2);
		} else {
			System.out.println("Sample4 객체가 아님...");
		}
		
		// Sample4 s2 = t2; // 컴파일 오류. down은 반드시 강제 캐스팅이 필요.
		Sample4 s2 = (Sample4)t2;
		Sample4 s3 = (Sample4)t3;
		System.out.println(s2.c+","+s3.c); // 200, 200
		Test4 t4 = (Test4)o;
		System.out.println(t4.a+","+t4.b); // 10, 20 필드는 무조건 자기것이 우선순위가 높다.
		Sample4 s4 = (Sample4)o;
		System.out.println(s4.a+","+s4.b+","+s4.c); // 10, 100, 200
		
	}
}
class Test4 {
	int a = 10;
	int b = 20;
	public void print() {
		System.out.println(a+":"+b);
	}
	public void disp() {
		System.out.println("disp...");
	}
	
}

class Sample4 extends Test4 {
	int b = 100;
	int c = 200;
	
	// 재정의
	public void print() {
		System.out.println(a+":"+super.b+":"+b+":"+c);
	}
	
	public void write() {
		System.out.println("write...");
	}
}

여기 자세히 봐야함. 보면서 그렇구나~ 하고 아는 것 같은데 했는데 

막상 다른 문제 보면 틀림ㅠㅠ

package ex0723;

public class Ex03_ClassTypeCast {
	public static void main(String[] args) {
		Test3 t = new Test3();
		t.print(); // a:10, b:20
		// System.out.println(t.c); 컴오류. 하위클래스 멤버는 접근불가
		System.out.println();
		
		// 클래스는 상속관계가 아니면 어떠한 경우에도 형변환이 불가능하다.
		// Integer 와 Long은 형변환이 불가능하다.(형제관계에서는 불가)
		
		// Test3(부) > Sample3(자) 상하관계
		// up-casting : 상위 클래스의 객체가 하위 클래스의 객체를 참조하는 것
		// up-casting은 언제나 가능하며 형변환을 하지 않아도 된다.
		Sample3 s1 = new Sample3(); // Test3도 메모리 할당을 받음.상위 클래스 메모리할당이 안돼면 자식도 생성불가
		Test3 t1 = s1; // 프로그램 실행 시점에 s1을 t1에 줌.

		System.out.println(t1 == s1); // true. 참조하는 영역이 동일하므로 동일한 객체임
		
		System.out.println(s1.b); // 100
		System.out.println(t1.b); // 20. 업캐스팅 객체라 할지라도 필드는 자기 자신것을 나타낸다.
		// System.out.println(t1.c); 컴파일 오류 Test3에 c라는 필드가 없으므로. 컴파일단계에서는 x
		
		// 업캐스팅 객체에서 재정의된 메소드는 숨어버리기 때문에 메소드는 하위 클래스의 메소드가 호출된다.
		// 이곳에서 Test3 클래스의 print() 메소드를 호출할 수 있는 방법은 없다.
		t1.print();
		System.out.println();
		
		t1.disp();
		
		// t1 객체가 업캐스팅 객체라 할지라도 Test3클래스에 write() 메소드가 존재하지 않기 때문에 컴파일 오류
		// t1.write();
		
		// down-casting up casting한 객체를 다시 원래 객체로 캐스팅하는 것
		// down-casting은 up casting한 객체만 가능하다.
		// down-casting은 반드시 강제 캐스팅을 해야 한다.
		Sample3 s2 = (Sample3) t1; // down-casting
		System.out.println(s2.c);
		
	}
}
class Test3 {
	int a = 10;
	int b = 20;
	
	public void print() {
		System.out.println(a+":"+b);
	}
	
	public void disp() {
		System.out.println("disp...");
	}
}

class Sample3 extends Test3 {
	int b=100;
	int c=200;
	
	
	@Override
	public void print() {
		System.out.println("a:"+a+", b:"+b+", super.b:"+super.b+", c:"+c);
	}
	
	public void write() {
		print();
		super.print();
		disp();
	}

업캐스팅은 언제나 가능하며 형변환을 하지 않아도 됨.

다운캐스팅은 "업캐스팅"한 객체만 가능하고 반드시 강제캐스팅을 해야함. ★★★

 

package ex0723;

public class Ex02_override {
	public static void main(String[] args) {
		Sample2 s = new Sample2();
		
		s.print();
		s.write();
	}
}
class Test2 {
	int a= 10;
	
	public void print() {
		System.out.println("a:"+a);
	}
}

class Sample2 extends Test2 {
	int x = 100;
	
	public void write() {
		super.print();
	}
	
	// 재정의되는 메소드의 접근 제어자는 크거나 같아야 한다.
	// 메소드 override : 메소드의 시그니처가 동일해야 한다.
	// 상위 클래스의 메소드를 재정의하면 재정의된 상위 클래스의 메소드는 숨는다.
	@Override // 메소드가 오버라이드 규칙에 맞는지를 검증하고 맞지 않으면 에러 발생
	public void print() {
		System.out.println("a:"+a+ ",x:"+x);
	}
	
	// overloading
	public void print(int n) {
		System.out.println(n);
	}

 

package ex0723;

public class Ex01_override {
	public static void main(String[] args) {
		
		User1 ob1 = new User1("1001", "홍길동");
		User1 ob2 = new User1("1001", "홍길동");
		
		System.out.println( ob1 == ob2 ); // 주소를 비교(false)
		
		// User1에서 equals() 메소드를 재정의해서 학번과 이름이 동일하면 true를 반환
		System.out.println( ob1.equals(ob2)); //
		
	}
}
class User1 {
	private String hak;
	private String name;
	
	public User1() {
	}
	
	public User1(String hak, String name) {
		this.hak = hak;
		this.name = name;
	}
	
	public String getHak() {
		return hak;
	}
	
	public void setHak(String hak) {
		this.hak = hak;
	}
	
	public String getName() {
		return name;
	}
	
	public void setName(String name) {
		this.name = name;
	}

	// Object 클래스의 equals() 메소드를 재정의
	@Override
	public boolean equals(Object obj) {
		User1 u = (User1)obj; // Object 객체를 User1 객체로 다운 캐스팅
		
		return this.hak.equals(u.getHak()) && this.name.equals(u.getName());
	}
}

package ex0722;

public class Ex06_override {
	public static void main(String[] args) {
		Test6 tt = new Test6();
		tt.setName("홍길동");
		tt.setAge(20);
		
		System.out.println(tt.getName()+", "+tt.getAge());
		System.out.println(tt.toString()); // 클래스명@해쉬코드
		System.out.println(tt);
	}
}
class Test6 {
	private String name;
	private int age;
	
	
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}
	public int getAge() {
		return age;
	}
	public void setAge(int age) {
		this.age = age;
	}
	@Override
	public String toString() {
		return name+"\t"+age;
	}
	
	
}

원래 String의 toString() 메소는 클래스명@해쉬코드를 반환하는 메소드인데 밑에서 오버라이딩을 통해 상속받은 toString을 이름+탭공간만큼 띄고+나이 를 반환하는 String으로 바꿈.

package ex0722;

public class Ex05_Inheritance {
	public static void main(String[] args) {
		Sample5 ss1 = new Sample5();
		ss1.disp();
		System.out.println();
	
		Sample5 ss2 = new Sample5(77);
		ss2.disp();
		System.out.println();
		
		System.out.println(ss1.equals(ss2)); // 주소비교

	}
}
class Test5 {
	int x;
	
	public Test5() {
		x = 0;
		System.out.println("상위 클래스-인자없는 생성자");
	}
	
	public Test5(int x) {
		this.x = x;
		System.out.println("상위 클래스-인자 하나인 생성자");
	}
	
	public void print() {
		System.out.println(x);
	}
}

class Sample5 extends Test5{
	int a;
	
	public Sample5() { 
		// super(); 이 생략된 것임
		a = 0;
		System.out.println("하위 클래스-인자없는 생성자");
	}
	
	public Sample5(int x) {
		// super(); 와 this는 동시에 쓸 수 없다.
		this(10, x); // this([인수]); 가 있으면 super([인수]);는 있을 수 없다.
		System.out.println("하위 클래스-인자 하나인 생성자");
	}
	
	public Sample5(int a, int x) {
		super(x);
		this.a = a;
		System.out.println("하위 클래스-인자 두개인 생성자");
	}
	
	public void disp() {
		System.out.println(a+","+x);
	}
}

this.a // 내 자신의 필드 a
super.a // 아버지의 필드 a

this(10); // 자신의 클래스에서 다른 생성자를 호출

super(); 
super(10); // 상위 클래스의 인자가 하나인 생성자 몸체 실행

 

 

 

package ex0722;

public class Ex04_Inheritance {
	public static void main(String[] args) {
		// Test4 t = new Test4(); 컴파일 오류. 인자가 없는 생성자가 없음.
		// Test4 t = new Test4(5)
		
		Sample4 ss = new Sample4 ();
		ss.disp();
	}
}
class Test4 {
	int x;
	
	
	// 인자가 있는 생성자만 존재
	public Test4(int x) {
		this.x = x;
	}
	
	public void print() {
		System.out.println(x);
	}
}

// 상위 클래스에 인자가 있는 생성자만 존재하면
// 하위 클래스는 반드시 생성자를 만들고 명시적으로 상위 클래스 생성자를 호출해야 한다.
class Sample4 extends Test4 {
	int a = 10;
	
	public Sample4() {
		// super(); 컴파일 오류. 인자가 없는 생성자가 상위에 없으므로
		super(100);
	}
	
	public void disp() {
		System.out.println(a);
	}
}

package ex0722;

public class Ex03_Inheritance {
	public static void main(String[] args) {
		Sample3 ss = new Sample3();
		ss.disp();
		
		/*
		 - 하위 클래스의 객체를 생성하는 경우
		 	1. 상위 클래스의 필드 메모리 할당, 기본값 초기화, 초기화 블럭 실행
		 	2. 하위 클래스의 필드 메모리 할당, 기본값 초기화, 초기화 블럭 실행
		 	3. 상위 클래스의 생성자 몸체 실행(하위 클래스 생성자의 최상단의 super([인수])호출되어 실행됨)
		 	4. 하위 클래스의 생성자 몸체 실행
		 */
		
	}
}
class Test3 {
	int a=10;
	
	public Test3() {
		System.out.println("Test2 생성자...");
	}
	
	public void print() {
		System.out.println(a);
	}
}

class Sample3 extends Test3{
	int x=100;
	
	public Sample3() {
		super(); // 상위 클래스 생성자 몸체 호출. 최상단에 한번만 가능. 
				 // 없으면 컴파일할 때 컴파일러가 super(); 추가하여 상위 클래스의 디폴트 생성자 몸체 호출 
		System.out.println("Sample3 생성자...");
	}
	
	public void disp() {
		System.out.println(a+","+x);
	}

 

+ Recent posts