자바 용어 정리

Violet_Evgadn·2023년 4월 23일
0

Java

목록 보기
6/13

자바 프로그램 구조

클래스

JAVA의 모든 프로그램 소스는 클래스 단위로 시작한다.

일반적으로 클래스 이름과 소스파일명은 동일하며, 실행을 위해서는 main() 메서드가 필요하다.

객체(인스턴스) 설계도를 담당한다. 클래스를 선언하고 인스턴스를 만들면 클래스 형태를 가진 인스턴스가 만들어지는 것이다

인스턴스

클래스의 형태로 생성된 객체이다.

클래스가 설계도라면 인스턴스는 실제 목자재 등의 재료로써 이런 인스턴스들을 쌓아서 전체 프로그램을 구성하게 된다.

인스턴스의 목적은 멤버 변수를 통한 정보 보관 및 멤버 메서드를 통한 행위이다.

인스턴스의 주솟값을 레퍼런스라고 하며, 레퍼런스 값을 저장한 변수를 레퍼런스 변수라고 한다.

예시를 통해서 본 클래스와 인스턴스

class Class_Example{
	int num1;
	String name;
}
// Class_Example : 클래스. 인스턴스를 만들 때 모든 인스턴스는 num1, name이라는 공간을 가지는 형태로
// 생성되게 된다.

public class Main2 {
	
	public static void main(String[] args) {
		Class_Example classes = new Class_Example();
        	// classes : Class_Example이라는 클래스로 만들어진 Instance. 
	}
}

주석

대부분의 프로그램 언어는 주석을 지원한다.

코드 자체에 주석을 달기 위해서 JAVA 에서는 //를 통해 1줄 주석을 달 수 있으며, /* ~~~~ */를 통해 여러 줄 주석도 가능하다

또한 JavaDoc과 같은 특수한 목적도 존재하는데 JavaDoc은 /** ~~~ */으로 추가할 수 있다.

class Class{
	// 주석을 1줄만 달기 위해선 //를 사용!
    
    /* (원래 여기서부터 주석을 달아도 되지만, 개인적으로 여기는 너무 더러워 보여서 비워놓는 편)
    *  주석을 여러줄 달기 위해선 /* 사용!
    *  중간 *표시는 엔터를 입력하면 자동으로 추가되며 주석칸이 늘어남
    *  중간 *표시가 없어도 주석으로 처리됨
    */
    
