[Java] instanceof 연산자/다형성/자바프로그램실행과정/static

2022. 10. 5. 14:53Dev.Program/Java & Spring

728x90

p260

  • 형변환을 처리하다가 java.lang.ClassCastException을 발생
    • ⇒ 뭔가 해선 안되는 변환을 했다고 알려주는 오류!

< instanceof 연산자 >

  • 좌변의 객체(참조변수)가 우변 클래스의 타입인지 판별하는 연산자
    • (=실제 메모리에 있는 객체가 특정클래스 타입인지를 boolean 타입으로 리턴)
  • 판별 결과가 true 이면 형변환이 가능한 관계(업캐스팅 또는 다운캐스팅)
  • 판별 결과가 false 이면 절대로 형변환 불가능
  • 형변환을 바로 수행하지 않고, instanceof 연산자를 통해 검사 후 수행하는게 안전하다

< 기본 문법 >

if(A instanceof B) {}
⇒ A 는 참조변수, B 는 클래스명

 

======== 오늘날짜 프로젝트 만들고 Ex.java 만들기

- in 까지만 치고 ctrl + space 누르면 자동완성

- 오류! 뒤에는 변수명 아니고 클래스명 (A is a B 생각해보기)

  • 기본 문법 [참조변수 instanceof 클래스명]
  • instance of 아니고 instanceof(띄어쓰기X) 입니다(자주하는 실수!! 특히 필기시험!!!!)

- c is a Parent? 질문과 동일

  • 이건 아니다! 가 떴으니까 변환하면 오류난다는 것!
class HandPhone {
	String number;
	String model;
	
	public HandPhone() {}
	
	public HandPhone(String number, String model) {
		this.number = number;
		this.model = model;
	}
	
	public void call() {
		System.out.println("전화 기능!");
	}
	
	public void sms() {
		System.out.println("문자 기능!");
	}
	
}
class SmartPhone extends HandPhone {
	String osName;

	 → 이 자리에서 Alt + Shift + S → O
	public SmartPhone(String number, String model, String osName) {
		super(number, model);
		this.osName = osName;
	}
	→ 그럼 이 부분 자동 생성됨

	public void kakaoTalk() {
		System.out.println("카톡 기능!");
	}
	
}



if(sp instanceof HandPhone) { // sp는 HandPhone 입니까?
	System.out.println("sp는 HandPhone 이다!");
	System.out.println("그러므로 sp 는 HandPhone 으로 형변환이 가능하다!");
	HandPhone hp = sp;
} else {
	System.out.println("sp는 HandPhone이 아니다!");
}
 
  • 업캐스팅, 자동형변환(=묵시적 형변환)이 일어남.
  • 스마트 폰 고유의 기능은 못쓴다!

문제 ) hp 는 SmartPhone 입니까? 만들어보기.

if(hp instanceof SmartPhone) {
    System.out.println("hp는 SmartPhone 이다!");
} else {
    System.out.println("hp는 SmartPhone이 아니다!");
}
 
  • 출력창

 

이렇게 가능 한 경우가 딱 한가지 있었다! (업캐스팅 후 다운캐스팅 하기)

HandPhone hp2 = new SmartPhone("010-1111-2222", "갤럭시S9", "안드로이드");
 

업캐스팅 수행

문제 ) hp2 는 SmartPhone 입니까? 다시 물어보기.

if(hp2 instanceof SmartPhone) {
	System.out.println("hp2 는 SmartPhone 이다!");
} else {
	System.out.println("hp2는 SmartPhone이 아니다!");
}
 
  • 출력창
  • 위랑 질문이 똑같은데 스마트폰이라고 출력됨(true 출력)
  • 그러므로 hp2 는 SmartPhone 으로 형변환 가능!

⇒ 그런데 적으면 오류남. Why? 자동 형변환이 지원 안되기 때문.

⇒ 강제 형변환이 필요하다

 

  • 원래의 모든 기능들 다 사용 가능.



p.261

======== Ex2.java 만들기

p.264

< 동적 바인딩 >

  • 상속 관계에서 업캐스팅 후 메서드를 실행할 때 컴파일(번역) 단계에서의 실행 대상과, 실행 단계에서의 실행 대상이 달라지는 것
  • 참조 변수의 타입과 무관하게 실제 인스턴스의 메서드를 실행하는 것
  • 단, 멤버변수를 사용할 때에는 참조변수 타입에 따라 접근되는 변수가 달라짐

 

