Notice
Recent Posts
Recent Comments
«   2024/10   »
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 26
27 28 29 30 31
10-10 22:21
Archives
Today
Total
관리 메뉴

Developer_Neo

[코드스테이츠 백엔드 2기(40기) SEB BE] 8일차 본문

코드스테이츠

[코드스테이츠 백엔드 2기(40기) SEB BE] 8일차

_Neo_ 2022. 7. 4. 13:43
반응형

오늘 나의 학습 목표는 무엇인가요?

   자바의 기초 문법인 변수, 타입, 문자열에 대해 다시 복습해보고 왜? 라는 질문을 던져 깊게 들어가보자.

 

오늘 학습할 내용 중에 이미 알고 있는 내용은 무엇인가요?

     자바 문법


Java

- 객제지향 프로그래밍 언어

특징

1. 운영체제에 독립적이다.

윤성우 열혈 Java 프로그래밍

 

- C, C++ 각각의 플랫폼(window, mac등등)에 따라 코드 및 실행 파일이 다르므로, 플랫폼이 달라지면 컴파일을 새로 해야 한다. 하지만,  Java는 한번 작성하면 어떤 코드든 간에 플랫폼에 상관없이 동작시킬수 있다.

 

- JVM은 자바 프로그램을 실행시키는 도구

 

왜냐하면 Java는 Middle ware라고 불릴 수 있는 JVM이라는 자바가상머신이 존재한다. 이것 역시 java Compiler를 통해 JVM이 읽을 수 있는 형식으로 바꾸어주어야하지만 플랫폼에 따라서는 상관이 없다는 것이다. 즉, JVM에서 변환하고 알아서 운영체제와 통신하는 API들을 가지고 있어 운영체제에 상관없이 돌아간다는 것이다.

이에 따라 운영체제에 상관없이 돌아가지만 Java를 설치할때에는 운영체제에 맞게 설치해주어야한다. 이말은 Java는 운영체제에 독립적이지만 JVM은 운영체제 종속적이다라는 것이다.

 

extra)

자바런처가 불리는 Java.exe는 자바가상머신을 구동하고 자바프로그램이 실행되도록 돕는 프로그램이다.

Javac.exe는 자바컴파일러로 소스파일에 저장된 소스코드를 자바 가상머신이 이해할 수 있는 자바 바이트코드로 변환하며 확장자가 class인 클래스 파일에 담긴다.

자바 바이트코드로 변환된 class파일은 운영체제가 이해할 수 있게 한번 더 변환이 필요하다.

즉, 자바 컴파일러가 자바 프로그램 코드 바이트코드로 변환한 다음, 실제 바이트코드를 실행하는 시점에서 자바 가상 머신이 바이트코드를 JIT 컴파일을 통해 기계어로 변환한다.

JIT 컴파일 -  프로그램을 실제 실행하는 시점에 기계어로 번역하는 컴파일 기법

JIT 컴파일러는 바이트코드를 읽어 빠른 속도로 기계어를 생성할 수 있다. 이런 기계어 변환은 코드가 실행되는 과정에 실시간으로 일어나며(그래서 Just-In-Time이다) 

전체 코드의 필요한 부분만 변환한다. 기계어로 변환된 코드는 캐시에 저장되기 때문에 재사용시 컴파일을 다시 할 필요가 없다.
출처 : https://ko.wikipedia.org/wiki/JIT_%EC%BB%B4%ED%8C%8C%EC%9D%BC

 

2. 객체 지향 언어(Object Oriented Programming, OOP)

- 객체지향 프로그래밍 언어로 모든 기능은 객체로 만들어 사용해야한다는 것이다. 자바의 객체는 Class또는 Wrapper Class 등등으로 이루어진다. 이렇기에 main문도 역시 class객체안의 메서드로 적어주어야 실행이 가능하다.

wrapper class

 

3. 함수형 프로그래밍 지원

- 기존 절차적 프로그래밍과 객체 지향형 프로그래밍과는 다른 새로운 방식으로 순수함수, 비상태,불변성, 선언형 함수 등의 특징을 가지고 있으며 함수 단위의 코드 재사용이 수월하다는 장점이 있다.

 

4. 자동 메모리 관리(Garbage Collection)

C, C++의 경우 메모리의 생성과 소멸을 개발자가 직접 설계해야 했지만, 자바는 가비지 컬렉터(Garbage Collector)를 실행시켜 자동으로 사용하지 않는 메모리 없애준다. 가비지컬렉션은 파일 시스템에서 쓰이는 것이다. 

 


