산술 연산자

+    // 더하기
-    // 빼기
*    // 곱셈
/    // 몫
%    // 나머지

❗ index 의 중앙 값을 구하는 로직의 경우 항상 오버플로우를 조심해야 함

int a = 2_100_000_000;
int b = 2_000_000_000;

int mid = a + ((b - a) / 2);
int mid = a + b >>> 1; // 모든 비트를 왼쪽으로 한칸 -> 나누기 2 한 것과 같음
int mid = (a + b) / 2; // overflow

 

 

비트 연산자

2 << 3 // 2를 비트로 나타낸 후 왼쪽으로 3비트 이동 == 2^3 곱한것과 같음 
                // 주의사항 : 부호부(제일왼쪽 부호결정하는 값)에 1이 들어가서 부호가 이상해질 수 있음
16 >> 3 // 16을 비트로 나타낸 후 오른쪽으로 3비트 이동 == 2^3 나눈것과 같음
                // 주의사항 : 부호부는 기존의 값(기존의 부호)를 계속 복사해서 옆으로 보냄
16 >>> 3 // 부호부와 관계없이 무조건 왼쪽 값이 0으로 채워짐(양수)

& // AND
| // OR
^ // XOR -> 교환법칙 성립 A^B^C^D == D^A^C^B
~ // NOT

| 을 사용하게 되면 if(조건) 에서 조건문에서 short-circuit 이 발생하지 않음
// short circuit 예제

int a = 0;
int b = 0;
if( a++ == 0 || b++ == 0) {
    System.out.println("Hello");
}

System.out.println(a);
System.out.println(b);

// 1
// 0
===================================

int a = 0;
int b = 0;
if( a++ == 0 | b++ == 0) {
    System.out.println("Hello");
}

System.out.println(a);
System.out.println(b);

// 1
// 1

 

 

관계 연산자

>
<
>=
<=
==
!=

 

 

논리 연산자

&&
||
!

 

 

instanceof

A instanceof B

A is kind of B 관계를 만족하면 true 아니면 false 를 반환한다.

결과가 true 라면 참조변수가 검사한 타입으로 형변환이 가능하다

null instanceof Integer // false

public class App {
    public static void main(String[] args) {
        Student me = new Student();
        if (me instanceof Student) { // true
            System.out.println("This is a Student instance.");
        }
        if (me instanceof JavaStudy) { // true
            System.out.println("This is a JavaStudy instance.");
        }
        if (me instanceof Object) { // true
            System.out.println("This is a an Object instance.");
        }
        System.out.println(Me.getClass().getName());
    }
}

class JavaStudy {

}
class Student extends JavaStudy {

}

출처 : https://yadon079.github.io/2020/java study halle/week-03#instanceof

 

assignment(=) operator

우측의 값을 좌측에 할당함.

기본타입의 경우 값을 복사

참조타입의 경우 객체의 주소값을 복사

 

화살표(→) 연산자

람다에서 사용되는 연산자이다.

 

3항 연산자

조건식 ? true일때 반환값 : false일때 반환값

빨라서 Javadoc을 보면 3항 연산자를 사용한 경우를 많이 볼 수 있음

 

연산자 우선순위

  1. . [ ] ( ) : 참조연산자, 배열 첨자, 괄호
  2. ! ~ ++ -- 부호(+,-)
  3. 산술연산자 * / %+ -
  4. 쉬프트 >> << >>>
  5. 비교 연산자 < > <= >= instanceof
  6. 비교 연산자 == !=
  7. 논리 &^|&&||
  8. 3항 연산자
  9. 대입 연산자

 

switch operatar

String time;

switch(weekday) {
    case MONDAY, FRIDAY -> time = "10:00 ~ 18:00";
    case TUESDAY, THURSDAY -> time = "10:00 ~ 16:00";
    default -> time = "휴일";
}

 

'Java' 카테고리의 다른 글

Whiteship Study Week2  (0) 2021.12.19
Whiteship Study Week 1  (0) 2021.11.14

primitive type 종류와 값의 범위 그리고 기본 값

값을 변경하면 메모리 값이 바로 변경된다.

 

❗primitive type에 값이 저장되는 과정

Operand stack에 리터럴이 일시적으로 적재 된 후 변수에 저장될 때는 형변환을 통해 변수에 저장됨

정수는 기본적으로 4byte 크기로 스택 메모리 공간에 저장되고 실수는 8byte 크기로 저장된다.

