#오류에 대해 지적해 주시면 수정하겠습니다.

 

람다 표현식 (Lambda Expression)이란?

람다식은, 쉽게 말해 메서드를 하나의 식으로 표현한 것을 의미한다. 메서드를 람다식으로 표현하면, 메서드의 이름과 반환값이 없어지므로 람다식을 익명 함수라고도 한다. , 익명 함수의 일종이다.

 

 

 

람다 표현식은 왜 나왔을까?

Runnable Interface는 함수형 인터페이스!

 

 

위에 있는 Runnable interface처럼 메서드를 하나만 가진 인터페이스를 함수형 인터페이스라고 한다.

이전에는 Thread class를 생성하기 위해 Runnable interface안에있는 run 메서드가 필요한데, 자바는 메서드만 매개변수로 전달할 방법이 없으므로, 해당 메서드를 가지고 있는 Runnable 객체를 생성해서 전달해야한다. 즉, 자바는 매번 객체를 생성해서 매개변수로 전달 해야한다. 

메서드만 전달 할 수 있다면 좀더 편하게 프로그래밍 할 수 있지 않을까? 해서 등장한게 람다다.

 

 

 

 

 

JVM은 Thread의 생성자를 보고, 이게 무엇인지 대상을 추론한다고 한다!

 

 

생성자 매개변수로 뭔가 메서드가 하나 들어왔는데, Thread의 생성자를 보아하니 이건 Runnable이겠군!

Thread 생성자 API 보면, Runnable 인터페이스를 받아들이는 것을 알고있는 JVM람다식을 Runnable을 구현하는 객체로 자동으로 만들어서 매개변수를 넣어준다.

 

 

 

함수형 인터페이스

// @FunctionalInterface

함수를 1급 객체처럼 다룰 수 있게 해주는 어노테이션으로, 인터페이스에 선언하여 단 하나의 추상 메서드만 갖도록 제한하는 역할을 한다.

왼쪽은 메서드가 두개니까 오류가 난다

# 1급 객체 : 변수나 데이터에 할당할 수 있으며, 객체의 인자로 넘길수 있어야하고, 객체의 리턴값으로 리턴할 수 있는 객체

 

 

Java에서 제공하는 함수형 인터페이스

  • Supplier<T>
  • Consumer<T>
  • Function<T>
  • Predicate<T>

 

 


 

 

람다식이 없었을 땐?

1. 인터페이스를 구현한 클래스의 객체 생성

기존 자바에서 다형성을 제공하기 위해 인터페이스를 만들고, 그것을 구현한 클래스를 작성한 뒤,

사용시에는 인터페이스 타입의 참조변수에 인터페이스를 구현한 클래스 객체를 생성해서 사용했다.

인터페이스 구현한 클래스 객체 생성

 

 

 

2. 익명 객체

위와 같이 따로 클래스를 만들지 않고, 바로 코드 내에서 익명 객체를 만들어서 사용하기도 했다. 하지만 익명 객체는 재활용이 불가능하므로 Good를 구현한 객체가 자주 사용되어야 한다면, 아래와 같은 코드를 반복해서 사용하게 되고, 그러면 코드가 지저분해진다.

익명객체

 

 

 

람다식으로 바꿔보자!

람다

 

람다 표현식 정리!

1.컴파일러는 람다식을 해석해, 자동으로 익명구현객체로 만든다.

2.이 때, 익명구현객체의 기반이 되는 인터페이스의 타입을 타겟 타입이라고 한다.

3.타겟 타입이 될 인터페이스는 2개 이상의 추상 메서드를 가지면 안된다.

그 이유는, 2개 이상의 추상 메서드를 가질 경우, 컴파일러가 해당 람다식이 타겟 타입의 어떤 메서드를 구현한 것인지 알 수 없기 때문이다.

 

 

 


 

 

람다식 표현법

1.매개변수 타입을 추론할 수 있는 경우, 타입을 생략할 수 있다.

