JAVA-10

이강민·2022년 3월 28일
0

웹 개발반 - JAVA

목록 보기
10/19
post-thumbnail

JAVA-10

상속

  • 기존에 선언된 클래스의 필드를 다른 클래스에서 사용하고자 할 때
class A {
	A의 필드
}
class B extends A {
	B의 필드 + A의 필드
}
B b = new B();

b 객체는 실제로는 A의 필드와 B의 필드 둘 다 가지고 있다.

  • A : 부모 클래스, 상위 클래스, 슈퍼 클래스, 기반 클래스
  • B : 자식 클래스, 하위 클래스, 서브 클래스, 파생 클래스

  • 자식 클래스의 생성자 호출 시 일어나는 일
    • 자식 클래스의 객체는 자식 생성자를 호출하여 객체화를 진행한다.
      자식 생성자를 호출 했으므로 자식 클래스의 필드가 메모리에 올라 갈 것이다.
      메모리에 자식 클래스의 필드만 올라 갔다면 자식 객체로 절대 부모 클래스에 있는 필드에 접근 할 수 없다. 자식 생성자를 호출하게 되면 그 자식 클래스가 상속 받기로 약속되어 있는 부모 클래스의 생성자가 자동으로 먼저 호출하게 된다. 그 이후에 자식 클래스의 필드가 부모 클래스의 필드에 이어 붙여서 객체의 필드가 완성하게 된다.
      따라서 자식 클래스로 만든 객체는 부모 필드가 먼저 메모리에 생성되어 있기 때문에 접근이 가능해진다.
  • 자식 생성자의 첫 줄에는 항상 super클래스의 생성자가 호출된다. 명시적으로 적지 않았을 때에는 보이지 않지만 super() 가 호출하고 있다.
    super()는 부모의 기본 생성자를 호출한다.
package day10;

public class Road_my {
	public static void main(String[] args) {
//		부모 클래스 객체화
		Moto momcar = new Moto("K8", 4500);
		Suv mycar = new Suv("XC90", 8000, "sports");
		mycar.engineStart();
	}
}
// 부모 클래스 생성
class Moto {
	String brand;
	int price;
//	Car 클래스의 전역 변수를 이용하여 생성자를 오버로딩하였음
	public Moto(String brand, int price) {
		this.brand = brand;
		this.price = price;
	}
	void engineStart() {
		System.out.println(brand + "시동 켜기");
	}
	void engineStop() {
		System.out.println(brand + "시동 끄기");
	}
}
// Car클래스를 상속 받는 하위 클래스를 정의한다.

class Suv extends Moto{
	String mode;
//	기본 생성자 super()를 호출 하고 있어서 오류가 발생함.
//	오류가 나지 않으려면 상위 클래스에서 기본 생성자도 정의 해주어야하거나
//	자식 생성자를 오버로딩 해주어야한다.
	public Suv(String brand, int price) {
		super(brand, price);
	}
//	부모의 생성자를 가져와서 자식의 변수를 활용하여 오버로딩 할 수있다.
	public Suv(String brand, int price, String mode) {
//		부모 생성자를 가져옴
		super(brand, price);
		this.mode = mode;
	}
//	자식의 고유 메소드를 정의할 수 있다.
	void roofOpen(){
		System.out.println(brand + " 뚜껑 열기");
	}	
}

다형성

  • 오버로딩
  • 오버라이딩
    • 부모 클래스에 이미 a()라는 메소드가 존재한다면 자식 객체 생성 시 부모 생성자가 먼저 호출되기 때문에 부모 클래스의 a()가 먼저 메모리에 올라간다. 그 다음 자식의 필드를 완성 시킬 때 같은 이름으로 2개가 만들어지는 것이 아니어도 기존에 만들어진 부모 필드의 a() 메소드에 자식에서 작성한 메소드 내용이 덮어 씌어진다.
      그러므로 자식 객체로 a()메소드를 사용하게 되면 재정의된 기능으로 사용하며 이것을 오버라이딩이라고 한다.
package day10;