Ex.java 에서 Parent, Child 긁어오기 (2로 만들기)

> Child2 클래스 안에 오버라이딩 자동으로 시켜보기

@Override
public void parentPrn() {
    System.out.println("서브클래스에서 오버라이딩 된 ParentPrn()");
}
 
  • Alt + Shift + S → V (오버라이딩 자동완성)

  • p.parentPrn(); 만 보면 슈퍼클래스의 parentPrn()만 안다.
  • 번역하는 시점에선모름. 실제 실행하는 시점에서 아는거
    • ⇒ 이 걸 동적 바인딩이라고 부름

  • ⇒ Parent2 타입이기 때문에 Child2꺼 안보임
  • → 실행하는 시점이 되어서야 Parent2가 아니라 Child2꺼라는걸 알게 되서 출력창에선 Child2 의 parentPrn()을 실행시켜줌.

 

p.263 (3) - p.264

> 동적 바인딩은 메서드()에만 해당

  • Child2 의 String name = "Child2"; 인데 Parent2 가 나옴. (동적 바인딩 X)
  • 변수는 말 그대로 변할 수 있는 값! 굳이 부모의 변수명을 똑같이 가져 올 필요는 없다.
    • → 메서드()는 실제 인스턴스에 따라 달라짐
    • → 멤버변수는 참조변수 타입에 따라 달라짐




======== Ex3.java 만들기

다형성 얘기 하다 말아서 마저….ㅎㅎ

p.254 다형성

< 다형성 >

  • 상속은 기본 전제
  • 하나의 참조변수로 여러 인스턴스를 참조할 수 있는 특성
  • 인스턴스를 업캐스팅 하여 슈퍼클래스 타입으로 서브클래스의 멤버를 다루는 것
  • 독립적으로 만들어진 애들( 밑에 print()나 design() ) 은 사용 못함 ⇒ 단점
    • → 그러나 다시 다운캐스팅 해서 쓸 수는 있다
  • 업캐스팅 왜 하는지, 다형성 왜 쓰는지 ? 코드의 통일성을 위해서! (장점)
class Shape {
	public void draw() {
		System.out.println("도형 그리기!");
	}
}

class Circle extends Shape {

	@Override
	public void draw() {
		System.out.println("원 그리기!");
	}
}

class Rectangle extends Shape {

	@Override
	public void draw() {
		System.out.println("사각형 그리기!");
	}
}

class Triangle extends Shape {

	@Override
	public void draw() {
		System.out.println("삼각형 그리기!");
	}
}
 

 

	public void paint() {
		System.out.println("원 그리기(paint)!");
	}
  • class Circle extends Shape{} 에 추가
	public void design() {
		System.out.println("사각형 그리기(design)!");
	}
  • class Rectangle extends Shape{} 에 추가

 

> 슈퍼클래스의 메서드를 상속받아 오버라이딩을 할 경우 코드의 통일성이 향상되어 오버라이딩을 통해 draw(); 이름을 똑같이 만들어준다.

그런데,

		c.draw();
		r.draw();
		t.draw();
 

이렇게 하는 것 보다 더 통일성을 줄 수 있다!

 

코드의 통일성을 더욱 향상시키기 위해 업캐스팅 활용

⇒  Circle과 Rectangle과 Triangle의 공통 슈퍼클래스인 Shape 클래스 타입 활용

		Shape s = c;
		s.draw();
		
		s = r;
		s.draw();
		
		s = t;
		s.draw();
 

이렇게 가능.

 

근데 s.print(); 나 s.design(); 은 가능할까? No.

  • 오류!  부모가 이 메서드를 모름!

그래서 오버라이딩을 시킨다! (오버라이딩 하는 이유!)




> 다형성을 배열에 적용시키는 경우

	Shape[] sArr = new Shape[3];
	sArr[0] = new Circle(); // Circle → Shape 업캐스팅
	sArr[1] = new Rectangle(); // Rectangle → Shape 업캐스팅
	sArr[2] = new Triangle(); // Triangle → Shape 업캐스팅
 
  • 원래 배열을 생성하려면 이렇게 각각 생성해야하는데

  • 한번에 배열에 초기화 시키기!
  • 이 자체가 업캐스팅이 수행된 것.

  • 한번에 실행할 수 있다!

 