2.매개변수가 하나인 경우에는 괄호() 생략할 수 있다. (타입이 없을 때만 가능)

3.함수의 몸체가 하나의 명령문만으로 이루어진 경우, 중괄호{} 생략할 수 있다.
  (
이 때, 세미콜론은 붙이지 않는다.)

4.함수의 몸체가 하나의 return 문으로만 이루어진 경우, 중괄호를 생략할 수 없다.

5.return문 대신 표현식을 사용할 수 있으며, 이 때 반환값은 표현식의 결과값이 된다.
  (
이 때, 세미콜론은 붙이지 않는다.)

 

 

#오류에 대해 지적해 주시면 수정하겠습니다.

 

JDK

JDK = JRE + 개발툴( ex. apt, appletviewer, javac, javap, jar, jdb )

 

개발툴 중 대표적으로 javac를 보자면 Java코드를 컴파일 하는 친구이다. 아래 그림처럼 Java코드를 byte코드로 컴파일한다.

 

•apt : 어노테이션 툴

•appletviewer : 웹브라우저 없이 자바 애플릿을 실행하고 디버깅하기 위한 툴

•javac : 자바 컴파일러. 자바 소스파일을 바이트코드로 변환

•java : javac가 만든 클래스 파일을 해석 및 실행

•jar : 서로 관련있는 클래스 라이브러리들과 리소스를 하나의 파일로 묶어주는 툴

•jdb : 자바 디버깅 툴

 

 

 

 

 

JDK의 종류

  1. Java SE(Standard Edition) 
    Java가 어떠한 문법적인 구성을 가졌는지와 같은 것들을 나타내는 명세표
    네트워킹,보안,그래픽 사용자 인터페이스 개발,XML파싱,데이터베이스 등을 지원
  2. Java EE(Enterprise Edition)
    Java SE + 서버에서 동작하는 기능
    추가적으로 웹프로그래밍에 필요한 JSP, Servlet, JDBC 등의 기능을 제공
  3. Java ME(Micro Edition)
    Java SE + 휴대전화,PDA에서 java 프로그래밍 지원

 

 

 


 

 

JRE

JRE = JVM + Java Class Library

 

Java Class Library는 런타임시 클래스 로딩이 발생하는데 그때 참조하는 class들이 모여있는 도서관이다.

Class Loader의 위치에 대한 고찰은 Class Loading에 대해서 다룰때 더 자세히 언급하겠다. 일단은 JVM에 포함 시켰다.

 

 

 

 


 

 

JVM

다른 언어는 OS의 종류에 따라, CPU아키텍처에 따라 동작안한다. 그니까 컴파일한 환경이랑 그 프로그램을 실제 동작시킬 환경이랑 다르면 동작이 안할 수도 있다는 뜻이다. 따라서 컴파일 된 코드를 어디서나 실행 될 수 있도록 하기위해 탄생한게 JVM이다.

 

 

 

 

JVM의 구성요소

JVM은 크게 Class Loader, Execution Engine, Runtime Data Areas로 나누어져 있다.

Class Loader Subsystem – 로드, 링크 및 초기화 담당, 동적 클래스 로드라고도 함
  (클래스로더 편에서 자세히 다룰예정)

Runtime Data Areas method areas, PC registers, stack areas,  threads.

  (JVM의 메모리 구조편에서 자세히 다룰 예정)

Execution Engineinterpreter,  compiler ,  garbage collection area.

  (JVM의 메모리 구조편과 GC편에서 자세히 다룰 예정)

 

 

 

 

JVM의 특징

1. 스택 기반의 가상머신

2. 심볼릭 레퍼런스

3. 가비지 컬렉션

4. 기본 자료형을 명확하게 정의하여 플랫폼 독립성 보장

5. 네트워크 바이트 오더(network byte order)

 

이들 중 가비지 컬렉션은 GC편에서 자세히 보도록 하고, 1,2,5번을 중점으로 보겠다.

 

스택 기반의 가상머신?

