2023.01.31 - 안드로이드 앱개발자 과정

CHA·2023년 1월 31일
0

Java



Object class

모든 Java 클래스의 부모 클래스(최상위 클래스)


단군 할아버지 Object

자바 언어에 존재하는 모든 클래스들은 extends 의 명시여부와 상관없이 무조건 Object 라는 클래스를 상속받은 상태로 만들어 집니다. Test 클래스를 설계해봅시다.

-------------- Test.java
public class Test {
	int a = 10;
}
-------------- Main.java
public class Main {
	public static void Main (String[] args) {
    	Test t = new Test();
    }
}

Test 클래스는 명시적으로는 아무 클래스도 상속하지 않았습니다. 그러나 기본적으로 Object 클래스를 상속받고 있습니다. 만일, 명시적으로 First 라는 클래스를 Test 가 상속받았다고 하더래도 Object 클래스는 상속됩니다. 다만, 다중상속의 개념은 아니고 Object 클래스를 상속받는 First 클래스를 Test 가 상속받으므로, 줄줄이 사탕 개념입니다.


Object 가 가진 기능메소드!

1. toString()

- 객체에 대한 소개 문자열을 리턴해주는 메소드

  • 사용법

    Test t = new Test();
    System.out.println(t.toString());
    // 출력결과 : Test@6504e3b2

    toString() 의 리턴값이 패키지명.클래스명@해시코드 의 형태로 리턴됩니다.(해시코드란 메모리 물리주소를 상대적인 주소로 표현한 숫자입니다. 자바에서의 주소라고도 합니다.)
    toString() 은 Object 클래스가 가진 기능 메소드 이므로 당연하게 Java System API 2000여개의 클래스들도 toString() 을 보유하고 있습니다.

  • toString() 이 가지는 특이한 결과

    다음 코드를 봅시다.

    String name = new String("sam");
    System.out.println(name.toString());
    // 출력결과 : sam
    

    위 코드의 결과는 기존에 사용했던 객체 소개글이 아니라 문자열의 데이터가 출력되었습니다. 즉, 기존의 toString() 이 가지고 있던 기능으로 동작하지 않았다는것은 메소드가 오버라이드되었음을 의미합니다. 다시 말해, Object 클래스의 메소드도 오버라이드가 가능함을 말해줍니다.

2. equals(Object obj)

- 같은 객체인지 확인하는 메소드

  • 사용법

    Test t1 = new Test();
    Test t2 = new Test();
    boolean b = t1.equals(t2);
    System.out.println(b);
    // 출력결과 : false
    t1 객체와 t2 객체가 동일한 객체인지 판별하는 코드 입니다. 메서드의 리턴타입은 boolean 입니다. 같으면 true 다르면 false 를 반환합니다.

사실, 같은 객체 인지 판별하고자 할 때, equals() 메소드는 잘 사용하지 않습니다. 참조변수의 주솟값끼리 비교연산이 가능하기 때문입니다. 즉, t1 == t2 와 같이 연산하면 같은 결과를 얻을 수 있습니다. 이 메소드 역시 오버라이드가 가능합니다. 자바에서 대표적인 예가 String 입니다.

  • String 과 equals()

    String s1 = new String("Hello");
    String s2 = new String("Hello");
    
    System.out.println(s6 == s7); 
    System.out.println(s6.equals(s7));
    // 출력결과 : false / true
    String 은 객체이기 때문에 == 연산자를 통해 값비교를 할 수 없다고 하였습니다.(자동 new 연산자의 경우는 가능합니다. String constant pool) 그래서 Object 클래스의 메서드인 equals() 를 오버라이드 하여 값비교를 합니다.

3. getClass()

- 클래스의 정보를 가진 Class 객체를 리턴해줌.

  • 사용법

    Test t = new Test();
    Class obj = t.getClass();
    System.out.println(obj.getName());
    // 출력결과 : Test

4. hashCode()

- 자바에서의 주솟값 [ 객체마다 고유한 번호가 부여됨 ]

  • 사용법

    Test t = new Test();
    System.out.println(t.hashCode());
    // 출력결과 : 359023572

5. wait(), notify(), notifyAll() : 이 녀석들.. Thread 배운 뒤 다시 보자!


Object class 를 이용하는 대표적인 상황

업캐스팅

Object class 는 모든 클래스의 최상위 부모 클래스이므로 어떤 클래스의 객체든 업캐스팅을 통한 참조가 가능합니다.

ex)
Object obj = null;