함수 : 특정 기능을 수행하는 코드들을 묶은 것

메서드 : 클래스 내에 포함되어 있는 함수

자바는 객체지향 언어이며, 모든 코드를 클래스 내에 작성하기 때문에 보통 함수라는 용어보다는 메서드라는 용어를 사용

 

public class Main {  //클래스
  public static void main(String[] args) { //메서드
	System.out.print("Hello, World!");
  }
}

// 출력결과 Hello, World!

자바에서 main 메서드는 진입점 함수이며, 자바로 어떤 소스 코드를 작성할 때 반드시 main 메서드가 있어야 하고, main 메서드로부터 코드의 흐름이 시작된다.

 

 


변수와 타입

 

변수

- 데이터의 저장과 참조를 위해 할당된 메모리 공간에 붙인이름

- 메모리 공간의 활용, 메모리 공간의 할당과 접근을 위한 도구

- 변수의 선언은 메모리 공간의 할당으로 이어진다.

int num;

위의 코드를 기준으로 설명하자면, int라는 자료형이자 타입이 선언되어있네? -> int라는 4byte메모리공간을 확보해줘, 그리고 이 공간의 이름을 num이라고 할께 라는 것이다.

즉, 변수의 이름은 할당받은 확보한 메모리 공간에 대한 별명이라고 보면 된다. 왜냐하면 공간 즉 메모리 주소는 0xa65f2c2로 되어있는 것으로 우리가 이것을 일일이 쓰기에는 번거롭고 오타가 날 수 있기 때문이다.

 

변수 명명 규칙

일반적 - 카멜 케이스(camelCase)

int camelCase;
//  2번째 단어부터 대문자로 시

- 영문자, 숫자, _, $를 사용할 수 있으며, 영문자는 대소문자가 구별되어 인식

숫자로 시작하는 변수명은 사용할 수 없다

-  예약어(reserved word)는 변수명으로 사용할 수 없음.

 


상수

- 변수와 같이 선언하고 할당하여 사용할 수 있지만, 재할당이 금지되어있다.

- final이라는 키워드를 사용해 선언하며, 대문자에 언더바(_)를 넣어 구분하는 SCREAMING_SNAKE_CASE를 사용한다.

사용 이유

1. 대문자에 언더바(_)를 넣어 구분하는 SCREAMING_SNAKE_CASE를 사용

2. 코드 가독성을 높이고 싶은 경우

3. 코드 유지관리를 손쉽게 하고자 하는 경우

 


기본 타입과 참조 타입

- 자바의 타입은 실제 값을 의미하는 기본 타입(primitive type)

  • 값을 저장할 때, 데이터의 실제 값이 저장됩니다.
  • 정수 타입(byte, short, int, long), 실수 타입(float, double), 문자 타입(char), 논리 타입(boolean)

- 어떤 값이 저장된 주소를 값으로 갖는 참조 타입(reference type)

 

  • 값을 저장할 때, 데이터가 저장된 곳을 나타내는 주소값이 저장됩니다.
  • 객체의 주소를 저장, 8개의 기본형을 제외한 나머지 타입

 

즉, 기본타입에 대한 변수를 다른 변수에 저장할 때 기본타입 변수의 주소값이 저장되는 것이 아닌 값이 저장되는 반면에, 참조타입 변수의 경우에는 다른 변수에 저장할 때 주소값이 저장되고 주소값이 출력된다.

 

 

리터럴(Literal)

- 문자가 가리키는 값 그 자체   ex) 20, true, 'A' , "string"

  1. float 타입의 변수에 실수형 리터럴을 할당할 때, 뒤에 접미사 f를 붙여주어야 합니다.
  2. long 타입의 변수에 정수형 리터럴을 할당할 때, 뒤에 접미사 L을 붙여주어야 합니다.

자료형 종류와 구분

윤성우 열혈 Java

위의 것들은 원시(primitive) 자료형으로 new 키워드로 생성할 수 없다 (int, long, double, float, boolean, char 등의 원시 자료형은 각각에 대응하는 Wrapper 클래스들이 존재)

 

byte형은 8bit의 크기 중 1bit는 부호 표현에 사용하며, 7bit는 숫자 표현에 사용하여 -128 ~ 127의 정수 범위를 표현

 

long 타입 리터럴의 경우에는 리터럴 뒤에 접미사 L 또는 l을 붙여준다.