하지만 long과 float 타입의 경우 정수이지만 8byte, 실수이지만 4byte 이므로 리터널에 long 변수와 float 변수임을 알 수 있도록 접미사를 붙여야 한다

long a = 10000000000000L;
float b = 3.141592F;

 

값 할당

정수와 실수의 맨 앞 1bit 는 부호비트이다. 0이면 양수, 1이면 음수를 나타낸다

정수부는 정수를 표현하는 비트에서 부호비트를 제외한 나머지 부분을 나타낸다

int 는 4byte 이고 1bit의 부호비트와 31bit의 정수부를 가지고 있으므로 -2^31 ~ 2^31 - 1 의 범위를 갖게 된다.

 

float의 부동소수점 방식 → 단정도(single precision)

부호 비트(1bit) + 지수부(8bit) + 가수부(23bit)

 

double의 부동소수점 방식 → 배정도(double precision)

부호 비트(1bit) + 지수부(11bit) + 가수부(52bit)

 

❗실수를 부동소수점 방식으로 저장하는 법

  1. 3.141592 에서 정수 부분을 추출 (3)
  2. 정수 부분을 이진수로 표현 (11)
  3. 소수부분의 값이 0이 될 때까지 또는 가수부 비트 수(float 23, double 52) 이하까지 소수부분에 2를 곱하면서 이진수를 추출
    1. 0.141592 * 2 = 0.28... (1을 넘지 않으므로 0)
    2. 반복..
  4. 정수부의 2진수와 소수부분의 이진수를 연결
  5. 소수점을 맨 앞의 bit 전까지 이동 (= 부동소수점 이동 자리수)
  6. 앞의 1 비트를 삭제 (어차피 무조건 1이기 때문)
  7. 비트수가 가수부의 bit 수(23 or 52) 가 넘어간 경우는 삭제
  8. 부동소수점 이동 자리수 + (32bit Bias (float) or 64bit Bias (double)) → + (127 or 1023)
  9. 8번에서 나온 값을 이진수로 표기
  10. 부호 비트 + 9번의 이진수 + 7번의 이진수를 순서대로 합침

 

실수의 부동소수점으로 저장하는 방식으로 인해 값에 오차가 발생한다. (3번, 7번과 같은 과정 때문에 데이터 손실이 발생)

따라서 돈과 같이 중요한 실수 데이터를 다룰 대는 BigDecimal 로 다뤄야 한다.

double a = 10.0000;
double b = 3.0000;

a + b; // 13.000001999999
a - b; // 6.99999999999
a * b; // 30.00001300000
a / b; // 3.333332555555

 

 

primitive type과 reference type

primitive type이 아닌 다른 모든 변수는 다 reference type 이다.

Call by Value(값에 의한 호출), Call by Reference(주소에 의한 호출)

자바는 Call by Value만 있다. reference type은 Call by Reference 아니냐고 묻는다면 아니다.

사실 reference type은 heap 메모리 영역의 메모리주소을 가지고 있으며 이 값을 복사하여 다른 변수에 보낸다.

 

리터럴

리터럴은 변수나 상수에 저장되는 값 그 자체를 말함

정수 리터럴, 실수 리터럴, 문자 리터럴, 문자열 리터럴, boolean 리터럴 들이 있다.

❗인스턴스의 값이 imutuable 이라면 (ex String) 객체 지터럴이 될 수 있다. 따라서 문자열은 리터럴이라고 할 수 있다.

 

변수 선언 및 초기화하는 방법

int a = 10;

변수타입 변수이름 = 리터럴;

 

 

변수의 스코프와 라이프타임

변수의 스코프란?
변수를 사용할 수 있는 유효범위
변수가 선언된 블럭{ }이 그 변수의 유효범위이다.
변수의 유효범위는 작을수록 좋다

지역변수 (Local 변수)

지역변수는 지역 안(메소드 내)에 있어서 그 영역이 끝나면 메모리에서 해제된다. 보안성이 뛰어나며 사용자가 직접 초기화해야 한다.

지역변수는 {가 시작되는 시점(메서드가 실행될 때 시점)에 생성되고 } 로 끝나는 지점에 소멸된다.(선언되어 있는 메서드 내부가 지역변수의 스코프)

매개변수

메서드를 실행하기 위해 필요한 입력값을 저장한 변수
지역변수와 생명주기가 같다. (선언되어 있는 메서드 내부가 매개변수의 스코프)

멤버변수(=전역변수)