obj = new String();
obj = new Random();
obj = new int[5];
obj = new ArrayList<String>();

또한 업캐스팅은 메소드의 파라미터, 리턴값에도 사용이 가능합니다. 어떠한 객체든 파라미터로 받고 싶을 때, Object 로 매개변수 타입을 정해주기도 합니다. 예를 들어 System.out.println(Object x); 의 경우도 어떠한 값이든 받아서 출력해주는 코드입니다. 기본형 변수는 물론이며 참조형 변수도 출력이 가능합니다. 참조형 변수의 경우 toString() 이 자동으로 호출됩니다.


Exception

- 우리가 만날 수 있는 잘못된 상황들


Error(오류) 와 Exception(예외)

Error 와 Exception 은 비슷한듯 다른 개념입니다. 먼저 Error 의 경우 , 프로그램 실행자체가 불가해집니다. 반면에 Exception 의 경우 실행중(Runtime) 에 문제가 발생합니다. 즉, 앱이 사용중에 다운이 되는 상황이 만들어 집니다.

Exception 의 대표적인 예로는 다음이 있습니다.

1. 사용자가 잘못된 데이터를 입력하는 경우
숫자입력 상황에 문자를 입력하는 상황

2. 개발자가 개발로직이나 계산을 잘못한 경우
배열의 인덱스 번호 오류 or 0으로 나눗셈

3. 네트워크나 하드웨어 오류
하드디스크 파일 제어 오류, 특정 사이트(서버) 접속 오류(URL 실수, 서버 불량)

예외 처리

예외 처리란, 앱이 실행 중에 멈춰버리는 문제들을 미연에 방지해서 예외가 일어난 코드의 다음 코드들이 정상적으로 실행되도록 하는 기법을 말합니다. 한가지 주의할 점은 예외를 방지하는것이 아닌, 예외를 처리하는 기법이라는 점입니다. 즉, 예외는 일어납니다. 또한 경우에 따라서 일단 실행을 해보아야 예외인지 아닌지를 파악할 수 있는 경우도 있습니다. 네트워크 접속같은 부분이 그렇습니다. 이런 경우에 사용할 수 있는 문법이 예외 처리 입니다. try - catch - finally 문법 이라고도 합니다.

예외처리 기법 : try - catch - finally

try {

} catch( ) {

} finally {

}

try - catch 문은 위와 같은 구조를 가집니다. try 실행문에는 예외가 일어날 가능성이 있는 코드를, catch 실행문에는 예외가 일어날 경우 실행될 코드를, finally 는 예외의 발생유무와는 관계없이 실행될 코드를 작성합니다.

1. 0으로 나눗셈

int a = 0;
try {
	System.out.println(10 / a);	
}catch(ArithmeticException e){
	System.out.println("예외가 발생했어요!");
	System.out.println("예외 메시지 : " + e.getMessage());
	System.out.println(e.toString());
	e.printStackTrace();
}

try 문 안에는 예외가 일어날 가능성이 존재하는 10/a 코드를 넣었습니다. catch 문에는 예외가 발생했을때, 예외가 발생했음을 알리는 코드와, 예외의 정보들을 알려주는 코드를 넣었습니다.

또한 이런 경우의 예외는 ArithmeticException 로 처리합니다. 예외에도 예외마다 클래스가 존재합니다. 그래서 예외가 발생하게 되면, 예외에 맞는 각 클래스가 객체로 만들어지며 발생한 예외를 받습니다.

2. 배열의 인덱스 번호 오류

int[] aaa = new int[5];
		
try {
	for(int i = 0; i < 6 ; i++) {
		System.out.println(aaa[i]);
	}
} catch(ArrayIndexOutOfBoundsException e) {
	System.out.println("예외가 발생했어요!");
			
}

배열의 크기가 5인 배열에서 크기를 넘어서는 인덱스를 참조할 때 나타나는 예외상황입니다. 이런경우 ArrayIndexOutOfBoundsException 예외를 발생시킵니다.

3. null 참조변수로 객체의 메서드를 사용

String s= null;
try {
	System.out.println(s.length());
} catch(NullPointerException e) {
	System.out.println("객체가 읎써~~");
}

참조변수 s 가 가지고있는 값이 null 인데, 없는 객체를 참조해서 length() 값을 가져오려니 예외가 발생합니다. 이럴때 나타나는 예외는 NullPointerException 입니다.

4. 잘못된 데이터를 입력하는 경우

