on
JAVA(Programmers) - 1
Java 공부 시작!
맨날 공부 시작 시작 말만 하다가 이제서야 제대로 시작하려고 한다. 나의 주력언어로 쓸 것이니 처음 부터 하나하나 꼼꼼히 보도록 할 것이다.
Java의 탄생 - 출처
- 1995년에 썬 마이크로시스템즈에서 발표한 객체지향 언어. 현재는 오라클에 인수됨.
Java의 특징 - 출처
- 쉬운 언어이다.
- C와 C++언어의 문법을 기본으로 차용하여 개발된 언어
- C와 C++ 이 가진 어려운 문법인 포인터와 다중 상속 제거
- C와 C++에 비해 쉬운 언어이다.
- 플랫폼에 독립적이다.
Java는 JVM 만 있으면 윈도우, 리눅스, 맥등 어떤 플랫폼에서도 실행이 가능
- 객체지향 언어이다.
- 메모리 관리를 자동으로 해준다.
- C에서는 동적으로 메모리를 할당해주면 사용자가 코드 상에 반드시
free()와 같은 함수로 할당해준 메모리를 해제해줘야 했다. 그러나Java에서는Garbage Collector(GC)가 알아서 이러한 메모리들을 알아서 할당 해제 시켜준다.
- C에서는 동적으로 메모리를 할당해주면 사용자가 코드 상에 반드시
JVM(Java Virtual Machine)이란?
JVM은 Java 프로그램뿐 아니라
Java bytecode로 컴파일된 다른 언어로 작성된 프로그램도 컴퓨터에서 실행할 수 있도록 하는 가상 시스템. - 출처: wikipedia
위에서 Java는 어느 플랫폼에서도 실행이 가능하다고 했다. 과연 왜 그럴까?

그 이유는 바로 C와는 달리 Java는 OS에 상관없이 JVM위에서 실행되기 때문이다. C처럼 어떤 OS인지에 따라 영향을 받을 수 있는게 아니기 때문에 플랫폼에 독립적이다. Java 에 대한 유명한 말 중 하나인 “Write once, run erveywhere” 이 있는데 어떤 OS인지에 상관없이 동일한 코드가 어느 곳에서든 동일하게 실행이 된다는 뜻이다. 물론 JVM 자체는 OS에 영향을 받기 때문에 해당 OS에 맞는 JVM으로 설치를 해야한다.
C같은 경우는 소스코드가 컴파일하면 .obj라는 assembly code 가 되고, 어셈블러로 machine code가 된다. Java의 실행단계는 간략하게 말하자면 아래와 같다. (아래 사진과 문항은 해당 블로그를 참고했다)

