이미지 - 스타터스 취업 부트캠프(STARTERS) 공식 블로그

4주차 학습 내용을 정리합니다.
Java 상속, 형변환, 추상클래스, 인터페이스, 내부클래스, 익명클래스, 예외처리 등의 내용을 학습했습니다.
상속
  • 정의
    • 기존 클래스를 재사용하여 새로운 클래스를 정의하는 것
  • 상속의 장점
    • 썼던 코드를 반복해서 사용하지 않아도 됨
    • 코드를 공통적으로 관리할 수 있음
    • 코드의 추가 및 변경이 용이해짐
  • 특징
    • extends 키워드 사용
    • 상속 관계 (부모 클래스 - 자식 클래스)
    • Java에서 다중 상속은 허용하지 않음 ➡ 이러한 경우, 인터페이스 사용!
    • is-A 관계일 때만 사용! (상속받은 클래스의 모든 기능을 다 갖게 됨)
      • has-A 관계는 (클래스 내부에서) 다른 클래스의 객체를 생성하여 필요한 기능 사용
      • is-A 관계가 아니면 모두 has-A 관계로 생각할 것!  

참조형 변수의 형변환

기본형 변수와 마찬가지로 '참조형 변수'도 형변환이 가능함.

Java에서 "형변환(Type Casting)"은 다형성(Polymorphism)을 보장하는 매우 중요한 개념임!

  • 자동 형변환 (자식클래스 ➡ 부모클래스)
    • 1) 자식 클래스로 객체 생성
    • 2) 생성된 객체를 부모 클래스로 형변환
  • 명시적(강제) 형변환
    • 1) 자식 클래스로 객체 생성
    • 2) 생성된 객체를 부모 클래스로 형변환 ➡ 자동 형변환
    • 3) 자동 형변환된 부모 타입의 변수에서 자식 클래스로 다시 변환  ➡ 명시적(강제) 형변환
  • 명시적(강제) 형변환 제약
    • 초기에 부모 클래스로 생성되어 부모 타입을 갖는 변수가 명시적 형변환으로 자식 타입으로 변경될 수는 없음!
    • 초기에 '자식 클래스'로 생성될 경우 ➡ 가능⭕ 
      • 자식 클래스의 생성자(Constructor)가 호출될 때 내부적으로 가장 먼저 부모의 생성자를 호출함
      • HEAP 메모리 상에 부모 객체와 자식 객체가 존재하고 있으므로 자식 변수는 부모 타입으로 형변환(=접근)이 가능함
      • 이렇게 부모 타입으로 형변환된 변수는 여전히 HEAP 메모리에 자식 객체가 존재하고 있으므로 다시 자식 타입으로 형변환(=접근) 할 수 있음 ➡ 명시적(강제) 형변환
    • 초기에 '부모 클래스'로 생성될 경우 ➡ 불가능❌
      • 부모 클래스의 생성자(Constructor)가 호출될 때 자식 클래스의 생성자가 호출되지는 않음
      • 따라서 HEAP 메모리 상에는 부모 객체만 존재함
      • 이 때 자식 타입으로 형변환을 시도할 경우, 메모리 상에 존재하는 자식 객체가 없으므로 에러 발생 
class Parent {
	int su = 10;
	void print() {
		System.out.println(su); // 10
	}
	// non-overriding 메서드 (부모만의 메서드)
	void mp() { 
		System.out.println("Parent클래스");
	}
}

class Child1 extends Parent {
	// int super.su = 10;
	int su = 20;
	// overriding 메서드
	void print() {
		System.out.println(su); // 20
		// super.su를 쓰려면 오버라이딩을 하지 말아야 함!
	}
	// 자식만의 메서드
	void mc() { 
		System.out.println("Child1클래스");
	}
}

public class CastingTest {

