필드는 클래스에 포함된 변수를 의미하는 것으로 객체의 속성을 정의할 때 사용된다. 일단 변수는 클래스 변수, 인스턴스 변수, 지역 변수 3가지로 구분할 수 있다.
이 중 필드라고 부르는 것은 클래스 변수와 인스턴스 변수를 말하며 이 둘은 static 키워드로 구분이 가능하다
static이 포함된 변수를 클래스변수, 포함되지 않은 변수를 인스턴스 변수라고 말하고 메소드 밖에 있는 변수들을 포괄해서 멤버변수라고 부른다. 그리고 메소드 내에 포함된 모든 변수를 지역변수라고 한다.
class car{
static int wheel = 4; //클래스 변수
String name = "포르쉐";// 인스턴스 변수
void stop(){
boolean stop = true; //지역 변수
if(stop == true) {
System.out.println("멈춤");
}
}
}
인스턴스 변수는 인스턴스가 가지는 '각각의' 고유한 속성을 저장하기 위한 변수로 new 생성자()를 통해 인스턴스가 생성될 때 만들어진다.
클래스 변수는 독립적인 저장공간을 가진 인스턴스 변수와 다르게 공통된 저장공간을 공유한다.
public class Main {
public static void main(String[] args){
car c = new car(); //car class 인스턴스 c 생성
c.wheel = 5; // c에 wheel 변수값 5 할당
car c2 = new car(); //car class 인스턴스 c2 생성
System.out.println(c2.wheel); // c2.wheel값 출력 -> 결과값은 5가나옴
}
}
class car{
static int wheel = 4; //클래스 변수
String name = "포르쉐";// 인스턴스 변수
void stop(){
boolean stop = true; //지역 변수
if(stop == true) {
System.out.println("멈춤");
}
}
}
예문을 실행해보면 c.wheel에서 선언한 변수값이 c2에도 그대로 영향을 미치고 있음을 알 수 있다. 이와 같이 클래스 변수는 한 클래스로 부터 생성되는 모든 인스턴스 들이 특정한 값을 공유해야하는 경우 주로 선언된다. 이렇게 되는 이유는 메모리 구조에서 클래스 변수 또한 클래스 영역에 저장되어 그 값을 공유하기 때문이다.
또한 위와 같은 방식 보다는
car.wheel = 5; // 클래스명.클래스변수명
위와 같은 방법이 주로 사용된다. 객체명으로 클래스 변수를 바꾸는 것은 가능하지만 수많은 값을 다루게 될 경우 인스턴스 변수와 클래스변수중 어느것을 바꿨는지 바로 알아차리기 어려운 부분도 있기 때문인듯.
지역변수는 메서드 내에서 선언되며 메서드 내부블록 안에서만 사용이 가능하다. 또한 멤버 변수와는 다르게 스택메모리에 저장되기 때문에 메서드가 종료되는 동시에 변수가 함께 소멸되어서 더이상 사용할 수 없게된다.
왜냐하면 스택 메모리에 저장되는 지역변수는 한동안 사용되지 않는 경우 자동으로 가상머신에 의해 삭제되기 때문이다. 필드변수는 힙 메모리에 저장되는데 객체가 없어지지 않는 한 절대로 사라지지 않는다.
필드변수와 지역변수는 초기값에 있어서 차이점이 있는데 지역변수는 직접 초기화 하지 않으면 값을 출력할 때 오류가 발생하고 필드변수는 직접적으로 초기화를 실행하지 않더라도 강제로 초기화가 실행된다.
public class Main {
public static void main(String[] args){
car c = new car();
c.stop();
}
}
class car{
static int wheel = 4; //클래스 변수 초기화
String name;// 인스턴스 변수 선언
void stop(){
boolean stop; // 지역변수 선언
System.out.println(name); // -> 출력시 null값이 나옴
System.out.println(stop); // ->지역변수 값이 초기화 되지 않았다는 오류가 출력됨
}
}
이는 힙 메모리에는 빈 공간이 저장 될 수 없기 때문에 힙메모리에 저장되는 필드는 강제로 초기화되지만 스택메모리는 강제로 초기화가 되지 않으므로 지역변수는 선언시 반드시 초기화가 필요하다.
위에서 언급되었던 static 키워드는 클래스 멤버(필드, 메서드, 이너클래스)에 사용하는 키워드이다. 이런 static 키워드가 붙어 있는 멤버를 정적 멤버(static member)라고 부르고 인스턴스 변수와 구분한다. 가장 큰 특징은 위에서도 언급했듯 메소드 영역(클래스 영역)에 저장되기 때문에 객체 생성 없이 곧바로 사용할 수 있다는 특징이 있다.
public class Main {
public static void main(String[] args){
System.out.println(car.wheel);// 4가 출력됨
}
}
class car{
static int wheel = 4; //클래스 변수
}
대신 static 메서드의 경우 인스턴스 변수 또는 인스턴트 메서드를 사용할 수 없는데 정적 메서드는 인스턴스 생성 없이 호출이 가능하기 때문에 정적 메서드가 호출되었을 때 인스턴스가 존재 하지 않을수 있기 때문이라고 한다.
class car{
String name;// 인스턴스 변수
void ride() {
System.out.println("붕~");
}
static void stop(){
boolean stop;
System.out.println(name); //Non-static field 'name' cannot be referenced from a static context
ride();//Non-static method 'ride()' cannot be referenced from a static context
}
}
해당 코드를 작성해 볼경우 위와같은 에러가 나오는 것을 알 수 있다.
메서드는 특정 작업을 수행하는 일련의 명령문들의 집합이라고 할 수 있다. 클래스의 기능에 해당하는 내용들을 담당한다. 이런 메서드들은 메서드 시그니처와 메서드 바디로 구분이 가능하다.
자바제어자 반환타입 메서드명(매개 변수)//메서드 시그니처
{ 메서드 내용 } // 메서드 바디
하나하나 설명해 보자면 반환 타입은 메서드가 어떤 타입을 반환하는지 명시하는 것이며 반환탄입은 void가 아닌 경우에는 메서드 바디안에 반드시 return문이 존재해야한다. 여기서 return문은 작업을 수행한 결과값을 호출한 메서드로 전달하는 역할을 맡는다.
메서드명은 메서드의 이름이고 관례적으로 소문자로 표시한다.
매개 변수는 해당 작업을 수행하기 위해서 필요한 변수를 명시한다.
메서드 바디는 {}안에 해당 메서드가 호출 되었을때 수행할 일련의 작업들을 표시한다.
메서드를 호출할때는 메서드도 클래스의 멤버이므로 클래스 외부에서 메서드를 사용하기 위해서는 먼저 인스턴스를 생성해야한다.(static 메서드는 인스턴스 생성 없이 사용이 가능하다) 포인트 연산자(.)를 통해 메서드를 호출할 수 있으며 클래스 내부에 있는 메서드 끼리는 따로 객체를 생성하지 않고도 서로 호출이 가능하다.
public class Main {
public static void main(String[] args){
car moning = new car();//인스턴스 생성
moning.stop(); //포인트 연산자를 이용해 메서드를 호출
}
}
class car{
void ride(int speed) {
System.out.println("시속"+speed+"km의 속력으로 달립니다.");
}
void stop(){
ride(150); // 클래스 내부에서는 객체를 생성하지 않고 호출가능함//인자값 150
System.out.println("멈춥니다.");
}
}
위의 ride(150)과 같이 메서드를 호출시 괄호() 안에 넣어주는 입력값을 인자(Argument)라고 한다. 인자의 개수와 순서는 반드시 메서드를 정의할 때 선언된 매개변수와 같아야 하며 인자 타입 또한 매개변수타입과 일치하거나 자동 형변환이 가능한 것이어야 한다.
메서드에는 메서드 오버로딩(Method Overloading)이라는 개념이 있다. 이 개념은 하나의 클래스 안에 같은 이름의 메서드를 여러개 정의하는 것인데, 이와같이 1개의 클래스에 동일한 이름의 메서드를 과적하는 듯한 모양새여서 Overloading이 아닌가 싶다.
public class Main {
public static void main(String[] args){
bus b = new bus();
b.board(1200); //"1200원을 지불했습니다."
b.board("저기요"); // "저기요아저씨 멈춰주세요!"
}
}
class bus{
void board(int money) {
System.out.println(money+"원을 지불했습니다.");
}
void board(String say){
System.out.println(say+"아저씨 멈춰주세요!");
}
}
예시를 통해 bus 클래스 안에 있는 모든 메서드들이 board라는 메서드명을 가지고 있음에도 각기 다른 값을 가지고 있음을 알 수 있다.
무조건 같은 메서드 명을 사용한다고 해서 오버로딩이 되는 것은 아니고 크게 두가지 조건이 필요하다
1. 같은 이름의 메서드명을 써야한다.
2. 매개변수의 개수나 타입이 다르게 정의되어야 한다.
해당 조건중 하나라도 충족이 되지 않는다면 중복정의로 간주되어 컴파일 에러가 발생한다.
똑같은 int 값을 할당했을 때 오류가 발생하는 것을 볼 수 있다.
이와 같은 오버로딩은 하나의 메서드로 여러 경우의 수를 해결할 수 있다는 장점이 있고 대표적인 예시로 println()메서드가 있다. 매개변수의 타입에 따라 호출되는 println메서드가 달라지는데 오버로딩이 지원되지 않았다면 하나하나 일일이 메서드를 지정해줘야하는 번거로움이 발생했을 것이다.
'공부 > 오늘의공부' 카테고리의 다른 글
상속 (0) | 2022.12.31 |
---|---|
생성자 (0) | 2022.12.30 |
클래스와 객체 (0) | 2022.12.28 |
12월 23일 오늘의 수업 (0) | 2022.12.23 |
12월 22일 오늘의 수업 (0) | 2022.12.22 |