> 메서드에 다형성 활용

  • 이게 한 번에 수행되려면 물음표 안에 뭐가 들어가야 할까?

		polymorphism(c); // Circle → Shape
		polymorphism(r); // Rectangle → Shape
		polymorphism(t); // Triangle → Shape
		
	}

	public static void polymorphism(Shape s) {
		// 메서드 호출 시 업캐스팅 일어남
		s.draw();
	}
 
  • Shape s 만 넣어주면 한번에 오류 없어짐!

 

⇒ 뒷 부분에 추상클래스까지 배우면 완벽한 코드의 통일성을 쓸 수 있다!!!






p.182   3.3

======== Ex4.java

class StaticMember {
	int a = 10;
	int b = 20;
}
 

 

  • 출력창 보면 s1.a 랑 s1.b 만 바뀜!
class StaticMember {
	static int a = 10;
	int b = 20;
}
 

  • 앞에 static 써주면 a 기울어짐!

⇒ int a 앞에 static만 붙여줌! (차이)

  • s1.a 값만 바꾼건데 s2.a 값까지 같이 바뀜(출력창) ⇒ static 변수이기 때문
  • 정적(static) 변수 = 모든 인스턴스에서 공유하는 멤버변수



  • StaticMember.a 로 접근하라고 경고창 띄워줌 (실행하면서 오류는 안남)
  • ⇒ 정석대로 사용하는 방법(결과는 같음)



  • 참조 변수 선언 전에 접근 불가
  • 일반 멤버변수는 반드시 인스턴스 생성 후 참조변수를 통해서만 접근이 가능

  • 근데 얘는 된다!
  • static 멤버변수의 경우 클래스명만으로 인스턴스 생성과 상관없이 접근이 가능

 

  < 자바 프로그램 실행 과정 >

0. 소스 코드 작성 및 컴파일(번역) 후 클래스 실행

1. 클래스 로딩 ⇒ static 변수 및 메서드가 메모리에 로딩됨

2. main() 메서드 실행 (자동 실행)

3. 인스턴스 생성 ⇒ 인스턴스 변수 및 메서드가 메모리에 로딩됨

4. (인스턴스 내의) 메서드 호출(실행) ⇒ 메서드 내의 로컬 변수가 메모리에 로딩됨

5. 결과 출력됨

System.out.println("StaticMember.a : " + StaticMember.a);

⇒ 그래서 바로 위의 이 문장이 오류가 안난거

인스턴스 생성을 하지 않더라도 접근 가능! “ 1. ” 에서 static 변수가 메모리에 로딩되기 때문.

  • 우리는 항상 3번부터 시작했었다! ( 오늘 배운 static 을 배우기 전까지는 )

 

< static 키워드 >

  • 클래스, 메서드, 변수의 지정자로 사용
  • 메서드 또는 변수에 static 키워드를 사용할 경우 인스턴스 생성과 상관없이 클래스가 로딩되는 시점에 함께 메모리에 로딩됨
    • ⇒  따라서, 참조변수 없이 클래스명만으로 해당 멤버에 접근 가능

< 기본 문법 >

클래스명.멤버변수
또는
클래스명.메서드()
 

⇒ 이 시점에선 참조변수가 없기 때문에 클래스명. 을 사용

    (참조변수가 있을 수도 있지만 클래스명. 을 사용하는게 좋음!)

  

 < static 변수 >

  • 인스턴스 생성 전, 클래스가 메모리에 로딩될 때 static 변수도 함께 로딩됨
  • 참조변수 없이 클래스명만으로 해당 멤버에 접근 가능
  • 멤버변수에 static 키워드를 사용할 경우 클래스 변수(정적 변수)로 취급되며 모든 인스턴스가 하나의 변수를 공유함(클래스 당 하나만 생성됨) 
  • 로컬변수가 만들어지는 시점 : 4. 메서드 호출()
    • 없어지는 시점 : 메서드가 끝나는 시점
  • 인스턴스변수가 만들어지는 시점 : 3. new 할 때!
    • 없어지는 시점 : 인스턴스가 끝나는 시점
  • static 변수가 만들어지는 시점 : class 가 시작될때
    • 없어지는 시점 : class 가 끝날때 (=프로그램 종료)

 

p. 192

< Ex4.java >

자신의 클래스 내의 메서드에서 static 변수나 인스턴스 변수 접근 방법 동일

 

 

728x90