안녕하세요. 개발자 Mommoo 입니다.

오늘은 CheckedExceptionUnCheckedException에 대해 포스팅 합니다.

해당 내용에 대해 알아보는것도 의미가 있습니다만, 포스팅 하는 핵심 부분은 CheckedException 의 단점에 대해 알아보는 것입니다. 해당 주제는 면접에서도 많이 나와요.


ChecekdException 과 UnCheckedException이란?

CheckedException 처리는 컴파일 시점에 명시적으로 예외상황을 처리해야하는 예외 기법입니다. 자바 CLASS 중 Exception 을 상속받아 만들 수 있습니다.

명시적으로 예외를 처리한다 함은, 자바 언어 기준으로, try~catch 구문을 사용하는것을 의미합니다. 명시적인 예외를 처리하지 않는다면 컴파일 되지 않아, 코드 에디터에서 빨간 줄이 그어져 있는것을 확인하 실 수 있습니다.

UnCheckedException 처리는 런타임 시점에 예외상황을 처리하는 예외 기법입니다. 자바 CLASS 중 RuntimeException 을 상속받아 만들 수 있습니다.

런타임 시점이란, 컴파일이 된 후 프로그램이 실행될 때, 어느 특정 상황을 의미합니다.

위에서 살펴본 CheckedException 예외와는 다르게, 명시적으로 처리할 필요가 없습니다. 개발자가 필요시에 try~catch 구문을 이용하여 처리합니다.


ChecekdException의 특징

CheckedException 은 사실 현대적인 언어에서는 제공하지 않는 경우가 많습니다. CheckedException 은 사실상 필요없다는 의견도 많을 뿐더러, 프로그래밍에 있어서 큰 단점을 가지고 있기 때문입니다. 하지만 장점도 가지고 있는데요, 해당 내용을 알아봅시다.

CheckedException 의 최고 장점은 아무래도 안정적인 소프트웨어를 만들 수 있는 길을 제시해준다는 점입니다. CheckedException 을 제공하는 개발자는 빈번하게 발생할 수 있는 예외 케이스 를 제공해줌으로써, 해당 메서드를 사용하는 개발자로 하여금 UnHappyPath 에 대해 생각할 수 있는 여지를 제공해줍니다.

물론, UnCheckedException도 예외케이스를 제공해주지만 아무래도 명시적으로 작성해야 하는 효과가 주는 안정성이 있다고 생각합니다.

하지만, 큰 단점이 있는데요. 그것은 항상 명시적으로 작성해야 한다는 점 입니다.

예를들어, FileInputStream("파일이름") 객체를 만든다고 가정해봅시다. 해당 객체는 FileNotFoundException 이라는 CheckedException 처리를 해야합니다. 해당 파일이름으로 된 파일이 없는 경우를 대비하라는 의미이지요. 그런데 해당 파일이 항상 존재한다고 가정할 수 있는 경우에는 어떨까요? 해당 경우에는 불필요한 try~catch 구문이 들어가, 코드 가독성을 해치게 됩니다. 또한 해당 파일이 항상 존재한다는 상황의 표현도 되지 않는것도 큰 문제라 볼수 있습니다.

프로그래밍이란 것은 아무래도 흐름을 통해 특정 상황을 만드는 일이 빈번하다 보니, CheckedException은 프로그래밍에 있어서 짜증나는 상황으로 다가오는 경우가 많습니다.


UnChecekdException의 특징

UnCheckedExceptionCheckedException 의 명확한 단점을 극복할 수 있는 장점이 있지만, 반대로 단점은 명시적으로 예외를 정의할수 있게 유도하지 못한다는 점입니다.

하지만 이는 예외상황은 어쨌거나, 프로그래머가 신경써야 한다는 점에 있어서 큰 단점이 되지 않습니다. 특정 메서드를 사용할 때는 메서드를 탐색하면 어떤 예외가 있는지 확인할 수 있기 때문에 예외 대처에 있어 큰 문제가 되지 않습니다.

그렇기에 현대적인 언어에서는 예외처리를 UnCheckedException 으로 제공하는 경우가 많습니다.


마무리

개인적인 생각으로는 숙련된 프로그래머는 CheckedException 의 단점이 더 부각되고, 초보 프로그래머에게는 CheckedException의 장점이 더 부각되는 상황이 될거 같습니다.

그렇기에 프로그래밍을 많이 할 수록 예외 처리는 RuntimeException 을 상속받아 처리하는 부분으로 빈번하게 처리되는거 같습니다.

글에는 개인적인 의견도 포함됬기 때문에 틀린점이 있을 수 있습니다. 틀린부분에 대해 의견주시면 감사히 받겠습니다.

글 읽어주셔서 감사합니다. :)

'Java' 카테고리의 다른 글

[Java] 파일 경로 처리하기.  (2) 2019.01.24
JAVA - JNI 사용하기  (2) 2017.09.02
JAVA - [SWING] LinearLayout 사용하기.  (0) 2017.08.25
JAVA - DownCasting(다운캐스팅)  (24) 2016.08.27
JAVA - HashMap key 구하기.  (1) 2016.08.25

포스팅이 도움 되셨다면, 커피 한잔 후원해주세요!
더 좋은 포스팅 작성에 큰 힘이 됩니다.

Buy me a coffeeBuy me a coffee




안녕하세요. 오늘은 Java를 이용하여, OS에 호환 되는 파일 경로 구성 방법과 웹 경로에 사용되는 / 문자열을 OS에 맞게, 파일 구분자로 변환하는 방법을 간단하게 포스팅 합니다.