public class Road_my {
	public static void main(String[] args) {
//		부모 클래스 객체화
		Moto momcar = new Moto("K8", 4500);
		Suv mycar = new Suv("XC90", 8000, "sports");
		momcar.engineStart();
//		자식 객체는 오버라이딩 한 메소드를 이용하고 있다.
		mycar.engineStart();
	}
}
// 부모 클래스 생성
class Moto {
	String brand;
	int price;
	
//	Car 클래스의 전역 변수를 이용하여 생성자를 오버로딩하였음
	public Moto(String brand, int price) {
		this.brand = brand;
		this.price = price;
	}
	void engineStart() {
		System.out.println(brand + " 시동 켜기");
	}
	void engineStop() {
		System.out.println(brand + " 시동 끄기");
	}
}
// Car클래스를 상속 받는 하위 클래스를 정의한다.

class Suv extends Moto{
	String mode;
//	기본 생성자 super()를 호출 하고 있어서 오류가 발생함.
//	오류가 나지 않으려면 상위 클래스에서 기본 생성자도 정의 해주어야하거나
//	자식 생성자를 오버로딩 해주어야한다.
	public Suv(String brand, int price) {
		super(brand, price);
	}
//	부모의 생성자를 가져와서 자식의 변수를 활용하여 오버로딩 할 수있다.
	public Suv(String brand, int price, String mode) {
//		부모 생성자를 가져옴
		super(brand, price);
		this.mode = mode;
	}
//	자식의 고유 메소드를 정의할 수 있다.
	void roofOpen(){
		System.out.println(brand + " 뚜껑 열기");
	}
//	부모클래스의 메소드를 상속받은 자식 클래스에서 메소드를 오버라이딩 해보자
	void engineStart() {
		System.out.println(brand + " 지문으로 시동 켜기");
	}
	void engineStop() {
		System.out.println(brand + " 지문으로 시동 끄기");
	}
}

static(정적)

  • static이 붙은 변수, 메소드, 구역 등은 프로그램 실행 시 가장 먼저 메모리에 올라간다. static이 붙은 메소드는 내부에서 객체의 필드에 올라오는 일반 전역변수와 일반 메소드는 아직 존재하지 않기 때문에 프로그램 실행 시 해석이 불가하여 사용 할 수 없다. 따라서 static이 붙은 전역변수, static이 붙은 메소드, 자지 자신 안에 선언된 지역변수만 사용할 수 있다.
    static이 붙은 전역변수, 메소드는 모든 객체가 공유한다.
    따라서 static 필드는 클래스 이름으로 직접 접근이 가능하다.
    실제로 공유해야하는 값, 메소드, 필드를 사용하지 않는 메소드에는 static을 붙여서 선언한다. (공유하지 않아야 하는 필드는 무조건 static을 붙이면 안된다.)
    package day10;
    public class Static_example {
    	public static void main(String[] args) {
    		Moto1 momcar = new Moto1();
    //	부모 클래스의 객체가 생성되기 전에 이미 static변수는 메모리에 올라와 있다.
    //	따라서 static변수에 접근하면 momcar를 통한 주소값 접근이 아니라 Moto에서 접근하는 클래스 접근이 이루어진다.
    		momcar.wheel -= 1;
    		Suv1 mycar = new Suv1();
    //		그래서 상속 받는 자식 클래스가 사용할 수 있어도 그 값이 변한다.
    		System.out.println(mycar.wheel);
    	}
    }
    // 부모 클래스 생성
    class Moto1 {
    	String brand;
    	int price;
    //	정적 변수 생성
    	static int wheel = 4;
    }
    // Car클래스를 상속 받는 하위 클래스를 정의한다.
    class Suv1 extends Moto1{
    	String mode;
    }

upcasting, downcasting

upcasting

  • 부모 타입의 객체에 자식 클래스의 필드를 담아주는 것
  • 부모 타입의 객체에 자식 객체를 넣어주는 것
  • 부모 타입의 객체에 자식 생성자를 호출하는 것
  • 업 캐스팅 된 객체는 자식 클래스에서 추가된 내용을 사용 할 수 없다.
    단, 오버라이딩 된 메소드는 가지게 된다.
부모 클래스명 객체명 = new 자식 생성자();
부모 객체명 = 자식 객체;
package day10;

public class Casting_my {
	public static void main(String[] args) {
		IphoneXR up = new Iphone13();
//		아래와 같이 부모 객체가 자식 객체로 객체화 되면 업캐스팅이라고 하며
//		이때 부모 객체는 자식객체에서 오버라이딩 된 메소드를 이용가능하다.
		up.f();
//		단, 아래처럼 자식 클래스의 고유 메소드는 접근이 불가하다.
		// up.f2();
	}
}

class IphoneXR {
	int data; 
	
	void f() {
		System.out.println("아이폰 10의 고유기능");
	}
}

