과학

자바로 프로그래밍에 입문할래요: 3.1. 자료형 (1)

내가 번역할 마지막 챕터인 3장, 객체지향의 시작이야.

개인적으로 자바는 객체지향의 정수라고 생각해.

 

2.3. 재귀 (2)

2.3. 재귀 (1)

2.2. 라이브러리와 클라이언트 (3)

2.2. 라이브러리와 클라이언트 (2)

2.2. 라이브러리와 클라이언트 (1)

2.1. 정적 메소드 (2)

2.1. 정적 메소드 (1)

1.5. 입출력 (2)

1.5. 입출력 (1)

1.4. 배열 (3)

1.4. 배열 (2)

1.4. 배열 (1)

1.3. 조건문과 반복문 (2)

1.3. 조건문과 반복문 (1)

1.2. 내장 자료형 (2)

1.2. 내장 자료형 (1)

0.0. 여는 글, 1.1. 첫 프로그램 만들기

 

================================

 

 

객체지향 프로그래밍

  효과적인 프로그래밍을 위한 다음 단계는 개념적으로 단순합니다. 여러분은 이제껏 기본 자료형들을 어떻게 사용하는지 배웠고, 이제는 더 높은 단계의 자료형들을 다뤄볼 것입니다. 이는 여러분들이 직접 만들고 설계할 수 있죠.

 

  추상화란, 무언가를 간단히 묘사하는 것입니다. 세부사항들은 뒤로 하고, 필수적인 부분들만 가져다 놓는 것이죠. 과학, 공학, 프로그래밍 등의 분야에서 우리는 복잡한 시스템을 이해하기 위해 추상화를 사용합니다. 자바 프로그래밍은 곧 객체지향 프로그래밍입니다. 거대하고 복잡한 시스템을, 서로 상호작용하는 요소 및 객체로 세분화하여 다루죠. 객체지향은 전자, 사람, 건물, 태양광 시스템과 같은 현실 세계의 개체를 모델링하는 것으로부터 비롯된 아이디어입니다. 더 나아가 우리는 비트, 숫자, 색, 사진, 프로그램과 같은 추상화 개체로 손쉽게 확장해나갈 것입니다.

 

  기억나시나요? 자료형이란, 값과 그 값에 정의된 연산들의 집합입니다. 기본 자료형으로, int와 double 등이 자바에 내장되어 있었습니다. 객체지향 프로그래밍에서, 우리는 이와 같은 자료형을 새로 만들 것입니다. 객체란, 해당 자료형의 값을 가질 수 있는 것입니다. 객체의 값은 그 자체로 클라이언트에게 반환돼 이용될 수도 있죠. 또, 해당 자료형의 연산을 통해서 값이 변경되기도 합니다.

 

  새로운 자료형을 정의하고 해당 자료형의 값을 지니는 객체를 생성한다는 것은 곧 자료 추상화를 해내는 것입니다. 또한 우리가 챕터 2에서 해왔던 함수 추상화를 자연스럽게 확장하고, 곧 모듈화 프로그래밍을 해낼 수 있습니다. 이번 챕터의 주문은 다음과 같습니다: "자료 및 해당 자료와 관련된 작업을 분할할 수 있다면, 그렇게 해야 합니다."

 

 

자료형

  우리는 컴퓨터 프로그램을 개발하기 위해, 반드시 자료를 정리해야 합니다. 자바에서의 프로그래밍은 자료형(기본 자료형과 구분하여, 참조형이라고도 말합니다)에 기반을 두고 있습니다. 자료의 구성 및 처리를 용이하게 하는 객체지향이죠. 

 

  여러분이 이제껏 사용해왔던 8가지 기본 자료형(boolean, byte, char, double, float, int, long, short)은 곧 참조형의 기반이 됩니다. 이들을 통해 수많은 응용프로그램들을 다룰 수 있죠. String 역시 이러한 예시 중 하나입니다. 아시다시피 String은 기본 자료형이 아니죠. 자바에 내장되어 있을 뿐입니다.

 

  우리는 이러한 참조형들에 대해서 배울 것이며, String과 함께 같이 내장되어 있는 Color, 그리고 In, Out, Draw, Picture 등의 자료형들 또한 공부해볼 것입니다. 이들은 1.5절에서 다루었던 Std* 정적 메소드 라이브러리들처럼 다뤄볼 것입니다.

 

  여러분들은 이제껏 두 챕터를 공부하면서, 수학에 진절머리가 났을 것입니다. 당연히 그 이유는 자바의 기본 자료형들이 수를 표현하기 때문입니다. 다행히 지금부터는 참조형과 함께 프로그램을 작성할 수 있습니다. 문자열, 그림, 소리, 그리고 수백 가지의 추상화들을 제공해드릴 예정입니다.

 

  이렇게 제공되는 라이브러리를 사용할 수 있다는 사실보다 더 중요한 것은, 여러분들이 어떤 것이든 간에 추상화를 통해 자신만의 자료형을 정의할 수 있다는 사실입니다. 이 능력은 현대 프로그래밍에서 아주 중요합니다. 모든 응용프로그램을 아우를 수 있는 라이브러리란 존재하지 않습니다. 여러분들은 이러한 상황에 언젠가는 직면할 것이며, 결국 자신만의 자료형을 다루는 능력이 필요할 것입니다.

 

 