OS마다 서로 다른 파일 구분자

파일 구분자는 OS마다 서로 다릅니다. 예를들어, 윈도우 운영체제는 파일 구분자로 \\ 역슬래쉬 두개를 사용합니다. 리눅스 운영체제는 웹 경로 문자열과 똑같이 파일 구분자로 /를 사용합니다.

Java는 이러한 서로 다른 파일 구분자를 처리하기 위해 JVM이 실행되는 OS 환경에 맞는 파일 구분자를 제공하는 API가 존재합니다.

String fileSeparator = File.separator;

따라서, 위의 API를 이용하면 OS에 호환되는 파일 경로를 구성할 수 있습니다.

String filePath = "Java" + File.separator + "Mommoo";

만약 Java7이상을 사용 하신다면, OS에 호환되는 파일 경로는 Path API를 사용하면 쉽게 구성할 수 있습니다.

String filePath = Paths.get("Java", "Mommoo");

OS 파일 구분자와 / 구분자 변환 처리하기

때때로, / 구분자를 파일 저장을 하기 위해 OS에 호환되는 파일 경로를 구성하고 싶을때가 있습니다. 단순히, / 구분자를 File.separator로 바꿔주면 됩니다만, Java API에 특정처리를 해줘야 합니다.

우리는 어떤 문자를 다른 문자로 바꾸고 싶을 때, Java String API의 replace API를 사용하곤 합니다. replace API는 바꿀 기준을 정할 때, 문자열이 아닌 정규식으로도 구성 할 수 있습니다. 문제는 여기서 생깁니다. 우리가 파라미터로 넣어준 것이 문자열 인지, 정규식 인지 구분이 안가는 상황이면, API는 정규식으로 처리합니다. 즉, 아래와 같이 구분자 처리를 한다면,

String testPath = "Java/Mommoo";
String filePath = testPath.replaceAll("/", File.separator);

윈도우 OS 에서는 오류가 발생합니다.

그 이유는, 윈도우 OS의 File.separator"\\"로 나오는데, 이 문자열을 정말 문자열로 해석하는 것이 아닌 정규식으로 해석합니다.

그러한 이유로 제대로 작동 되질 않습니다.

따라서, "\\"를 작동 가능한 문자로 바꿔주어야 합니다.

사실 아스키 코드 92번인'\\' char 문자로 넣어주면 됩니다만, replace API는 문자열을 파라미터로 받는 이유로 char 배열을 다시 String으로 변환 하는과정이 번거롭습니다.

따라서, Matcher API인 quoteReplacement를 사용합니다. 해당 API는 위에서 말한, char 문자 '\\'를 넣어준 문자열로 바꿔주는 역할을 합니다.

최종적으로 아래와 같이 API를 사용하면 정상적으로 작동 합니다.

String testPath = "Java/Mommoo";
String OsFilePath = testPath.replaceAll("/", Matcher.quoteReplacement(File.separator));
String reverseSlashPath = OsFilePath.replaceAll(Matcher.quoteReplacement(File.separator), "/");

오늘 준비한 포스팅은 여기까지 입니다.

읽어주셔서 감사합니다.

'Java' 카테고리의 다른 글

[Java] CheckedException vs UnCheckedException  (0) 2020.09.27
JAVA - JNI 사용하기  (2) 2017.09.02
JAVA - [SWING] LinearLayout 사용하기.  (0) 2017.08.25
JAVA - DownCasting(다운캐스팅)  (24) 2016.08.27
JAVA - HashMap key 구하기.  (1) 2016.08.25

포스팅이 도움 되셨다면, 커피 한잔 후원해주세요!
더 좋은 포스팅 작성에 큰 힘이 됩니다.

Buy me a coffeeBuy me a coffee
  1. 번외수사 다시보기 2020.06.23 15:29

    잘 보고 갑니다~~

  오늘 포스팅은 Java JNI ( Java Native Interface) 입니다.


자바는 특정 운영체제에 종속되지 않도록, JVM이라는 가상머신 위에서 실행되게끔 만들어진 언어입니다.


운영체제에 맞는 JVM이 각기 존재하기 때문에, Java 개발자는 하나의 Java 파일만 만들면, 


운영체제 상관없이 원하는 결과물을 쉽게 얻을 수 있습니다.


하지만 단점도 있습니다.


그중 하나의 단점은 운영체제의 모든 기능을 JVM이 담지 못하는 것입니다.


따라서, 구현하고 싶은 몇몇 기능들은 Java 언어 자체로도 해결 안되는 경우가 존재합니다.



JNI (Java Native Interface) 란?


  위에서 언급한 Java언어 자체로도 해결 안되는 경우, 대처할 수 있는 방법중 하나입니다.


운영체제의 고유기능(Native)을 Java로 해결 하는 것이 아닌 운영체제가 구현된 언어 (보통 C, C++)로


운영체제의 고유기능을 만듭니다. 


JVM은 C,C++로 만들어진 고유기능 즉, 함수를 Java 메서드와 연결해줍니다.


그로인하여 Java 메서드를 호출 할 시, C나 C++로 작성된 함수가 실행 됩니다.




JNI를 구현하기 위해 필요한 것



  C, C++을 작성하기 위한 비쥬얼 스튜디오가 필요합니다. 저는 2015 Community 썼습니다.




Java 코드 작성하기.



  먼저 필요한 자바 코드를 작성합니다.


