배열

  • 정의: 같은 타입의데이터를 메모리상에 연속적으로 나열시키고, 각 데이터에 인덱스(index)를 부여해 놓은 자료 구조
  • 인덱스: 첨자값, [](대괄호) 사용
  • 배열은 참조 타입에 속한다.

배열의 선언


/* 대괄호의 위치 차이 */
int[] intArray; // 타입[] 변수(배열명);
int intArray[]; // 타입 변수(배열명)[];

/* null로 초기화 */
String[] stringArray = null;

/* 값 목록을 가진 배열 생성 */
String[] names = { "홍길동", "전지현", "설현", "수지" };
int[] scores = { 80, 90, 95, 99 };

/* new 연산자로 바로 배열 객체 생성 */
double[] doubleArray = new double[5]; // 배열의 길이를 지정한다. (이 때 인덱스는 0~4)

/* 컴파일 에러 */
String[] names = null;
// names = { "홍길동", "전지현", "설현", "수지 }; -> 배열 변수 선언 후 중괄호를 사용한 배열 생성은 에러 발생
names = new String[] { "홍길동", "전지현", "설현", "수지 };


  • 중괄호{}는 주어진 값들을 가진 배열 객체를 힙(heap) 메모리 영역에 생성하고, 배열 객체의 번지(주소)를 리턴한다.
  • 배열 변수는 리턴된 번지를 저장하여 참조한다.
  • 위의 예에서 "홍길동"은 names[0] "전지현"은 names[1], 80은 scores[0] 이다.

배열의 값 바꾸기


String[] names = { "홍길동", "전지현", "설현", "수지" };
System.out.println("names[0] > " + names[0]); // 홍길동
names[0] = "에일리";
System.out.println("names[0] > " + names[0]); //에일리

  • 배열의 값 바꾸기는 = (대입 연산자)를 사용한다.

배열 길이

  • 배열의 길이: 배열에 저장할 수 있는 전체 항목 수를 말한다.
  • 배열 객체의 length 필드(field)를 읽어야 한다.
  • 필드(field): 객체 내부의 데이터
  • 배열의 마지막 요소의 인덱스는 배열 길이-1이다.

int[]  intArray = {100, 200, 300};
int len = intArray.length;
System.out.println("배열 intArray의 길이는 > " + len);

참조 타입(reference type)

  • 참조 타입의 종류: 배열, 열거, 클래스, 인터페이스

  • 참조 타입 변수는 스택(stack) 영역에 생성되어 힙(heap) 메모리 영역의 번지(주소)를 값으로 갖는다.

  • 주소를 통해 객체를 참조한다는 뜻에서 참조 타입이라고 부른다.

참조 변수의 ==, != 연산

  • 참조 타입 변수들 간의 ==, != 연산은 동일한 객체를 참조하는지, 다른 객체를 참조하는지 알아볼 때 사용된다.

  • 서로 다른 객체를 참조하는 참조 타입 변수들간의 비교는 기본 타입과 다른 결과를 나타낸다.

  • 예)

int x = 3;
int y = 3;
String hello = new String("안녕하세요");
String hi = new String("안녕하세요");

if ( hello == hi ) {
    System.out.println("안녕하세요.");
} else if ( hello != hi) {
    System.out.println("안녕 못해요.");
}

if (x == y) {
   System.out.println("X와 y는 같습니다.");
} else if ( x != y) {
   System.out.println("x와 y는 다릅니다.");
}
  • 출력
  • 안녕 못해요.
    x와 y는 같습니다.
    

참조 타입 변수의 null

  • 참조 타입 변수가 null 값을 가질 경우 참조할 객체가 없으므로 객체는 힙 메모리 영역에 생성되지 않고, 변수만 스택 영역에서 생성되어 null 값을 가진다.
  • 따라서, null 값을 가진 참조 타입 변수의 ==, != 연산은 기본 타입과 동일하다.
  • 참조 타입 변수가 null 값을 가진 상황에서 프로그램을 실행할 경우 (혹은 프로그램 실행 중 참조 타입 변수가 null 값을 가질 경우) NullPointerException 예외가 발생한다.

