본문으로 바로가기

openJDK 설치

jdk (java development kit) 설치 후 설치된 경로에 들어가 java.exe, javac.exe 가 있는 경로를 환경 변수에 넣어주자.

oracleJDK보다 openJDK를 주로 사용한다. 왜? 돈이 없으니까...

 

  • JDK : java development kit 자바 개발 도구
  • JRE : java runtime environment 자바 실행 환경

자바 프로그램을 개발하기 위해서는 JDK를 설치해야하고 실행하기 위해서는 JRE가 있어야 한다.

JDK를 설치하면 JRE도 포함되어 같이 설치된다.

 

음.. 사실 jdk는 oracle jdk 외에 여러 jdk가 있고 이들을 openjdk라고 퉁쳐서 부른다. (사실 openjdk라는 이름의 jdk가 따로 있다.) java기반 프로그램에서 특정 jdk를 사용할 경우 상업적 목적으로 사용할 경우 비용을 지불해야할 수도 있다.

 

 

일반적으로 openJDK 사용하는데 mac은 adoptopenjdk사용해야 한다.

brew tap AdoptOpenJDK/openjdk
brew install --cask adoptopenjdk8 // cask로 설치

java -version // 버전 확인
openjdk version "1.8.0_282"
OpenJDK Runtime Environment (AdoptOpenJDK)(build 1.8.0_282-b08)
OpenJDK 64-Bit Server VM (AdoptOpenJDK)(build 25.282-b08, mixed mode)

javac -version // java 컴파일러 버전 확인
javac 1.8.0_282

 

/usr/libexec/java_home  // 현재 사용하고 있는 jvm 확인
/Library/Java/JavaVirtualMachines/adoptopenjdk-8.jdk/Contents/Home

/usr/libexec/java_home -V // 설치되어 있는 Java Virtual Machines 전체 목록을 확인하기
Matching Java Virtual Machines (2):
    14.0.1, x86_64:    "OpenJDK 14.0.1"    /Users/cjos/Library/Java/JavaVirtualMachines/openjdk-14.0.1/Contents/Home
    1.8.0_172, x86_64:    "Java SE 8"    /Library/Java/JavaVirtualMachines/jdk1.8.0_172.jdk/Contents/Home

# ~/.zshrc에서 JAVA_HOME 등록
export JAVA_HOME="/Library/Java/JavaVirtualMachines/adoptopenjdk-8.jdk/Contents/Home"

 

 

설치 확인을 위해 version도 명령창에서 실행해보자.

java -version
javac -version

 

 

JVM이란 무엇인가

 

JVM(Java Virtual Machine)은 자바 가상 머신의 준말으로 바이트코드(byte code)를 실행하는 주체이다. JVM 덕분에 한 번 작성한 코드는 실행할 환경에 독립적으로 즉, 어디에서나 실행할 수 있다.(Write Once Run Anywhere) 중간 언어를 해석해주는 추상화된 장치가 없는 언어들은 OS가 바뀔 때마다 그게 맞는 실행 가능한 환경을 조성해야 했기 때문에 불편했다. Java는 JVM 위에서 실행되기 때문에 이러한 과정을 생략할 수 있다.

 

이러한 장점에도 불구하고 JVM은 직접 실행 가능한 코드가 아니라 바이트코드를 만들고 이 바이트 코드를 JVM이 인터프리터 방식으로 기계어로 번역하여 실행하기 때문에 느리다는 단점이 있다. 그런데 JAVA의 느린 속도가 문제가 될 프로젝트라면 그냥 Rust나 C 계열 언어를 쓰는 것이 좋다. 현재도 많은 프로젝트들이 JAVA로 문제없이 돌아가고 있다.

 

자바가 컴파일되고 실행되는 전체적인 과정

 