JNI 구현 예시로 쓸 2개의 메서드를 만듭니다. 


1개는 HelloWorld를 콘솔에 찍는 메서드, 다른 한개는 단순히 숫자 3을 가져오는 메서드를 만들 예정입니다.


코드는 아래와 같습니다.


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
public class JNI {
    
    static {
        System.loadLibrary("JNI");
    }
    
    private native int getNumber();
    private native void printHelloWorld();
    
    public static void main(String[] args){
        JNI jni = new JNI();
        
    
        jni.printHelloWorld(); //JNI로 호출 한 HelloWorld!
        
        System.out.println(jni.getNumber()); //JNI로 호출 한 숫자 메서드
    }
}
cs


static 초기화 블럭으로, 추후에 만들 dll 파일을 불러야 하는게 특징입니다.


또한, native 메서드를 만드는 갯수는 상관 없지만, 구현부가 비어있습니다.


dll 파일에 존재할 실제 구현된 함수를 호출하기 위해 만든 껍데기 메서드 입니다.



Java 코드 파일 컴파일, 헤더파일 만들기



  Java 파일 컴파일은 이클립스 같은 툴에서 진행 해도 됩니다.


하지만 헤더파일은 터미널 환경에서 컴파일을 진행 해야합니다. 


이클립스가 제공해주는 Terminal 환경에서 해도 무방합니다. 


하지만 헤더파일 컴파일은 Path 설정등으로 인하여,


잘 안되는 경우가 있기 때문에 아래의 방법을 추천합니다.


먼저 이클립스에서 JNI클래스를 컴파일 합니다.


당연히 dll파일을 찾지 못한다고 오류가 뜹니다. 상관없구요.


그다음 이클립스 workspace로 찾아가셔서 프로젝트폴더 - bin폴더로 갑니다.


그곳에서 Shift + 마우스 오른쪽 클릭 후, 


명령창 여기에서 열기 or PowerShell 여기에서 열기를 누릅니다.


터미널이 뜨면, 그곳에 아래와 같이 입력합니다.


javah 패키지명.클래스명

저 같은 경우 패키지명이 jni 클래스명이 위 예시와 같이 JNI 이므로


javah jni.JNI


로 했습니다.


제대로 컴파일 됬다면, bin폴더 어딘가에


패키지명_클래스명.h 파일이 생깁니다.


그 파일을 잘 보관합니다.



Visual Studio에서 C, C++ 작성하기.




1. 프로젝트 만들기


  Visual Studio를 실행합니다. 


아래와 같이 새로운 프로젝트를 만들어줍니다.



위와 같이 빈 프로젝트로 만들어 줍니다. 추후 dll파일을 만들때, 프로젝트명 으로 dll파일의 이름이 되므로,


프로젝트명을 잘지어줍니다.


2. 헤더 파일 넣기



위와 같이 헤더파일 폴더에 앞서 만들었던 헤더파일을 넣어줍니다.


조심해야 할 건, 복붙으로 넣지말고, 헤더 파일 폴더에 오른쪽 버튼 눌러서 툴의 도움으로 추가를 해야합니다.


그래야, 코드상에서 참조 가능합니다.


3. 프로젝트 속성 변경.



솔루션 탐색기 안에서 프로젝트 속성으로 들어갑니다.


그 후 프로젝트 기본값 - 구성 형식을 동적 라이브러리(.dll)로 바꿔주시고


일반 - 대상 확장명 도 .dll로 바뀌었는지 확인 해주세요.



4. 외부 라이브러리 설정




추가 포함 디렉토리를 누른 후 아래와 같이 입력합니다.


중요한점은, 개인 컴퓨터에 깔린 jdk 버전이 다르기 때문에 jdk 폴더 명은 다를 수 있습니다.




5. 코드 작성


헤더 파일에 있는 함수정보를 복사해서 파라미터를 아래와 같이 맞춰줍니다. (JNIEnv *  => JNIEnv *env , jObject -> jObject)




컴파일 한 후, 컴파일 된 dll파일을 찾습니다. ( 출력창에 dll이 생성된 path가 나옵니다.)



Java 프로젝트에 dll파일을 넣고 컴파일 하기



  만든 dll파일을 Java프로젝트 폴더 바로 아래에 넣고 컴파일 합니다.


dll파일을 아무곳에나 넣어도 상관은 없지만 대신 path를 맞게 입력해줘야 합니다.


프로젝트 폴더 바로 아래에 넣을 시, path 필요없이 파일명만 입력해도 되므로, 프로젝트 폴더 바로아래에 넣었습니다.


넣고 컴파일 해보면 아래와 같이 잘 작동하는걸 볼 수 있습니다.




여기까지가 준비한 내용입니다.


추가적으로 궁금한 사항있으면 댓글 달아주세요.


감사합니다.

'Java' 카테고리의 다른 글

[Java] CheckedException vs UnCheckedException  (0) 2020.09.27
[Java] 파일 경로 처리하기.  (2) 2019.01.24
JAVA - [SWING] LinearLayout 사용하기.  (0) 2017.08.25
JAVA - DownCasting(다운캐스팅)  (24) 2016.08.27
JAVA - HashMap key 구하기.  (1) 2016.08.25

포스팅이 도움 되셨다면, 커피 한잔 후원해주세요!
더 좋은 포스팅 작성에 큰 힘이 됩니다.

