ToBe끝판왕

[ JAVA ] 타입 변환과 다형성 , 중첩클래스 , 익명구현객체 , 예외 본문

■ 프로그래밍 SKILLS/JAVA

[ JAVA ] 타입 변환과 다형성 , 중첩클래스 , 익명구현객체 , 예외

업그레이드중 2022. 5. 27. 22:09
반응형

 


 

타입 변환

 

•  다형성을 위해 부모클래스로 타입변환을 허용한다.

•  부모타입에 모든 자식 객체가 대입이 가능하다.

•  특정 자식을 통해 만들어진 부모는 그 자식으로만 강제 형변환 가능하다.

•  모든 클래스는 Object 로 자동 형변환이 가능하다.

 

class Parent {
	Parent() {
    	System.out.println( "Parent 생성자" );
    }
}

class Child {
	Child() {
    	System.out.println( "Child 생성자" );
    }
}

public class Study {
	
    public static void main( String[] args ) {
    	
        Parent p = new Parent();
        Child c1 = new Child();
        
        Child c2 = c1;		// 얕은복사
        System.out.println( c2 );
        System.out.println( c1 );
        
        // 자동 형변환
        Parent p2 = c1;		// 부모 형변환
        System.out.println( p2 );
        System.out.println( c1 );
        Parent p3 = new Child();
        
        // 모든 클래스 Object로 자동형변환 가능
        Object obj1 = new Child();
        Object obj2 = new Parent();
        
        // 강제 형변환
        Child c3 = (Child)p2;
        
        /*
        
        - 에러- 
        Child c4 = ( Child )p;
        Child c5 = ( Child )new Parent();
        
        반드시 자식을 통해서 만든것만 자식으로 강제 형변환 가능하다.
        특정 자식을 통해서 만들어진 부모는 그 자식으로만 강제 형변환 된다.
        p : Parent로 만듬
        p2 : Child로 만듬
        p2만 Child로 강제 형변환 가능
        
        */
    }
}

 

 

▶ 자동 타입 변환

•  작은 타입에서 큰 타입으로의 변환을 말하지만, 객체의 상속에서 자식클래스가 부모클래스보다 작으므로

    자식클래스에서 부모클래스로의 형변환은 자동타입변환이다.

Cat cat = new Cat();

Animal animal = cat;

/*

cat과 animal은 같은 Cat객체를 참조 즉, 같은 주소값을 가지므로
자동타입변환이 일어난것이다.

*/

 

•  바로 위 부모가 아니더라도, 상속 계층에서 상위 타입이라면 자동타입변환이 일어날 수 있다.

•  부모타입으로 자동타입변환 후, 부모클래스에 선언된 필드와 메서드만 접근이 가능하다.

•  변수로 접근 가능한 멤버는 부모클래스 멤버로만 한정된다.

•  예외는, 메서드가 자식클래스에서 오버라이딩 되었다면 자식클래스의 메서드가 대신 호출된다.

 

 

 상속과 자동타입변환에 대한 예제

-  D 객체는 B 와 A 타입으로 자동타입변환 가능하다.

-  E 객체는 C 와 A 타입으로 자동타입변환 가능하다.

-  D 객체는 C 타입으로 변환 X

-  E 객체는 B 타입으로 변환 X

class A {}
class B extends A {}
class C extends A {}

class D extends B {}
class E extends C {}

public class Study {

    public static void main( String[] args ) {
        
        B b = new B();
        C c = new C();
        D d = new D();
        E e = new E();

        // 자동형변환
        A a1 = b;
        A a2 = c;
        A a3 = d;
        A a4 = e;

        B b1 = d;
        C c1 = e;

        // 상속되지 않았으므로 자동형변환 불가 - 컴파일에러 발생
        // B b3 = e;
        // C c2 = d;
    }
}

 

 

▶  강제 형변환

String 클래스의 toString() 메서드를 재정의하고 배열을 이용하여 부모타입인 objs 변수를

Car타입으로 자동변환한 후, 다시 objs를 Car타입으로 강제형변환해서 출력해보자.