Scanner scan = new Scanner(System.in);
int n;
try {
	n = scan.nextInt();
	System.out.println("n : " + n);
} catch(InputMismatchException e) {
	System.out.println("정수만 입력해~~");
}

사용자 입력을 받을 때 나올 수 있는 예외상황입니다. 예를 들어 개발자는 int 형 변수 n 을 설정했고, 사용자 입력을 통해 n 값을 설정하는 코드를 작성했습니다. 그런데 사용자가 n 값에 정수가 아닌 문자를 입력하게 되면 예외가 발생합니다. 이런 경우 InputMismatchException 이 발생합니다.

5. 숫자로 바꿀 수 없는 데이터를 숫자로 바꾸는 경우

String s = scan.next();
try {
	int num = Integer.parseInt(s);
} catch(NumberFormatException e) {
	System.out.println("숫자만 입력해~~");
}
		

예를 들어, 사용자로부터 문자열을 입력받고 그 문자열을 숫자로 바꾸는 코드를 짜본다고 합시다. 그런데 사용자가 문자열을 입력할때 숫자모양이 아닌 abc 와 같은 문자열을 입력한다고 하면 예외상황이 발생하며, 이와 같은 예외상황은 NumberFormatException 입니다.

즉, 예외처리는 예외가 발생하더라도 프로그램이 종료되지 않도록 하는 기술입니다.

다중 catch 문

앞서 본 예제들에서는 모두 한 가지의 예외만 발생한 예제였습니다. 그렇다면 예외가 두 가지 이상일때는 어떤 방식으로 처리하면 될까요? 지금까지 배웠던 개념으로만 처리하자면 try - catch 문을 중첩으로 작성해서 예외처리를 하면 될것같습니다. 물론 맞는 이야기지만 이렇게 처리할 경우 중첩의 특성상 코드가 상당히 복잡해 집니다. 그래서 나온 문법이 다중 catch 문 입니다.

예를 들어 두 수를 입력받아 나눗셈을 하는 코드를 작성한다고 합시다.

Scanner scan = new Scanner(System.in);
int a,b;

try {
	a = scan.nextInt();
	b = scan.nextInt();
			
	System.out.println( a / b);
} catch(InputMismatchException e) {
	System.out.println("숫자만 입력해라~");
} catch(ArithmeticException e) {
	System.out.println("0으로 나누지 마라~");
} catch(Exception e) {
	System.out.println("예외 발생");
}

숫자를 입력받을 때 나올수 있는 예외상황인 InputMismatchException을 catch 문을 통해 처리해주었으며, 0으로 나눌 때 발생할 수 있는 예외상황인 ArithmeticException 을 처리해주었습니다. 그외의 상황을 Exception 으로 처리해주었습니다.

모든 예외 클래스들은 Exception 을 상속 받기 때문에 보통 마지막 catch문에는 Exception 객체를 인수로 전달받습니다.

finally

예외 발생의 여부와 관계없이 무조건 실행되어야 할 코드가 있을 때 사용하는 영역이 있습니다. 바로 finally 영역입니다. 다음과 같이 사용합니다.

int x = 5;
try {
	System.out.println( 10 / x );
	System.out.println("계산성공");
} catch(ArithmeticException e) {
	System.out.println("계산실패");
} finally {
	System.out.println("예외여부와 상관없이 무조건 실행");
}

사실, 논리적으로 바라볼 때, finally 의 실행문이 밖에 있어도 동일한 결과를 냅니다. 다만, 개발을 진행할 때, finally 안에 있는 실행문은 try - catch 문과 관련된 실행문이라는 것을 명시하기 위해 사용한다고 보면 좋을것 같습니다.

또한 finally 에는 또 하나의 역할이 있습니다. finally 를 사용하면 catch 문의 생략이 가능합니다. 만일, 강제적인 예외처리를 해주어야 한다고 할 때, 그리고 예외발생에 대한 처리를 해주고 싶지 않을 때, try - finally 문을 사용하여 처리 할 수 있습니다.

CheckedException 과 UnCheckedException

- CheckedException : 예외처리를 하지 않으면 에러가 발생하는 예외들.
- UncheckedException : 예외처리를 해도 되고, 안해도 되는 예외들.

UncheckedException 은 앞서 살펴봤던 예외들 입니다. 여기서는 CheckedException 을 알아보도록 하겠습니다.

네트워크 연결 시 예외발생

try {
	URL url = new URL("http://www.naver.com");
	url = new URL("www.naver.com"); 
} catch(MalformedURLException e) {
	System.out.println("서버주소 이상");
}