기본 정의들

  자료형이란, 값의 집합과 그 값에 정의된 연산의 집합입니다. 이 문구는 너무나도 중요하기에, 지속적으로 외워야 할 주문과 같습니다. 챕터 1에서 우리는 자바 기본 자료형의 세부사항에 대해서 이야기해봤죠. 예를 들어, int형은 정수를 표현하며, -2^31 ~ 2^31-1의 값을 표현합니다. 연산은 +, *, %, <와 같은 산술 및 비교 연산들로 이루어졌습니다. 

 

  또한, String과 같은 기본 자료형이 아닌 것도 다루어봤습니다. 여러분은 "특정 자료형을 사용하기 위해서 해당 자료형이 어떻게 구성되어있는지 전혀 알 필요가 없음"을 경험해보셨을 것입니다. 단순히 문자들의 집합이라는 것과, 연결 연산자를 활용하는 방법정도만 알고 있었죠. 여러분들은 String에, 길이를 알아내거나 문자열의 일부를 추출하는 등 꽤 많은 연산들이 숨어있다는 사실을 이번 절에서 배우게 될 것입니다. 

 

  또한, 여러분이 자료형을 사용할 때는 이 아닌 연산에 집중해야 합니다. 여러분이 프로그램을 작성하면서 int나 String의 값을 사용할 때에는, 그 값들이 어떻게 표현되는지에 대해 스스로 고민할 필요가 없습니다.(실제로, 우리는 세세히 파고들지 않았습니다) 또한 이는 여러분이 앞으로 프로그램에서 색이나 그림을 다룰 때에도 마찬가지입니다.

 

 