class Car {
    private String name;
    private int numberOfWheels;
    private String color;

    Car( String name, int numberOfWheels, String color ) {
        this.name = name;
        this.numberOfWheels = numberOfWheels;
        this.color = color;
    }
    
    // override
    public String toString() {
        return name + ":" + numberOfWheels + ":" + color;
    }
}

public class Study {

    public static void main( String[] args ) {
        Car[] cars = new Car[3];
        Car car1 = new Car( "test1", 3, "Green" );
        Car car2 = new Car( "test2", 4, "White" );
        Car car3 = new Car( "test3", 5, "Black" );

        cars[0] = car1;
        cars[1] = car2;
        cars[2] = car3;

        for( Car car : cars ) {
            System.out.println( car );
        }

        Object[] objs = new Car[3];
        objs[0] = car1;
        objs[1] = car2;
        objs[2] = car3;

        for( Object obj : objs ) {
            Car car = ( Car )obj;
            System.out.println( car );
        }
    }
}

 

 

 

다형성

 

하나의 객체가 여러가지 타입을 가질수 있는것을 의미한다.

부모클래스 타입의 참조변수를 통해서 자식클래스 타입의 인스턴스를 참조할 수 있도록 한다.

animal = new Cat();
animal.sound();

animal = new Cow();
animal.sound();

위 두개는 다른 sound()를 불러오는데
이것을 다형성이라고 할 수 있다.

 

 

1) 다형성은 abstract로 구현 가능 ( 부모클래스를 abstract화 한다. )

class Emplyee {
	void salary() {
    	System.out.println( "Employee salary()" );
    }
}
abstract class Employee {
    abstract void salary();
}

class ChildEmployee1 extends Employee {
    void salary() {
        System.out.println( "임원 Salary()" );
    }
}

class ChildEmployee2 extends Employee {
    void salary() {
        System.out.println( "정직원 Salary()" );
    }
}

public class StudyEx {

    public static void main( String[] args ) { 
    
        // 기본호출방법
        ChildEmployee1 ce1 = new ChildEmployee1();
        ce1.salary();
        ChildEmployee2 ce2 = new ChildEmployee2();
        ce2.salary();

        // 다형성을 이용한 호출방법
        Employee e1 = new ChildEmployee1();
        Employee e2 = new ChildEmployee2();
        e1.salary();
        e2.salary();
    }
}

 

 

2) 다형성은 Interface로 구현 가능( 부모클래스를 interface로 둔다. )

interface Tire {
	void roll();
}

class HankookTire implements Tire {
	@Override
    	public void roll() {
    	System.out.println( "한국 타이어가 굴러갑니다." );
    }
}

class KumhoTire implements Tire {
	@Override
    	public void roll() {
    	System.out.println( "금호 타이어가 굴러갑니다." );
    }
}

// Tire. 객체를 만드는 클래스
class Car {
	Tire frontLeftTire = new HankookTire();
    	Tire frontRightTire = new HankookTire();
   	Tire backLeftTire = new HankookTire();
    	Tire backRightTire = new HankookTire();
    
    public void run() {
    	frontLeftTire.roll();
        frontRigthTire.roll();
        backLeftTire.roll();
        backRightTire.roll();
    }
}

public class CarExample {

	public static void main( String[] args ) {
    	
        Car myCar = new Car();
        
        myCar.run();
        
        // 자식인 KumhoTire로 다시 만듬
        myCar.frontLeftTire = new KumhoTire();
        myCar.frontTRightTire = new KumhoTire();
        
        myCar.run();
    }
}

 

 

▶  instanceof ( 객체타입 확인 )

모든 상속, 포함관계를 알 수 있고

만약 부모클래스가 자식클래스로 만들어진다면 부모 instanceof 자식 = true 가 성립한다.

interface Vehicle { 

}

class Bus implements Vehicle { 

}

class Taxi { 

}

public class Study {

    public static void main( String[] args ) { 
    
        Vehicle v = new Bus();
        Taxi t = new Taxi();

        System.out.println( v instanceof Bus );
        System.out.println( v instanceof Object );
        System.out.println( v instanceof Vehicle );
        System.out.println( t instanceof Vehicle );
    }
}

 

 


 