	public static void main(String[] args) {
		
		Parent p1 = new Parent();
		System.out.println(p1.su); // 10
		p1.print(); // 10
		p1.mp();
		p1.mc(); // 컴파일 에러 -> 메모리에 존재하지도 않음!
		
		Child1 c1 = new Child1();
		System.out.println(c1.su); // 20
		c1.print(); // 20
		c1.mp();
		c1.mc();
		
		// 자동 형변환 (자식 -> 부모) - 자식클래스로 생성
		Parent p2 = new Child1();
		System.out.println(p2.su);//10 (부모 멤버 변수 출력)
		p2.print(); // 20 (자식의 오버라이딩된 메서드 실행됨 - this.su)
		p2.mp();6
		p2.mc(); // 컴파일 에러 -> 오버라이딩되지 않은 자식 메서드에는 접근 불가 (기본적으로 자식 객체 접근 불가!)
		// p2.mc()는 메모리에 존재하기는 함 -> "접근할 수 있는 방법이 없을까?" = <명시적 형변환> 필요!
	}

}

 

인터페이스
  • 문제 상황
    • '학생' 클래스가 존재하고 '교직원' 클래스가 존재하는 상황에서 '조교' 클래스를 정의하려고 함
    • 두 클래스의 특성을 모두 갖는 '조교' 클래스는 두 클래스를 상속받으려고 하지만 Java에서 다중 상속은 불가능함
      • 다중상속을 막는 이유 : 상속받는 서로 다른 클래스 내부에 동일한 이름의 멤버 변수 또는 메서드가 존재할 경우, 상황이 매우 복잡해지기 때문!
    • 이러한 문제 상황을 해결하기 위해 '인터페이스' 사용
  • 인터페이스는 일종의 추상 클래스임
    • 오직 추상메서드와 상수만을 변수로 가짐
      • public abstract [메서드명]([매개변수]); ➡ 추상 메서드 (선언부만)
      • public static final [타입] [변수명] = [값]; ➡ 상수
    • 생성자 없음 
      • 인터페이스로 객체 생성 불가
    • 추상 클래스보다 추상화 정도가 더 높음
      • 인터페이스는 '완벽하게 추상적'임!
  • 서로 다른 클래스에 공통적으로 들어가야 하는 메서드 스펙을 정의한 것 (=표준화)
  • 장점
    • 1) 개발 시간 단축 가능
    • 2) 표준화 가능
    • 3) 서로 관계없는 클래스들에게 관계를 맺어줄 수 있음
    • 4) 독립적인 프로그래밍 가능
      • 인터페이스에 꼭 필요한 내용이 정해져 있으니, 서로 다른 코드에서 각자의 부분만 구현하면 됨!
// [1]
interface I { // 이미 메서드 종류(=구조)가 정해져 있으니, 구현에만 신경쓰면 됨!
	void m1();
	void m2();
}

// [2]
interface I { // 이미 메서드 종류(=구조)가 정해져 있으니, 구현에만 신경쓰면 됨!
	void m1();
	void m2();
}

// [3]
// 자식클래스로 객체를 생성하고 부모 인터페이스 타입으로 형변환 (*다형성*)
I i1 = new B();
I i2 = new C();

// B와 C 객체를 하나의 배열 안에 묶을 수 있음!
I[] array = new I[2];
array[0] = i1;
array[1] = i2;
  • 사용 예시
    • 서로 다른 클래스 중 일부 클래스의 부모 클래스가 이미 정해진 상태(= 이미 다른 클래스를 상속받고 있어서 변경이 어려운 상태)라면 Interface를 사용하여 유연하계 대처할 수 있음!

추상클래스
  • 추상 메서드를 하나라도 가지고 있으면 추상 클래스임!
    • 추상 메서드
      • 구현부가 없이 선언부만 존재하는 메서드 (abstract 키워드 사용)
      • 메서드의 내용(=구현부) 구현은 해당 클래스를 상속받는 하위클래스(=구체클래스)에게 맡김
  • 일반적인 메서드(=구체 정의 메서드)도 가질 수 있음
    • 추상 클래스는 "부분적으로 추상적"임!
  • 일반적인 클래스와 동일하게 단 한 개의 클래스만 상속(=extends) 가능 ➡ 단일 상속 

 