    /**
    *   JavaDoc 달기. JavaDoc은 나중에 따로 정리할 예정
    /
}

자바 식별자(Identifier) 규칙

변수, 상수, 메서드, 클래스 등을 선언할 때 이름을 붙여야 하는데, 이를 식별자라고 하며 규칙이 몇 개 존재한다.

  • 첫 문자는 문자나 _, $으로 시작해야 한다.
    • 대부분 문자로 시작하는 경우가 많다
  • 첫 문자가 아닐 경우 특수문자, 문자, 숫자 모두 활용할 수 있다
    • 단지, 공백은 포함할 수 없다.
  • 자바 예약어는 식별자로 사용할 수 없다
    • 예약어란 이미 자바 측에서 문법 적인 용도로 활용하고 있는 단어(식별자)를 말한다.
    • 예를 들어, 정수형 자료를 나타내는 int, 문자형 변수를 나타내는 String 등은 식별자로 활용할 수 없다.
  • 자바 식별자는 대소문자를 구분한다.
  • 식별자 길이는 제한이 없다

Coding Convention

Convention이란 문법적으로 무조건 지켜야 하는 약속은 아니지만, 관례 같은 것을 의미한다.

즉, 굳이 이렇게 코드를 짜지 않아도 되지만 코드를 읽을 때 조금 더 편하게 읽기 위해 이렇게 짜는 것을 추천하는 약속 같은 개념이다

  • 클래스 이름은 대문자 알파벳으로 시작 & 명사형
  • 메서드 이름은 소문자 동사
  • 변수는 소문자 알파벳으로 시작하는 명사
  • 상수는 대문자로만 이루어진 명사
  • 이름을 지정하는 방법은 Camel Case와 Snake Case가 가장 유명하다
    • Camel Case : 낙타 등처럼 알파벳 대문자를 단어가 단어(형태소)가 끝날 때 추가해주는 것이다.
      • (Ex) camelCase
    • Snake Case : 언더바(_)가 들어 있는 표현 방식으로 뱀을 닮았다고 해서 Snake Case라고 한다.
      • (Ex) snake_case
    • Pascal Case : Camel Case는 "중간 알파벳"이 대문자이지만, Pascal Case는 첫 알파벳도 대문자를 가진다. PascalCase 처럼 식별자 이름을 정하는 것이다

변수

변수란?

변수는 데이터를 저장하기 위한 메모리 공간에 대한 이름이다.

내가 메모리 100에 1을 저장했다고 가정했을 때, 우리는 메모리 100을 직접 찾지 않고 mem이라는 변수에 메모리 주소를 저장하여 mem을 통해 메모리 100에 저장된 1값을 활용하는 것이다.

(mem : 레퍼런스 변수, 주소값 100 : 레퍼런스)

자바의 경우 원시 자료형, 클래스 타입을 모두 지원하고 있으며 원시 자료형들도 클래스 타입으로 표기할 수 있는데 이를 Wrapper Class라고 한다.

(원시 자료형 : 자바 측에서 미리 제공하는 자료형. 클래스 타입 : "우리가 만들었거나 자바 측에서 만들었던" 클래스 자료형)

원시 자료형

자바 원시 자료형 종류는 위 사진과 같다.

  • byte : 가장 작은 단위. 8bit로 구성되어 있음
  • char : 음수를 포함하지 않는 Unsigned 자료형. 문자(알파벳) 표현에 적합. 2 Byte
  • short : 음수를 포함한 2 Byte 크기 자료형.
  • int : 정수의 기본 자료형으로 4 Byte 크기를 가짐. 생각보다 범위가 작음에 주의하자
    • -2147483648~2147483647가 int형 범위
    • 주로 10⁹이 넘지 않는 수를 활용할 때 사용하는 자료형(넘으면 long 사용)
  • long : 충분한 정수 범위를 활용해야 할 경우 사용하는 자료형. 8 Byte 크기를 가짐
  • float : 4 Byte 크기를 가진 실수 자료형. 실수형의 기본이 아니기 때문에 숫자 뒤에 f를 붙여 float임을 명시해줘야 한다
  • double : 실수형의 기본 자료형. 8 Byte 크기를 가짐
  • boolean : 참/거짓을 나타내는 자료형으로 1 Byte 크기를 가짐. True / False 값밖에 가질 수 없음

여기서 중요한 점은 JAVA에서 많이 활용되는 String은 기본 자료형이 아니라는 것이다.

C언어 등에서 문자열을 활용해봤으면 결국 문자형도 문자의 배열형태라는 것을 알 수 있다.

따라서 String은 "클래스 타입"으로 간주해야 하는 것이다

Wrapper Class

JAVA에서는 원시 자료형이 아닌 "Class Type" 형태만 입력으로 받는 경우가 존재한다.(대표적인 예시로 Collection이 존재한다)

Primitive 원시 자료형은 클래스가 아닌데, 그러면 이 때문에 새로운 클래스를 하나 선언해야 할까?

정답은 NO이다.

이런 문제를 해결하기 위해 활용하는 것이 Wrapper 클래스이다. Primitive 자료형마다 개별의 Wrappper 클래스가 존재하며 클래스 이름은 아래와 같다.

  • Integer : int
  • Byte : byte
  • Long : long
  • Short :short
  • Float : float
  • Double : double
  • Boolean : boolean
  • Character : char

추가 Auto Boxing과 Auto Unboxing이라는 것이 존재한다.

Auto Boxing이란 Primitive 데이터를 자동으로 Wrapper 클래스로 바꿔주는 과정이고, Auto UnBoxing이란 Wrapper 클래스로 저장되었더라도 연산을 수행할 때는 다른 클래스처럼 주솟값을 활용하는 것이 아닌 Primitive 자료형처럼 실제로 저장되어 있는 Data로 계산을 수행하는 과정을 말한다. 예시를 통해 자세히 알아보자.

// Auto Boxing
Integer num = 10; 
// num은 클래스 이므로 원래라면 new Integer(10)으로 선언해줘야 한다.
// 하지만 Integer는 Wrapper 클래스로써 10이라는 Primitive 데이터를 자동으로 클래스로 변환해준다

// Auto Unboxing
num + 1; 
// num은 현재 "클래스" 형태를 띄기 때문에 사실은 +1 연산을 수행할 수 없다.
// 하지만 Auto Unboxing을 통해 num을 int형처럼 생각하여 10 + 1 = 11 연산을 자동으로 수행해준다

변수 유형

  • 멤버 변수(Field)

    • 클래스 내부에 선언된 변수들
    • 인스턴스 변수와 클래스 변수로 구분됨
      • 인스턴스 변수 : Instance화(객체로 만들어질 때) 초기화되는 변수로 만들어진 인스턴스를 통해서만 접근할 수 있음. 인스턴스 1개당 독립적으로 1개씩 존재한다.
      • 클래스 변수 : static으로 선언된 변수. 중요하기 때문에 따로 설명
  • 매개 변수

    • 메서드에 인자로 전달되는 값을 받기 위한 변수
    • 메서드 내에서는 지역변수 처럼 활용됨
  • 지역 변수

    • 메서드 내에서 선언된 변수
    • 멤버 변수와 동일한 이름을 가질 수 있지만, 이 경우 지역 변수가 우선시 된다.
      • this 예약어를 통해 멤버 변수에 접근 가능하지만, 개인적으로는 생성자 이외의 경우에는 지역 변수와 멤버 변수 이름을 구분짓는 것이 좋은 것 같다
  • 클래스 변수

    클래스 변수를 생성하는 방법은 간단하다. 인스턴스 변수에 static 예약어만 붙여주면 된다.
    그렇다면 이 클래스 변수가 도대체 뭐가 중요하길래 인스턴스 변수와는 다르게 따로 설명까지 추가하였을까?

    클래스 변수는 모든 인스턴스(객체)가 공통된 값을 공유한다.
    따라서 모든 인스턴스들이 공통된 메모리 값을 바라보며, 이 때문에 클래스가 로딩될 때 생성되어 메모리에 딱 한번 올라가고 이후 메모리 값이 바뀌지 않는다.

    자. 머리가 헷갈릴 수 있다. 예시를 들어보자.
    "소나기"라는 책이 팔리고 있다고 가정하자.
    "소나기"라는 책은 고유의 특징을 가지고 있다. 책 고유 번호인 ISBN 값도 다를 것이며 생성 시간도 다를 것이다. 또한 바코드도 다를 것이다.
    이런 Instance 1개가 생성될 때 마다 온전히 Instance 고유의 값을 가질 수 있는 것이 "인스턴스 변수"이다.
    하지만 소나기라는 책의 가격은 동일해야 할 것이다. 또한 책이 팔릴 때마다 팔린 책의 숫자도 1 증가 해야 할 것이다.
    이 때 클래스 변수를 사용하는 것이다.

    static int selling = 0static long price = 2000이라고 설정되었다고 가정하자.
    그리고 소나기 책 1, 2, 3, ..., 100이 존재한다고 가정하자.
    1, 2, 3, ..., 100은 모두 똑같은 주솟값의 selling과 price를 가진다. 조금 더 쉽게 이해해보자.
    만약 1, 2, 3이 팔렸다. 그렇다면 책 1, 2, 3의 selling 값에 1씩을 더해준다.
    이후 책 100에서 selling이라는 주솟값에 접근한다고 가정해보자. 책 1, 2, 3은 결국 "똑같은 주솟값"에 접근하여 1씩을 증가시켰으므로 3이 될 것이고, 해당 주솟값에 책 100이 접근할 것이기 때문에 책 100은 아무 것도 하지 않았지만 selling 값이 3으로 변하게 된 것이다.
    또한 책 값을 변경할 때에도 책 100의 price에 접근하여 3000으로 수정하더라도 "똑같은 주솟값"에 접근하여 수정한 것이므로 결국 책 1, 2,... , 99의 price도 3000으로 변경된 값을 가지게 되는 것이다.

    모든 Instance가 같은 주솟값을 보기 때문에 굳이 여러 번 초기화 할 필요가 없으므로 클래스가 처음으로 로딩될 때 메모리 할당을 해주고 더 이상 메모리를 할당하지 않는 것이다.

    이 static이라는 예약어가 매우 특수한 이유는 static 함수 내에는 외부에서 선언된 변수 중 static 변수밖에 사용할 수 없다. 또한 결국 모든 Instance가 공유하는 값이므로 취급에 주의를 기울여야 한다. 따라서, 꼭 static이 필요한지 잘 생각해보고 활용하는 것을 추천한다.


용어 정리

아래 용어는 사실 JAVA에서만 활용되는 것은 아니다. Python이나 C언어에서도 매우 중요시 하는 개념들이다.
단지 JAVA에서 처음 다루기 때문에 JAVA Section에서 다룰 뿐이므로 JAVA를 사용하지 않을 것이더라도 꼭 이해야하는 개념들이다

얕은 복사, 깊은 복사

얕은 복사는 복사본에 변경이 일어날 경우 원본에도 변경이 일어나는 복사이다(반대로 원본이 변경되더라도 복사본이 변경된다)

깊은 복사는 반대로 원본으로부터 Item 값만 복사해 오는 복사로써 원본의 변형이나 복사본에 영향을 끼치지 못하고 반대의 경우도 그러하다.

왜 이런 상황이 벌어질까? 이는 복사의 방법 차이이다.

얕은 복사는 한 마디로 말하자면 "주솟값의 공유"이다. 사실은 실제로 복사가 되는게 아니라는 의미이다.

JAVA가 Instance에 접근하는 방법은 간단하다. 레퍼런스 변수에 저장되어 있는 메모리 주소를 찾아가 해당 메모리에 저장되어 있는 값을 꺼내오는 것이 Instance에 접근하는 방식이다.

그렇다면, 2개의 레퍼런스 변수가 똑같은 메모리 주소를 가지면 어떻게 될까? 마치 외부에서 볼 때는 2개의 변수가 복사되었다(일치한다) 라고도 착각할 수 있지 않을까? 이것이 얕은 복사의 개념인 것이다.

원본 파일의 주솟값이 100이라고 했을 때 얕은 복사는 복사본이 주솟값 100을 가리키도록 만들어준다. 그렇다면 우리는 복사본이 원본과 동일한 것처럼 보이기 때문에 복사가 되었다고 착각하는 것이다.

이제는 왜 원본과 복사본이 서로 영향을 끼치는지도 알 수 있을 것이다. 결국 원본이든 복사본이든 똑같은 주솟값을 가리키고 있기 때문에 원본을 복사본을 변경하든 똑같은 객체를 변경하는 것이라고 볼 수 있는 것이다.

깊은 복사는 정말로 우리가 생각하는 복사이다.

원본과 다른 공간(메모리 주소)에 원본 크기의 공간을 마련한 뒤 원본의 모든 값을 복사 + 붙여넣기 하여 원본을 복사하는 방식이다.

깊은 복사는 다른 메모리 주소에 새로운 Instance를 만들어 값을 복사 후 붙여넣은 것이기 때문에 원본과 복사본은 다른 주솟값을 가지며 당연히 이후 서로 영향을 끼치지 않은 독립적인 2개의 Instance가 되는 것이다

동적 할당, 정적 할당

프로그램에서 값을 저장하기 위해 필요한 만큼 메모리에 공간을 확보하는 것을 메모리 할당이라고 한다. 할당을 해 주는 방법에는 동적 할당과 정적 할당이 있는데, 과연 어떤 차이가 존재할까?

  • 정적 할당
    • Compile 때 할당 여부가 결정됨
    • 수명이 결정되어 있음
    • 자료형에 따라 메모리 크기가 정해지고, 정해진 메모리 크기는 프로그램을 실행할 때 마다 변하지 않음
    • 한 번 할당되면 자료형과 Size를 변경할 수 없음
    • 지역 변수, 정적 변수, 상수 등
    • RAM 메모리의 Stack 영역 활용
    • 정적 할당은 Compile 시 이미 할당 여부가 결정되고 확장이 불가능하므로 무조건 필요한 메모리 크기를 알고 있어야 한다. 만약 필요한 메모리 크기를 알지 못한다면(예를 들어, 배열의 길이를 모르는 경우) 충분히 큰 크기로 공간을 할당하여야 하는데 이 경우 공간이 부족하다면 코드를 다시 수정해야하고 공간이 너무 남는다면 메모리가 낭비될 것이다.(친구가 1명이 있을 수도 있고 100명이 있을 수도 있는데 친구 이름을 담기 위한 배열 길이를 50으로 짜버리면 100명 친구는 모두 들어갈 수 없고 1명을 가진 사람을 위해 49개의 공간이 낭비되게 된다.)
      위와 같은 이유로 메모리를 효율적으로 사용하기 어렵고, 프로그램이 정상적으로 실행되지 못하는 경우도 발생한다.
  • 동적 할당
    • 런타임(프로그램 실행) 때 할당 여부가 결정됨
    • 정적 할당과 달리 프로그램 실행하면서 결정되는 크기나 요구하는 만큼 메모리를 할당해주기 때문에 정적 할당처럼 미리 메모리 크기를 조사하여 코드를 짤 필요가 없음
    • 원하는 시점에서 추가하고 해제가 가능하지만, JAVA에서는 Garbage Collection을 활용하므로 자원 해제는 사실상 불가함
    • RAM 메모리의 Heap 영역 활용
    • JAVA에서 적극적으로 사용하는 할당으로, new 연산자를 통해 활용할 수 있다

프로그램 언어별 동적 할당 및 메모리 해제 방법

  • C언어 : free()
  • 동적 할당 : malloc()
  • 해제 : free()
  • Python : del()
  • 동적 할당 : 변수만 선언해주면 됨
  • 해제 : free()
  • JAVA
  • 동적 할당 : new 연산자 활용
  • 해제 : Garbage Collection을 통해 Unreachable Object 자동으로 해제

요약

자바 프로그램 구조는 클래스, 인스턴스, 주석과 변수로 크게 구성된다.

클래스는 설계도의 역할을 하며 인스턴스는 클래스를 가지고 와서 실제로 내가 사용할 물건을 만든 것이라고 생각하면 된다.

변수란 데이터를 저장하기 위한 메모리 공간을 가리키는 이름을 의미하는데 JAVA에서는 원시 자료형, 클래스 타입을 모두 지원하고 있다.

원시 자료형은 byte, char, short, int, long, float, double, boolean형이 존재하며 각각의 원시 자료형마다 Wrapper Class라는 것이 존재하여 클래스 타입으로도 활용할 수 있다

변수 유형은 클래스 내부에 선언된 멤버 변수(Field), 메서드 인자로 전달되는 매개 변수, 메서드 내에서 선언된 지역 변수와 static 예약어를 활용하여 모든 Instance에서 공유하는 클래스 변수가 존재한다.

복사 방식에는 주솟값을 공유하는 얕은 복사와 다른 주솟값에 모든 값을 복사하여 새로운 객체를 만드는 깊은 복사가 존재한다.

메모리에 공간을 확보하는 것을 메모리 할당이라고 하는데, 방식에는 Compile 시에 할당 여부가 결정되는 정적 할당과 Runtime 시 할당 여부가 결정되는 동적 할당 방식이 존재한다.

profile
혹시 틀린 내용이 있다면 언제든 말씀해주세요!

0개의 댓글