중첩 클래스 / 중첩 인터페이스

 

•  클래스 내부에 선언한 클래스

( 클래스가 여러 클래스와 관계를 맺는 경우에는 독립적으로 사용하는것이 좋지만 특정 클래스와 관계를

맺을 경우에는 관계클래스를 클래스 내부에 선언하는 것이 좋다. )

 

•  두 클래스 멤버들을 서로 쉽게 접근할 수 있는 장점이 있다.

•  외부에는 불필요한 코드를 감춤으로써, 코드의 복잡성을 줄일 수 있는 장점이 있다.

•  중첩클래스는 메서드 실행시에만 사용되며 메서드가 실행 종료되면 없어진다.

 

 

▶  중첩클래스의 종류

선언 위치에 따른 분류 선언위치 설명
멤버 클래스 인스턴스
멤버 클래스
class A {
      class B { ... }
}
A 객체를 생성해야만 사용할 수 있는 B 중첩 클래스
정적
멤버 클래스
class A {
     static class B { ... }
}
A 클래스로 바로 접근할 수 있는 B 중첩 클래스
로컬 클래스 class A { 
     void method() {
          class B { ... }
     }
}
method( ) 가 실행할때만 사용할 수 있는 B 중첩클래스

 

 

▶  인스턴스 멤버 클래스

인스턴스 필드와 메서드만 선언이 가능하고 정적 필드와 메서드는 선언 불가능

class Outer {

    //멤버필드
    private int x1 = 100;
    public int x2 = 100;

    Outer() {
        System.out.println( "Outer 생성자" );
    }

    //인스턴스 멤버 중첩 클래스
    class Inner {
        private int y1 = 200;
        public int y2 = 200;

        Inner() {
            System.out.println( "Inner 생성자" );
        } 

        public void viewInner() {
            System.out.println(x1);
            System.out.println(x2);
            System.out.println(y1);
            System.out.println(y2);
        }
        
    }
}

public class Study {

    public static void main( String[] args ) {
    
        Outer o = new Outer();
        Outer.Inner oi = o.new Inner();

        // 바로 o.x1을 호출하면 오류 ( 접근제한 때문 )
        // System.out.println( o.x1 );
        
        // 중첩클래스 생성
        System.out.println( o.x2 );

        // 줃첩클래스인 oi객체의 viewInner()을 이용하면 private접근제한이 걸린 멤버필드를 읽을 수 있다.
        oi.viewInner();
    }
}

 

 

▶  정적 멤버 클래스

•  모든 종류의 필드와 메서드를 선언 가능

•  외부클래스 객체를 만들 필요 .X ( 외부클래스 , 중첩클래스로 객체 만들 수 있다. )

class Outer {

    // 멤버필드
    private int x1 = 100;
    public int x2 = 100;

    Outer() {
        System.out.println( "Outer 생성자" );
    }

    // 인스턴스 멤버 중첩 클래스
    static class Inner {
        private int y1 = 200;
        public int y2 = 200;

        Inner() {
            System.out.println( "Inner 생성자" );
        }

        public void viewInner() {
            // System.out.println(x1);
            // System.out.println(x2);
            // static이여서 안됨
            
            System.out.println(y1);
            System.out.println(y2);
        }
        
    }
}

public class Study {

    public static void main( String[] args ) { 
    	 // Outer o = new Outer();
         
        Outer.Inner oi = new Outer.Inner();
        oi.viewInner();
    }
}

 

 

▶ 로컬 클래스

•  메서드가 실행 될 때 메서드 내에서 객체를 생성하고 사용해야 함

•  외부클래스에서 메서드를 선언하고 그 메서드 안에 중첩클래스를 선언

class Outer {

    void viewInner() {
    
        // viewInner를 호출하면 Inner 클래스를 선언
        class Inner {
            void view() {
                System.out.println("view 호출");
            }
        }
        
        // class Inner 안의 view() 메서드를 실행시킨다.
        Inner i = new Inner();
        i.view();
    }
}