Buy me a coffeeBuy me a coffee
  1. dg 2022.01.26 17:22

    5. 코드작성은 jni_JNI.h 파일을 수정하는건가요? 아니면 새로 만들어서 작성하는건가요

  2. dumbassmommoo 2022.02.10 19:53

    이용약관위배로 관리자 삭제된 댓글입니다.

  오늘 포스팅 할 내용은 Android LinearLayout과 비슷한 Java의 Swing LinearLayout Manager 입니다.


Java가 기본적으로 제공하는 레이아웃은 아래와 같습니다.


  "FlowLayout,  BorderLayout, GirdLayout, BoxLayout, GridBagLayout"


우리는 GUI를 만들때, 버튼이나 라벨같은 컴포넌트들이 수직 정렬로 배치 되는걸 선호 합니다.


만약 컴포넌트들을 수직 정렬로 배치한다면, 위 레이아웃 중 무엇을 선택해야 할까요?


하나씩 살펴보겠습니다.




FlowLayout


  FlowLayout은 가로 방향으로 하나씩 쌓아가면서, 가로 방향 공간이 없을 시, 한칸 내려서 다시 가로 방향으로 쌓습니다.


이 특징을 이용하여 우리는 컴포넌트의 가로 크기를 가로 크기를 창 가로 크기 만큼 잡았을 시, 수직 정렬을 구현 할 수 있습니다.


하지만, 컴포넌트의 가로크기를 창 크기만큼 잡아야 한다는 단점과, 창의 크기를 움직였을때, 가로에 남는 공간이 생긴다면 수직정렬이


깨지기도 합니다. padding 크기를 준다 하더라도, 각 컴포넌트에게 JPanel을 감싸야 하는 불편함이 있죠.





BorderLayout


  BorderLayout은 동서남북 가운데 방향에 컴포넌트를 넣을 수 있습니다. 수직 정렬로 쌓으려면 북, 가운데, 남 이렇게 3방향을 써야 하는데요


이렇게 3개의 공간뿐이 쓰질 못하니, 3개의 공간안에 또, JPanel을 배치한 후, 그 JPanel안에 또 컴포넌트를 쌓는 방법밖에 없습니다.


그리고 해보시면 알겠지만, 컴포넌트 사이즈를 원하게 조종하는것도 만만치 않습니다.




GridLayout


  GridLayout은 간단하면서도 짜증납니다. 그 이유는 수직정렬 자체는 쉽습니다.


다만,  GridLayout 레이아웃 특성상 모든 컴포넌트의 크기가 같습니다. 


모든 컴포넌트의 크기가 같아야 하는 경우도 있겠지만, 그런 경우는 흔치 않습니다.





BoxLayout, GridBagLayout


  BoxLayout, GirdBagLayout이 우리가 원하는 수직 정렬을 하기 위해 필요한 레이아웃이라 볼 수 있습니다. 


단점은 너무 어렵습니다.


BoxLayout은 제 개인적으로 사용해 본 결과 이상하게 오작동하며, 


특히 GridBagLayout은 GridBagConstraints라는 제약조건을 설정할 수 있는 객체와 함께 사용하는데, 사용 방법이 무척 어렵습니다.






LinearLayout


 간단한 수직정렬 조차 괜찮은 레이아웃이 없던 상황에, 안드로이드 프로그래밍을 할때 썼었던 LinearLayout이 생각났었습니다. 


있을땐 몰랐는데 없으니까, 참 쓰기 괜찮은 레이아웃 이였다는 생각이 들었습니다.


결국 직접 만들었습니다.  오픈소스로 제작했구요, 해당 URL 은 아래와 같습니다.


https://github.com/Mommoo/FlatSwing/tree/master/src/com/mommoo/flat/layout/linear


사용방법이 어려운건 선호하지 않기 때문에 최대한 간단한 방향으로 만들었습니다.


아래의 코드는 LinearLayout을 이용한 예시입니다.


예시는 전부 수직정렬만 보여주지만, 수평정렬도 가능합니다.


주석을 읽어보면 어렵지 않게 쓰실 수 있습니다.


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
JFrame frame = new JFrame();
frame.setSize(500,500);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
 
JPanel panel = new JPanel();
panel.setLayout(new LinearLayout(Orientation.VERTICAL, 15));
 
// 기본 컴포넌트 크기입니다.
panel.add(new JButton("Test1"));
 
// 설정한 방향과 상반되는 방향의 크기를 부모창 크기 만큼 맞춥니다.
panel.add(new JButton("Test2"), new LinearConstraints().setLinearSpace(LinearSpace.MATCH_PARENT));
 
// 기본 컴포넌트 크기에 가운데 정렬 입니다.
panel.add(new JButton("Test3"), new LinearConstraints().setLinearSpace(LinearSpace.WRAP_CENTER_CONTENT));
 
// 원하는 컴포넌트 크기입니다.
JButton button = new JButton("Test4");
button.setPreferredSize(new Dimension(300,200));
panel.add(button);
 
frame.setContentPane(panel);
frame.setVisible(true);
cs


아래의 스샷은 결과물 입니다.



또한 만든 LinearLayout은 멋진 Weight 속성을 줄 수 있습니다.


무게 속성을 이용한다면, 예쁘게 GUI배치를 할 수 있습니다.


아래의 코드를 참고하세요. 


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
JFrame frame = new JFrame();
frame.setSize(500,500);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
 
JPanel panel = new JPanel();
panel.setLayout(new LinearLayout(Orientation.VERTICAL, 15));
 