일단 스택 기반과 대조되는 레지스터 기반 가상머신을 보겠다.

5 + 30 + 40 을 계산한다고 하면, CPU의 덧셈 연산은 2개의 피연산자를 다루므로 5 + 30 를 계산한 결과를 40 과 더해야만 한다. 레지스터 기반의 VM은 피연산자를 레지스터에서 가져와서 계산하고, 결과를 다시 레지스터에 저장한다.

, 레지스터 기반의 VM은 피연산자를 레지스터에서 가져와서 계산한 뒤 다시 레지스터에 저장한다. 레지스터 기반의 VM의 장단점은 다음과 같다.

명령어의 수가 적고 스택을 사용하지 않아 스택에 대한 오버헤드가 없으나 명령어의 크기가 커지고, 명령어에 오퍼란드를 명시해야 하므로 명령어가 길어진다.

 

레지스터 기반 가상머신

 

 

이번에는 스택 기반 가상머신을 보겠다.

13 + 20 + 7 을 계산한다고 하자. CPU의 덧셈 연산은 2개의 피연산자를 다루므로 20 + 7 를 계산한 결과를 13 과 더해야만 한다. 스택 기반의 VM은 이 결과를 바로 스택에 저장한다. 위 그림을 보면, 207을 더하기 위해서 두 피연산자를 스택에서 꺼낸다. 꺼낸 결과를 가지고 계산한 뒤에 다시 결과를 스택에 넣는 것을 알 수 있다.

, 스택 기반의 VM은 피연산자를 저장하고 가져올 때 스택을 활용한다. 스택 기반의 VM의 장단점은 아래와 같다.

이러한 스택 기반의 VM은 명령어의 수가 많아지고 오버헤드에 대한 위험성이 존재한다.

 

하지만 그럼에도 JVM스택기반을 쓰는 이유는 JVM의 모토가 WORA이기 때문이 아닐까.

레지스터 기반의 가상머신은 CPU내의 레지스터에 저장하기 때문에 하드웨어 의존적이 되기 쉽다. 예를들면 레지스터 개수나, 레지스터의 사이즈 같은 것들이 있다.

 

 

스택 기반 가상머신

 

 

 

심볼릭 레퍼런스?

아까 말한것처럼 .java를 컴파일해서 만들어진 파일이 .class파일이다.

컴파일 된 바이트코드를 javap를 사용해 역 어셈블리화해보면 아래와 같다. 이러한 결과물을 자바 어셈블리라고 부른다.

위에서 다섯번째 줄에있는 5: invokevirtual #23; 를 보자.

Invokevirtual은 메서드를 호출하는 대표적인 명령어다. 그밖에도 아래와 같은 것들이 있다.

 

•invokeinterface: 인터페이스 메서드 호출

•invokespecial: 생성자, private 메서드, 슈퍼 클래스의 메서드 호출

•invokestatic: static 메서드 호출

•invokevirtual: 인스턴스 메서드 호출

 

자바 바이트코드의 명령어는 OpCode와 피연산자(Operand)로 분리할 수 있으며, invokevirtual과 같은 OpCode는 2바이트의 피연산자를 필요로 한다. 당연히 무언가를 호출하는 명령어니까 피연산자가 필요하다.

그니까 5: invokevirtual #23; 를 해석해보면, 코드앞에 숫자 (지금같은경우는 5)는 바이트번호이고 뒤에 #23은 피연산자이다. 그니까 23번에 해당하는 인스턴스 메서드를 호출하라는 뜻인 것이다.

 

 

 

 

 

 

JVM을 거치면서 .class파일은 실행가능한 형태로 바뀌게 되는데 이때 JVM에서 실행가능한 형태로 바뀌는 과정을 Linking이라 부른다. 이처럼 .class파일은 그때그때 Link를 할 수 있도록 Symbolic Reference만을 가지고 있다.

이러한 Linking필요할때마다 동적으로 이루어지기 때문에 Dynamic Linking이라 부르게 되었다.