public class Study {

    public static void main( String[] args ) { 
    
        Outer o = new Outer();
        o.viewInner();
    }
}

 


 

익명 객체

 

•  프로그램에서 일시저기으로 한번만 사용되고 버려지는 객체( 재사용 X , 확장성 좋지 않다. )

•  실행클래스에서 바로 인터페이스 타입의 객체를 만들고 중괄호 안에서 추상메서드를 재정의하여 바로 사용하는 것

•  클래스와 인터페이스로부터 만들 수 있다.

 

 

▶  익명객체 예

interface Inner {

    int x = 10;
    void viewInner();	// 내용 구현 X , 추상메서드 선언
}

public class Study {

    public static void main( String[] args ) { 
    
        int y = 100;
        
        // 익명 inner class
        Inner i = new Inner() {
            public void viewInner() {
                System.out.println( x );
                
                // 지역변수 접근 가능
                System.out.println( y );  
            }
        };

        i.viewInner();
    }
}

 

 

▶  익명객체 로컬변수 사용

익명객체 내부에서는 외부 클래스의 필드나 메서드를 제한없이 사용 가능하다.

메서드 내에서 생성된 익명객체는 메서드 실행이 끝나도 Heap 메모리에 존재해 계속 사용이 가능하다.

But, 매개변수나 로컬변수는 메서드 실행이 끝나면 Stack 메모리에서 사라지기 때문에 문제가 발생한다.

 

=> 익명객체 내부에서 메서드의 매개변수 / 로컬변수를 사용할 경우 final 특성을 가져야 한다. ( final 키워드 자동 생성 )

interface Calculatable {
    public int sum();
}

class Anonymous {
    private int field;
    
    public void method( final int arg1, int arg2 ) {
        final int var1 = 0;
        int var2 = 0;

        field = 10;

        Calculatable calc = new Calculatable() {
            @Override
            public int sum() {
                int result = field + arg1 + arg2 + var1 + var2;
                return result;
            }
        };

        System.out.println( calc.sum() );
    }
}

public class Study {

    public static void main( String[] args ) { 
    
        Anonymous a = new Anonymous();
        a.method(0, 0);
    }
}

 


 

예외 / 예외 클래스

 

•  예외란 사용자의 잘못된 조작 or 개발자의 잘못된 코딩으로 인해 발생하는 프로그램 오류

•  예외는 예외처리를 통해 프로그램을 종료하지 않고 정상 실행 상태가 유지도되도록 할 수 있다.

 

▶  예외 종류

-  일반 예외( = 컴파일러 체크 예외 ) : 자바 소스를 컴파일 하는 과정에서 예외 처리 코드가 필요한지 검사

                                                                 ( 예외처리코드가 없다면 컴파일 오류 발생 )

-  실행 예외 : 컴파일 하는 과정에서 예외 처리 코드를 검사하지 않는 예외

 

 

•  참고페이지

https://baby9235.tistory.com/37?category=1021977 

 

[ JAVA - 예외 ] Exception 개념 / 예외처리( try-catch문 )

자바에서 코딩을 하다보면 Exception , 예외처리를 한 코딩을 많이 볼 수 있는데 Exception의 개념과 예외처리를 어떻게 하는지에 대해 정리해보려 한다. Exception Exception( 예외 ) 는 오류의 일종이며,

baby9235.tistory.com

 

 

 

▶  런타임에러 예 ( 0으로 나누기 상황 )

•  if 조건문 혹은 try ~ catch문으로 예외처리를 해주어야 한다.

public class Study {

    public static void main( String[] args ) { 
    
        System.out.println( "시작" );

        //int num1 = 2;
        int num1 = 0;
        int num2 = 10;
        int result = num2/num1;
        System.out.println( result );

        System.out.println( "종료" );
    }
}

 

 

▶  문자열 변수 null 일 경우 예외

public class Study {

    public static void main( String[] args ) { 
        System.out.println( "시작" );

        String data = null;
        System.out.println( data.toString() );
        
        System.out.println("종료");
    }
}

 

 

반응형
Comments