Hello.java라는 소스코드를Java compiler로 컴파일 한다.- 컴파일이 되면,
Hello.class라는Java byte code가 생성된다. Java byte code(Hello.class)를 JVM이 읽고 실행하게 된다.- Java Class Loader : JVM안으로 class파일들을 load한다. Loading 된 class파일들은
Runtime Data Area에 배치된다.Runtime Data Area: JVM이 프로그램을 수행하기 위해 OS로 부터 별도로 할당 받은 메모리 공간.
- Execution Engine : Load된 Class의
ByteCode를 실행하는 Runtime Module이 바로 Execution Engine. Execution Engine은Java bytecode를 명령어 단위로 읽어서 실행. - 실행 엔진은
Java bytecode를 명령어 단위로 읽어서 실행.
Java Array
// array declare
final static int arrSize = 5;
int[] arrInt = new int[arrSize];
int[] arrInt2 = new int[]{1,2,3,4,5};
int[] arrInt3 = {1,2,3,4,5};
배열의 크기를 반드시 명시해줘야한다.
Array length
int[] arr1 = new int[20];
int arrLength = arr1.length; // arr1 길이 : 20
Array length vs String length
근데 배열을 배우다가 문득 들었던 생각인데, 분명 나는 Java에서 length()라는 method를 쓴 기억이 있는데 배열에서는 length를 써야했었다. 뭐가 다르길래 하나는 method를 쓰고, 하나는 instance variable를 쓰는 것일까 싶어서 찾아봤다.
해당 링크를 참고하여 정리해봤다.
- Array
length: 선언될 때 배열같은 경우는 반드시 배열의 크기를 명시해줘야 하고, 이는 고정된 값으로서 바뀔 수 없다. 따라서length변수는 직접적으로 배열의 크기를 얻기 위해 사용되어진다. - String
length(): String class의static method이다.length()를 사용하여 문자열의 길이를 구한다. 왜냐하면 해당 객체에 다양한 연산이 진행돼서 문자열의 길이가 변할 수 있기 때문에 변수를 사용하여 곧바로 구할 수가 없다.- 여기서 의문이 들었다. programmers라는 사이트의 강의에서 “String은 다른 class와는 다르게 한번 생성되면 변하지 않는다”라고 배웠기 때문이다. 근데 해당 링크는 “length of a string can be modified using the various operations on an object.”라고 돼있었다. 과연 뭐가 맞는 것일까 싶어서 더 찾아봤다.
String literal vs new declare
해당 의문을 해결하기 위해서는 먼저 이것부터 알아야 한다. String object는 2가지 방법으로 선언할 수 있다.
String str1 = "Hello"; // literal
String str2 = new String("Hello"); // new operator
하나는 constructor를 안쓰고 선언했고, 하나는 constructor로 선언했다. 여기서 분석을 해보자.
str1, str2: reference variable.instance의 위치를 가리키고 있다. 그렇기 때문에 reference인 것.String: 문자열을 선언할 때 쓰는 class."Hello": “상수가 저장되는 memory”에 저장된다.- 상수가 저장되는 메모리 : String Constant Pool. Heap영역에 있다.
literal선언을 하게 되면, 해당 문자열의 값은String Constant Pool에 저장된다.
- 상수가 저장되는 메모리 : String Constant Pool. Heap영역에 있다.
new String("Hello"):constructor로 선언을 해줬다. Heap영역에 새로운instance생성.
이렇게 분석을 해봤다. 아직까지는 둘의 차이가 뭔지 잘 모를 수 있다. 더 자세히 말해보도록 하겠다.
먼저 literal선언을 하게 되면, 해당 문자열은 Heap영역의 String Constant Pool에 저장이 된다. 근데 또 다른 literal선언을 했는데 같은 문자열 값을 썼다면, String Constant Pool에 이미 존재하는 값이므로 2번째로 선언된 reference variable은 1번째로 선언된 reference variable와 같은 곳을 가리킨다.
그러나 new String()으로 선언을 했다면, String Constant Pool에 같은 문자열이 있든지 말든지 무조건 새로운 instance를 생성하는 것이다.
이렇게 설명만 들으면 이해가 잘 안갔기에 코드로 구현을 해봤다. Java에는 System.identityHashCode("reference variable")라는 함수가 있다.System.identityHashCode()는 객체의 고유한 hashcode를 리턴하는 method이다. reference variable이 어디를 가리키는지를 출력을 해준다. literal선언된 2개의 변수가 가리키는 instance가 같다면, 해당 함수의 결과 값 또한 같아야 할 것이다.
public class StringTest{
public static void main(String[] args) {
String str1 = "Hello";
String str2 = "Hello";
String str3 = "Hi";
System.out.println("변경 전 str1(Hello literal)->" + System.identityHashCode(str1));
String str4 = new String("Hello");
String str5 = new String("Hello");
str1 = str1 + " World!";
String str6 = "Hello World!";
System.out.println("변경 후 str1(Hello World literal)->" + System.identityHashCode(str1));
System.out.println("str2(Hello literal)->" + System.identityHashCode(str2));
System.out.println("str3(Hi)->" + System.identityHashCode(str3));
System.out.println("str4(Hello new)->" + System.identityHashCode(str4));
System.out.println("str5(Hello new)->" + System.identityHashCode(str5));
System.out.println("str6(Hello World literal)->" + System.identityHashCode(str6));
}
}
programmers git:(main) ✗ java StringTest
변경 전 str1(Hello literal)->705927765
변경 후 str1(Hello World literal)->366712642
str2(Hello literal)->705927765
str3(Hi)->1829164700
str4(Hello new)->2018699554
str5(Hello new)->1311053135
str6(Hello World literal)->118352462

reference variable은 Java의 Stack영역에 생긴다. 위 그림은 코드의 reference variable들이 참조하고 있는 곳을 나타낸 것이다.
-
str1(변경 전), str2:literal선언되어"Hello"라는 같은 문자열 값을 갖는다. 따라서 참조하는 위치는 같다. 코드의 출력 결과 또한변경 전 str1(Hello literal)->705927765 str2(Hello literal)->705927765으로 같다.
-
str3:"Hi"라는 문자열 값을 갖는다.String Constant Pool에"Hi"가 저장된다. 따라서 참조하는 위치는"Hi"라는instance값이 있는 곳이다. -
str4, str5: 같은"Hello"문자열을 갖는instance를 각각 생성했다. 따라서 가리키는 곳은 서로 다르다. 코드의 출력은str4(Hello new)->2018699554 str5(Hello new)->1311053135보다시피 다른 것을 알 수 있다. 물론
str1(변경 전), str2와도 다르다. -
str6:literal선언되어"Hello World!"라는 문자열 값을 가진다. 인스턴스의 위치를 가리키고 있다. -
str1(변경 후): instance값을 변경해서"Hello World!"라는 문자열로 만들었으나 이는 기존의 인스턴스가 변한 것이 아니라 새로운 인스턴스가 생성된 것이다. 따라서str1에 있는 빨간 점선이 바로 새로 생성된 인스턴스를 가리키는 것이다.변경 후 str1(Hello World literal)->366712642 str6(Hello World literal)->118352462str1(변경 후)와str6이 같은"Hello World!"라는 문자열 값을 가진다고 해도, 서로str1(변경 후)는 변경됐을 때 시점으로 새로운 인스턴스가 따로 생성된 것이기 때문에 서로 가리키는 인스턴스가 다르다.
참고 사이트
https://starkying.tistory.com/entry/what-is-java-string-pool
https://www.guru99.com/java-stack-heap.html
https://changhozz.tistory.com/entry/String%ED%81%B4%EB%9E%98%EC%8A%A4%EC%9D%98-%ED%8A%B9%EC%A7%95
https://www.tutorialspoint.com/what-are-the-differences-between-length-and-length-in-java
https://pienguin.tistory.com/entry/JAVA-%EC%9E%90%EB%B0%94-%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%A8-%EC%8B%A4%ED%96%89-%EA%B3%BC%EC%A0%95-%EB%B0%8F-%EA%B8%B0%EB%B3%B8-%EA%B5%AC%EC%A1%B0