이 다이나믹 링킹 기술 덕분에 class의 크기를 작게 유지할 수 있었고 Network를 통해 배포하는데 유리하다.

 

Class파일의 4가지 특징

1. Compact한 형태

2. Bytecode로의 변경

3. Platform 독립적

4. 네트워크 바이트 오더(network byte order)

 

 

 

 

 

 

 

네트워크 바이트 오더?

일단 네트워크 바이트 오더를 말하기전에 엔디안(Endian)이라는 말을 알아야한다.

엔디안이라는 말은 걸리버 여행기에서 소인국 릴리퍼트 이야기에서 달걀을 깰때 뭉뚝한 끝을 먼저 깨는 사람들, 뾰족한 끝을 먼저 깨는 사람들 사이에 싸운거에서 따온거라고 한다.

마치 한국의 부먹 찍먹같은거 인가보다. 마찬가지로 빅 엔디안과 리틀 엔디안 중 무엇을 쓰는지에 대해 논란이 있는편이라고 한다.

 

 

 

 

 

일단 컴퓨터는 1Byte단위로 읽기 때문에 bit를 읽는 순서는 변하지 않는다.

하지만 Byte를 읽는 순서는 CPU마다 차이가 있다고 한다. 그러므로 바이트 오더는 바이트를 읽는 순서를 의미한다.

바이트 오더는 빅 에디안 방식과 리틀 에디안 방식으로 나뉘는데 각각

 

빅 에디안 방식은 상위비트 -> 하위비트 순으로,

리틀 에디안 방식은 하위비트 -> 상위비트 순으로, 읽는다.

 

자바 클래스 파일은 네트워크 전송 시에 사용하는 바이트 오더인 네트워크 바이트 오더를 사용한다.

네트워크 바이트 오더는 빅 엔디안이다. 이러한 사실은 JAVA 설계될때부터 Network를 고려했음을 알게 해준다. 

 

 

 

 

 

 

#오류에 대해 지적해 주시면 수정하겠습니다.

 

다형성이란?

객체 지향 프로그래밍의 중요한 특징 중의 하나로 함수 이름이나 연산자가 목적으로 사용될 수 있는 것을 의미.

객체 지향에서 다형성이란 클래스가 하나의 메시지에 대해 각 클래스가 가지고 있는 고유한 방법으로 응답할 수 있는 능력을 의미하며, 응용 프로그램에서 하나의 함수가 연산자 두 개 이상의 서로 다른 클래스의 인스턴스들을 같은 클래스에 속한 인스턴스처럼 수행 할 수 있도록 하는 것을 말한다.

 

 


 

 

자바에서의 다형성

자바에서의 다형성은 하나의 객체가 여러가지 타입을 가진다는 것을 의미한다. 자바에서는 이러한 다형성을 부모 클래스 타입의 참조 변수로 자식 클래스 타입의 인스턴스를 참조하는 방식으로 구현하게 된다.

아래의 Parent 클래스와 Child 클래스를 보면 Parent 클래스가 자신을 상속받고 있는 Child 클래스를 참조할 수 있음을 확인 할 수 있다.

 

 

 

하지만 반대의 경우는 성립 되지 않는다. Child class가 Parent class를 상속 받았기 때문에, Child class에서 사용할 수 있는 멤버의 개수는 Parent class보다 무조건 많거나 최소 같을 것이다. 그러므로 아래와 같은 경우 참조 변수가 사용할 수 있는 멤버의 개수가 실제 인스턴스의 멤버 개수보다 많기 때문에 다음과 같이 쓸 수 없다.

 

 

오류가 났다!

 

 

일반 클래스 뿐만 아니라 자체로 객체 생성이 불가능한 인터페이스도 해당 인터페이스를 implements한 클래스를 참조하는 방식으로 다음과 같이 작성할 수 있다.

 

 

 

 

 


 

다형성을 사용하는 이유

1. 동적할당

 

2. 기능 제한

 