String 타입

  • 문자열을 저장하는 참조 타입

  • 자바에서 String은 문자열 리터럴이 동일할 경우 객체를 공유하도록 되어 있다. (new 연산자로 새로운 객체를 생성하지 않고 = 대입 연산자로 같은 문자열을 저장할 경우)

  • String 객체의 equals() 메소드를 사용해서 객체에 상관없이 문자열을 비교할 수 있다.

  • 형식

    String x; // 기본값은 null
    x = "hello"; // 선언한 x에 문자열 값을 대입, " " (쌍따옴표) 사용
    String  y = "hello"; // 선언과 동시에 문자열 저장 x == y 는 true
    String  z = new String("hello"); // 새로운 객체 생성, y == z 는 false
    if ( y.equals(z) ) {
       System.out.println("true"); // true 출력
    }



JVM 구조

  • 실행될 클래스 파일을 메모리에 로드 후 초기화 작업 수행

  • 메소드와 클래스변수들을 해당 메모리 영역애 배치

  • 클래스로드가 끝난 후 JVM은 main 메소드를 찾아 지역변수, 객체변수, 참조변수를 스택에 쌓음
  • 다음 라인을 진행하면서 상황에 맞는 작업 수행(함수 호출, 객체 할당 등)

자바 메모리 구조



  • Class Loader: JVM내로 클래스를 로드하고 링크를 통해 배치하는 작업을 수행하는 모듈로써 런타임시 동적으로 클래스를 로드한다.
  • Execution Engine: Class Loader를 통해 JVM 내의 런타임 데이터 영역에 배치된 바이트 코드를 실행한다. 이 때, Execution Engine은 자바 바이트 코드를 명령어 단위로 읽어서 실행한다.
  • Garbage Collector: JVM은 Garbage Collector를 통해 메모리 관리 기능을 자동으로 수행한다. 애플리케이션이 생성한 객체의 생존 여부를 판단하여 더 이상 사용되지 않는 객체를 해제하는 방식으로 메모리를 자동 관리한다.
  • Runtime Data Areas: JVM이 운영체제 위에서 실행되면서 할당받는 메모리 영역이다. Class Loader에서 준비한 데이터들을 보관하는 저장소이다.

Runtime Data Areas


Runtime Data Areas & Heap Area



  • Method (Static) Area: JVM이 읽어들인 클래스와 인터페이스 대한 런타임 상수 풀, 멤버 변수(필드), 클래스 변수(Static 변수), 생성자와 메소드를 저장하는 공간이다.
  • Runtime Constant Pool
    • 메소드 영역에 포함되지만 독자적 중요성이 있다.
    • 클래스 파일 constant_pool 테이블에 해당하는 영역이다.
    • 클래스와 인터페이스 상수, 메소드와 필드에 대한 모든 레퍼런스를 저장한다.
    • JVM은 런타임 상수 풀을 통해 해당 메소드나 필드의 실제 메모리 상 주소를 찾아 참조한다
  • 메소드 영역/런타임 상수 풀의 사용기간 및 스레드 공유 범위
    • JVM 시작시 생성
    • 프로그램 종료 시까지
    • 명시적으로 null 선언 시
    • 구성 방식이나 GC 방법은 JVM 벤더마다 다를 수 있다.
    • 모든 스레드에서 공유한다.
  • Heap Area
    • JVM이 관리하는 프로그램 상에서 데이터를 저장하기 위해 런타임 시 동적으로 할당하여 사용하는 영역이다.
    • New 연산자로 생성된 객체 또는 객체(인스턴스)와 배열을 저장한다.
    • 힙 영역에 생성된 객체와 배열은 스택 영역의 변수나 다른 객체의 필드에서 참조한다.
    • 참조하는 변수나 필드가 없다면 의미 없는 객체가 되어 GC의 대상이 된다.
    • 힙 영역의 사용기간 및 스레드 공유 범위
      • 객체가 더 이상 사용되지 않거나 명시적으로 null 선언 시
      • GC(Garbage Collection) 대상
      • 구성 방식이나 GC 방법은 JVM 벤더마다 다를 수 있다.
      • 모든 스레드에서 공유한다.
  • Stack Area
    • 각 스레드마다 하나씩 존재하며, 스레드가 시작될 때 할당된다.
    • 메소드를 호출할 때마다 프레임(Frame)을 추가(push)하고 메소드가 종료되면 해당 프레임을 제거(pop)하는 동작을 수행한다.
    • 선입후출(FILO, First In Last Out) 구조로 push와 pop 기능 사용
    • 메소드 호출 시 생성되는 스레드 수행정보를 기록하는 Frame을 저장
    • 메소드 정보, 지역변수, 매개변수, 연산 중 발생하는 임시 데이터 저장
    • 기본(원시)타입 변수는 스택 영역에 직접 값을 가진다.
    • 참조타임 변수는 힙 영역이나 메소드 영역의 객체 주소를 가진다.
  • PC Register
    • 현재 수행 중인 JVM 명령 주소를 갖는다.
    • 프로그램 실행은 CPU에서 인스트럭션(Instruction)을 수행.
    • CPU는 인스트럭션을 수행하는 동안 필요한 정보를 CPU 내 기억장치인 레지스터에 저장한다.
    • 연산 결곽값을 메모리에 전달하기 전 저장하는 CPU 내의 기억장치
  • Native Method Stack Area
    • 자바 외 언어로 작성된 네이티브 코드를 위한 Stack이다.
    • 즉, JNI(Java Native Interface)를 통해 호출되는 C/C++ 등의 코드를 수행하기 위한 스택이다.
    • 네이티브 메소드의 매개변수, 지역변수 등을 바이트 코드로 저장한다.