추가적인 지식으로, Java만 JVM에서 돌아가지는 않는다. 사촌격인 Kotlin도 JVM을 통해 바이트 코드를 기계어로 번역하여 실행하는 방식이고 함수형 프로그래밍 언어로 유명한 scala도 JVM을 통해 실행된다.

 

 

컴파일 하는 방법 + 실행하는 방법

 

컴파일을 한다는 것은 .java 파일을 .class 파일로 만드는 것을 의미한다. JDK(java development)를 설치하면 javac라는 자바 컴파일러가 포함되어 있는 것을 확인할 수 있다. 즉, javac를 통해 컴파일한 후 java로 실행하면된다.

 

보통 컴파일 과정은 직접 하기보다 IDE에서 자동으로 지원하기 때문에 직접 할 일은 드물다.

그러나 직접 해보고 싶다면 이전에 작성한 아래 포스트를 참고해보자.

 

* 자바 파일명에 대하여

소스파일의 이름은 public class의 이름과 대소문자까지 일치해야 한다.  
하나의 소스파일에 둘 이상의 public class가 존재할 수 없다. 
한 소스 파일 내부에 여러개의 클래스가 존재할 수는 있지만 public class는 하나여야만 한다.

만약 public class가 없다면 어떤 클래스의 이름도 괜찮지만
소스파일의 이름이 클래스의 이름이어야 하는 건 변함없다. 

 

darrengwon.tistory.com/820?category=910003

 

IDE없이 직접 컴파일하고 실행해보기

종종 할 일이 있습니다. javac로 컴파일하고 java로 실행한다는 것만 알아두면 됩니다. 우선 실행 환경을 세팅합시다. * java 경로를 못 찾고 있다면? java.exe, javac.exe가 있는 경로를 환경 변수에 추가

darrengwon.tistory.com

 

  • 바이트코드(byte code)란 무엇인가

 

java는 사람이 이해할 수 있는 언어이며 컴퓨터는 이해할 수 없기 때문에 컴퓨터가 이해할 수 있는 형태로 전환한 후 컴퓨터가 기계어로 변환한다. 바이트코드는 일종의 중간 언어인 셈이다. 위에서 살펴본 javac를 통해 class 파일을 생성한 것이 곧 바이트코드를 생성한 것이라고 할 수 있다. 이 바이트코드를 JVM이 실행한다.

 

C는 컴파일러에 의해 소스파일(.c)이 목적파일(.obj)로 컴파일될 때 0과 1로 이루어진 바이너리 코드로 변환된다. 즉시 기계가 이해할 수 있다.

 

반면 Java에서는 컴파일러(javac)에 의해 소스파일(.java)이 컴퓨터가 바로 인식할 수 없는 바이트코드(.class)로 변환된다. 바이트 코드는 JVM이 이해할 수 있는 언어로, JVM이 또 한 번 번역 과정을 거쳐야 기계가 이해할 수 있다.

 

바이너리 코드 / 바이트 코드 / 기계어의 차이에 대해서 잘 정리해둔 블로그가 있어 첨부한다.

shrtorznzl.tistory.com/82

 

바이트코드와 바이너리 코드의 차이는 무엇일까?

C언어는 컴파일러에 의해 소스파일(*.c)이 목적파일(*.obj)로 변환될때 바이너리 파일, 즉 0과 1로 이루어진 코드로 변환된다. 즉, 컴파일 후에 이미 컴퓨터가 이해할 수 있는 이진코드로 변환되는

shrtorznzl.tistory.com

 

바이너리(binary) 코드

컴퓨터가 인식할 수 있는 0과 1로 구성된 이진코드를 의미한다.

 

기계어

기계어는 0과 1로 이루어진 바이너리 코드지만 모든 바이너리 코드가 기계어인 것은 아니다.

기계어는 특정한 언어가 아니라. CPU 제조에서 CPU에게 내리는 명령어 집합을 '기계어'라고 부른다. 따라서 기계어는 CPU가 변경되면 달라진다. 같은 1000101001 과 같은 기계어라고 하더라도 CPU마다 다른 명령어로 인식할 수 있다는 것. 물론 아주 기본적인 연산자들은 호환이 되는 편이다.