숫자가 길면 언더바로 구분할 수 있습니다. 
int   intNum   = 12_345_678_910;
long  longNum  = 12_345_678_910L;

정수형의 오버플로우와 언더플로우

오버플로우

  • 자료형이 표현할 수 있는 범위 중 최대값 이상의 값을 표현한 경우 발생합니다.
  • 최대값을 넘어가면 해당 데이터 타입의 최소값으로 값이 순환합니다.

언더플로우

  • 자료형이 표현할 수 있는 범위 중 최소값 이하의 값을 표현한 경우 발생합니다.
  • 최소값을 넘어가면 해당 데이터 타입의 최대값으로 값이 순환합니다.
Q : byte형 값 125에 10을 더하면 어떤 값이 될까요? , byte형 값 -125에서 10을 빼면 어떤 값이 될까요?
A :  -121, 121

 

실수형의 오버플로우와 언더플로우

  • 오버플로우
    • 값이 음의 최소 범위 또는 양의 최대 범위를 넘어갔을 때 발생하며, 이 때 값은 무한대가 됩니다.
  • 언더플로우
    • 값이 음의 최대 범위 또는 양의 최소 범위를 넘어갔을 때 발생하며, 이 때 값은 0이 됩니다.

double형 리터럴에는 접미사 d를 붙여도, 붙이지 않아도 되지만, float형 리터럴에는 반드시 접미사 f를 붙여주어야 합니다.

 

boolean은 참 또는 거짓을 저장할 수 있는 데이터 타입으로, 오직 true 혹은 false를 값으로 가집니다.

 

문자형 리터럴을 작성할 때에는 반드시 큰 따옴표()가 아닌 작은 따옴표()를 사용

왜냐하면 자바에서 문자형과 문자열은 다르기 때문이다.

 

문자 타입의 리터럴은 문자 타입 변수에 유니코드로 저장한다.


 

타입 변환

 

boolean을 제외한 기본 타입 7개는 서로 타입을 변환할 수 있다. 

 

자동 타입 변환

  1. 바이트 크기가 작은 타입에서 큰 타입으로 변환할 때 (예 : byte → int)
  2. 덜 정밀한 타입에서 더 정밀한 타입으로 변환할 때 (예 : 정수 → 실수)

수동 타입 변환

차지하는 메모리 용량이 더 큰 타입에서 작은 타입으로는 자동으로 타입이 변환되지 않습니다. 이때  수동으로 타입을 변환하는 것인 캐스팅(casting)을 해야한다.

 

 

  • java int to string
    • Integer객체의 toString메서드이용
  • java string to int
    • Integer객체의 parseInt메서드이용

문자열(String)

- 자바에서 문자열을 나타내는 자료형 이자 클래스

// 문자열 리터럴을 String 타입의 변수 name에 할당하는 방법
String name1 = "Hyun Ho";

// String 클래스의 인스턴스를 생성하는 방법
String name2 = new String("Hyun Ho");

 

문자열에서의 같은지 여부 연산

1. == 

  -> 주소값 비교

2. equals()라는 String의 메소드

   -> 객체든 변수든 주소값이 아닌 String비교

 

 

String클래스의 메서드

1. charAt() 메서드

- 문자열의 특정 인덱스에 해당하는 문자를 반환

String str = new String("Java");

System.out.println(str.charAt(0)); // 'J'
System.out.println(str.charAt(1)); // 'a'
System.out.println(str.charAt(2)); // 'v'
System.out.println(str.charAt(3)); // 'a'

2. compareTo() 메서드

- 문자열을 인수로 전달된 문자열과 사전 편찬 순으로 비교 (대소문자를 구분하여 비교)

- 문자열이 인수로 전달된 문자열보다 작으면 음수를, 크면 양수를 반환

 

3. concat() 메서드

- 문자열의 뒤에 인수로 전달된 문자열을 추가한 새로운 문자열을 반환

- 즉 합쳐준다.

 

4. indexOf() 메서드

- 문자열에서 인수로 전달한 특정 문자나 문자열이 처음으로 등장하는 위치의 인덱스를 반환

 

5. trim() 메서드

- 해당 문자열의 맨 앞과 맨 뒤에 포함된 모든 공백 문자를 제거

 

6. toLowerCase() / toUpperCase() 메서드

해당 문자열의 모든 문자를 소문자로 변환시켜 준다./ 해당 문자열의 모든 문자를 대문자로 변환시켜 줍니다.

 


StringTokenizer

- 문자열을 우리가 지정한 구분자로 문자열을 쪼개주는 클래스