Heap Area

  • Young Generation: 이 영역은 자바 객체가 생성되자마자 저장되고, 생긴지 얼마 안되는 객체가 저장되는 공간이다. 시간이 지나 우선순위가 낮아지면 Old 영역으로 옮겨진다. 이 영역에서 객체가 사라질 때 Minor GC가 발생한다.
  • Old(Tenured) Generation: Young Generation 영역에서 저장되었던 객체 중에 오래된 객체가 이동되어 저장되는 영역이다. 이 영역에서 객체가 사라질 때 Major GC(Full GC)가 발생한다.

None Heap Area

  • Permanent Generation(Java 7 이전): 클래스 로더에 의해 로드되는 클래스, 메소드 등에 대한 메타 정보가 저장되는 영역으로 JVM에 의해 사용된다. 리플렉션을 사용하여 동적으로 클래스가 로딩되는 경우에 사용된다. 내부적으로 리플렉션 기능을 자주 사용하는 Spring Framework를 이용할 경우 이 영역에 대한 고려가 필요하다. 런타임시 사이즈를 조절할 수 없어 OutOfMemoryError: PermGen Space error 가 발생하는 메모리 영역이다. JVM 실행시 PermSize와 MaxPermSize 옵션을 사용한다.
  • Metaspace(Java 8 이후): Permanent Generation이 Metaspace로 변경 되었다. 기능은 비슷하지만, 주요 차이점은 동적으로 사이즈를 바꿀 수 있다. JVM 옵션도 PermGem관련하여 사라지고, Metaspace 관련하여 MetaspaceSize 및 MaxMEtaspaceSize 옵션이 새로 생겼다.

참고자료


수정이력

  • 2019-05-07: Permanent Generation None Heap Area로 재분류 및 설명 추가, Meataspace 추가

반복문

  • 어떤 작업이 반복적으로 수행되도록 할 때 사용되는 구문

반복문의 종류

  • for문: 주로 반복횟수를 알고 있을 때 사용
  • 향상된 for문: 컬렉션과 배열을 처리할 때 더 효과적인 문법으로 JDK5.0 이후에 사용 가능
  • while문: 조건식으로 반복할 때 주로 사용
  • do-while문: 반복하기 전에 먼저 실행해야 하는 구문이 있을 때 사용

for문

  • for문 선언 형식
  • for( 초기식; 조건식; 증감식) {
      // 명령코딩
    }
    
  • 예제: 1부터 10까지의 합
  • public class ExFor {
    	public static void main (String[] args)
    	{
    		int i , sum = 0;   
            for ( i=1 ; i<=10 ;  i++) {
            	System.out.printf(i==10?"%d":"%d+",i);
    			sum+= i;    
    		}
            System.out.println("="+sum);
    	}
    }
    
    1+2+3+4+5+6+7+8+9+10=55
    