3. 기능변경 / 추가

 


 

 

 

instanceof

instanceof는 변수의 타입을 확인할 수 있는 예약어로 true/false를 반환한다.

프로그램의 안정적 동작을 위해 객체의 형변환시 변환하려는 참조변수의 타입을 확인할 때 사용한다.

아래의 경우 b인스턴스는 Bus를 참조하고 있지만, b는 Bus가 상속받고 있는 Vehicle 또한 참조할 수 있으므로 아래와 같은 코드에서 b instanceof Vehicle은 true를 반환하게 된다.

 

(+) Serializable이나 Comparable과 같은 인터페이스를 상속받았는지 확인 할 때도 많이 쓴다고 한다!

 

 

 


 

 

 

Overloading / Overriding

사실 overloading은 자바의 다형성과는 관련이 없지만 overriding과 이름이 비슷하기 때문에 같이 다뤘다.

 

 

-overloading

단어 뜻을 보자면 겹쳐서 짐따위를 싣는다는 것이다. 

우리가 매일같이 쓰는 println을 보면 똑같은 이름의 메서드로 여러개가 만들어져 있음을 알 수 있다. 이처럼 오버로딩은 이름이 같은 함수를 여러개 선언하는 것을 의미한다.

이름만 똑같으면 되고, 반환형은 달라도 상관없으며, 매개변수는 반드시 달라야 한다. 또한 접근제어자도 상관없이 사용할 수 있다.

 

 

 

-overriding

단어 뜻을 보자면 치환한다는 것이다. 다시 말해서 부모의 메소드를 자식 클래스에서 재정의 하는 것을 의미한다.

아래의 경우를 보면, 여러 종류의 자동차 클래스들이 Vehicle을 상속받고 있고 maxPassenger 메소드를 overriding 하고 있다. overriding을 할 땐, 메소드명, 매개변수, 리턴형이 반드시 같아야하며 접근제어자는 부모 클래스의 메소드의 접근 제어자보다 더 넓은 범위의 접근 제어자를 자식 클래스의 메소드에서 설정할 수 있다.

 

(+) 리스코프 치환원칙에 따라 더 넓은 범위의 접근 제어자를 써야한다.

https://stackoverflow.com/questions/5378995/confused-with-java-overriding-the-access-level

 

 

오버라이딩을 사용해서 구현하면 장점이 무엇이 있을까?

다음 코드에서 v객체의 참조형을 변경해가면서 각각 오버라이딩한 메서드를 호출하는 것을 확인해 볼 수 있다.

override를 적절히 활용하면 코드가 유연해지고 유지보수성이 높아진다. 

 

 

 

결론

다형성이란, 부모 클래스가 자신을 상속받은 다른 클래스들의 형태로 변할 수 있다는 것.이를 사용해 오버라이딩에 대해 정리 해봤고, 이름이 비슷한 오버로딩도 같이 정리해 봤다.

  오버로딩 오버라이딩
접근제어자 상관없다. 부모클래스보다 더 넓은 범위여야한다.
리턴형 상관없다. 반드시 같아야한다
메소드명 반드시 같아야한다 반드시 같아야한다
파라미터 반드시 달라야한다 반드시 같아야한다

 

#오류에 대해 지적해 주시면 수정하겠습니다.

 

직렬화(Serialization)

객체 등 특정 구조의 데이터를 이후 복원할 수 있는 형태의 데이터로 전환하는 과정

 

역직렬화(Deserialization)

직렬화된 데이터를 복구하는 과정

 

하지만 이렇게만 보기엔 왜 이름이 직렬화인지 와닿지 않을 수 있으므로

좀더 와닿게 써보자.

 

 

 

이미지의 직렬화 과정

나는 컴퓨터 비전이라는 과목에서 직렬화를 처음 접했다.

컴퓨터비전은 영상이나 이미지속에서 특정 물체를 검출하거나 배경 검출, 색상 검출 등등 을 하는데 이미지를 바로 처리할 수 없으므로 항상 직렬화를 해야했다.