// 기본 컴포넌트 크기에 무게 4만큼 차지 합니다.
panel.add(new JButton("Test1"), new LinearConstraints().setWeight(4));
 
// 설정한 방향과 상반되는 방향의 크기를 부모창 크기 만큼 맞추고, 무게 2만큼 차지 합니다.
panel.add(new JButton("Test2"), new LinearConstraints().setWeight(2).setLinearSpace(LinearSpace.MATCH_PARENT));
 
// 기본 컴포넌트 크기에 가운데 정렬이 진행되며 무게 1만큼 차지 합니다.
panel.add(new JButton("Test3"), new LinearConstraints().setWeight(1).setLinearSpace(LinearSpace.WRAP_CENTER_CONTENT));
 
// 원하는 컴포넌트 크기와, 무게 3만큼 차지합니다.
JButton button = new JButton("Test4");
button.setPreferredSize(new Dimension(300,200));
panel.add(button, new LinearConstraints().setWeight(3));
 
//총 무게는 4 + 2 + 1 + 3 = 10이므로, 각 컴포는트는 10에서 무게 크기 만큼 크기를 나눠 가집니다.
 
frame.setContentPane(panel);
frame.setVisible(true);
cs



아래의 스샷은 결과물 입니다.




오늘 포스팅은 여기까지 입니다. 


LinearLayout은 현재 만들고 있는 Swing 라이브러리에 있습니다. 


현재 제작중이라... 버그가 있을 수 있습니다. 


알려주시면 빠르게 수정 할 수 있으니, 알려주시면 감사하겠습니다.


좀더 많은 정보를 알고 싶으시면 아래의 URL을 참고해주세요. 


FlatSwing - https://github.com/Mommoo/FlatSwing (멋진 Flat디자인이 적용된 스윙 라이브러리)


감사합니다.

'Java' 카테고리의 다른 글

[Java] 파일 경로 처리하기.  (2) 2019.01.24
JAVA - JNI 사용하기  (2) 2017.09.02
JAVA - DownCasting(다운캐스팅)  (24) 2016.08.27
JAVA - HashMap key 구하기.  (1) 2016.08.25
JAVA - 변수 선언할때 m을 왜 붙일까?  (2) 2016.07.05

포스팅이 도움 되셨다면, 커피 한잔 후원해주세요!
더 좋은 포스팅 작성에 큰 힘이 됩니다.

Buy me a coffeeBuy me a coffee

이번 포스팅은 저번에 이어


마지막 차례인 DownCating(다운 캐스팅)이다.


아래의 URL은 현재 기술할 내용을 이해하기 위해


필요한 내용을 기술한 포스팅이다.


http://mommoo.tistory.com/40 - 캐스팅

http://mommoo.tistory.com/41 - 업캐스팅


이전 업캐스팅 내용을 토데로 복습하자면


자바에서는 관련있는 데이터 끼리 형변환이 가능 했었다.


ex) (Child 클래스가 Parent 클래스를 상속받은 경우)


Parent parent = new Child();


윗 경우는 업캐스팅이라 했었고, 형변환 기호( (Parent) )를 붙여주지 않더라도


생략이 가능하다.


그렇다면 반대인 경우는 어떨까?


Child child = new Parent();


앞서 포스팅에서 기술 한 것처럼, 관련있는 데이터 끼리는


캐스팅이 가능하다고 했다. 하지만 , 위의 경우는 성립하지 않는다.


왜냐하면 앞서 포스팅에서 덧붙여 설명했던 개념인,


변수가 원하는 정보를 다 채워줘야하는 원칙에 어긋난다.


Child 클래스는 Parent 클래스를 상속받았기 때문에 Parent 클래스보다는 


Child 클래스가 더욱 많은 데이터를 가졌을 것이다.


즉,


child 변수가 원하는 정보는 Child 클래스의 데이터 전부를 원하는데,


Parent 인스턴스 ( new Parent(); ) 는 Parent 데이터만 가지고 있을 뿐,


Child의 데이터를 가지지 않는다. 그러므로 빨간줄이 그어지면서


컴파일 오류를 발생시킨다.



그렇다면, 위의 경우에서 형변환을 시켜준다면 어떨까?


Child child = (Child)new Parent();


개발툴에서 확인해보면, 컴파일 오류에서 벗어나면서 빨간줄이 사라질 것이다.


하지만, 저 코드는 런타임 오류가 발생한다.


이유는 아래와 같다.



"컴파일러에게 프로그래머가 형변환을 함으로써, 일단 데이터를 맞게 넣어준것 처럼 보여준다.


컴파일러는 문법이 맞다고 생각하여 넘어간다.


하지만, 프로그램이 실제로 동작할때, new Parent(); 인스턴스는 Child 형 데이터로 바꾸지 못한다는 것을


깨닫고, 런타임 오류를 뿜으며 프로그램이 종료된다. "



그렇다면, 왜 런타임 오류를 발생할까? 


그 이유는 JVM은 new Parent(); 인스턴스를 Child 데이터로 형변환 하려 했지만,


Child 데이터가 무엇인지 모르기 때문이다. 조금더 구체적인 이유는


Child 데이터는 만드는 프로그래머 마다 성질이 다를 것인데, 그것을 JVM 추리하지 못하기 때문이다.


이전 캐스팅 포스팅에서 나오길, 기본자료형 끼리는 추리가 가능하기 때문에,


알아서 알맞은 데이터 크기로 변환하여 넣어준다고 설명했다.