향상된 for문

  • 향상된 for문 선언 형식
  • for( 자료형  변수명 : 배열 또는 컬렉션 ) {
     // 명령코딩
    }
    
  • 예제: 배열에 담긴 국어 점수 출력
  • public class ExEnhancedFor
    {
    	public static void main (String[] args)
    	{
    		int [] kors = new int[5];
    		kors[0] = 100;
    		kors[1] = 90;
    		kors[2] = 77;
    		kors[3] = 23;
    		kors[4] = 88;
    		
    		for (int kor : kors) {
    			System.out.println(kor);
    		}
    	}
    }
    
    100
    90
    77
    23
    88
    

while문

  • while문 선언 형식
  • while( 조건식 ) {
     // 조건식이 참일 동안 반복될 명령 코딩
    }
    
  • 예제: 10부터 0까지의 합
  • public class ExWhile
    {
    	public static void main (String[] args)
    	{
    		int i = 10 , sum = 0;
    		while( i >= 0 ){
    			System.out.printf(i==0?"%d":"%d+",i);
    			sum += i; 
    			i--;
    		}
    		System.out.println("="+sum); 
    	}
    }
    
    10+9+8+7+6+5+4+3+2+1+0=55
    

do-while문

  • do-while문 선언 형식
  • do{
    // 먼저 한번 실행하고, 조건식이 참일 동안 반복할 명령 코딩
    }while( 조건식 );
    
  • 예제: 증가치에 따라 증가하는 항 값의 누적 합
  • public class ExDoWhile
    {
    	public static void main (String[] args) throws java.lang.Exception
    	{
    		int h = 1; // n 항의 누적 합
    		int n = 1; // 각 항: [1]+[2]+[4]+[7]+[11]+[16]+[22]
    		int k = 0; // 증가치:   1   2   3   4    5    6
     
    		do{
    			k+=1;
    			n += k;
    			if( n > 100) break;
    			h += n; // (누적)
    			System.out.printf("%d - %d - %d\n",n,k,h);
    		}while(true);	
    	}
    }
    
    2 - 1 - 3
    4 - 2 - 7
    7 - 3 - 14
    11 - 4 - 25
    16 - 5 - 41
    22 - 6 - 63
    29 - 7 - 92
    37 - 8 - 129
    46 - 9 - 175
    56 - 10 - 231
    67 - 11 - 298
    79 - 12 - 377
    92 - 13 - 469
    

제어문(Control Flow Statement)

  • 제어문이란, 프로그램 실행 흐름을 개발자가 원하는 방향으로 바꿀 수 있도록 해주는 것이다.
  • 일반적으로 조건식과 실행 구문인 중괄호(블록, { })으로 구성되어 있다.

제어문의 종류

  • 조건문(decision-making statements): if문, switch문
  • 반복문(looping statements): for문, while문
  • 분기문(branching statements): break, continue, return

조건문-if문

  • 조건식의 결과에 따라 블록 실행여부가 결정
  • 조건식에는 boolean 변수 또는 true/false 값을 산출하는 연산식
  • 조건식이 true이면 블록 실행, false이면 실행하지 않음