내부클래스
  • 소속(= 포함관계)을 분명히하여 사용 방법을 제한할 때 사용
  • 클래스를 마치 멤버 변수처럼 취급함
// A라는 클래스를 외부 클래스에서 사용하지 못하게 하고 나만 사용하고 싶은 경우

class B { // outer class
	
    class A { // inner class
   		.... 
     }
     
     A a1 = new A();
     
 }
 
class C {
 	A a1 = new A(); // 사용 불가!
    ... 
}

 

익명클래스
  • Javascript의 익명 함수와 유사
  • 클래스를 정의하는 동시에 객체를 생성하여 일회성으로 사용
  • 사용 예시
    • 한 클래스가 여러 개의 인터페이스를 복잡하게 구현하고 있을 경우, 클래스와 인터페이스의 관계가 불분명해질 수 있음
    • 여러 인터페이스 중 일부를 분리시켜 클래스와 인터페이스의 관계를 조금 더 명확히 표현하는 것!
interface I1 {
	void m1();
	
}

interface I2 {
	void m2();
}
	

/*
class Anon implements I1, I2 {
	
	public void m1() { }
	public void m2() { }
}
*/


public class AnonymousTest {

	public static void main(String[] args) {
		
		//Anon a = new Anon();
		// a.new I1(); // 인터페이스 타입이라 직접 객체를 생성할 수 없음
		
		// 지역변수처럼 사용 -> 이름이 없으므로 바로 생성한 뒤 사용
		// => 여러 인터페이스 중 일부를 분리시키는 것! *
		// => 인터페이스와의 관계를 좀 더 명확하게 표현하기 위해! **
		//class Anon implements I1 {
		I1 i1 = new I1() { // "이름없는 class 블록 {}" -> i1을 상속받자마자 m1메서드 오버라이딩
			
			public void m1() {
			
				System.out.println("m1 호출");
			
			} // m1 method end
		
		}; // new I1();
		
		// => I1 인터페이스를 상속을 받은 클래스(무명 클래스)를 정의해주고, 동시에 객체를 생성하는 문장 작성
		// => 해당 무명클래스의 객체를 생성하고 타입을 인터페이스 타입으로 형변환 하는 것!
		i1.m1();
		
		// ===============================================================================
		
		// 더 축약된 표현 -> 객체도 일회용으로 사용
		new I1() {
			public void m1() {
				System.out.println("m1 호출");
			}
		}.m1();
		
		// ===============================================================================
		
		I2 i2 = new I2() {
			public void m2() {
				System.out.println("m2 호출");
			}
		};
		
		i2.m2();
	}

}

 

