ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • 221210. 자바5 (클래스 형변환)
    스타터스 백엔드 3기 2022. 12. 13. 14:14

    하루입니다.

    StaticImportTest, BookMgr, SalaryTest, CastingTest, CastingTest2


     

    복습!

     

    생성자란?

    • 객체 특성을 표현하는 게 아님.
    • 클래스를 정의한 후, 객체를 생성하는 시점에서 수행해야 할 문장들을 정의한 것이다.
    • 생성자는 객체가 생성될 때 생성되기에, new 뒤에 적혀야 한다. 메소드 호출하듯 적을 수는 없다.
    • 클래스명과 같다.
    • 메소드와 유사한 구조를 가지고 있다. 
    •  
    메소드 생성자
    [modifier] 리턴타입 메소드이름 (매개변수) {
           {
                      내용
           }
    }
    [modifier]메소드이름 (매개변수) {
           {
                    객체 생성을 수행하는 문장
                    객체 변수들을 메모리에서 초기화하는 문장
           }
    }

     

     

     

    this

    • 자신 객체를 의미하는 자바 키워드이다.
    • super도 문장 처음에 와야 하기 때문에, 생성자의 경우 동시에 올 수 없다.

    사용법 1. 현재 객체에 포함된 변수와 지역변수(매개변수)의 이름이 같은 경우에 구분하기 위해 사용한다.

                    생성자, 메소드 모두 사용 가능

    사용법 2. this([매개변수]) : 현재 객체의 다른 생성자를 호출하는 용도이다.

                    생성자 내부의 첫 문장에 사용되어야 한다.

     

     

     

     

    패키지 (캡슐화)

    변수와 메소드를 묶어 클래스, 클래스들을 묶어 폴더를 만든다.

     

     

     

    접근제어자

      class 변수 메소드 생성자  
    public O O O O 모든 자바 클래스에서 사용 가능하다.
    protected         현재 패키지의 다른 클래스들 사용 가능하다 + 다른 패키지의 자식 클래스 사용 가능하다.
    no modifier
    (default)
    O O O O 현재 패키지 안의 다른 클래스들은 사용 가능하다.
    private X O O O 현재 자바 클래스 안에서만 사용 가능하다.

     

     

     

     

    상속

    • 기존의 클래스 정의 후에 새로운 클래스 정의시 기존 클래스에 정의된 변수 + 메소드를 필요로 할 때 상속을 사용한다.
    • 위의 상태이며 is - a 관계라면 상속받는다.
    • 위의 상태이며 has - a 관계라면 객체를 생성한다. 클래스 내부에 객체를 가진다는 뜻이다.

     

    상속의 변수

    • 부모 클래스의 변수는 자식 클래스에 자동 포함된다.
    • 단 private 변수에는 접근 불가능하다.
    • 만약 부모 자식 동일 변수가 있다면 자식 클래스가 우선이다.

     

    상속과 메소드 overrideng

    • 부모 자식 동일한 이름의 메소드가 존재한다면
    • 부모에서 정의한 메소드를 자식이 수정한다.
    • 자식의 modifier는 부모보다 같거나 더 넓어야 한다.
    • 리턴타입, 이름, 매개변수까지 완전히 동일해야 한다.
    • 자식클래스의 overriding한 메소드가 우선된다.

     

     

    상속과 생성자

    • 자식클래스 생성자의 첫 문장은 super( ) 가 자동으로 정의된다.
    • 부모클래스 기본 생성자를 호출하는 것이다. 부모객체가 생성되어야 그 안의 데이터를 사용할 수 있기에 자식 객체가 생성될 때 부모 객체도 같이 생성한다.
    • super는 나의 부모 객체를 의미하는 키워드이다.
    • 1. super.변수명                  부모클래스의 변수
    • 2. super.메소드명()            부모클래스의 메소드
    • 3. super()                           자식 클래스에 생성자 첫 문장에 자동으로 호출된다.
    • 4. super(매개변수)             부모 클래스에 기본 생성자가 없다면 부모 클래스에서 매개변수가 정의된 다른 생성자를 호출한다. 명시적 정의가 필요하다.

     

     


     

     

    static import

    // Math의 noStatic 변수와 static의 변수를 모두 사용 허락한다.
    import java.lang.Math
    
    // Math의 static으로 된 변수와 메소드만 사용을 허락하겠다.
    import static java.lang.Math.*;		
    
    // Integer의 static으로 된 변수와 메소드만 사용을 허락하겠다.
    import static java.lang.Integer.*;		
    
    public class StaticImportTest {
    	
    	public static void main(String[] args) {
    		// int ran = (int)(Math.random()*100)+1; 원래 이렇게 적어야 하지만
    		int ran = (int)(random()*100)+1;	// static이라서 math 없애도 된다.
    		// random()은 Stitic 메소드임!
          	  	// public static double random() {    }
    		System.out.println(ran);
    		System.out.println(MAX_VALUE);
    	}
    }

     

     

     

    자바 실행 과정

    • code 검증 - static 변수나 메소드 할당 - main 실행 - 객체 생성 - non-static변수나 메소드 할당
    static 변수 1개 공유 - 클래스 영역 - 객체 생성 이전 할당
    static 메소드 객체 생성 이전 할당
    static 변수만 사용하는 메소드이다.
    객체 생성 이전에 호출이 가능하다.
    non-static 메소드 static 변수 + non-static변수도 모두 사용하는 메소드이다.

     

     

    final

    final 변수 변수갑 수정이 불가하다. 
    상수이다.
    final 메소드 메소드 구현부 수정이 불가하다.
    메소드의 overriding이 불가하다.
    final 클래스 클래스 수정 불가하다.
    상속 후 자식 클래스에서 모든 메소드의 overriding이 불가하다.
    상속이 불가하다.
    모든 메소드에 final을 붙인 것과 같은 의미이다.
    사용하고 싶다면 객체를 생성해서 사용해야 한다.

    사용하는 경우
        0. 프로젝트를 할 때, 공통으로 사용하는 변경 금지인 클래스를 약속할 때 사용한다.
        1. 절대불변의 진리값을 표현하는 경우
        2. 아래의 경우

    class 수학공식 {     
          제곱();  
          제곱근();
           final 근의 공식(); 
    }
    class MyClass extends 수학공식  {
             @override
             근의 공식( ) { }                                      // 오류이다.
    }
    final class 수학공식 {     
          제곱();  
          제곱근();
           근의 공식(); 
    }
    class MyClass extends 수학공식  {           
              // class가 final이라 extends 받는 거 자체가 오류이다.
    }

     

     


     

    다형성.

    내가 제일 좋아하는 다형성!!!

     

    객체지향 언어의 조건

    1. 캡슐화 / 정보은닉

    2. 상속

    3. 다형성 - 이름은 같지만 결과가 다르다.

    overload, overroading

     

    A a1 = new A();

    A a1 = new AA();

     

     

    기본형변수의 형변화 규칙을 다시 보자.

    1. boolean은 제외

    2. (데이터형) 변수 ===> 형변환연산자

        자동형변환 규칙

        byte - short - int - long - float - double

        char -  int - long - float - double

     

    참조형변수의 형변화 규칙을 다시 보자.

    1. 상속관계여야 한다.

    2. 자동형변환 규칙

    • 부모클래스 변수명1 = new 자식클래스객체;
    •  
    • 변수명1.변수       ==>   부모클래스
    • 변수명1.메소드() ==>   부모클래스
    • 변수명1.overriding 메소드()  ==>  자식클래스
    • 부모의 메소드를 자식이 재정의했다면, 자식 클래스의 메소드가 우선이다.

     

    3. 명시적(강제) 형변환

    • 부모클래스 변수명1 = new 자식클래스객체;
    • 자식클래스 변수명2 = (자식클래스명)변수명1;
    •  
    • 변수명2.변수 ==> 부모클래스 + 자식클래스
    • 변수명.메소드() ==> 부모클래스 + 자식클래스

     

     

     

    class A { }

    class B extends A { }

    class C extends A { }

    class D extends C { }

    class F { }
    A a1 = new A(); 형변환 불필요
    A a2 = new B(); 자동형변환 가능
    A a3 = new C(); 자동형변환 가능
    A a4 = new D(); 자동형변환 가능
    A a5 = new F(); 자동형변환 error (상속관계 X)
    B b1 = new C(); 자동형변환 error (상속관계 X)
    B b2 = new D(); 자동형변환 error (상속관계 X)
    B b3 = new A(); 자동형변환 error (부모를 자식으로 변환 불가)
    C c1 = new D(); 자동형변환 가능
    C c2 = new C(); 형변환 불필요

     

    class A { int i = 10; }

    class B extends A { int j = 20; }

    class C extends A { }

    class D extends C { }

    class F { }
    A a1 = new A();


    형변환 불필요

    a1 . i  가능
    B b1 = (B) a1; 컴파일 오류 아니다. 실행오류이다.
    A a2 = new B(); 자동형변환 가능

    a2 . i ;  가능 (A 객체로 판단되어 A객체 접근 가능)
    a2 . j ;  불가능 (B 객체에 접근 불가능)
    B b2 = (B) a2; 명시적 형변환 가능. 자식클래스가 부모클래스에 담겼다가, 다시 자식 타입으로 형변환 되는 경우이다.

    a2 . i ;  가능 (상속받음)
    a2 . j ;  가능
    자식이 부모에 담겼다가 다시 자식 타입으로 형변환 되는 경우만 명시적 형변환이 가능하다. 

     

     

     

    자동형변환과 강제형변환의 존재이유

    부모클래스
          class Tire{  }


    class Car {
          Tire t[] = new Tire[4];
          t[0] = new 한국타이어();
          t[1] = new 뫄뫄타이어();
          t[2] = new 금호타이어();
          t[3] = new 한국타이어();
    }
    자식클래스
          class 한국타이어 extends Tire{ }
          class 금호타이어 extends Tire{ }
          class 뫄뫄타이어 extends Tire{ }
    Test t = new Test();
    t,ma(new 한국타이어())
    t.ma(new 금호타이어())
    clss Test {
          ma(Tire k) {

          }
    }
    상위클래스를 하나 더 두고, 유연하게 사용 가능하도록 한다.
    서로 다른 타입의 여러 객체들이 있으면, 그 객체들의 타입을 통일하는 것이다.

     

     

     

    실습1

    class Parent class Child1 extends Parent class Child2 extends Parent
    Parent p1 = new Parent();
    System.out.println(p1.su);
    p1.print();
    Child1 c1 = new Child1();
    System.out.println(c1.su);
    c1.print();
    Parent p2 = new Child1();
    System.out.println(p2.su);
    p2.print();
    su = 10
    p1.print() = 10
    su = 20
    c1.print() = 20
    su = 10
    p2.print() = 20
    형변환을 했다는 건 앞의 객체를 참조하라는 뜻이다!!! 가리키라는 뜻이다!!!
    - p1이 만들어졌을때 p1은 10번지를 가리킨다.  - parent 객체 먼저 만든다.
    - child1 객체 만든다.
    - c1은 child 가리킨다.
    - child는 parent 가리킨다.
    - parent 객체 먼저 만든다.
    - child1 객체 만든다.
    - p2 변수가 parent를 가리킨다.
    - parent의 su는 10이니까 syso(p2.su)는 10이다.
    - print() 오버라이딩되었기에 child 클래스의 메소드를 사용한다. parent 클래스의 메소드는 감춰진다. 

     

     

     

    실습2

    • p1은 mp() 메소드는 있으나 mc()는 메모리에 존재하지도 않는다.
    • c1은 p1에서 mp()를 상속받고, mc()를 가지고 있어 둘 다 사용 가능하다. 
    • p2는 mc가() 메모리에는 있으나 사용할 수 없다.
    • ((Child1)p2).mc();   이렇게 명시적형변환을 해 주면 사용할 수 있다.

    ((Child1)p2).mc();				// 명시적형변환

     

     

     

     

     

    instanceof

    if(p3 instanceof Child2) {
        ((Child2)p3).mc2();
    } else {
        System.out.println("p3는 child2으로 형변환 불가");
    }

     

    public class CastingTest2 {
    	
    	public static void main(String[] args) {
    		Parent array[] = new Parent[3];
    		// 자동형변환은 여러가지 타입의 객체를 1개 타입으로 통일해서 사용하고 싶어서 사용하는 것이다.
    		array[0] = new Parent();
    		array[1] = new Child1();
    		array[2] = new Child2();
    		
    		for(int i = 0; i < array.length; i++) {
    			System.out.println(
    					array[i].getClass().getName() + ":" + i + "번 인덱스 객체");
    			array[i].print();
                	// Child2 객체인 경우에만 mc2를 호출하려고 한다.
    			if(array[i] instanceof Child2) {
    				System.out.println("if문: " + i);
    				((Child2)array[i]).mc2();
    			}
    		}
    	}
    }
    
    __________________________________________________________________________________
    
    chap7.Parent:0번 인덱스 객체
    10
    chap7.Child1:1번 인덱스 객체
    20
    chap7.Child2:2번 인덱스 객체
    40
    if문: 2
    Child2 클래스

     

     


     

    이 코드를 보아라!

    package chap7;
    
    class Parent {
    	int su = 10;
    	void print() {
    		System.out.println(su);
    	}
    	void mp() {
    		System.out.println("Parent 클래스");	// non-overriding한 메소드이다.
    	}
    }
    
    class Child1 extends Parent {
    //	int su = 10;		부모로부터 상속받은 su = 10;까지 있는 셈이다.
    	int su = 20;
    	void print() {
    		System.out.println(su);	// overriding한 메소드이다.
    	}
    	void mc() {
    		System.out.println("Child1 클래스");	// 자식에서 추가한 메소드
    	}
    }
    
    class Child2 extends Parent {
    	int su = 30;
    	void print() {
    		System.out.println(super.su + su);
    	}
    	void mc2() {
    		System.out.println("Child2 클래스");	// 자식에서 추가한 메소드
    	}
    }
    
    public class CastingTest {
    	public static void main(String[] args) {
    		Parent p1 = new Parent();		// 형변환 발생 x
    		Child1 c1 = new Child1();		// 형변환 발생 x
    		Parent p2 = new Child1();		// 자동형변환 발생
    		
    		System.out.println(p1.su);
    		p1.print();
    		p1.mp();
    		// p1.mc();		메모리에 존재하지도 않음
    		System.out.println(c1.su);
    		c1.print();
    		c1.mp();
    		c1.mc();
    		System.out.println(p2.su);	// 자동형변환발생
    		p2.print();					// 오버라이딩 메소드 - child1
    		p2.mp();					// 사용메소드 - perent
    		// p2.mc();		메모리에 있다. 어떻게 볼 수 있을까?
    		
    		if (p2 instanceof Child1) {
    			((Child1)p2).mc();
    		} else {
    			System.out.println("p2는 child1으로 형변환 불가");
    		}
    		((Child1)p2).mc();				// 명시적 형변환
    		
    		Parent p3 = new Child2();		// 자동형변환 발생
    		System.out.println(p3.su);		// 사용변수 ㅣ parent
    		p3.print();						// 오버라이딩메소드: child2
    		p3.mp();
    		if(p3 instanceof Child2) {
    			((Child2)p3).mc2();
    		} else {
    			System.out.println("p3는 child2으로 형변환 불가");
    		}
    		((Child2)p3).mc2();
    		// 아하! 최초에 만들어진 타입으로 명시적 형변환이 가능한데, child2가 아닌 child1으로 변경하려고 해서 오류가 발생했구나@
    	}
    
    }
    public class CastingTest2 {
    	void setParent(Parent target) {
    		Parent p = target;
    	}
    	
    	public static void main(String[] args) {
    		Parent array[] = new Parent[3];
    		array[0] = new Parent();
    		array[1] = new Child1();
    		array[2] = new Child2();
    		
    		for(int i = 0; i < array.length; i++) {
    			System.out.println(
    					array[i].getClass().getName() + ":" + i + "번 인덱스 객체");
    			array[i].print();
                
    			// Child2 객체인 경우에만 mc2를 호출하려고 한다.
    			if(array[i] instanceof Child2) {
    				System.out.println("if문: " + i);
    				((Child2)array[i]).mc2();
    			}
     	   }
    }

    형변환이 잘 정리되었다고 생각하는 코드이다.

     

     


     

     

     

     

     

Designed by Tistory.