if문 종류

  • if문
  • if(조건식) {
    
     // 조건식이 참일 경우 실행 구문
    
    }
    
    • 조건식의 결과에 따라 블록 실행여부가 결정
    • 조건식에는 boolean 변수 또는 true/false 값을 산출하는 연산식
    • 조건식이 true이면 블록 실행, false이면 실행하지 않음
  • if-else문
  • if(조건식) {
    
     // 조건식이 참일 경우 실행 구문
    
    }else {
    
     // if문의 조건식이 거짓일 경우 실행 구문
    
    }
    
    • if문이 false일 경우 else 문으로 넘어감
    • 조건식의 결과에 따라 이 두 개의 블록 중 한 블록만 실행 후 if문을 벗어남
  • if-else if-else문
  • if(조건식A) {
    
     // 조건식A가 참일 경우 실행 구문
    
    } else if(조건식B) {
    
    // 조건식A가 거짓이고, 조건식B가 참일 경우 실행 구문
    
    } else if(조건식C) {
    
    // 조건식A, B가 거짓이고, 조건식C가 참일 경우 실행 구문
    
    } else {
    
    // 모든 조건식이 거짓일 경우 실행 구문
    
    }
    
    • 조건문이 여러 개인 다중 if문
    • if 블록 끝에 else if문을 통해 false 일 경우 계속 다음 else if 문으로 넘어감
    • else if문의 수는 제한이 없다
    • 여러 개의 조건식 중 true가 되는 블록만 실행하고 전체 if문을 벗어남
  • 중첩 if문
  • if(조건식 A) {
         // 조건식 A가 참일 경우 실행 구문
         if(조건식 B) {
                    // 조건식 A와 B가 참일 경우 실행 구문
         }
    }
    
    • if문 블록 내에 또 다른 if문을 사용하는 것
    • 중첩의 단계는 제한이 없어 실행흐름을 잘 판단하여 작성
  • 참고: Oracle JAVA Documentation에서는 if-then (=if)문과 if-then-else(if-else문과 if-else if-else문)문 두개로 나눈다. (여기서는 if-else문 설명을 위해 좀더 자세히 분류했다.)

switch문

  • if문과 달리 변수가 어떤 값을 갖느냐에 따라 실행문이 선택
  • if문의 경우의 수가 많아질 수록 switch 문을 사용하는 것이 효과적
  • 괄호 안의 동일한 값을 갖는 case로 가서 실행문을 실행
  • 동일한 값의 case가 없으면 default로 가서 실행문 실행(생략 가능)
  • 변수 값에 따라 case가 실행된 후 제어문을 빠져나가기 위해 break; 사용

형식

switch(변수) {
	case 값1:
		실행문;
		break;
	case 값2:
		실행문;
		break;
	default: // 생략 가능
		실행문;
		break;
}


연산 관련 개념

  • 연산(Operation): 프로그램에서 데이터를 처리하여 결과를 산출하는 것

  • 연산자(Operator): 연산에 사용되는 표시나 기호

  • 피연산자(Operand): 연산되는 데이터
  • 연산식(Expressions): 연산자와 피연산자를 이용하여 연산의 과정을 기술한 것

연산자 정리표

연산자 종류

연산자

피연산자

산출값

기능 설명

산술

+, -, *, /, %

이항

숫자

사칙연산 나머지 계산

부호

+, -

단항

숫자

음수와 양수의 부호

문자열

+

이항

문자열

문자열을 연결

대입

=, +=, -=, *=, /=, %=,

&=, ^=, |=, <<==, >>==, >>>==

이항

다양

우변의 값을 좌변의 변수에 대입

증감

++, --

단항

숫자

1만큼 증가/감소

비교

==, !=, >, <, >=, <=,

instanceof

이항

boolean

값의 비교

논리

!, &, |, &&, ||

단항

이항

boolean

논리적 NOT, AND, OR 연산

조건

(조건식) ? A : B

삼항

다양

조건식에 따라 A또는 B 하나를 선택

비트

~, &, |, ^

단항

이항

숫자

boolean

비트 NOT, AND, OR, XOR 연산

쉬프트

>>, <<, >>>

이항

숫자

비트를 좌측/우측으로 밀어서 이동


연산의 방향과 우선순위

연산자

연산방향

우선순위

증감(++,--), 부호(+,-), 비트(~), 논리(!)

높음

산술(*,/,%)

 

산술(+,-)

 

쉬프트(<<, >>, >>>)

 

비교(<, >, <=, >=, instanceof)

 

비교(==, !=)

 

논리(&)

 

논리(^)

 

논리(|)

 

논리(&&)

 

논리(||)

 

조건(?:)

 

대입(=, +=, -=, &=, /=, %=, &=, ^=, |=, <<=, >>=, >>>=)

낮음


증감 연산자( ++ , -- )

  • 전위형: 피연산자 앞에 위치, 다른 연산보다 증감 먼저 수행 ( int i = 0; ++i )
  • 후위형: 피연산자 뒤에 위치, 다른 연산 수행 후 증감 실행 ( int j = 0; j++; )

