클래스 선언
클래스
- 자바는 객체를 만들기 위해 반드시 클래스를 먼저 만들어야 함. 클래스는 객체를 만들기 위한 일종의 틀.
- 클래스는 멤버(member)로 속성을 표현하는 필드(field)와 기능을 표현하는 메소드(method)를 가짐
- 클래스를 만드는 형식: class 클래스명 { };
- 붕어빵이 객체라면, 붕어빵 틀은 클래스
- 자동차 클래스 생성
public class Car{
}
- Car.java란 파일을 만듦
- 저장을 하면 이클립스는 컴파일하여 디스크에 Car라는 클래스를 생성
- 자동차 클래스가 생성되었다고 해서 자동차가 만들어진 것은 아님
Car객체 생성하기 (자동차 만들기)
public class CarExam{
public static void main(String args[]){
Car c1 = new Car();
Car c2 = new Car();
}
}
- new 연산자: new연산자 뒤에 나오는 생성자를 이용해 메모리에 객체를 만들라는 명령
- 메모리에 만들어진 객체를 인스턴스(instance)라고도 함
- 이렇게 만들어진 객체를 참조하는 변수가 c1 , c2 (클래스가 참조형 타입이 됨)
- 위의 코드가 실행되면 Car라는 객체가 2개가 만들어지고 각각의 객체를 참조하는 c1과 c2변수가 선언됨
실습
public class Car{
}
public class CarExam{
public static void main(String[]args){
// c1에 Car 객체를 생성해서 넣어주세요.
Car c1 = new Car();
}
}
참조타입
- Java에선 변수를 선언하려면 변수의 데이터타입을 정해줘야 함
- Java의 변수 타입
- 기본 타입
- 논리형(boolean), 문자형(char), 정수형(byte, short, int, long), 실수형(float, double)
- 참조 타입
- 기본형 타입을 제외한 모든 타입
- 앞서 배웠던 배열도 참조 타입이고, 클래스도 모두 참조 타입
- 기본 타입
- 참조형 변수
- String str = new String("hello");
- str 변수 앞에 기본형 타입이 아닌 String클래스가 적혀있음
- 이퀄(=)뒤에는 new 다음에 생성자가 있음
- new 라는 키워드는 객체를 메모리에 올려줌(클래스를 메모리에 올려주세요). 이렇게 메모리에 올라간 객체를 인스턴스라고 함.
- String str = new String("hello");
- (메모리에 올라간 인스턴스를 가리키는 변수, 참조하는 변수, 레퍼런스 하는 변수가 str 이다). (클래스를 참조한다. 레퍼런스한다)라는 것은 변수가 인스턴스를 가지고 있는 게 아니라 말 그대로 가리킨다는 의미
- str이라는 변수에는 메모리의 위치 값이 저장됨. 메모리의 위치값이 저장된다고 하더라도, 어떤 메모리에 저장되는지 그 정보를 알 수 있는 방법은 없음. 그렇기 때문에 str변수는 String 인스턴스를 참조한다라고만 알면 됨
- 앞으로 배울 클래스들은 모두 참조형
참고 (Java의 메모리 구조)
- heap
- new를 통해 생성된 모든 인스턴스가 저장되는 공간
- 인스턴스는 결국 참조형(reference type) 데이터 타입임을 의미하는데, 참조형으로 선언된 변수의 값은 heap 메모리 공간에 할당됨
- 참조형 데이터 타입의 값 자체는 heap 메모리 공간에, 해당 값의 주소는 stack영역에 저장됨
- heap 영역의 메모리는 가비지 컬렉터(Garbage Collector)를 통해 관리되며, 참조되지 않는 경우에는 해당 공간에 할당된 메모리가 해제됨 (때문에 개발자는 메모리 관리를 신경쓸 필요가 없음)
- static (=method 영역)
- 전역변수와 static이 붙은 클래스 메서드의 경우에 static 영역에 할당되어 프로그램의 시작부터 종료까지 메모리에 유지되며, 프로그램이 종료되는 때에 메모리에서 해제됨
- static 메모리가 차지하는 공간은 프로그램 로드시에 결정되기 때문에 프로그램 컴파일 시간에 많은 영향을 줌
- static으로 선언된 경우 프로그램 전체에서 공유됨
- import 하여 사용하는 패키지 파일들도 static 영역에 저장됨.
- 클래스 메서드나 클래스 변수의 경우 인스턴스를 생성하지 않고 ‘ 클래스명.메서드명’ or ‘클래스명.변수명’ 이와 같은 식으로 사용
- stack (call stack 또는 execution stack)
- 지역변수와 일반 메서드가 저장되는 공간
- 기본형의 경우, 값 자체가 stack 영역에 할당됨
- 참조형 타입의 값을 지역 변수에 할당 시, stack 메모리 공간에 실질적으로 할당되는 것은 heap 메모리 공간에 저장된 값의 참조값(=주소값)
- 메서드의 경우는 메서드가 호출될 때 메모리에 할당되고, 해당 메서드가 종료되면 메모리에서 해제됨
- stack 영역은 LIFO(=Last In First Out) 구조로 되어 있음
- LIFO(Last In Fist Out) 구조
- 후입선출 즉, 가장 마지막 항목이 가장 먼저 제거됨
package chapter06; public class CallStackTest { public static void main(String args[]) { System.out.println("main(String[] args)실행됨"); firstMethod(); System.out.println("main(String[] args)종료됨"); } static void firstMethod () { System.out.println("firstMethod 실행됨"); secondMethod(); System.out.println("firstMethod 실행됨"); } static void secondMethod () { System.out.println("secondMethod 실행됨"); System.out.println("secondMethods 실행됨"); } } // 출력 순서 ----------------- // main(String[] args) 실행 > 스택 메모리에 가장 먼저 올라감 // firstMethod 실행 > firstMethod 메서드가 main 메서드 위에 올라감 // secondMethod 실행 > firstMethod 메서드 위에 secondMethod 메서드 위에 올라감 // 메모리에서 제거될 때는 메모리에 올라간 순서와 반대 // secondMethods 실행 > secondMethod 메서드가 모든 실행을 끝내고 제거 // firstMethod 실행 > 메모리에서 제거 // main(String[] args) 종료 > 메모리에서 제거
- cf) 스택오버플로우(StackOverFlow, SOF)
- 재귀호출이나, 무한반복을 하는 for문이나 while문이 실행되어 함수가 실행되지 않고, 계속해서 스택에 메모리가 쌓이게 되는 경우 스택 메모리가 감당할 수 있는 범위를 초과하는 경우 발생하는 에러를 의미
String클래스
- 문자열을 표현하는 클래스 (자바에서 가장 많이 사용)
- public static void main(String[ ] args( ){ } 에서 String도 String클래스
- 하나의 문자가 아닌 여러 문자(문자열)를 저장할 수 있으며, char와 다르게 빈 문자열도 저장 가능
- 큰따옴표(” “)로 값을 감싸야 함 (char는 작은따옴표(’ ‘) 사용)
- 가장 많이 쓰기 때문에 특별대우 받음
- new 연산자를 사용하지 않아도 되고, 해도 됨 But, 어떤 인스턴스를 참조하는지는 다름
Java 인스턴스 생성 방법
- new연산자를 이용하지 않고 인스턴스를 만드는 경우
String str1 = "hello";
String str2 = "hello";
- "hello"라는 문자열이 메모리 중에서 상수가 저장되는 영역에 저장됨
- 상수는 변하지 않는 값을 의미
- String str2 = "hello"; 이 문장이 실행될 때에 hello 라는 문자열 상수는 이미 만들어져 있으므로 str1이 참조하는 인스턴스를 str2도 참조
- 메모리를 아끼려면 String은 new를 사용하지 않고 사용하는 것이 좋음
- new연산자를 이용해서 인스턴스를 만드는 경우
String str3 = new String("hello");
String str4 = new String("hello");
- new연산자를 이용하여 인스턴스를 만들면 인스턴스는 무조건 새롭게 만들어짐
- String str4 = new String("hello"); 이 문장이 실행될 때도 인스턴스를 새롭게 만들게 되므로, str3과 str4는 서로 다른 인스턴스를 참조
if(str1 == str2){
//같은 인스턴스를 참조하므로 결과는 true (출력됨)
System.out.println("str1과 str2는 같은 레퍼런스이다.");
}
if(str1 == str3){
//str1과 str3은 서로 다른 인스턴스를 참조하므로 결과는 false (출력 안 됨)
System.out.println("str1과 str3는 같은 레퍼런스이다.");
}
if(str3 == str4){
//str3과 str4는 서로 다른 인스턴스를 참조하므로 결과는 false (출력 안 됨)
System.out.println("str3과 str4는 같은 레퍼런스이다.");
}
- 참조형 변수끼리 == 로 비교하면 서로 같은 것을 참조하는지(가리키고 있는 메모리영역의 주소가 같은지) 비교 (값을 비교하는 게 아님)
- String은 불변 클래스
- 불변이란, String이 인스턴스가 될 때 가지고 있던 값을 나중에 수정할 수 없다는 뜻
- String은 문자열과 관련된 다양한 메소드를 가지고 있음
- 메소드를 호출한다 하더라도 String은 내부의 값이 변하지 않음
- String이 가지고 있는 메소드 중 String을 반환하는 메소드는 모두 새로운 String을 생성해서 반환
String str5 = "hello world";
String str6 = str5.substring(3);
System.out.println(str6); //결과: lo world
System.out.println(str1); //결과: hello
System.out.println(str1.substring(3)); //결과: lo
System.out.println(str1); //결과: hello
- substring은 문자열을 자른 결과를 반환하는 메소드. 해당 코드가 실행되어도 str5는 변하지 않음
- str6은 str5가 가지고 있는 문자열 중 3번째 위치부터 자른 결과 즉, 새로운 String을 참조
실습
필드(field) 선언
- 자동차는 자동차 이름, 번호를 가지고 있고, 자동차는 달리고 멈추는 기능이 있음.
- 학생은 이름, 학번 등을 속성으로 가짐. 한 반에 학생이 20명 있다면 학생 객체가 20개 있다는 것을 의미. 각각의 학생은 이름이 구별됨(객체별로 속성의 값이 유지된다는 의미)
- 여기에서 가지고 있는 것을 속성이라고 함. Java에서는 이러한 속성을 **필드(Field)**라는 용어로 사용
- 필드의 선언
- 데이터타입 필드명;
- 이름과 번호를 필드로 가지고 있는 Car클래스 선언
- public class Car{ String name; int number; }
- Car 클래스를 인스턴스화 하기
*public class CarExam {
public static void main(String[] args) {
Car c1 = new Car();
Car c2 = new Car();
//Car라는 인스턴스(객체)가 메모리에 2개 만들어짐
//객체별로 name과 number라는 속성을 가짐
}
}*
- 속성(필드) 이용하기
- 참조 변수 다음에 나오는 점(dot)은 참조변수가 참조하는 객체가 가지고 있는 것을 사용할 때 사용
- Car라는 객체가 c1, c2마다 생성되고 그 객체들마다 각각 속성(name, number)이 생김
Car c1 = new Car();
Car c2 = new Car();
*//c1.name은 c1이 참조하는 객체의 name을 의미*
c1.name = "소방차"; *//c1이 참조하는 객체의 name을 소방차로 설정*
c1.number = 1234; *// c1.number = 1234란 c1이 참조하는 객체의 number를 1234로 설정*
c2.name = "구급차"; *//c2가 가리키는 객체의name을 구급차로 설정*
c2.number = 1004; *//c2가 가리키는 객체의 number를 1004로 설정*
System.out.println(c1.name); *//콘솔에 c1이 참조하는 객체의 name을 출력*
System.out.println(c1.number); *//콘솔에 c1이 참조하는 객체의 number를 출력*
String name = c2.name;
*//c2가 참조하는 객체의 name을 String타입 변수 name도 참조하게 함*
필드 변경 제한: final
- final을 필드 앞에 붙이면 그 필드의 내용을 변경할 수 없음
- 마지막 변수 값을 갖기 때문에 변경할 수 없는 것
- 보통 final을 붙이는 필드는 상수처럼 고정된 형태이며, static과 함께 클래스 변수를 상수처럼 지정하는 데에 사용됨
실습
public class Song {
// 이곳에 코드를 작성하세요.
String songTitle;
String singer;
String albumName;
int trackNumber;
}
// Song.java 코드를 실행하기 위한 코드입니다. 이 코드는 수정하지 마세요.
public class SongExam {
public static void main(String[] args) {
Song song = new Song();
song.songTitle = new String("곡명");
song.singer = new String("가수");
song.albumName = new String("앨범");
song.trackNumber = 5;
}
}
메소드(Method)란?
- 필드와 메소드
- 필드: 물체의 상태 (car클래스의 이름과 번호)
- 메소드: 물체의 행동 (car클래스의 전진 or 후진하는 행동)
- 메소드
- 클래스가 가지고 있는 기능. 클래스 안에 선언됨
- 입력값이 있고 그 입력값을 받아서 무언가 한 다음 결과를 도출해내는, 수학의 함수와 비슷한 개념
- 이때 입력값을 매개변수라고 하고, 결과값을 리턴값이라고 함
- 인자(Argument): 어떤 함수를 호출시에 전달되는 값
- 매개변수(Parameter): 그 전달된 인자를 받아들이는 변수
메소드 선언
메소드 선언 방법
- public 리턴타입 메소드명 (매개변수들) { 구현할 기능 }
- 리턴값의 유무, 매개변수의 유무로 메소드의 형태가 나뉨
다양한 형태의 메소드
- 리턴값의 유무
- 리턴값 O: 리턴타입 자리에 해당 값의 타입 작성 (3,5번 메소드)
- 리턴값 X: 리턴타입 자리에 void 작성 (1,2,4번 메소드)
- 매개변수의 개수
- 여러 개면 콤마( , )로 구분
- 리턴하는 값 앞엔 return이라는 키워드 사용
1. 매개변수도 없고 리턴하는 것도 없는 형태의 메소드 (매개변수 X, 리턴값 X)
- 리턴하는 것이 없을 경우 void라는 예약어 작성
public class MyClass{
public void method1(){
System.out.println("method1이 실행됩니다.");
}
}
2. 정수를 받아들인 후, 리턴하지 않는 메소드 (매개변수 O, 리턴값 X)
- 받아들이는 값은 어떤 타입이라도 상관없음
public class MyClass{
public void method2(int x){
System.out.println(x + "를 이용하는 method2입니다.");
}
}
3. 아무것도 받아들이지 않고, 정수를 반환하는 메소드 (매개변수 X, 리턴값 O)
- 메소드 이름 앞에는 리턴하는 타입을 적어줌
- 리턴타입은 하나만 사용할 수 있으며 어떤 타입이라도 상관없음 (기본형뿐만 아니라 참조형도 가능)
public int method3(){
System.out.println("method3이 실행됩니다.");
return 10;
}
*//위 메소드가 실행되면
//콘솔에 'method3이 실행됩니다.'를 출력, 이 메소드를 호출한 쪽에 10을 리턴*
4. 정수를 2개 매개변수로 받고, 아무것도 반환하지 않는 메소드 (매개변수 O, 리턴값 X)
public void method4(int x, int y){
System.out.println(x + "," + y + " 를 이용하는 method4입니다.");
}
5. 정수를 한 개 받아들인 후, 정수를 반환하는 메소드 (매개변수 O, 리턴값 O)
public int method5(int y){
System.out.println(y + " 를 이용하는 method5입니다.");
return y*5;
}
실습
메소드 사용해보기
- 클래스가 가진 메소드를 사용하기 위해서는 객체로 만들어야 함
MyClass
public class MyClass{
public void method(){
System.out.println("method1이 실행됩니다.");
}
public void method2(int x){
System.out.println(x + " 를 이용하는 method2입니다.");
}
public int method3(){
System.out.println("method3이 실행됩니다.");
return 10;
}
public void method4(int x, int y){
System.out.println(x + "," + y + " 를 이용하는 method4입니다.");
}
public int method5(int y){
System.out.println(y + " 를 이용하는 method5입니다.");
return 5;
}
}
- 메소드를 사용하기 위해서는 메소드가 정의된 클래스인 MyClass가 생성되어야 함
- 객체를 생성할 때는 new 연산자를 이용
- 메소드 사용할 때는 생성된 클래스를 참조하는 레퍼런스변수.메소드명( ) 으로 사용할 수 있음
MyClassExam
public class MyClassExam{
public static void main(String args[]){
MyClass my1 = new MyClass(); //메소드가 정의된 클래스 생성
my1.method1(); //MyClass에서 정의해 놓은 메소드 method1() 를 호출
my1.method2(10);
int x = my1.method3();
//method3의 리턴값을 변수로 받아줘야 함
System.out.println("method3 이 리턴한 " + x + " 입니다.");
my1.method4(10,100);
int x2 = my1.method5(50);
//method5의 리턴값을 변수로 받아줘야 함
System.out.println("method5 가 리턴한 " + x2 + " 입니다.");
}
}
- 메소드의 리턴값을 출력하기 위해서는 변수에 담아줘야 함
실습
class ReferenceTypeExam {
public static void main(String []args) {
ReferenceTypeExam exam = new ReferenceTypeExam();
//기본형 변수 value1을 addOne에 전달
int value = 10;
exam.addOne(value);
System.out.println("기본형 변수의 값을 다른 메소드에서 변경한 결과: " + value);
//참조형 변수arr을 addOne에 전달
int []arr = {10};
exam.addOne(arr);
System.out.println("참조형 변수의 값을 다른 메소드에서 변경한 결과: " + arr[0]);
}
public void addOne(int value) {
value++;
}
public void addOne(int[] arr) {
for(int i = 0; i < arr.length; i++){
arr[i] ++;
}
}
}
- 결과
- 기본형 변수의 값을 다른 메소드에서 변경한 결과: 10
- 참조형 변수의 값을 다른 메소드에서 변경한 결과: 11
- 기본형 타입과 참조 타입의 차이
- 기본형 타입
- 다른 메소드에 매개변수로 전달될 때, 10이라는 값이 그대로 전달됨
- addOne에서 1을 더하더라도 value라는 변수에 영향 X
- 참조형 타입
- 다른 메소드에 매개변수로 전달될 때, 변수의 주소가 전달됨
- '몇 번째 박스에 값이 있다'는 식으로 값이 들어있는 주소가 전달됨 > 그걸 전달받은 메소드 addOne에서는 그 박스에 가서 들어있는 값에 1 더함
- addOne을 실행하고 나서 arr[0]을 확인해 볼 때도 같은 박스에 가서 값을 확인하기 때문에 값이 11로 변해있는 것
- 기본형 타입
실습 1
class ReferenceTypeExam {
public static void main(String []args) {
ReferenceTypeExam exam = new ReferenceTypeExam();
//기본형 변수 value1을 addOne에 전달
int value = 10;
exam.addOne(value);
System.out.println("기본형 변수의 값을 다른 메소드에서 변경한 결과: " + value);
//참조형 변수arr을 addOne에 전달
int []arr = {10};
exam.addOne(arr);
System.out.println("참조형 변수의 값을 다른 메소드에서 변경한 결과: " + arr[0]);
}
public void addOne(int value) {
value++;
}
public void addOne(int[] arr) {
for(int i = 0; i < arr.length; i++){
arr[i] ++;
}
}
}
- 결과
- 기본형 변수의 값을 다른 메소드에서 변경한 결과: 10
- 참조형 변수의 값을 다른 메소드에서 변경한 결과: 11
- 기본형 타입과 참조 타입의 차이
- 기본형 타입
- 다른 메소드에 매개변수로 전달될 때, 10이라는 값이 그대로 전달됨
- addOne에서 1을 더하더라도 value라는 변수에 영향 X
- 참조형 타입
- 다른 메소드에 매개변수로 전달될 때, 변수의 주소가 전달됨
- '몇 번째 박스에 값이 있다'는 식으로 값이 들어있는 주소가 전달됨 > 그걸 전달받은 메소드 addOne에서는 그 박스에 가서 들어있는 값에 1 더함
- addOne을 실행하고 나서 arr[0]을 확인해 볼 때도 같은 박스에 가서 값을 확인하기 때문에 값이 11로 변해있는 것
- 기본형 타입
실습 2
class Car{
void run(){
System.out.println("차가 달립니다.");
}
}
class CarExam {
public static void main(String [] args) {
// 이 아래에서 car에 Car클래스의 인스턴스를 생성하고 run메소드를 사용해 보세요.
Car car = new Car();
car.run();
}
}
String클래스의 메소드
- String클래스를 사용하기 위해 먼저 String을 선언해야 함
- 일반적으로 new 연산자를 이용해 생성자를 쓰고, 해당 생성자를 이용해 객체를 생성
- String str = new String("hello");
- But, String클래스는 new 연산자 없이 객체 생성 가능
- String str = “hello”;
- 문자열 길이 구하기 (length)
- str.length()는 str이 참조하는 문자열의 길이를 구해서 int 타입으로 리턴해주는 메소드
System.out.println(str.length()); //str
- 문자열 붙히기 (concat)
- str.concat("world") 메소드는 str이 참조하는 문자열 hello에 메소드의 인자로 들어온 문자열 world를 붙혀서 String 타입으로 리턴하는 메소드
String str = new String("hello");
System.out.println(str.concat(" world")); //출력결과는 hello world
System.out.println(str); //출력결과는 hello
- String Class는 불변 클래스
- 메소드가 수행되면 새로운 문자열을 만듦 > 원래 클래스는 변하지 않음
- 변수 str과 str2 모두 hello라는 String 객체를 참조
- String 객체 자체를 바꿔버리면 같은 객체를 참조하는 다른 변수에 문제가 생기기 때문에 한 번 만들어진 객체를 바꾸지 않음
- str이 hello world라는 String 객체를 참조하게 하려면
- str = str.concat(”world”); 이렇게 이퀄 관계를 바꿔줘야 함
- 문자열 자르기 (subString)
- str.subString(1,3) 은 str이 참조하는 문자열을 인덱스 1번부터 3번 전까지 자른 결과
- str.subString(2) 은 str이 참조하는 문자열을 2번 인덱스부터 마지막까지 자른 결과
- 문자열의 인덱스는 0번부터 시작
System.out.println(str.substring(1, 3)); //출력결과 el
System.out.println(str.substring(2)); //출력결과 llo world
실습
변수의 scope와 static
변수의 scope
- 변수들이 사용 가능한 범위 > 변수가 선언된 블럭이 그 변수의 사용범위
public class ValableScopeExam{
int globalScope = 10; *// 인스턴스 변수*
public void scopeTest(int value){
int localScope = 10;
System.out.println(globalScope);
System.out.println(localScpe);
System.out.println(value);
}
}
- 클래스의 속성으로 선언된 변수 globalScope 의 사용 범위는 클래스 전체
- 매개변수로 선언된 int value 는 블럭 바깥에 존재하기는 하지만, 메서드 선언부에 존재하므로 사용범위는 해당 메소드 블럭 내
- 메소드 블럭내에서 선언된 localScope 변수의 사용범위는 메소드 블럭 내
main메소드에서 사용하기
- 같은 클래스 안에 있는데 globalScope 변수를 사용할 수 없음
- 사용 가능하게 하려면 static int glovalScope = 10; 로 바꿔주면 됨
- main은 static한 메소드
- static한 메소드에서는 static 하지 않은 필드를 사용할 수 없음
- static한 메소드가 static하지 않은 필드를 사용하는 시점에 해당 클래스가 인스턴스화되지 않았을 수도 있기 때문
public class VariableScopeExam {
int globalScope = 10;
public void scopeTest(int value){
int localScope = 20;
System.out.println(globalScope);
System.out.println(localScope);
System.out.println(value);
}
public static void main(String[] args) {
System.out.println(globalScope); *//오류*
System.out.println(localScope); *//오류*
System.out.println(value); *//오류*
}
}
static
non-static 멤버 | non-static 멤버 | |
선언 | class Sample{ int n; void g( ) {...} } |
class Sample{ static int n; static void g( ) {...} } |
공간적 특성 | 멤버는 객체마다 각각 존재 - 인스턴스 멤버라고 부름 |
멤버는 클래스당 하나만 생성 - 멤버는 객체 내부가 아닌 별도의 공간(클래스 코드가 적재되는 메모리)에 생성 - 클래스 멤버라고 부름 |
공간적 특성 | 객체 생성 시에 멤버가 생성됨 - 객체가 생길 때 멤버도 생성 - 객체 생성 후 멤버 사용 가능 - 객체가 사라지면 멤버도 사라짐 |
클래스 로딩 시에 멤버 생성 - 객체가 생기기 전에 이미 생성 - 객체가 생기기 전에도 사용 가능 - 객체가 사라져도 멤버는 사라지지 않음 - 멤버는 프로그램이 종료될 때 사라짐 |
공유의 특성 | 공유되지 않음 - 멤버는 객체 내에 각각 공간 유지 |
동일한 클래스의 모든 객체들에 의해 공유됨 |
- 모든 클래스는 인스턴스화 하지 않은 채로 사용할 수 없음 (static은 예외)
- 인스턴스화: 메소드와 변수를 모아놓은 것에 불과한 클래스를 사용할 수 있도록, 해당 클래스 타입의 객체명을 선언하고 값을 넣어줘서 해당 클래스의 변수나 메소드를 사용 가능한 상태로 만드는 것 (= 클래스로부터 객체를 만드는 것)
- 문법: 클래스명 변수명 = new 변수명( );
- 인스턴스: 메모리에 만들어진 객체
- main 메소드는 static 이라는 키워드로 메소드가 정의되어 있음. 이런 메서드를 static한 메소드라고 함.
- static한 필드 / static한 메소드: 키워드 static을 사용하면 Class가 인스턴스화되지 않아도 사용할 수 있음
public class VariableScopeExam {
int globalScope = 10;
static int staticVal = 7; //static한 필드
public void scopeTest(int value){
int localScope = 20;
}
public static void main(String[] args) { //main 메소드: static한 메소드
System.out.println(staticVal); *//사용 가능
//VariableScopeExam staticVal = new VariableScopeExam();로 인스턴스화하지 않아도 사용 가능*
}
}
static한 변수는 공유된다
- static하게 선언된 변수는 값을 저장할 수 있는 공간이 하나만 생성됨
- = 인스턴스가 여러 개 생성되어도 static한 변수는 하나임
- 마지막으로 넣은 값이 최종 값이 됨
- static한 메소드 안에서 static하지 않은 참조변수를 사용하는 방법
- 객체를 생성한 후 사용하면 됨
- ValableScopeExam v1 = new ValableScopeExam( );
- 객체를 생성한 후 사용하면 됨
- static한 메소드 안에서 static하지 않은 필드를 사용하는 방법
- 필드를 static하게 바꿔주면 됨
- static int globalScope = 10;
- 필드를 static하게 바꿔주면 됨
ValableScopeExam v1 = new ValableScopeExam();
ValableScopeExam v2 = new ValableScopeExam();
v1.golbalScope = 20;
v2.golbalScope = 30;
System.out.println(v1.golbalScope); *//20이 출력*
System.out.println(v2.golbalScope); *//30이 출력*
v1.staticVal = 10;
v2.staticVal = 20; //마지막으로 넣은 값이 최종 값이 됨
System.out.println(v1.statVal); *//20이 출력*
System.out.println(v2.statVal); *//20이 출력
//v1.staticVal 대신* VariableScopeExam.staticVal를 쓰는 게 더 바람직
public class VariableScopeExam {
static int globalScope = 10;
}
- golbalScope같은 변수(필드)는 인스턴스가 생성될 때 생성되기 때문에 인스턴스 변수라고 함
- staticVal같은 static한 필드를 클래스 변수라고 함
- 클래스 변수는 레퍼런스.변수명 하고 사용하기보다는 클래스명.변수명으로 사용하는 게 더 바람직
- VariableScopeExam.staticVal
실습
열거형(enum)
- Java에서 변수를 선언할 때 열거형을 변수타입으로 사용할 수 있음
- 열거형은 JDK5에서 추가되었음 (JDK5 이전에는 상수를 열거형 대신 사용)
- 상수를 이용하는 방법 (public static final)
- public static final 데이터타입 변수명 = 값;
- 변수는 모두 대문자로 작성 (예: FEMALE)
public class EnumExam {
public static final String FEMALE = "FEMALE";
public static final String MALE = "MALE";
public static void main(String[] args) {
String gender1;
gender1 = EnumExam.MALE;
gender1 = EnumExam.FEMALE;
}
}
상수를 사용했을 때의 문제점
- String으로 선언된 gender1에는 FEMALE, MALE 둘 중 하나의 값을 갖기 원하는데, gender1의 type이 String이기 때문에 gender1 = "소년"; 과 같이 String 값 아무거나 들어가도 컴파일 시점에는 전혀 문제가 되지 않음 (실행할 때 문제가 생김)
- 실행할 때 원했던 값인 FEMALE, MALE이 아닌 다른 값이 들어오게 되므로 문제를 발생시킬 수 있음
해결 방법
- 위와 같은 문제를 발생시키지 않게 하기 위해 열거형을 사용
- 열거형 정의 방법
enum Gender{
MALE, FEMALE; //Gender라는 enum에는 FEMALE과 MALE 두 개의 값만 들어올 수 있다고 정의
}
- 열거형 사용 방법
- enum인 Gender 자체가 타입이 됨 (따로 String 타입을 쓸 필요 X)
Gender gender2;
gender2 = Gender.MALE;
gender2 = Gender.FEMALE;
//gender2 = "boy"; //컴파일할 때부터 오류 발생
*//Gender타입의 변수에는 MALE이나 FEMALE만 대입이 가능. 다른 값은 저장할 수가 없음*
특정 값만 가져야 한다면 열거형을 사용하는 것이 좋음
'☕ Java 웹 프로그래밍 > Java' 카테고리의 다른 글
[프로그래머스] Java(자바) 입문 | Part 7. 상속 (2) | 2023.05.03 |
---|---|
[프로그래머스] Java(자바) 입문 | Part 6. 클래스 다듬기 (0) | 2023.05.03 |
Java | 클래스, 객체, 인스턴스, 인스턴스화 (0) | 2023.05.01 |
[프로그래머스] Java(자바) 입문 | Part 4. 배열 (0) | 2023.04.28 |
[프로그래머스] Java(자바) 입문 | Part 3. 제어문 (0) | 2023.04.27 |