멤버 변수에는 클래스 변수와 인스턴스 변수가 있으며 사용자가 직접 초기화 하지 않아도 초기화 된다.

클래스 변수 (static 변수)

static 변수는 컴파일 시 가장 먼저 메모리에 올라가고 어떠한 경우에도 초기화되지 않는 변수이다. 프로그램 종료 시에만 메모리에서 해제된다.

클래스가 로드될 때(클래스가 메모리에 올라갈 때 / 클래스가 실행될 때) 클래스 로더에 의해 static 변수가 static area(Method Area 내부)에 올라간다. static 변수는 static area 메모리에 고정되어 프로그램 종료시까지 유지되기 때문에 너무 많은 static 남용 시 메모리 혹은 프로그램 실행 속도에 악영향을 준다.

스태틱 변수는 공통으로 한개만 생긴다. 여러개의 객체가 생겨도 스태틱 변수는 한개

static변수는 메모리에 올라가 있으므로
객체를 생성하지 않아도 Class에 선언된 스태틱 변수를 사용할 수 있음.

인스턴스 변수

static이 없는 멤버 변수로서 객체 생성시 값이 초기화된다.

public static void main (String[] args) {

    // 기본타입 지역변수
    // int타입의 지역변수 a에 값 4가 할당되었다.
    int a = 4;

    // 참조타입 지역변수 Jerry <- 휴먼 클래스의 인스턴스를 만들어서
    // 그 객체의 주소를 저장
    // 참조타입의 지역변수 Jerry가 Heap 영역의 Human 클래스를 만들어서
    // 그 객체의 주소를 저장하고 있다.
    Human Jerry = new Human ("Jerry", 26, 64 );

    // int 배열, 참조타입
    // Heap 에 배열 4개가 생기고 그 첫번째 주소를 b가 가지고 있음.
    // 참조타입의 지역변수 b가 Heap영역의 int 배열 4개 객체를 가르키고 있다.
    int[] b = new int[4];

    // Human 배열, 참조타입
    Human cocoas = new Human[5];

    for (int i = 0; i < 5; i++) {
        cocoas[i] = new Human();
    }

}
Class Person{
    //멤버 변수, 클래스 변수
    static int Legs;

    //멤버 변수, 인스턴스 변수
    //객체 생성시마다 각자 다른 값을 가진 수 있음
    // Jerry.age 와 Honux.age는 값이 다름
    int age;
    int weight;

    public Person(){
    }

    //메소드...
    //메소드...
}

 

 

타입 변환, 캐스팅 그리고 타입 프로모션

타입 변환 → 변수 또는 상수의 타입을 다른 타입으로 변환하는 것

변수나 리터럴의 타입을 다른 타입으로 변환하는 것을 형변환(타입변환)이라고 함

type casting

크기가 더 큰 자료형을 크기가 더 작은 자료형에 대입하는 것

int a = 100;
byte b = (byte) a;

타입 캐스팅 시 값 손실이 발생할 수 있으므로 조심해야 한다.

type promotion

크기가 작은 자료형을 더 큰 자료형에 대입하는 것

byte b = 100;
int a = b;

데이터의 손실이나 변형이 발생하지 않고 형변환을 명시적으로 적지 않아도 변환이 가능하다.

 

1차 및 2차 배열 선언하기

배열은 같은 타입의 여러 변수를 하나의 묶음으로 다루는 것

int[] arr = new int[10];
for (int i = 0; i < 10; i++) {
    arr[i] = i;
}

int[] arr2 = {0, 1, 2, 3, 4, 5};

arr 참조변수는 arr[0]이 들어가있는 힙영역의 메모리의 주소만을 저장한다. 이후에 arr을 호출하게 되면 idx 값에 따라서 첫 주소값 + 4(int의 byte 크기) * idx 값을 찾아가 알맞은 정보를 꺼내온다.

System.arraycopy() 를 이용해서 배열을 복사함으로써 배열을 더 큰 배열로 복사할 수 있다.

int[][] arr = new int[5][2];

for (int i = 0; i < 5; i++) {
    for (int j = 0; j < 2; j++) {
        arr[i][j] = i + j;
    }
}

int[][] arr2 = {{1, 2}, {3, 4}, {5, 6}};

arr 참조변수는 arr[0][0] 의 주소를 가지고 있어 나머지 idx 값을 통해 빠르게 알맞은 정보를 찾아올 수 있다.

 

타입 추론, var

데이터 타입을 소스코드에 var 로 정의하면 컴파일 단계에서 컴파일러가 알아서 타입을 유추해 정해주는 것을 말한다.