class Iphone13 extends IphoneXR{
	int data2;
	
	void f() {
		System.out.println("아이폰의 공통기능");
	}
	
	void f2() {
		System.out.println(" 아이폰 13의 고유기능 ");
	}
}

downcasting

  • '업 캐스팅 된 객체'를 다시 자식 객체를 담는 기법
  • 업 캐스팅 된 객체에 다식 자식 클래스의 필드를 달아주는 것
  • 업 캐스팅 시 잘려나갔던 자식 클래스의 내용들을 다시 사용할 수 있게 하려면 자식 클래스 타입으로 바꿔주어야 한다.
(자식클래스)업 캐스팅 된 객체
자식클래스 다운캐스팅객체 = (자식클래스)업캐스팅 된 객체;
다운캐스팅객체.필드;

단, 단항연산자는 .인 최우선 연산자의 우선순위 밑임으로 위와 같이 객체에 담아서 사용.

package day10;

public class Casting_my {
	public static void main(String[] args) {
		IphoneXR up = new Iphone13();
//		아래와 같이 부모 객체가 자식 객체로 객체화 되면 업캐스팅이라고 하며
//		이때 부모 객체는 자식객체에서 오버라이딩 된 메소드를 이용가능하다.
		up.f();
//		단, 아래처럼 자식 클래스의 고유 메소드는 접근이 불가하다.
		// up.f2();
//		아이폰 13의 고유기능을 가지고 싶다면 다운캐스팅하여 가져 올 수 있다.
		Iphone13 down = (Iphone13)up;
		down.f2();
	}
}

class IphoneXR {
	int data; 
	
	void f() {
		System.out.println("아이폰 10의 고유기능");
	}
}

class Iphone13 extends IphoneXR{
	int data2;
	
	void f() {
		System.out.println("아이폰의 공통기능");
	}
	
	void f2() {
		System.out.println(" 아이폰 13의 고유기능 ");
	}
}

instanceof

객체 instanceof 클래스 명 : 객체가 뒤에오는 클래스 타입이면 참, 아니면 거짓
부모객체 instanceof 부모클래스 : true;
자식객체 instanceof 자식클래스 : true;
자식객체 instanceof 부모클래스 : true;

//부모객체는 자식 클래스의 고유 기능을 사용할 수 없다.
부모객체 instanceof 자식클래스 : false;

업(다운)캐스팅객체 instanceof 부모클래스 : true

//캐스팅화하면 사용이 가능함
업(다운)캐스팅객체 instanceof 자식클래스 : true

package day10;
public class Casting_my {
	public static void main(String[] args) {
		IphoneXR up = new Iphone13();
//		아래와 같이 부모 객체가 자식 객체로 객체화 되면 업캐스팅이라고 하며
//		이때 부모 객체는 자식객체에서 오버라이딩 된 메소드를 이용가능하다.
		up.f();
//		단, 아래처럼 자식 클래스의 고유 메소드는 접근이 불가하다.
		// up.f2();
//		아이폰 13의 고유기능을 가지고 싶다면 다운캐스팅하여 가져 올 수 있다.
		Iphone13 down = (Iphone13)up;
		down.f2();
		// 다운 캐스팅하면 자식 클래스의 모든 것을 사용할 수 있다.
		System.out.println(down.data2);
		IphoneXR [] arr = {
				new IphoneXR(),
				new Iphone13(),
				new IphoneXR(),
		};
		for (int i = 0; i < arr.length; i++) {
			System.out.println(arr[i]);
			if(arr[i] instanceof Iphone13) {
//				data2에는 자식객체 또는 다운캐스팅한 업캐스팅만 접근이 가능하다.
//				아래와 같이 업캐스팅만 조건문으로 걸러내어 다운캐스팅화 해야한다.
//				앞서 이야기 했듯이 .은 최우선 연선자로 먼저 계산됨으로 아래처럼 괄호로 묶어주어야 한다.
				System.out.println(((Iphone13)arr[i]).data2);
			}
		}
	}
}
class IphoneXR {
	int data; 
	
	void f() {
		System.out.println("아이폰 10의 고유기능");
	}
}
class Iphone13 extends IphoneXR{
	int data2;
	
	void f() {
		System.out.println("아이폰의 공통기능");
	}
	void f2() {
		System.out.println(" 아이폰 13의 고유기능 ");
	}
}
profile
배움은 끝없이

0개의 댓글