회사마다 CPU는 다른 명령어를 가지며 회사 내 제품 중에서도 버전마다 명령어가 달라질 수 있다.

 

바이트 코드란

가상 머신용 중간 언어이다. 바이트 코드로 컴파일된 java.class는 JVM에 의해 기계어로 변환된다.

 

 

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

 

JIT 컴파일러는 Just In Time 컴파일러의 준말로, 바이트코드를 기계어로 번역하여 실행하는 것을 의미한다.  

 

컴파일 기법에는 크게 두 가지가 있다. 인터프리터 방식과 정적 컴파일 방식.

python의 경우 인터프리터 방식으로 런타임시에 바이트코드를 한 줄씩 읽어나가며 코드를 실행한다. 이 방법은 동일한 메서드를 여러번 사용하는 경우 중복해서 번역하는 비효율이 있다.

C의 경우 정적 컴파일을 진행한다. 컴파일 먼저 다하고 실행하기만 한다.

 

JIT는 기본적으로 인터프리터 방식으로 작동하지만 번역한 내용을 캐싱해두었다가 동일한 메소드를 실행할 때 캐싱된 내용을 사용한다. 

 

자, 여기서 python과 java의 차이를 살펴보자. 둘다 인터프리터 방식으로 컴파일 하긴 한다.

 

python은 소스 코드를 던져주면 아무 것도 하고 있지 않다가 런타임 시에 하나하나 읽어가며 변환하는 인터프리터 방식으로 컴파일된다. 여기가 끝이다.

 

그런데 java는 우선 java 코드를 바이트 코드(.class)로 컴파일한 후 해당 바이트 코드를 JIT 방식으로 변환해나간다. 아무리 JIT가 캐싱 때문에 인터프리터보다 빠르다고는 해도 느리긴 느리다.

 

출처 : https://catch-me-java.tistory.com/11?category=438116

 

 

  • JVM 구성 요소

JVM은 크게 네 가지의 구성 요소를 가진다.

1. Class Loader 

JRE(java runtime environment, 자바 실행 환경)의 일부로 바이트 코드를 실행할 때 class 객체를 메모리에 생성한다. 클래스를 통해 인스턴스를 생성하면 class loader를 통해 메모리에 로드한다.

 

2. 가비지 컬렉터

java는 메모리 관리를 JVM이 알아서 해준다. 여타 다른 가비지 컬렉터가 그러하듯 참조되지 않는 메모리를 정리한다.

 

3. Execution Engine

메모리에 로드된 바이트코드를 실행한다. class loader가 메모리에 클래스의 인스턴스를 올려놓으면 execution engine이 실행해준다. 이를 JIT 방식으로 실행한다.

 

4. Runtime Data Area

JVM의 메모리 영역이다. 실행할 클래스들을 저장하는 클래스 영역, 가비지 컬렉션 힙 영역, 런타임 스택 영역, 네이티브 메서드 스택 영역으로 나뉜다.

 

아래 두 포스트를 참고하면 더욱 좋다.

 

catch-me-java.tistory.com/12

 

[Java-4] JVM의 구조

전 글에서는 JVM에 대해서 간단하게 알아 보았다. 이제 JVM 구조에 대해서 알아보고 JRE와 JDK 에 대해서 알아보도록 하자. 1. JVM 구조 JVM 의 구성요소는 크게 3가지로 구성 되어있다. 클래스 로더 시

catch-me-java.tistory.com

homoefficio.github.io/2019/01/31/Back-to-the-Essence-Java-%EC%BB%B4%ED%8C%8C%EC%9D%BC%EC%97%90%EC%84%9C-%EC%8B%A4%ED%96%89%EA%B9%8C%EC%A7%80-2/

 

Back to the Essence - Java 컴파일에서 실행까지 - (2)