Map<Integer, String> map = new HashMap<>();

map.put(100, "value");
map.put(40, "value2");
map.put(50, "value3");

for (var v : map.entrySet()) {
    System.out.println("Key : " + v.getKey() + " : " + v.getValue());
}

/* var 의 실제 타입 : Entry<Integer, String> -> 빡세다.. var이 편함.
for (Entry<Integer, String> v : map.entrySet()) {
    System.out.println("Key : " + v.getKey() + " : " + v.getValue());
}
*/

// Key : 50 : value3
// Key : 100 : value
// Key : 40 : value2
// HashMap 이므로 넣은 순서 또는 key값에 따른 정렬따위는 없다.

'Java' 카테고리의 다른 글

Whiteship Study Week3  (0) 2021.12.26
Whiteship Study Week 1  (0) 2021.11.14

JVM이란 무엇인가

JVM(Java Virtual Machine) 으로 자바를 실행하기 위한 가상머신이다. 자바 어플리케이션은 모두 JVM 위에서 실행된다. JVM이 있기 때문에 Java는 OS에 독립적이다.

 

컴파일 하는 방법

컴파일이란 소스코드를(.java) 바이트코드(.class)로 변환하는 것을 말한다. 자바는 JDK의 javac.exe 라는 컴파일러를 통해 소스코드(.java)를 바이트코드인 .class 파일로 변환한다.

컴파일 시 여러가지 옵션을 줄 수 있다. 아래의 예시는 -encoding 옵션과 -target 옵션을 주었다.

javac Main.java

javac Main.java -encodig utf-8 → 문자열 인코딩을 utf-8 로 컴파일

javac -target 1.8 Main.java → 1.8 버전에서 호환되는 Main.class 파일 생성

 

javap -v -l -p Main 으로 바이트코드(.class)를 우리가 볼 수 있도록 변환하여 볼 수 있다.

 

실행하는 방법

컴파일 된 바이트코드(.class)를 JRE의 java.exe 를 통해 JVM이 이해할 수 있게 만들어 실행한다.

java.exe로 해석된 바이트코드를 JVM이 인터프리터로 읽으며 코드를 실행하게 된다.

java Main

java -Dfile.encoding=UTF-8 Main

 

바이트코드란 무엇인가

.class 파일로서 자바 컴파일러(javac.exe)에 의해 변환되는 코드의 명령어 크기가 1바이트라서 바이트코드라고 불린다. 자바 가상 머신이 이해할 수 있는 언어로 변환된 자바 소스 코드를 바이트코드라고 한다.

 

JIT 컴파일러란 무엇이며 어떻게 동작하는가

JIT(Just In Time) 이라는 뜻으로 이미 한번 컴파일한(읽은) 코드는 다시 번역하지 않는다. JIT 가 기억을 하고 있다가 동일한 코드(읽은 코드)가 나오면 바로 JIT에 저장되어 있던 컴파일 된 코드로 컴파일 한다.

JIT 컴파일러의 성능이 발전함에 따라 Java가 느리다는 단점을 보완해 현재는 느리다고 말하기 힘든 언어가 되었다.

 

JVM 구성요소

JVM 메모리 구조

 

Class Loader

  • 클래스 파일을 로드하는 데 사용되는 하위 시스템

Execution Engine

  • 런타임 데이터 영역에 할당된 코드를 실행하는 곳.(인터프리터 방식과 JIT 컴파일러를 통해 실행)

Runtime Data Area

Method Area

  • 메타데이터, 상수 런타임 풀, 클래스 구조를 저장한다. (공유자원)

Heap Area

  • 모든 객체가 저장되는 곳. 멀티쓰레드 시 힙영역은 공유되기 때문에 안정성을 확보를 해야한다.

Stack Area

  • 메서드가 실행될 때마다 Stack형식으로 저장되는 곳

 

JDK와 JRE 차이

자바 11 버전부터는 JDK만을 제공한다. (JDK 안에 JRE가 포함되어 있음)

JDK

javac.exe JDK (Java Development Kit)

java.exe JRE (Java Runtime Environment)

java.exe 실행 시 JVM (Java Virtual Machine) 위에서 실행

JDK = (개발에 필요한 툴 + JRE) 이라고 생각하면 된다.

'Java' 카테고리의 다른 글

Whiteship Study Week3  (0) 2021.12.26
Whiteship Study Week2  (0) 2021.12.19

+ Recent posts