예외처리
  • 예외처리가 필요한 이유
    • 견고한 프로그램을 만들기 위해서는, 발생 가능한 오동작을 미리 처리하여 프로그램이 항상 일정한 동작을 할 수 있도록 보장해야 함!
  • 오류의 종류
    • 컴파일 오류
      • 문법이나 구문이 잘못된 경우, 컴파일러에 의해 사전에 발견되는 오류
      • 소스코드를 수정하기 전까지 사라지지 않음
    • 실행 오류(=런타임 오류)
      • 실행 조건에 따라 발생하기도 하고 발생하지 않기도 하는 오류
      • 에러와 예외의 차이
        • 에러 : 프로그래밍적으로 해결이 불가능한 오류
          • 컴퓨터 전원 OFF
          • 메모리 부족
        • 예외(Exception) : 프로그래밍적으로 미리 처리하여 해결이 가능한 오류
          • 정수를 0으로 나누는 상황
          • 배열의 범위를 넘어서는 인덱스 조회
    • Exception 클래스
      • 예외 상황들을 미리 정의해 놓은 자바 클래스 ➡ Exception 클래스 중 최상위 클래스임
      • 대표적 예시
        • java.lang.ArithmeticException : 산술연산과 관련된 예외 정의
        • java.lang.ArrayIndexOutOfBoundException : 비정상적인 인덱스에 접근할 때 발생하는 예외
    • 예외처리 키워드
      • try-catch-finally
        • 예외 직접 처리 
        • 예외가 발생하고 있는 메서드 내부에서 예외를 직접 처리할 때 사용
        • 메서드 구현부 내부에 문장으로 작성
          • try문 ( = try { ... })
            • 내부에 예외상황이 발생할 것 같은( 또는 발생할 수 있는) 문장 - 일반적인 소스코드 - 가 포함됨
            • 예외상황이 발생하면 try문의 코드가 중단되고 곧바로 catch문으로 넘어감
          • catch문 (= catch ([예외클래스명] [변수명]) { ... })
            • try문 내부에서 예외상황이 발생했을 때 곧바로 catch문 블록으로 이동함
            • 해당 예외가 발생했을 때 처리할 로직을 작성
          • finally문 (= finally { ... })
            • try문이 종료되거나 catch문이 종료되었을 때, 반드시 실행되어야 하는 문장들이 포함된 블록
            • try문에서 예외처리가 발생하여 코드 실행이 중단되더라도 반드시 실행되어야 하는 부분은 finally문 내부로 이동시켜야 함! 
      • throws
        • 예외 간접 처리
        • 예외가 발생하고 있는 메서드 이외의 다른 메서드(=일반적으로 상위 클래스의 메서드)에서 처리하도록 예외 상황을 떠넘길 때 사용
          • 해당 클래스의 메서드에서 처리를 안 한다는 것 뿐이지, 상위 클래스에서 try-catch문으로 예외처리가 필요함!
        • 메서드 선언부에 키워드로 작성
          • throws [예외클래스명] { ... }
          • 발생할 수 있는 예외상황을 미리 파악(가정)하여 작성
      • throw
        • 의도적으로 예외를 발생시킴
        • 일반적으로 발생하면 안되는 상황을 조건식(if문)으로 가정하고 그 안에서 throw 키워드를 사용하여 예외 발생시킴
          • 예외가 발생하면 예외 상황이 상위클래스로 전달(throw)되므로, 상위 클래스에서 try-catch문으로 예외처리가 필요함!
        • 메서드 구현부 내부에 문장으로 작성
try {
	FileReader fr = new FileReader("a.txt");
	fr.read(); // 예외 발생 - 중단 (-> close 메서드 수행되지 못함)
  ...
  //fr.close(); // 중간에 예외가 발생하여 중단되더라도 이 부분은 반드시 실행되어야 함
} catch (AExcepction e) {
  ...
} finally {
  fr.close(); // finally 문 안으로 fr.close() 옮김!
}

try-catch-finally 문 상황 예시

 


회고

이번주 후반부터 남은 Udemy Java 기초 강의는 살짝 뛰어넘고, JSP 강의를 듣기 시작했습니다. JSP와 servlet의 기초 강의부터 상속, 인터페이스, 제어자, 추상클래스 등 그동안 열심히 배웠던 자바 개념들이 복합적으로 등장했습니다. 반갑기도 했지만 솔직히 좀 놀랐습니다. 왜 그렇게 사람들이 기초 문법을 중요시하는지 단번에 이해가 되었습니다. 남은 기초 문법 강의도 열심히 수강하고 정리해두면 이후 과정에 큰 도움이 될 것 같습니다. 

 

 


참고

  • 자바의 정석 기초편(2019), 도우출판, 남궁성 저 

* 유데미 바로가기 : https://bit.ly/3V220ri

* STARTERS 취업 부트캠프 공식 블로그 보러가기 : https://blog.naver.com/udemy-wjtb

본 후기는 유데미-웅진씽크빅 취업 부트캠프 3기 백엔드 과정 학습 일지 리뷰로 작성되었습니다.

+ Recent posts