Back to the Essence - Java 컴파일에서 실행까지 - (2)Java 11 JVM 스펙을 기준으로 Java 소스 코드가 어떻게 컴파일되고 실행되는지 살짝 깊게 알아보자. 이번엔 2탄 실행 편이다. 1탄 컴파일 편은 여기에..

homoefficio.github.io

 

hello world

 

간단히 HelloWorld 클래스를 만들어 출력해보자. 

public class HelloWorld {
    public static void main(String[] args) {
        System.out.println("Hello world"); // sout으로 snippet 생성
    }
}

 

간단히 연산을 해보자.

 

주의할 점은 다음과 같다.

 

  • 아쉽게도 문자열 템플릿이 없다...python의 f-string, javascript의 백틱(``) 그런거 없다...
  • '' 와 ""를 구별합니다. ''는 char, ""는 string입니다. javascript 처럼 혼용하면 안됩니다!
  • 이스케이프 문자 그대로입니다. 마음껏 씁시다.
public class Data {
    public static void main(String[] args) {
        System.out.println(6);
        System.out.println("str");

        System.out.println("6" + "6");
        System.out.println(6 + 6);
        System.out.println(Math.PI * 3);

        System.out.println("text".length());

        // 문자열 템플릿은 java에서 지원하지 않습니다. kotlin...
        // String name = "darren";
        // System.out.println("ma name is ${name}");
    }
}

 

 

당연하지만 간단한 opeator를 써보았다.

public class operations {
    public static void main(String[] args) {
        // simple operators
        System.out.println(3 * 3);
        System.out.println(7 / 2);
        System.out.println(7 % 2);

        // Math
        System.out.println(Math.max(3, 45));
        System.out.println(Math.abs(-4));
        System.out.println(Math.tan(35));
        System.out.println(Math.floor(Math.PI));
        System.out.println(Math.ceil(Math.PI));
    }
}

 

문자열

public class strings {
    public static void main(String[] args) {
        // ""와 '' 구분
        System.out.println("what");
        System.out.println('a');

        // escape 문자
        System.out.println("Hello \nworld");
        System.out.println("Hello \"world\"");

        // length, replace 등 문자열 객체가 가진 메서드들
        System.out.println("good".length());
        System.out.println("hello world".replace("hello", "bye cruel"));
        System.out.println();
    }
}

 

변수

public class variable {
    public static void main(String[] args) {
        int a = 1;
        System.out.println(a);

        double b = -1.1;
        System.out.println(b);

        // 템플릿 문자열 안되요 ㅜㅜ
        String name = "darren";
        System.out.println("hello, " + name);
    }
}

 

 

캐스팅(형변환)

public class casting {
    public static void main(String[] args) {

        // 1.1은 double임에도 불구하고 int로 할당 (타입 캐스팅)
        // 손실이 존재하는 형변환의 경우에는 수동으로 캐스팅을 해줘야 함.
        int a = (int) 1.1;
        System.out.println(a); // 1.0을 출력하게 됨

        // 넓은 범위의 데이터 타입에서 좁은 범위의 타입을 자동 캐스팅이 됨.
        double b =  1;
        System.out.println(b);

        // interger 객체의 toString 메서드
        String f = Integer.toString(1);
        System.out.println(f.getClass());
    }
}

 

docs 주석을 달아봤다. Nest 왜 함~ 자바하지~


/**
 * 샘플 클래스입니다.
 * @author mac
 * @date 2020.06.28
 * @deprecated 쓰지마~
 */
public class sampleClass3 {
	
	/**
	 * 메인 메서
	 * @param args
	 */
	public static void main(String[] args) {
		// print method
		printMethod();
	}
	
	public static void printMethod() {
		System.out.println("print");
	}
}

 

 

 

 

darren, dev blog
블로그 이미지 DarrenKwonDev 님의 블로그
VISITOR 오늘 / 전체