- java.util.StringTokenizer를 import해야한다.

 

메서드

int countTokens()

  • 남아있는 token의 개수를 반환합니다. 전체 token의 개수가 아닌 현재 남아있는 token 개수입니다.

 

boolean hasMoreElements(), boolean hasMoreTokens()

  • 둘다 동일한 값을 반환합니다. 메서드는 현재 위치 뒤에 있는 문자열에서 하나 이상의 토큰을 사용할 수 있는 경우 true를 반환하고 그렇지 않으면 false를 반환합니다.

 

Object nextElement(), String nextToken()

  • 이 두 메서드는 다음의 토큰을 반환합니다. 두 가지 메서드는 같은 객체를 반환하는데 반환형은 다릅니다. nextElement는 Object를, nextToken은 String을 반환하고 있습니다.

 


 

StringBuilder / StringBuffer

- String의 경우에는 선언한 문자열이 바뀌는 경우 무조건 새로운 객체를 만들어 내어 Heap 메모리영역에 저장하게 된다.(왜냐하면 String은 기본타입이 아니고 참조타입이다. 그러면 객체를 생성하는것과 같이 new를 사용해 Heap영역에 저장하기때문이다.) 이때 빈번하게 문자열이 바뀌게 된다면 Heap메모리에 많은 쓸수 없는 공간인(짧은 시간동안에 생성했었던 문자열들이 사라지지않았기에) Garbage가 있어 Heap메모리 부족으로 성능이 저하 될 수 있다.

String의 이러한 문제점을 보안하기 위한 것이 StringBuilder와 StringBuffer이다. 즉, StringBuilder와 StringBuffer 클래스는 가변성을 가지는 클래스다. 

따라서 문자열의 추가, 수정, 삭제가 빈번하게 발생하는 경우에는 String 클래스가 아닌 StringBuffer와 StringBuilder를 사용해야한다.

 

StringBuilder와 StringBuffer의 차이점

- 동기화의 유무가 가장 큰 차이이다

- StringBuffer는 동기화 키워드를 지원해 멀티쓰레드 환경에서 안전하다는 점이다.

- StringBuilder는 동기화를 지원하지 않기에 멀티쓰레드 환경에서 사용하기에 좋지 않다. 하지만 단일쓰레드의 경우의 성능은 StringBuffer보다 뛰어나다

 

참고

동기화가 지원되지 않는데 멀티쓰레드 환경에서 StringBuffer를 사용할 경우 Lock이 걸리지 않아 추가한 순서대로 추가되는 것도 아니고 덮어쓰기가 될 수 있다.

 

StringBuilder 

한번 생성된 String 클래스의 인스턴스는 여러 개의 문자열을 더할 때 매번 새로운 인스턴스를 생성해야한다. 이것은 많은 문자열을 더하는 작업이 필요하다면 인스턴스 생성과정이 매우 많이 일어나기 때문에 비효율적이다 이것을 해결하기 위해 StringBuilder를 사용

 

- apeend() 메서드를 이용해 문자열을 연결하고, 합친 문자열 출력시 toString() 메서드를 이용하면 된다.

 

StringBuffer

- String 클래스의 인스턴스는 한 번 생성되면 그 값을 읽기만 할 수 있고, 변경할 수는 없습니다 StringBuffer 클래스의 인스턴스는 그 값을 변경할 수도 있고, 추가할 수도 있습니다.

- 내부적으로 버퍼(buffer)라고 하는 독립적인 공간을 가지고 기본값은 16개의 문자를 저장할 수 있는 크기이며, 생성자를 통해 그 크기를 별도로 설정할 수도 있다.

 

(덧셈(+) 연산자를 이용해 String 인스턴스의 문자열을 결합하면, 내용이 합쳐진 새로운 String 인스턴스를 생성합니다. 참고로 덧셈 연산자를 문자열과 함께 사용하면 자동으로 문자열로 형변환이 이뤄지고 문자열이 결합됩니다. 따라서 문자열을 많이 결합하면 결합할수록 공간이 낭비될 뿐만 아니라 속도 또한 매우 느려지게 됩니다. 하지만 StringBuffer 인스턴스를 사용하면 문자열을 바로 추가할 수 있으므로, 공간의 낭비도 없으며 속도도 매우 빨라집니다.)

 

append(), capacity(), delete(), insert() 메서드