하지만, 위와 같이 참조형 데이터를 캐스팅 할때는, 


속성,성질이 정해져 있지 않은 참조형 데이터는 JVM이 알길 이 없다.


Child 데이터에 Parent 데이터를 넣는 경우는 화살표가 아래로 향하므로,


다운캐스팅이라 한다. 


위와 같은 예시에서 봤드시,


다운캐스팅은 일반적으로 성립하지 않는다. 


하지만, 다운캐스팅이 성립되는 경우가 존재한다.


아래의 예시를 보자.


Parent parent = new Child(); 


Child child = (Child)parent;


위의 예시는 다운 캐스팅이 성립되는 경우의 수이다.


왜 성립이 되는것일까?

 

parent 변수는 Parent클래스 형태의 변수지만, 


태생이 Child 인스턴스 인 데이터를 넣어주었다.


그러한 정보를 가지고 있는 parent 변수를 다시 Child 클래스형태로


다운캐스팅을 하였다.  parent변수 상태는 Parent 클래스형 상태이지만,


다운캐스팅을 해주는 경우 ( (Child)parent ) 태생이 Child 클래스 형이므로,


JVM이 parent 변수를 태생 정보인 Child 클래스 데이터 형으로 


다운캐스팅을 해줄 수 있는 것이다.




결과적으로, 다운캐스팅은 보통 성립하지 않는 문법이지만,


위와같이 업캐스팅이 선행된 경우, 다운캐스팅이 성립되는 경우가 존재한다.









'Java' 카테고리의 다른 글

JAVA - JNI 사용하기  (2) 2017.09.02
JAVA - [SWING] LinearLayout 사용하기.  (0) 2017.08.25
JAVA - HashMap key 구하기.  (1) 2016.08.25
JAVA - 변수 선언할때 m을 왜 붙일까?  (2) 2016.07.05
JAVA - UpCasting(업캐스팅)  (9) 2016.06.07

포스팅이 도움 되셨다면, 커피 한잔 후원해주세요!
더 좋은 포스팅 작성에 큰 힘이 됩니다.

Buy me a coffeeBuy me a coffee
  1. 남양불매운동 2016.11.13 19:59

    다운캐스팅 설명글인데
    " 마지막 차례인 UpCating(업캐스팅)이다. "라고 적혀있네요
    오타발견

  2. 이집잘하네 2017.08.24 19:57

    이집 설명잘하네여 업캐스팅 이해 잘됬습니다..
    ㅋㅋㅋㅋㅋㅋ
    감사합니당

  3. 지림 2018.03.12 09:49

    글 진짜 이해잘되게 간단하게 잘쓰시넹

  4. 졸린눈 2018.07.12 18:22 신고

    다운캐스팅은 돌아돌아 가는 느낌이 드는데 그러면 왜 ? 언제 쓰이는지 알 수 있을까요 ㅠㅠ

    • Mommoo 2018.07.17 17:55 신고

      이럴때 딱!! 쓰입니다. 하는 상황은 없구여..
      업캐스팅은 보통 관계가 있는 자료형을 클러스터링( 자료구조로 데이터 덩어리를 한번에 묶는 행위 ), 다형성을 사용 할 때 많이 쓰이구요, 다운 캐스팅은 업캐스팅된 자료형을 받았지만, 그 자료형이 어떤 자료형 인지 명백하고, 자식 자료형의 기능을 사용하고 싶을때, 다운캐스팅을 하여 해당 자식 자료형으로 변환하여 사용하곤 합니다.

  5. 코딩개못함 2018.08.30 21:30

    몸무님 글 잘읽었습니다. 궁금한게있는데요.
    오버라이딩해서 child c = new child() 라고하면 c변수는 child랑 parent 두개의 필드나 메쏘드들을 다쓸수있는데
    왜 업캐스팅,다운캐스팅을 하는거에요? 오버라이딩 vs 업캐스팅,다운캐스팅의 장단점이 뭔지 잘모르겠습니다..
    그냥 오버라이딩만 하면 되는거아닌가요..?

    • Mommoo 2018.09.11 16:58 신고

      답변이 늦었습니다.
      말씀대로 자료 하나만 사용할때는, 업캐스팅-다운캐스팅이 의미가 많이 없습니다. 업캐스팅-다운캐스팅은 `클러스터링`의 관점에서 큰 의미가 있는데요, `클러스터링`은 간단하게 배열과 같은 자료구조를 이용하여 자료를 '공통적인 특징' 으로 묶는걸 의미합니다. 이때 `공통적인 특징`을 묶는 방법은 child로 만 묶어도 상관없지만, 빈번하게 상위 개념으로 묶어야 할 순간도 발생합니다. Child의 상위 개념은 Parent 자료형을 `공통개념`으로 `클러스터링`을 진행하는 것이지요. 앞서 설명했드시, 이런 경우 업캐스팅을 많이 사용합니다.

      반대로 다운캐스팅은 상위개념으로 제공되는 자료를, 만약 하위개념( 더 구체적인 자료형, 자식 클래스 )을 알고 계시고 사용하고 싶으시다면 이를 다운캐스팅을 통해 형변환하고 해당 자료형을 사용하는것이지요.

      사실상, 말로 설명하기 힘든 부분입니다..^^ 윗 설명으로 살짝 감만 잡으시고 실습을 해보면서 깨우치셔야 할 개념입니다.

  6. 성엽이 2019.04.18 19:20 신고

    포스팅 해두신 캐스팅 시리즈 주~욱 한번에 다 봐버렸네요

    글 너무 깔끔하게 잘쓰셔서 도움 많이 됬어요. 감사합니다 ㅎㅎ

  7. 우와! 2019.04.20 21:46

    정말 유익하네요! 감사합니다.

  8. 전지공대생 2019.10.05 00:21

    정말 감사합니다! 한번에 이해했습니다.

  9. 와우 2019.10.29 14:27

    감사합니다.

  10. ㅇㅇ 2020.08.05 17:57

    감사합니다! 이제 절대 안 까먹을 것 같아요

    • Mommoo 2020.08.05 18:11 신고

      그렇죠??ㅎㅎ
      그걸 노린건데, 정확하게 보셨습니다. ^^

      읽어주셔서 감사합니다.

  11. zzino 2021.01.23 17:37

    안녕하세요 글 잘읽었습니다. 마침 배열에서 부모클래스형으로 배열 선언을하고 배열의 원소에 자식클래스형들을 집어넣으려는 상황에서 업캐스팅이라는 개념이 들어간다는걸 알고 이리저리 찾아봤는데 여기가 제일 설명이 잘되네요.....그런데 만약 부모자식 관계에서 업캐스팅이 일어난경우 업캐스팅이 일어난 변수에서 자식클래스의 메소드를 사용하고싶으면 다시 다운캐스팅을 해줘야 한다 이말인가요?

    • Mommoo 2021.03.25 00:25 신고

      읽어주셔서 감사합니다!!
      네 맞습니다. 정확하게 이해하셨네요 ^^

  12. ㄷㄷㄷ 2021.03.24 12:56

    미쳤다 멘탈나간상태로들어왔는데 너무 이해를 잘해버림.........