예제

  자료형을 어떻게 사용하는지 확인해봅시다. 우리는 Charge라는 자료형으로 하전 입자(전하를 띄고 있는 입자)를 다뤄볼 것입니다. 특히, 우리는 쿨롱 법칙(Coulomb's law)을 사용하는 2차원 모델에 관심이 있습니다. 쿨롱 법칙에서 한 입자의 전위는 주어진 점으로부터 V = kq/r 을 만족합니다. q는 전하 값, r은 전하와 점과의 거리, k는 상수입니다. 

 

  다양한 하전 입자들이 존재할 때, 특정 점의 전위는 각 전하로 인한 전위의 합입니다. 우리의 목적은 주어진 평면의 다양한 하전 입자로부터, 다양한 점에서의 전위를 계산하는 것입니다. 따라서 우리는 Charge라는 자료형을 정의해야 합니다. 3.2절에서 어떻게 자료형을 구현하는지에 대해서 배울 것입니다. 하지만, "자료형을 사용하기 위해 구현된 방법을 알 필요는 없습니다."

 

 

API

  자바 클래스는 자료형을 정의하는 메커니즘을 제공합니다. 클래스에서는, 자료형의 값과 자료형 연산의 구현을 명시합니다. "자료형을 사용하기 위해 구현된 방법을 알 필요는 없다"는 약속을 지키기 위해서, 우리는 그들의 메소드를 API에 목록화하는 것으로 클래스들의 행위를 명시합니다. 과거, 라이브러리들의 정적 메소드를 사용했을 때처럼 말이죠. API는 여러분들이 특정 자료형을 프로그램에서 손쉽게 사용할 수 있도록 작성되는 것입니다. 다음은 Charge 클래스의 API입니다.

 

하전 입자를 위한 API

 

 

 

  첫번째 항목은, 클래스 이름과 같고 반환 타입이 없는 특별한 메소드입니다. 바로 생성자(constructor)입니다. 그 외에는 인스턴스 메소드(instance method)라고 하여, 정적 메소드랑 동일한 형식의 메소드입니다. 단, 이들은 자료형을 위한 연산들을 구현합니다. Charge는 두 인스턴스 메소드를 구현합니다. potentialAt()은 주어진 점에서의 전하로 인한 힘을 계산합니다. toString()은 해당 하전 입자를 문자열로 표현하여 반환해줍니다.

 

 

자료형 사용하기

  라이브러리의 정적 메소드들을 사용해본 것과 다르지 않습니다. 클래스의 이름과 동일한 파일명을 지닌 .java 파일을 포함해주면 됩니다. Charge를 사용하는 프로그램을 작성하기 위해서, 여러분들은 Charge.java 파일에 접근해야 합니다. 자바의 클래스패스 메커니즘을 이용하거나, 여러분의 프로그램과 같은 경로에 Charge.java 파일을 포함하면 됩니다.

 

  이렇게 하면, 여러분들은 해당 자료형의 값을 갖는 객체를 생성하고 변수를 선언할 수 있습니다. 또한 각 값들에 대해 메소드를 호출할 수도 있죠. 이러한 작업들은 기본 자료형을 다룬 것과는 다릅니다. 하지만 아주 비슷하다는 것을 곧 알게 될 것입니다.

 

 

변수 선언하기

  변수 선언은 기본 자료형 변수를 선언할 때와 완벽하게 똑같습니다. 원하는 자료형과, 그 뒤에 변수의 이름을 쓴 구문을 사용하면 됩니다. 예를 들어, 다음 선언은 Charge 타입의 변수 c를 선언하는 것입니다.

 

 
Charge c;

 

  이 구문은 아무것도 생성하지 않습니다. 이는 단순히 c라는 이름으로 Charge 객체를 참조할 것이라는 의미일 뿐입니다.

 

 

객체 생성하기

  자바에서 자료형의 값은 객체에 저장됩니다. 클라이언트가 생성자를 호출하면, 자바 시스템은 각 객체를 생성(혹은 인스턴스화)합니다. 생성자를 호출하기 위해서, 여러분은 new라는 키워드를 사용할 수 있습니다. new 뒤에는 클래스 이름을 적고, 그 뒤에는 생성자의 인자들을 적습니다. 정적 메소드의 호출과 동일합니다. 예를 들어, new Charge(x, y, q)는 새로운 Charge 객체를 만듭니다. 위치는 (x, y)이 될 것이고, 전하량은 q가 될 것입니다.

 

 
Charge c = new Charge(0.51, 0.63, 21.3);

 

  여러분은 같은 클래스의 객체를 몇 번이고 생성할 수 있습니다. 각 객체는 고유하게 존재하며, 같은 값을 갖고 있더라도 서로 다른 객체로서 구분될 것입니다. 예를 들어, 다음 코드는 서로 다른 세 Charge 객체를 생성합니다. 특히, c1과 c3은 서로 다른 객체를 참조합니다. 서로 같은 값을 갖고 있더라도 말입니다.

 

 
Charge c1 = new Charge(0.51, 0.63, 21.3);
Charge c2 = new Charge(0.13, 0.94, 85.9);
Charge c3 = new Charge(0.51, 0.63, 21.3);

 

 

메소드 호출하기(Invoking methods)

  참조형 변수와 기본 자료형 변수의 중요한 차이점은, 참조형은 해당 자료형에 구현된 메소드를 호출할 수 있다는 것입니다.(+나 *와 같은 연산자하고는 조금 다릅니다) 이러한 메소드들을 인스턴스 메소드라고 합니다. 인스턴스 메소드를 호출하는 것은, 다른 클래스의 정적 메소드를 호출하는 것과 유사합니다. 단, 인스턴스 메소드는 단순히 클래스 뿐만 아니라 개별 객체와도 연관되어 있습니다. 정적 메소드의 경우, 메소드를 호출하기 위해 클래스의 이름을 이용했었죠. 인스턴스 메스드는 객체의 이름을 이용해서 메소드를 호출할 수 있습니다. 

 

 

프로그램 3.1.0: Charge

*해당 프로그램은 개정 되기 이전의 책에 있던 내용입니다. 책 개정 이후 현재 프린스턴 대학교에서 제공하지 않아, 역자가 직접 프로그램을 첨부합니다. 이를 복사하여 다른 Charge.java 파일을 만들어 다른 *.java 프로그램와 같은 경로에 삽입하면 됩니다. 내용에 대한 이해는 책의 순서 상 필요 없으니 넘어가도록 하세요.

 
public class Charge {
	private final double rx, ry;
	private final double q;

	public Charge(double x0, double y0, double q0) {
		rx = x0;
		ry = y0;
		q = q0;
	}

	public double potentialAt(double x, double y) {
		double k = 8.99e09;
		double dx = x - rx;
		double dy = y - ry;
		return k * q / Math.sqrt(dx * dx + dy * dy);
	}

	public String toString() {
		return q + " at (" + rx + ", " + ry + ")";
	}
	
	public static void main(String[] args) {
		double x = Double.parseDouble(args[0]);
		double y = Double.parseDouble(args[1]);
		Charge c1 = new Charge(0.51, 0.63, 21.3);
		Charge c2 = new Charge(0.13, 0.94, 81.9);
		StdOut.println(c1);
		StdOut.println(c2);
		double v1 = c1.potentialAt(x, y);
		double v2 = c2.potentialAt(x, y);
		StdOut.printf("%.2e\n", (v1 + v2));
	}
}

 

 

프로그램 3.1.1: Charge Client

 
public class ChargeClient {
	public static void main(String[] args) {
		// Print total potential at (x, y).
		double x = Double.parseDouble(args[0]);
		double y = Double.parseDouble(args[1]);
		Charge cl = new Charge(.51, .63, 21.3);
		Charge c2 = new Charge(.13, .94, 81.9);
		double vl = cl.potentialAt(x, y);
		double v2 = c2.potentialAt(x, y);
		StdOut.printf("%.1e\n", vl+v2);
	}
}
% java ChargeClient .2 .5
2.2e+12
% java ChargeClient .51 .94
2.5e+12

 

  <ChargeClient>는 두 개의 Charge 객체를 생성하고 주어진 위치에서의 전위를 계산합니다. 이 코드를 통해, 우리는 추상화된 모델이 어떻게 구현되어있는지는 상관 없이 클라이언트로부터 사용될 수 있음을 알 수 있습니다. Charge의 코드를 굳이 알지 않아도, 내부적으로 정의된 메소드들만을 이용해서 원하는 것을 해낼 수 있죠. 객체지향의 중요한 특징 중 하나입니다.

 

 

참조(Referneces)

  생성자는 객체를 생성하고 클라이언트에게 해당 객체의 참조를 반환합니다. 객체 자체를 반환하는 것이 아닙니다. 참조형이라고 불리는 이유입니다. 참조란 무엇일까요? 객체에 접근하는 방법 그 이상 그 이하도 아닙니다. 자바에서 참조를 구현하는 방식은 꽤 다양하고, 그것을 우리가 굳이 알 필요는 없죠. 그럼에도, 흔한 구현 방법 하나 정도는 알고 있는 것이 좋습니다. 

 

  그것은 바로 new 키워드가 객체의 현재 값을 저장하기 위해 메모리 공간을 할당하고, 그 주소를 가리키는 포인터(pointer, machine address)를 반환하는 것입니다. 우리는 객체 식별자처럼, 객체를 가리키는 주소를 참조합니다. 왜 곧바로 객체를 처리하지 않을까요? 

 

각 객체를 참조하는 c1, c2의 표현

 

  작은 객체들은 곧바로 객체를 처리해도 괜찮을지 모릅니다. 하지만 객체의 크기가 커지면 커질수록, 그 비용은 문제가 됩니다. 자료형 값은 굉장히 복잡할 수도, 많은 양의 메모리를 필요로 할 수도 있습니다. 객체를 복사하거나 그것의 자료를 옮기거나, 메소드의 인자로 넘기는 등의 상황에서는 결코 간단한 이야기가 아니죠. 어디서 좀 본 것 같은 이야기 아닌가요?

 

  배열을 정적 메소드와 같은 곳에 인자로 넘겨줄 때 우리는 이와 똑같은 이야기를 했습니다. 배열 또한 객체이며, 이번 절의 후반에 다루게 될 것입니다. 반면, 기본 자료형들은 메모리에 직접적으로 저장되며, 연산들 또한 기계 연산으로 바로 전환됩니다. 우리는 앞으로 예제들을 통해 참조에 대한 세부적인 내용들을 다뤄보게 될 것입니다. 자바에서 참조를 다루는 것이 위 그림과 같이 단순하지는 않겠지만, 기본 자료형과 참조형의 차이를 보여줍니다.

 

 

객체 사용하기

  우리는 객체의 변수 이름을 선언함으로써, 정수형이나 부동소수점 수들을 다루는 방법과 별반 다르지 않게 코드에서 사용할 수 있습니다. 

  • 메소드의 인자나 반환 값으로 사용할 수 있다.
  • 대입문에서 사용할 수 있다.
  • 배열에서 사용할 수 있다.

  우리는 이미 String 객체들을 수도 없이 이용해왔습니다. 대부분의 프로그램에서 StdOut.println()을 이용해 String 인자를 넘겼었죠. 또, main() 메소드는 String 객체의 배열을 인자로 받습니다. 또한, 위의 목록에서 하나 더 추가할 것이 있습니다. 아주 중요한 것이죠.

  • 해당 인스턴스에 정의된 메소드를 호출할 수 있다.

  이것은 기본 자료형에는 유효하지 않은 용법입니다. 기본자료형에 사용될 수 있는 연산자는 언어에 내장되어 있는 +, -, *, /와 같은 것들뿐이죠.

 

 

형변환(Type conversion)

  만약 여러분이 한 객체를 다른 객체로 변환하고 싶다면, 이를 위한 코드를 작성해야 합니다. 보통은 각 자료형이 지닌 값들이 서로 너무나도 달라, 서로 변환되는 것을 고려할 필요가 없습니다. 예를 들어, Charge를 Color로 변환하는 것은 의미조차 가늠하기 힘들죠. 

 

  하지만 여러분은 이미 수많은 형변환을 경험했습니다. 바로 toString() 메소드입니다. 자바의 모든 참조형들은 반드시 toString() 메소드를 이용해서 본인 객체를 String으로 반환합니다. 더군다나, 만약 String이 필요한 자리에 해당 객체가 있다면 자바가 알아서 그 객체의 toString() 메소드를 호출해줍니다. 여러분들이 변수 x를 표현하기 위해 StdOut.println(x)를 손쉽게 사용할 수 있는 이유입니다.

 

 

초기화되지 않은 변수

  만약 여러분이 참조형 변수를 선언만 하고 아무것도 대입하지 않는다면, 그 변수는 초기화되지 않은(uninitialized) 것입니다. 만약 여러분이 다음 코드처럼, 기본 자료형을 사용하듯이 참조형 변수를 사용하게 된다면 컴파일 에러가 발생합니다.

 

 
Charge bad;
double v= bad.potentialAt(.5, .5);

 

  이는 초기화되지 않은 변수를 사용하려고 시도했기 때문입니다. (NullPointerException이 발생합니다-옮긴 이)

 

 

인스턴스 메소드와 정적 메소드의 차이

  드디어 여러분들은 static 키워드의 진정한 의미를 알 준비가 되었습니다. 아마 여러분들이 자바 프로그램을 작성하면서 남은 마지막 의문이었을 겁니다. 정적 메소드는 기본적으로 함수를 구현하기 위해 사용합니다. 정적이 아닌(인스턴스) 메소드는 자료형의 연산을 구현하기 위해 사용합니다.

 

  여러분은 우리의 클라이언트 코드를 통해 메소드의 두 형태를 구분할 수 있을 것입니다. 정적 메소드는 언제나 클래스 이름(대문자로 시작, 이는 관습입니다)으로 시작하며, 인스턴스 메소드는 언제나 객체 이름(소문자로 시작, 이는 관습입니다)으로 시작합니다. 이 차이는 다음 표를 통해서 참고해보세요. 여러분들이 직접 코드를 쓰다보면, 이 차이는 금방 깨달을 수 있을 것입니다.

 

인스턴스 메소드 vs 정적 메소드

 

  우리가 방금 다룬 기초적인 개념은, 단순히 객체지향 프로그래밍의 시작점이므로 이를 요약하여 되새길 필요가 있습니다. "자료형이란 값의 집합과 그 값에 정의된 연산의 집합이다." 우리는 자료형을 독립적인 모듈에서 구현하며, 그것을 클라이언트 프로그램에서 사용합니다. 객체란 자료형의 인스턴스입니다. 객체의 특징은 세 가지 속성으로 볼 수 있습니다: 상태, 행위, 아이덴티티. 

  • 객체의 상태란, 그 자료형의 값입니다. 
  • 객체의 행위란, 그 자료형에 정의된 연산입니다. 
  • 객체의 아이덴티티란, 객체가 메모리에 저장된 곳입니다. 

  객체지향 프로그래밍에서, 생성자를 호출해 객체를 생성하며, 인스턴스 메소드를 이용해 그들의 상태를 변경합니다.

 

  우리는 몇몇 예제들을 통해, 객체지향의 힘을 입증해볼 것입니다. 먼저, 이미지 처리에 대해서 공부해볼 것입니다. 색과 그림 객체를 이용합니다. 그 후엔, String 객체와 연관된 연산들에 대해서 알아볼 것이며 그것이 과학 응용 프로그램에서 어떤 중요성을 갖는지 알아볼 것입니다.

 

계속.

4개의 댓글

2021.07.22

객체 자료형 이야기나와서그런데 자바가 왜 OOP언어인지 설명해주는 특집도 좋아보임

DI라던가 왜 추상클래스가있는지 이런거

내가 대학다닐때 처음에 c언어다배우고 java배우는데 이럴거면 c언어도 다되는데 왜 자바쓰는거지? 이생각 많이했는데

헤드퍼스트에서 전략패턴공부하면서 와 이게 객체지향언어구나 깨닿고 자바랑 사랑에빠짐

암튼 왜 객체지향언어인지 알려주는것도 재밌을거라 생각해

0
2021.07.22
@전산실김씨

맞아. 나도 디자인 패턴을 배우면서 객체지향에 대한 시야가 확 넓어졌었어. 아는 만큼 보인다는 게 이런 말이지 싶더라. 말한 것들에 대해 누군가가 정리해주면 재밌게 읽을 것 같네.

0
2021.07.23
0
무분별한 사용은 차단될 수 있습니다.
번호 제목 글쓴이 추천 수 날짜
11318 [호러 괴담] [살인자 이야기] 딸의 시신이 발견 된 가방은 3개. 범인이 가... 그그그그 3 18 시간 전
11317 [기타 지식] 비트코인에 물린 뉴턴 경 8 jdjj2828 3 1 일 전
11316 [기타 지식] DC유저의 개인프로젝트_월간 위스키 -2- 2 소가죽으면다이소 6 2 일 전
11315 [기타 지식] DC유저의 개인프로젝트_월간 위스키 -1- 4 소가죽으면다이소 5 2 일 전
11314 [기타 지식] 의사들은 공공의대를 왜 반대할까 1.5편 : 미용시장을 포화시... 21 막시무스아돌로프 15 2 일 전
11313 [기타 지식] [음감3]절대음감의 장점과 단점 10 Rockth 13 3 일 전
11312 [기타 지식] 의사들은 왜 공공의대를 반대할까? 1편 79 막시무스아돌로프 31 3 일 전
11311 [호러 괴담] [살인자 이야기] 캠핑을 갔다 사라진 소녀들. 베가 여학생 살... 6 그그그그 3 3 일 전
11310 [역사] 후삼국시대 호족 분포도 35 틱택톡탁 8 4 일 전
11309 [기타 지식] 인물사진 피부 보정하는 개인적인 루틴 23 우울한삐에로 6 4 일 전
11308 [기타 지식] (수도권) 부동산이 오를 수밖에 없는 이유. 62 허약체질개선 17 4 일 전
11307 [기타 지식] [음감2:부록]실제로 일본에서 있었던 절대음감 습득실험 6 Rockth 3 4 일 전
11306 [기타 지식] 개인적으로 생각하는 진실의 필요성 10 jdjj2828 4 5 일 전
11305 [기타 지식] 거주유형과 집값이 결혼과 출산율에 미치는 영향 22 로봇다닐 10 5 일 전
11304 [기타 지식] 트라우마에 대한 몇 가지 정보 7 jdjj2828 4 5 일 전
11303 [호러 괴담] [살인자 이야기] 1900년대 뉴욕에서 두 번째로 전기의자에 앉... 1 그그그그 3 5 일 전
11302 [역사] <북학의>: 기술 학문 예찬 4 미분가능하지않은... 6 6 일 전
11301 [기타 지식] (장문똥글 내 군생활글임)누군가를 진지하게 죽이고싶다 라고... 19 악마의속삭임 10 7 일 전
11300 [기타 지식] (장문똥글 내 군생활글임)누군가를 진지하게 죽이고싶다 라고... 악마의속삭임 1 7 일 전
11299 [기타 지식] (장문똥글 내 군생활글임)누군가를 진지하게 죽이고싶다 라고... 악마의속삭임 0 7 일 전