package ex0726;

public class Ex02_interface {
	public static void main(String[] args) {
		// Demo2 dm = new Demo2(); // 컴파일 오류. 인터페이스는 추상 클래스의 일종으로 객체 생성 불가

		// 인터페이스는 구현 클래스의 상위 클래스와 유사하다.
		Demo2 dm = new DemoImpl2(); // up casting
		dm.print();
		dm.disp();
		
		// dm.sub(); // 컴파일 오류. 
			// 구현 클래스에는 정의 되어 있지만 인터페이스에는 존재하지 않으므로
		((DemoImpl2)dm).sub(); // down casting
		
		System.out.println(Demo2.A);
		
		// Demo2.B = 50 ; // 컴오류. 인터페이스에 정의된 필드는 final 이므로
		
	}
}
// interface : 선언만 있고 정의가 없는 abstract 클래스의 일종
// 인터페이스 작성
interface Demo2 {
	// 인터페이스 필드는 static final만 가능
	public static final int A = 10;
	int B = 20; // public static final을 붙이지 않아도 public static final
	
	public void print(); // 메소드는 선언만 가능(abstract 메소드)
	public abstract void disp(); // abstract 는 생략 가능
	
	/*
	public void sub() { // 메소드를 정의 하면 컴파일 오류가 발생
		// 
	}
	*/
	
}

인터페이스 클래스에서는 메소드를 대괄호를 넣어서 정의를 하면 안되고, 따옴표를 찍어서 ; 선언만 가능!!

// 인터페이스 구현
// 인터페이스를 구현한 클래스가 추상 클래스가 아닌 경우 인터페이스의 모든 메소드를 재정의 해야 한다.
class DemoImpl2 implements Demo2 {
	@Override
	public void print() {
		System.out.println("print - 인터페이스 메소드 재정의...");		
	}

	@Override
	public void disp() {
		System.out.println("disp - 인터페이스 메소드 재정의...");
	}
	
	public void sub() {
		System.out.println("클래스에 정의된 메소드...");
	}
	
}

인터페이스에서 선안된 메소드를 인터페이스를 구현한 클래스가 꼭 Override를 해야함!

package ex0726;

public class Ex01_abstract {
	public static void main(String[] args) {
		// SortInt si = new SortInt(); // 컴파일 오류. 추상 클래스는 객체 생성 불가.
		// 추상 클래스는 반드시 하위 클래스가 존재하고 하위 클래스를 통해서만 객체를 생성
		
		int[] data = new int[] {40,50,30,35,25};
		// SortInt si = new BubbleSort(); // 업캐스팅
		SortInt si = new SelectionSort();
		
		print("source data : ", data);
		
		si.sort(data);
		
		print("sort data : ", data);
		
	}
	
	public static void print(String title, int[] value) {
		System.out.print(title);
		for(int n : value) {
			System.out.print(n+" ");
		}
		System.out.println();
	}
}

추상 클래스 (abstract class)

  • 선언만 있고 정의가 없는 하나 이상의 추상 메소드를 갖는 클래스. 
  • 추상 메소드가 하나 이상 존재하는 경우 반드시 추상 클래스로 선언 해야 한다.
  • 하위 클래스에서 overriding할 것으로 예상되는 메소드를 메모리 낭비 없이 미리 호출 계획을 세워 두기 위해 작성한다.
  • 추상 클래스는 객체를 생성할 수 없다.
  • 추상 클래스를 상속 받은 하위 클래스는 추상 클래스가 아닌 경우 상위 클래스의 추상 메소드를 재정의 해야한다.
  • 추상 메소드가 없어도 추상 클래스로 작성할 수 있다. 
abstract class SortInt {
	private int[] value;
    
    protected abstract void sorting(); // 추상 메소드
    
    public void sort(int[] value) {
    	this.value = value;
        sorting();
    }
    
    // 배열의 길이
    protected int length() {
    	int n = -1;
        if(value != null) {
        	n = value.length;
        }
        return n;
    }
    
    // 두 정수 비교. final 메소드 - 하위클래스에서 재정의 불가
    protected final int compare(int i, int j) {
    	return value[i] - value [j];
    }
    
    // 배열의 두 요소 값을 서로 바꾸기
    protected final void swap(int i, int j) {
    	int t = value[i];
        value[i] = value[j];
        value[j] = t;
    }
}
class SelectionSort extends SortInt {
	@Override
	protected void sorting() {
		for(int i = 0; i < length() - 1 ; i++) {
			for(int j = i+1; j < length(); j++) {
				if(compare(i, j) > 0) {
					swap(i, j);
				}
			}
		}	
	}
}
class BubbleSort extends SortInt{
	@Override
	protected void sorting() {
		boolean flag = true;
		
		for(int i = 1; flag ; i++) {
			flag = false;
			for(int j = 1; j < length() - i; j++) {
				if(compare(j, j + 1) > 0) {
					swap(j, j+1);
					flag = true;
				}
			}
		}
		
	}
}

업캐스팅 = 어떠한 경우라도 가.

다운캐스팅 = 업캐스팅한 것만 가능!

package ex0723;

public class Ex05_ClassTypeCast {
	public static void main(String[] args) {
		Test5 t1 = new Test5();
		Test5 t2 = new Sample5();
		Test5 t3 = new Demo5();
		
		t1.disp(); // Test5의 print...
		// 재정의 하면 어떠한 경우라도 원래의 메소드로 돌아가지 않음!!
		t2.disp(); // Sample5의 print...
		t3.disp(); // Test5의 print...
		
		// Integer a=10;
		// Long b = a; // 컴오류
		// Long b = (Long)a; 컴오류. 상속관계에서만 캐스팅 가능. 형제는 남이다.
		
	}
}
class Test5 {
	public void print() {
		System.out.println("Test5의 print...");
	}
	
	public void disp() {
		// write(); 컴오류
		print();
	}
}

class Sample5 extends Test5{
	public void print() {
		System.out.println("Sample5의 print...");
	}
	
	public void write() {
		System.out.println("write...");
	}	
}

class Demo5 extends Test5 {
	public void sub() {
		System.out.println("sub...");
	}
}

'쌍용강북교육센터 > 7월' 카테고리의 다른 글

0726_Ex02_interface  (0) 2021.07.26
0726_Ex01_abstract : 추상 클래스  (0) 2021.07.26
0723_Ex04_ClassTypeCast  (0) 2021.07.23
0723_Ex03_ClassTypeCast : up-casting, down-casting  (0) 2021.07.23
0723_Ex02_override : 재정의  (0) 2021.07.23
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으로 바꿈.

+ Recent posts