그림과 같이 이미지는 0 1로 구성된 화소들의 집합인데, 이것을 저렇게 직선으로 하나하나 펴서 배열로 처리를 하게된다. 그렇기 때문에 이름이 직렬화가 아닐까.

 

 

 

 

 


 

 

 

직렬화/역직렬화를 하기에 앞서

일단 그전에 직렬화/역직렬화를 할 객체에 Serializable interface을 상속받아야한다!

Serializable을 상속받은 User class

이 Serializable interface는 단순 마커 인터페이스이기 때문에 안이 텅텅 비어있다. 그래서 추가로 구현해야할 메소드도 없다! 단지 선언만 하면 된다.

하지만 직렬화/반직렬화 과정에서 Serializable이 있는지 없는지 체크하기 때문에 없다면 NotSerializableException이 발생하므로 반드시 상속받아놔야한다.

 

(+) instanceOf를 이용해 직렬화가 가능한 객체인지 확인하기도 좋다

 

 

직렬화

직렬화 할 땐, ObjectOutputStream class의 writeObject메소드를 이용해서 한다.

ObjectOutputSteam 인스턴스를 생성시 생성자안에 ByteStream계열을 넣어줘야한다.

직렬화 예시코드

 

 

역직렬화

역직렬화 할 땐, ObjectInputStream class의 readObject메소드를 이용해서 한다.

ObjectInputSteam 인스턴스를 생성할때 역시 생성자안에 ByteStream계열을 넣어줘야한다.

역직렬화 예시코드

 

 

 

 

방금 직렬화/역직렬화 과정을 그림으로 나타내보면 위와 같겠다

 

 

 

 

 


 

 

 

직렬화 관련 이슈사항

사실 직렬화 관련해서 이슈사항은 굉장히 많다. 이번 글에서 아래 두 가지에 대해 정리해 보겠다.

 

- 보이지 않는 생성자, readObject

- 싱글톤 패턴 객체 직렬화 시

 

 

 

보이지 않는 생성자, readObject

일단 직렬화를 할 객체를 생성했다. PositiveNumber객체로 직렬화를 위해 Serializable을 상속받았음을 확인 할 수있다.그리고 이름값을 하기 위해 필드에 선언되어있는 value는 양수의 값만 가져야 할 것이다.그렇게 되게 하기 위해 개발자는 생성자 내부에 value가 양수인지 확인하는 if문을 삽입했다.그럼 이 객체에 양수가 아닌 다른 의도하지 않은 수가 들어 올 수 없을까?

 

PositiveNumber 객체

 

정답은 NO이다. 

 

이 객체를 직렬화 하게 된다면

직렬화된 객체를 다시 반직렬화하는 과정에서 readObject 메서드를 호출하게 되는데 이과정은 개발자가 만든 생성자를 거쳐서 만들어지지 않기 때문에 value가 양수인지 확인하는 과정을 거치지 않는다.

 

따라서 악의적인 이용자가 의도적으로 내부 바이트를 수정하게 되면 다른 값으로 바뀔 수도 있다는 뜻이다.

 

이처럼 readObject()메서드는 실직적으로 숨겨진 또다른 생성자이다. 다른 생성자처럼 validation에 신경써야한다.

이를 해결하기 위해선 커스텀 readObject() 메서드를 만들면 되는데 이는 바이트 스트림을 매개변수로 받는 생성자라고 생각하면 된다. 일반 생성자와 동일하게 유효성 검사를 진행하면 앞서 말한 보안적 결함을 막을 수 있다.

 

커스텀 readObject를 생성한 PositiveNumber 객체

 

 

 

싱글톤 적용 객체 직렬화시

두번째 이슈사항은 싱글톤 객체를 직렬화 했을 때 이다.

일단 간단한 싱글톤 객체를 만들어보았다. 역시 직렬화를 위해 Serializable을 상속받았다.

