Java 기초
◎ JAVA와 그 특징
-> java는 객체지향언어(OOP : Object Oriented Programming)언어다
-> 특징
1. 운영체제에 독립적이다. : 자바에는 JRE라는 것이 있어서 각 컴퓨터의 운영체제에 맞게 실행이 가능하도록 만들어졌다.
2. 객체지향 언어다 : 객체란 실세계에 존재하는 자신의 속성을 가진 것으로 프로그래밍 언어에서 프로그램에 동작하게 하는 부품이다. 이런 부품들을 만들고 조립해서 하나의 프로그램을 실행하는 개념이 OOP개념이다.
3. 함수형 프로그램 지원 : 자바 8버전 부터 함수형 프로그래밍을 지원하는 람다식과 스트림이 추가되었다.
4. 자동 메모리 관리 : 자바에는 가비지 컬렉터라는 것이 있어 사용하지 않는 메모리를 자동으로 수거한다.
-> 자바는 컴파일러를 통해 기계어로 변환되는 언어다
-> 여기에 JVM(Java Virtual Machine)이라는 것이 있는데 이것은 자바 코드로 작성한 프로그램을 해석해 실행하는 프로그램이다. 즉, 자바 프로그램을 실행하는 도구다.
-> 개발자가 자바로 코드를 작성하고 컴파일을 하면 컴파일러가 이 코드를 바로 기계어로 변환하는 것이 아니라 먼저 바이트 코드로 변환을 하고 JVM을 거쳐 각 운영체제에 맞는 기계어로 변환하여 각 컴퓨터에서 프로그램이 실행되게 한다.
◎ JDK & JRE
-> JRE(Java Runtime Environment) : JVM+ 표준 클래스 라이브러리, 컴퓨터의 운영체제 소프트웨어 상에서 실행되고, 클래스 라이브러리 및 특정 자바 프로그램이 실행해야 하는 기타 리소스를 제공하는 소프트웨어 계층이다.
-> JDK(Java Development Kit) : JRE + 개발에 필요한 도구
-> JDK는 자바 프로그램을 생성할 수 있게 해준다.
◎ 변수와 타입
-> 컴퓨터는 메모리에 데이터를 저장한다. 메모리는 1바이트 크기의 메모리 셀들이 모여서 만들어지고 각 셀마다 고유번호가 오름차순으로 매겨져있다. 이 고유번호가 메모리 주소다.
-> 이 메모리 주소는 16진수로 이루어져있어 사람이 식별하기 까다롭다. 이걸 쉽게 식별하게 이 메모리 주소에 대한 이름을 붙인 것이 변수다. 또한 변수의 값은 바뀔 수 있다.
class Main {
public static void main(String[] args) {
0xf12345c = 1; // 값 저장
System.out.println(0xf12345c) // 값 사용
}
}
-> 메모리 주소를 그대로 사용하는 경우다. 메모리 주소를 그대로 사용하면 식별이 어렵고 오타 등으로 인해 오류가 발생할 가능성이 높다.
class Example {
public static void main(String[] args) {
int number = 1; // 값 저장
System.out.println(number) // 값 사용
}
}
-> 변수를 사용한 코드이다. 메모리 주소를 그대로 사용할 때 발생하는 문제점들을 해결한다.
-> 변수를 사용하려면 변수를 선언해야 한다. 위 의 코드에서 number라는 변수를 선언할 때 앞에 int라는 것이 붙었다. int는 정수형이라는 의미로 number에는 정수형 값이 들어감을 의미한다.
-> 변수 앞에는 int형 외에도 정수형, 실수형 등 다양한 형태가 붙을 수 있고 이를 타입이라고 한다.
◎ 상수
-> 변하지 않아야 하는 데이터를 임시로 저장하기 위한 수단이다.
final double PI = 3.14;
-> 위의 코드와 같이 타입 앞에 final키워드를 붙이면 상수로 사용할 수 있다.
-> 상수를 사용하는 이유는 프로그램이 실행되면서 값이 변하지 않아야 할 때 사용된다. 만약 상수에 값을 재할당하는 실수를 한다고 해도 에러가 발생하여 상수 값이 변하는 문제를 방지할 수 있다. 또한 상수로 값을 저장하면 코드에서 해당 값이 필요할 때 상수이름만 쓰면되기 때문에 코드의 가독성이 높아진다. 마지막으로 코드를 유지보수하기 쉽다. 만약 PI라는 이름의 상수가 3.14라는 값을 가지고 있다고 한 번 선언하고 이후에 값을 변경하고 싶다면 상수 선언 코드에서 값만 바꾸면 된다.
◎ 타입
-> 타입은 어떤 값의 유형이나 종류로 타입에 따라 값이 차지하는 메모리 공간 크기와 값이 저장되는 방식이 결정된다.
-> 정수형인 int형은 4byte, 실수형 double은 8바이트 등 타입에 따라 메모리 공간의 크기와 값이 저장되는 방식이 결정된다.
-> 타입에는 기본타입과 참조타입이 있다.
-> 기본 타입 : 값 저장 시 데이터의 실제 값이 저장되는 타입이다. 정수 타입, 실수 타입, 문자 타입, 논리 타입이 기본 타입에 해당한다.
-> 참조 타입 : 값 저장 시 데이터가 저장된 곳을 나타내는 주소 값이 저장되는 타입이다. 객체의 주소를 저장하거나, 위의 정수 타입, 실수 타입, 문자타입, 논리 타입을 제외한 나머지 타입이 참조 타입에 해당한다.
class Main {
public static void main(String[] args) {
int i = 1; // 기본 타입
Object obj = new Object(); // 참조 타입
System.out.println(i);
System.out.println(obj);
}
}
-> 결과
-> 기본 타입 i에는 데이터의 실제 값인 1이 들어있기 때문에 출력하면 1이 출력되고, 참조 타입 obj에는 데이터의 주소 값이 출력된다. 따라서 위 결과 이미지의 두번째 줄처럼 java.lang.Object@6e8dacdf가 출력이 된다.
◎ 리터럴
-> 문자가 가리키는 값 자체를 나타낸다.
-> int i =1;코드에서 i에 할당된 1이 리터럴이다.
◎ 기본 자료형
-> 기본 자료형에는 정수형(byte, short, int, long), 실수형(float,double), 문자형(char), 논리형(boolean)이 있다.
-> 각각 차지하는 메모리의 크기가 다르다.
◎ 타입 변환
-> 논리형(boolean)을 제외한 기본 자료형은 서로 타입변환이 가능하다.
-> 타입 변환에는 자동 타입 변환과 수동 타입 변환이 있다.
-> 자동 타입 변환 : 바이트 크기가 작은 타입에서 큰 타입으로 변환 시 자동으로 타입 변환이 이루어진다. 또한 덜 정밀한 타입에서 더 정밀한 타입으로 변환 시에도 자동으로 타입 변환이 된다. 여기서 정밀함의 정도는 정수에서 실수로 변환하느 는 경우를 생각하면 된다. 실수형은 소수점 자리까지 나타내기 떄문에 정수형보다 더 정밀하다고 할 수 있다. 따라서 정수형에서 실수형으로 변환되는 경우에도 자동 타입 변환이 이루어진다.
-> 수동 타입 변환 : 메모리 용량이 큰 타입에서 작은 타입으로 변환될 때 혹은 더 정밀한 타입에서 덜 정밀한 타입으로 변환될 때 수동으로 타입 변환을 해야한다. 이것을 캐스팅이라고 한다.
public class Practice {
public static void main(String[] args) {
// 실수형인 float이 정수형인 long보다 더 정밀하기 때무넹 자동 타입 변환이 이루어진다.
long lv = 3000L;
float fv = lv;
System.out.println("자동 타입 변환 결과 : " + fv);
int iv = 128;
byte bv = (byte)iv;
System.out.println("수동 타입 변환 결과 : "+ bv);
}
}
-> 결과
-> 수동 타입 변환 결과를 보면 -128이 출력된다. 원래대로라면 128이 출력되었어야 한다.
-> 이는 byte형이 표현할 수 있는 범위가 -128~127으로 byte형이 표현할 수 있는 최대 범위를 벗어났다. 이를 오버플로우라고 하고, 반대 상황 즉, 어떤 타입이 표현할 수 있는 최소 범위를 벗어나는 경우는 언더플로우라고 한다.
◎ String클래스
-> String 클래스는 문자열을 다루는 클래스다. 또한 String 클래스는 문자열과 관련된 다양한 *메서드들을 가지고 있다.
*메서드 : 어떤 기능을 하는 코드를 묶음으로 묶은 것이다. 즉, 어떤 기능을 수행하기 위한 코드 묶음이다.
-> String 클래스 사용
public class Practice {
public static void main(String[] args) {
String s1 = "hong"; // 문자열 리터럴을 String타입의 변수 s1에 직접 할당하는 방법
String s2 = new String("hong"); // String클래스의 인스턴스를 생성하는 방법
System.out.println("s1 : " + s1);
System.out.println("s2 : " + s2);
}
}
-> 결과
-> String 타입의 변수를 선언하고 사용하는 방식에는 위 코드 처럼 두 가지의 방법이 있다.
-> 이 두 가지 방법은 모두 참조 타입 변수에 해당한다. 즉 ,s1과 s2는 문자열 리터럴을 가지고 있는 것이 아니라 이에 해당하는 주소 값을 가지고 있는 것이다.
-> 그러면 이전에 참조 타입 변수 사용 예시 처럼 주소 값이 출력이 되어야 하는데 s1,s2는 문자열이 그대로 출력되었다. 그 이유는 String 클래스 내에 주소 값에 위치한 String 인스턴스의 값을 문자열로 변환해주는 toString()메서드가 있고, 이 메서드가 String 클래스 사용 시 자동으로 호출되기 때문이다.
-> 그렇다면 s1과 s2는 같은 문자열을 출렸했으니 같은 주소 값을 가지는 변수일까? ==> 아니다.
-> 이것을 동등 비교 연산자(==)와 equals()메서드를 통해 확인할 수 있다.
-> (==)동등 비교 연산자는 좌항 == 우항의 형태로 좌항과 우항의 주소 값을 비교하여 일치하면 true, 아니면 false를 리턴한다.
-> equals()메서드는 s1.equals(s2)의 형태로 사용하고 s1의 문자열 내용과 s2의 문자열 내용이 같으면 true 아니면 false를 리턴한다.
import java.util.ArrayList;
public class StringEx {
public static void main(String[] args) {
String n1 = "hong";
String n2 = "hong";
String n3 = new String("hong");
String n4 = new String("hong");
boolean c1 = n1 == "hong"; // 1
boolean c2 = n1 == n2; // 2
boolean c3 = n1 == n3; // 3
boolean c4 = n3 == n4; // 4
boolean c5 = n1.equals("hong"); // 5
boolean c6 = n1.equals(n3); // 6
boolean c7 = n3.equals(n4);// 7
System.out.println("1 : " + c1);
System.out.println("2 : " + c2);
System.out.println("3 : " + c3);
System.out.println("4 : " + c4);
System.out.println("5 : " + c5);
System.out.println("6 : " + c6);
System.out.println("7 : " + c7);
}
}
-> n1과 n2는 "hong"이라는 동일한 문자열 리터럴을 그대로 받은 변수다. 이 경우 n1,n2가 저장하는 문자열의 주소 값은 같다.
-> n3,n4는 String 클래스의 인스턴스를 생성해서 String 타입의 변수에 할당하는 방법을 사용하고 있다. 이 경우 String클래스의 인스턴스를 생성하게 되면 문자열 내용이 같더라도 별개의 인스턴스가 생성되므로 n3와 n4가 할당 받는 인스턴스 값은 서로 다른 값을 할당받게 된다.
-> 결과
출처 및 참고