두번째 대입된 url 을 보면 http:// 가 생략되어있습니다. 이로 인해 예외가 발생하였으며, MalformedURLException 의 객체를 catch 문에 전달하였습니다.

파일 입출력 시 예외발생

File file = new File("D:\\aaa.txt");
		
try {
	FileInputStream fis = new FileInputStream(file);
} catch (FileNotFoundException e) {
	// TODO Auto-generated catch block
	e.printStackTrace();
}

파일 입출력 시 발생하는 예외는 FileNotFoundException 입니다.

throws : 예외 떠넘기기

두 수를 나눗셈 하여 결과를 리턴해주는 메소드를 만들어봅시다.

int divide(int x, int y) {
	return x / y;
}

그런데 여기에서는 예외처리를 해주어야 합니다. 만일, y 값이 0 이라면 예외를 발생시키기 때문입니다. 그럼 다음 코드를 봅시다.

int divide(int x, int y) {
		try {
			return x/y;
		}catch(ArithmeticException e) {
			return ???
		}
}

try - catch 문을 이용하여 나눗셈 연산의 예외발생을 처리해주었습니다. 그런데 작성하다 보니 뭔가 이상합니다. 이 메서드는 리턴타입이 int 입니다. 그러므로 반드시 리턴값을 넘겨줘야 합니다. try 실행문이야 x/y 의 결과값을 리턴하면 된다지만, 만일 예외가 발생되면, 그래서 catch 문이 실행된다면 어떤값을 return 해주어야 할까요? 알수가 없습니다. 그래서 이 메소드안에서 직접적으로 예외처리를 하기가 애매한 경우가 생깁니다. 이럴때 이 메소드 내부에서 예외를 직접 처리하지 않고 이 메소드를 호출 하는 쪽으로 예외를 던져버리는 문법이 있습니다. 바로 throws 입니다. 코드로 봅시다.

----------------- Main.java
static int divide(int x, int y) throws ArithmeticException {
	return x / y;
}

public static void main(String[] args) {
	try {
    	int num = divide(10,0);
        System.out.println("num : " + num);
    } catch(ArithmeticException e) {
    	System.out.println("divide 메소드의 throws 된 예외 대신처리");
    }
}

// 출력결과 : divide 메소드의 throws 된 예외 대신처리

경우에 따라서는 throws 를 통해 여러번 넘겨줄 수도 있습니다.

static void bbb() throws MalformedURLException {
	aaa();
}
    
static void aaa() throws MalformedURLException {
	URL url = new URL("http://www.google.com");
}

public static void main(String[] args) {
	try {
		bbb();
	} catch (MalformedURLException e) {
		// TODO Auto-generated catch block
		e.printStackTrace();
	}
}

throw

코드를 통해 강제로 예외를 발생

바로 코드로 봅시다.

	try {
		System.out.println("aaa");
		throw new Exception();
		System.out.println("bbb");
	} catch(Exception e) {
		System.out.println("예외발생");
	}
		

throw 키워드를 이용하여 new Exception() 을 생성했습니다. 즉, 예외를 인위적으로 발생시켜 catch 문으로 들어가게 하였습니다.

활용 예시

뺄샘을 하는 메소드를 만들어봅시다. 단, 그 결과값이 음수가 나오면 예외로 처리해주었으면 합니다. 다음과 같이 작성합시다.

public static void main(String[] args) {
	int n;
    try {
    	n = aaa(10,15);
        System.out.println("n : " + n);
    } catch(Exception e) {	
    	System.out.println("계산결과가 음수인 예외");
    }
}

static int aaa(int a, int b) throws Exception {
	if( a < b ) {
    	throw new Exception();
    }
    return a - b;
}

코드를 차례대로 따라가 봅시다. 먼저 int n; 으로 변수하나를 선언하고, try - catch 문이 안에서 aaa 메소드를 호출합니다. 파라미터 값은 10 과 15로 넘겨주었습니다. aaa 메서드 안에서는 a가 b보다 작기 때문에 if 실행문이 실행 됩니다. 즉, 예외를 인위적으로 발생시켰으며, throws 키워드를 통해 이 메서드를 호출한 쪽으로 예외를 던져주었습니다. 그래서 main 메서드에서 try - catch 문으로 예외처리를 해주었습니다.

추가로, 나만의 Exception class 또한 만들수 있다는것도 참고합시다.

class MyException extends Exception{
	public MyException(String msg) {
		super(msg);
		
	}
}
profile
Developer

0개의 댓글