HashMap은 key 와 value 쌍으로 존재하는 


자료구조이다.


프로그래머가 key값을 알고 있는 상태에서 쓰는 경우도 있지만,


프로그래머가 동적으로 구한 데이터를 key, value 쌍으로 


HashMap을 쓴 경우는 프로그래머도 key 값이 무엇이 들어갔는지 알 수가 없다.


arrayList 처럼 index 가 정해져 있는것도 아니라


순차적으로 Log 에 찍어보기도 애매하다.


오늘 포스팅 내용은 이러한 상황에서 HashMap key값이 무엇이 있는지


구하는것이다.


HashMap 클래스 내부구조로 Set 자료구조에 key를 보관한 객체가 존재한다.


Set 객체를 통해 key를 가져오는 것이다. 


Set 객체에 들어있는 값(key)를 iterator 인터페이스를 통해, 순차적으로 탐색할 준비를한다.



HashMap<String,String> hashMap = new HashMap<>();

hashMap.put("key","value");


Set set = hashMap.keySet();

Iterator iterator = set.iterator();



가져온 후, iterator를 통해 순차탐색한다.


while(iterator.hasNext()){

  String key = (String)iterator.next();

  System.out.println("hashMap Key : " + key);

}


Entry 객체를 이용한 방법도 있다.


Entry 객체를 이용하면 key 와 value를 동시에 구할 수 있다.


물론 위에 코드로 key값을 구한 후, hashMap.get(key) 로 value를 구해도 상관없다.


Set set = hashMap.entrySet();

Iterator iterator = set.iterator();


while(iterator.hasNext()){

  Map.Entry entry = (Map.Entry)iterator.next();

  String key = (String)entry.getKey();

  String value = (String)entry.getValue();

  System.out.println("hashMap Key : " + key);

  System.out.println("hashMap Value : " + value);

}


주의할 점은 Set 자료형에 keySet() 을 넣은 경우와 entrySet() 경우를 잘 구별해서 이용 해야한다.




'Java' 카테고리의 다른 글

JAVA - [SWING] LinearLayout 사용하기.  (0) 2017.08.25
JAVA - DownCasting(다운캐스팅)  (24) 2016.08.27
JAVA - 변수 선언할때 m을 왜 붙일까?  (2) 2016.07.05
JAVA - UpCasting(업캐스팅)  (9) 2016.06.07
JAVA - Casting(캐스팅)  (0) 2016.05.26

포스팅이 도움 되셨다면, 커피 한잔 후원해주세요!
더 좋은 포스팅 작성에 큰 힘이 됩니다.

Buy me a coffeeBuy me a coffee
  1. 익명 2016.11.25 10:40

    비밀댓글입니다

아래의 코드를 보자.



public class Test{

  private Test mTest;

  public int add(int a, int b){

    int sum = a + b;

    return sum;

  }

}


Test 클래스의 변수엔 'm' 을 붙인 변수 mTest로 선언했고,


add메서드 안에 사용한 sum 변수는 m이 붙질 않았다.


라이브러리나, 가이드라인을 볼 시 많은 개발자들은 변수에 m을 붙이길래


궁금하여 찾아본 결과,


m은 Member의 약자라고 한다. 즉, 클래스의 멤버변수일시 m을 붙여줘 구분하는 것이였다.






'Java' 카테고리의 다른 글

JAVA - DownCasting(다운캐스팅)  (24) 2016.08.27
JAVA - HashMap key 구하기.  (1) 2016.08.25
JAVA - UpCasting(업캐스팅)  (9) 2016.06.07
JAVA - Casting(캐스팅)  (0) 2016.05.26
JAVA - ArrayList에서 배열로, 배열에서 ArrayList로  (2) 2016.04.25