append(문자열)  인수로 전달된 값을 문자열로 변환한 후, 해당 문자열의 마지막에 추가
capacity() StringBuffer 인스턴스의 현재 버퍼 크기를
delete(start,end) 전달된 인덱스에 해당하는 부분 문자열을 해당 문자열에서 제거 (start~end-1까지)
insert(index,문자열) 인수로 전달된 값을 문자열로 변환한 후, 해당 문자열의 지정된 인덱스 위치에 추가

연산자

산술 연산자

+ 더한 값 반환
- 뺀 값 반환
/ 나눈 값 반환
% 나머지 반환
++ 1 증가 시키기
-- 1 감소시키기
+= -=
/= *=
%=  

비교연산자

> >= < <= == !=    

 

논리연산자

&& || !  

 

연산자 우선순위

(),[]    ->    !, ~, ++, --(부정/ 증감 연산자)    ->   *, /, %(곱셈 / 나눗셈 연산자)     ->  <, <=, >, >=(대소 비교 연산자)   ->  &&   ->  ||   -> ? :(조건 연산자)   ->  =, +=, -=, /=, %=

 

 

콘솔 출력

System.out.print()  -> 소괄호 안의 내용을 단순히 출력하기만 하고, 줄바꿈을 하지 않습니다.

System.out.println()   -> 소괄호 안의 내용을 콘솔에 출력하고 줄바꿈을 합니다

System.out.printf() ->  지시자(specifier, 형식 지정자)를 이용해 변수의 값을 여러 형식으로 출력해주는 메서드입니다.

 

콘솔 입력

import java.util.Scanner;                 // Scanner 클래스를 가져옵니다.

Scanner scanner = new Scanner(System.in); // Scanner 클래스의 인스턴스를 생성합니다.
String inputValue = scanner.nextLine();   // 입력한 내용이 inputValue에 저장됩니다.

System.out.println(inputValue);           // 입력한 문자열이 출력됩니다.

scanner에는 문자열을 입력받는 nextLine()뿐만 아니라, 정수형을 입력받을 수 있는 nextInt(), 실수형을 입력받을 수 있는 nextFloat()등의 메서드들도 존재

 


SCANNER 클래스를 쓸 때 ERROR가 발생할 수 있는 것

- 위의 내용을 바탕으로 설명하면, scanner.nextInt() 로 정수를 입력 받은 다음 scanner.nextLine() 을 할 경우nextLine()에 대한 것이 정수를 입력할 때 받았던 Enter값이 들어가게 되어 건너띄게 된다.

import java.util.Scanner;                 

Scanner scanner = new Scanner(System.in); 
int num = scanner.nextInt();       // 9 입력
String inputValue = scanner.nextLine();   

System.out.println(num);
System.out.println(inputValue);     

// 출력
// 9

즉, 9만 입력했는데 nextLine에 해당하는 것은 건너띄게 되어 출력으로 넘어가 9만 출력이 된다.

 

이것을 피하기 위한 방법

해결방법 1 : Scanner.nextLine() 추가

import java.util.Scanner;                 

Scanner scanner = new Scanner(System.in); 
int num = scanner.nextInt();       // 9 입력
scanner.nextLine();  				// 9입력시 enter제거하기 위함
String inputValue = scanner.nextLine();   //  hello 입력

System.out.println(num);
System.out.println(inputValue);     

// 출력
// 9
// hello

 

해결방법 2 : Scanner.nextLine( )으로 입력받고 Integer.parseInt( )로 변환

import java.util.Scanner;                 

Scanner scanner = new Scanner(System.in); 
int num = Integer.parseInt(scanner.nextLine());       // 9 입력
String inputValue = scanner.nextLine();   //  hello 입력

System.out.println(num);
System.out.println(inputValue);     

// 출력
// 9
// hello

오늘 학습 내용 중 새롭게 배운 내용은 무엇인가요?

       -  StringBuilder, StringBuffer

 

오늘 새롭게 학습한 내용을 다른 사람에게 설명할 수 있나요?

      - o

 

오늘 학습한 내용 중 아직 이해되지 않은 불확실한 내용은 무엇인가요?

     -  new로 인해 할당받은 객체와 변수의 주소가 같은 메모리 공간에 담기는가?

 

이해되지 않은, 불확실한 내용을 보완하기 위해서 나는 무엇을 할 수 있을까요?

     -  직접 협업을 진행하면서 겪어보거나 구글링을 해본다.

 

나의 오늘 학습 만족도는 몇 점인가요?

     - 90점 (아는 내용들이라고 설렁설렁 넘어간 것들이 있는 것같다.)

반응형
Comments