이 객체를 직렬화했다가 역직렬화하게 되면 다른 객체가 생성되기 때문에 싱글톤이 의미가 없어지게 된다.

 

MySingleton 객체

 

이 문제를 해결할 수 있는 방법은 readResolve() 메서드이다.

MySingleton객체 안에 readResolve()메서드를 만들어서 이미 생성되어있는 인스턴스를 반환하도록 한다.

그러면 readObject메서드 이후 (생성되어있다면) 자동으로 readResolve()메서드를 실행한다.

이러한 방법으로 객체를 바꿔치기할 수 있다.

 

readResolve()를 생성한 MySingleton 객체

 

 

 

 

전체적인 flow

 

 

 

writeObject()이후 대상 바꾸기

readResolve 메서드는 역직렬화시 대상을 바꿔주는 일을 수행한다. 마찬가지로 직렬화 이후 대상을 바꿔주는 일을 수행하는 메서드도 있다. 바로 writeReplace 메서드이다!

 

 

이 메서드는 어디에 이용할 수 있을까?

 

 

 

 

보이지 않는 생성자의 또 다른 해결방안, 직렬화 프록시 패턴

이 메서드를 이용해서 아까 다루었던 보이지 않는 생성자 문제를 해결 할 수 있다.

아까의 PositiveNumber class를 다시 보자.

 

자세히 보면 유효한지 확인하는 것을 모든 생성자마다 해야함을 알 수 있다. (+ readObject메서드에서도)

이러한 작업은 신경써야할 포인트가 많다는 뜻이기도 하다. 이러한 단점을 보완할 수 있는 방법이 바로 직렬화 프록시 패턴을 이용하는 것이다.

 

 

PositiveNumberProxy라는 중첩클래스를 만든다. 이 친구는 직렬화만 전담하는 대변인인것이다.

직렬화를 하기위해 writeObject()메소드가 실행되면, writeReplace직렬화할 객체를 proxy객체로 바꾼다.

그러면 직렬화가 되는 객체는 본래 클래스가 아니라 프록시 클래스가 직렬화 되게 된다.

그리고 이후 직렬화된 상태를 나중에 역직렬화하게 된다면, readObject()메소드가 실행될것이고, 바로 readResolve()메소드가 실행되서 객체를 본 객체로 바꾼다.

러면 유효성 검사를 본래 객체 생성자에서만 하면되므로 코드 관리가 편안해진다.

 

직렬화 프록시 패턴

 

 

 

 


 

 

 

결론

정리해보자면 직렬화/역직렬화 할 때 앞서 말한 것들을 반드시 고려해야 하며 고려하지 않았을시 심각한 문제를 초래할 수 있다고 한다. 사실 직렬화 관련해서 이슈사항은 이 글에서 언급한 것들보다 훨씬 많다고 한다.

그렇기 때문에 직렬화말고 JSON이나 CSV와 같은 모든 플랫폼에 적용되는 형식을 사용하는 것이 바람직하다.

 

그럼 왜 공부한거ㅈ..

#오류에 대해 지적해 주시면 수정하겠습니다.

 

System class

입출력을 하기위해선 운영체제의 도움이 반드시 필요하다. 하지만 자바는 운영체제 상에서 바로 실행되는 것이 아니라 JVM이라는 가상 머신위에서 작동된다. 따라서 직접 운영체제가 제공하는 기능에 접근하기는 힘들다.

JVM

 

 

이러한 기능들을 접근할 수 있게 도와주는게 System class이다!

System class를 이용하면 운영체제의 일부 기능을 이용할 수 있다. 예를 들면 프로그램 종료, 입출력, 시간읽기 등이 있다. System class의 모든 필드와 메소드는 static으로 구현되어 있다.

System class의 일부

System class 내부를 보면 InputStream, PrintStream이라는 객체형태의 in, out, err이 선언되어있다. 바로 이것들을 사용해서 자바는 입출력을 한다!

 

 

 


 

 

InputStream/OutputStream

InputStream이나 OutputStream은