포스팅이 도움 되셨다면, 커피 한잔 후원해주세요!
더 좋은 포스팅 작성에 큰 힘이 됩니다.

Buy me a coffeeBuy me a coffee
  1. JAMINS 2016.07.14 16:46 신고

    부연설명하자면 저런 변수 Naming 방식을 헝가리안 표기법이라고 하네.
    (https://en.wikipedia.org/wiki/Hungarian_notation
    https://namu.wiki/w/%ED%97%9D%EA%B0%80%EB%A6%AC%EC%95%88%20%ED%91%9C%EA%B8%B0%EB%B2%95)
    C, C++에서 많이 보던 네이밍 형식ㅋㅋ
    Java는 대부분 카멜 케이스를 사용하는듯. 물론 개발자 취향에 따라 헝가리안 표기법을 쓰는 경우도 있고

저번 포스팅은 캐스팅에 관해 전반적으로 다루었다.


아래의 URL은 이전 포스팅 내용이다.


http://mommoo.tistory.com/40


이전 포스팅 내용을 요약하자면 아래와 같다.


자료형이 정해진 변수에 값을 넣을때는


변수가 원하는 정보를 하나도 빠짐 없이 다 넣어줘야 성립한다.



이전 포스팅은 기본형으로 캐스팅을 설명했다면,


이번 포스팅은 참조형으로 캐스팅을 설명하려 한다.


기본적으로 캐스팅은 서로 관련없는 데이터 끼리는 변환되지 않는다.


int a = (int) true;


boolean 자료형이랑 int 자료형이랑 은 서로 성질이 맞지 않는 데이터 이므로,


형변환이 안되는 것 이다.


참조형(자바에서는 클래스) 데이터 역시 마찬가지다. 


그렇다면 참조형 데이터가 서로 관련이 있다고 하는 것은 무얼 의미 하는 것일까?


아래와 같은 상황일 것이다.


1. 상속관계가 맺어진 경우.


2. 인터페이스로 인해 확장이 된 경우.



1번 경우인 상속관계를 통해 예시로 설명 하겠다.


class Parent , class Child extends Parent 클래스 가 있다고 가정하자.


Child 는 Parent 클래스를 상속 받으므로 Chiid 클래스가 Parent 클래스 보다 가지고 있는


데이터 양이 무조건 많다. 왜냐하면 Child 클래스는 적어도 Parent 클래스의 데이터를 가지고 있기 때문이다.



때문에 많은 이들이 두 클래스의 구식도를 표현 할때 는 위와 같이 많이 한다.


사람마다 틀리겠지만, 후에 업캐스팅 다운캐스팅 개념을 위해 위와 같이 알아 놓아야 한다.


클래스 데이터 즉, 참조형을 사용할때는 아래와 같이 쓴다.


Parent parent = new Parent();


Parent 데이터형인 parent 변수는 실제 데이터인 new Parent(); 란 인스턴스가 Parent 정보를 모두 가지고 있으므로


오류가 나지 않는다.


아래의 경우는 어떨까?


Parent parent = new Child();


윗 개념으로 생각해보자.


parent변수는 Parent 자료형 데이터 모두를 원한다.


new Child(); 라는 인스턴스는 Parent 자료형 데이터를 모두를 가지고 있을까?


대답은 Yes 이다. 왜냐하면 Child 클래스는 Parent 클래스를 상속 받았기 때문이다.


따라서 성립한다. 엄연히 말하자면 데이터형은 틀리므로 아래와 같이 형변환 기호를 붙여야 한다.


Parent parent = (Parent) new Child();


하지만 위에서 말했다 시피, 변수가 원하는 정보를 인스턴스가 모두 가지고 있으므로,


컴파일러가 형변환 기호를 붙이지 않더라도 다형성 측면에서 넘어가는 것이다.


위와 같은 캐스팅을 '업캐스팅' 이라 부른다.


왜냐하면 Parent 데이터형 에 Child형 데이터를 넣어 생기는 아래와 같은 구식도 때문이다.


Parent 에 Child데이터를 넣으므로 화살표 방향이 위로 향하게 된다.


이런식으로 구조를 이해한다면 업캐스팅인 경우를 외우지 않아도 가능 할 것이다.


준비한 내용은 여기까지다.



다음 포스팅은 다음 캐스팅에 다룰 것이다.



http://mommoo.tistory.com/51 - 다운캐스팅







포스팅이 도움 되셨다면, 커피 한잔 후원해주세요!
더 좋은 포스팅 작성에 큰 힘이 됩니다.

Buy me a coffeeBuy me a coffee
  1. 2017.10.26 13:17

    업캐스팅 진짜 설명 잘 해놓으셨네요... 감탄하고 갑니다

  2. guest 2019.06.12 13:52

    정말 설명 잘 돼있네요.. 감사합니다 책 읽다가 뭔 소린지 몰라서 찾다가 한 방에 이해됐어요!

  3. 이야 2020.01.14 00:58

    잘 읽고 갑니다!! 한번에 이해가 잘 되네요ㅎㅎ

  4. 익명 2020.01.28 19:38

    비밀댓글입니다

  5. zzino 2021.01.23 17:52

    안녕하세요 설명 잘하시네요 :) 혹시 참조형데이터가 서로 상관이 있다는 경우 중 1번 상속으로 맺어진 관계는 이해를 했는데요 2번 인터페이스로 인해 확장이 된 경우는 어떤걸 의미하시는 건가요?

+ Recent posts