논리 연산자( &&, ||, &, |, ^, !)

  • 일반논리AND연산자, 논리곱(&&): 피연산자 모두 true일 경우 연산 결과 true
  • 일반논리OR연산자, 논리합(||): 피연산자 중 하나만 true이면 연산 결과는 true
  • 배타적 논리합(^): 피연산자가 하나는 true이고 다른 하나가 false일 경우에만 연산 결과 true

논리 부정 연산자(!), (=not 연산자)

  • 참 또는 거짓을 부정한다.
  • !true → false
  • !false → true

덧셈연산자(+) / 문자열 연결 연산자(+) 비교

  • print( 4 + 5 ) => 정수 + 정수 => 9 // 덧셈연산자로 더하기 연산 수행
  • print( "4" + 5 ) => 문자열 + 정수 => "45" (문자열) // 문자열 연결 연산자로 4와 5 문자열을 연결
  • print( "4" + "5") => 문자열 + 문자열 => "45"(문자열) // 문자열 연결 연산자로 4와 5 문자열을 연결

0으로 나누기 또는 나머지 연산을 수행할 수 없음(오류 발생)

  • 실수를 0으로 나누면 무한대(Infinity) 결과값
  • 실수를 0으로 나머지 구하기 하면 NaN(Not a Number)결과값

조건연산자

  • 형식 => 항1 : 항2 : 항3;
  • 항1이 참이면 결과값은 항2
  • 항1이 거짓이면 결과값은 항3



클래스 선언 형식

[접근지정자][기타제어자] class 클래스명 [extends Super클래스][implements 인터페이스…]
{
    클래스 내용
}

  • 클래스는 객체를 표현한다.

  • [ ]: 생략 가능

  • 접근지정자(접근제한자): public, protected, default(기본), private     

  • { }: 클래스/메소드/생성자의 내용이 들어가는 블록이다. 빈 내용이더라도 블록은 꼭 써야 한다.
  • 기타제어자: static, final, abstract, native, transient, synchronized, volatile, strictfp 등

주의사항

  • 클래스명은 반드시 대문자로 시작
  • 자바언어는 대소문자 구별
  • 하드코딩(개발도구를 사용하지 않는 코딩) 시, 저장 확장자명을 .java로 할 것


생성자 선언 형식

[접근지정자]class 클래스명(파라미터) 

    생성자 내용
}

  • 선언한 Class가 실제로 생성될 때 실행되는 작업을 기술하는 공간이다.

  • [ ]: 생략 가능

  • 접근지정자(접근제한자): public, protected, default(기본), private     

  • { }: 클래스/메소드/생성자의 내용이 들어가는 블록이다. 빈 내용이더라도 블록은 꼭 써야 한다.
  • 파라미터: 생성자를 통해 클래스를 생성할 때 사용되는 인자값을 받아오는 변수 선언 부

주의사항

  • 생성자는 클래스명과 동일해야 한다.
  • { } 블록 안의 내용이 빈 공간인 것은 기본생성자이다. 그리고 기본 생성자는 생략 할 수 있다. 자바 컴파일러가 자동으로 생성한다.

함수 선언 형식

[접근제한자] [기타제어자] 리턴자료형 함수명([파라미터]) 

    [return 리턴값;]
}

  • 반복되어지는 코딩을 함수로 만들면 코드의 중복이 줄어든다.

  • 함수를 사용하면 구조적 프로그래밍이 가능하다.

  • 함수를 만들기 전에 생각해야할 3가지: 기능, 매개변수(파라미터), 리턴값(리턴자료형)

함수를 호출하는 방법

  • Call by Name: 파라미터 없이 함수명으로만 호출, 예) swap();
  • Call by Value: 파라미터에 값을 주고 호출, 예) swap(30);
  • Call by Reference: 파라미터에 참조 변수 값을 주고 호출, 예) swap(참조변수);
  • Call by Point: 포인트 주소값으로 호출(C언어에서 사용)

메인 함수 선언 형식

public static void main(String[] args)
{
// 실행 내용
}
  • 클래스를 만들고 실제로 실행하기 위해서는 메인(main) 함수가 필요하다.

  • 운영체제로부터 메모리를 할당 받아 프로그램을 실행하는 시작 지점이다.

  • 꼭 암기하자!!


+ Recent posts