"데이터가 들어오고 나가는 통로의 역할에 대해 규정해 놓은 추상클래스"라고 생각하면 된다.

InputStream class
OutputStream class

 

 

 


 

 

자바의 입출력

기본적으로 자바의 입출력은 Stream 기반이다. 컴퓨터 공학에서 스트림이란 연속적인 데이터의 흐름이나 데이터를 전송하는 소프트웨어 모듈을 의미한다. 다음 그림과 같이 자바는 스트림을 통해 입력/출력을 받게 된다.

책 - 황기태, 『 명품 JAVA Programming 』, 생능출판(2005), 442p

 

Stream의 특징

이러한 Stream은 3가지 대표적인 특징이있는데, 다음과 같다.

  1. 단방향
  2. 기본 단위는 바이트/문자
  3. FIFO구조

 

 

Byte Stream/Char Stream

Stream의 입출력 기본 단위는 바이트나 문자이다. 바이트를 기본단위로 받는 스트림을 Byte Stream, 문자를 기본단위로 받는 스트림을 Char Stream이라 한다.

 

-ByteStream중 입력을 받는 class들은 InputStream 추상클래스를 상속받아 만들어진다. 모두 InputStream로 끝난다.

-ByteStream중 출력을 하는 class들은 OutputStream 추상클래스를 상속받아 만들어진다. 모두 OutputStream로 끝난다.

-CharStream중 입력을 받는 class들은 Reader 추상클래스를 상속받아 만들어진다. 모두 Reader로 끝난다.

-CharStream중 출력을 하는 class들은 Writer 추상클래스를 상속받아 만들어진다. 모두 Writer로 끝난다.

InputStream/OutputStream/Reader/Writer을 상속받는 다양한 종류의 Stream들

 

 

자바의 버퍼입출력

버퍼입출력에 대해서는 조금더 자세히 알아보겠다.

ByteStream계열에는 BufferedInputStream, BufferedOutputStream

CharStream계열에는 BufferedReader, BufferedWriter이 해당된다.

 

입출력은 운영체제 API를 호출하는 방식으로 작동 되는데, 당연히 자주 운영체제 API가 호출될 수록 실행속도가 떨어진다. 그래서 스트림에게 각각 버퍼를 가지게 해서, 한번에 호출해서 가져오는 것이다.

책 - 황기태, 『 명품 JAVA Programming 』, 생능출판(2005), 442p

 

 

Stream Chain

스트림은 서로 연결 될 수 있다. 마치 쿠키를 만드는 시스템과 같다. 컨베이어 벨트 위에있는 밀가루 반죽을 한 파트는 적절한 크기로 자르고 한 파트는 쿠키틀로 모양을 내고 한 파트는 구울 것이다. 스트림도 그와 마찬가지로 입력 혹은 출력값을 내가 원하는 형태로 입력/출력하는 것이다. 스트림은 몇 개라도 연결 될 수 있다.

자바로 코딩테스트하면 맨날 쓰는 문장!

 

 

 


 

 

 

표준입출력과 객체입출력

- 표준입출력

System클래스를 사용하여 하는 입출력을 표준입출력이라 한다. 시스템 클래스를 보면 정수형, 실수형, 문자형, 바이트 등등.. 다양한 자료형을 입출력 하기위한 메서드가 있다.

 

표준입출력
출력을 하기위해 오버로딩된 print 메서드들

 

- 객체입출력

하지만 이세상에 그보다 훨씬 다양한 자료형이 존재한다. 이를테면 우리가 수업시간에 만든 class들이 있겠다. 이러한 객체들을 입출력하는 것을 객체입출력이라 한다. 객체입출력을 하기 위해서는 직렬화/역직렬화를 해야한다. 이에 대해서는 다음글에서 더 자세히 알아보겠다.

 

 

 

 

 

 

(+)

 

PrintStream vs OutputStream에 대해서

https://stackoverflow.com/questions/11372546/printstream-vs-printwriter

 

+ Recent posts