본문 바로가기
자바

[Java] 자바의 클래스 - WHITESHIP LIVE 자바 스터디

by 책 읽는 개발자_테드 2020. 12. 18.
반응형

유튜브에서 백기선님이 진행하는 온라인 스터디를 진행 중입니다. 아래는 스터디의 링크입니다.

 

www.youtube.com/watch?v=rPYhY5kFD5k

github.com/whiteship/live-study

 

클래스란?

객체지향 프로그래밍에서 사용하고 싶은 객체가 있다면 설계도로 해당하는 객체를 만드는 작업이 필요하다. 자바에서는 설계도가 바로 클래스다.

 

클래스에는 객체를 생성하기 위한 필드와 메소드가 정의되어 있다. 클래스로부터 만들어진 객체를 해당 클래스의 인스턴스라고 한다.

 

 

클래스를 정의하는 방법

 

1. 클래스이름.java 형태의 소스 파일을 만든다.

2. 소스 파일을 열고 아래와 같이 클래스를 선언한다.

 

class 클래스이름{
}

 

클래스는 public 접근 제한자와 함께 선언할 수도 있다. 이것은 클래스의 사용 범위를 동일한 다른 패키지 까지로 늘려준다.

 

public class 클래스이름{
}

 

접근 제한자를 붙이지 않으며 default 접근 제한자가 사용되며, 클래스의 사용범위가 동일한 패키지로 한정된다. 접근 제한자의 더 자세한 내용은 다음 링크에 정리한다.

 

scshim.tistory.com/202

 

 

클래스이름 작성 규칙

 

클래스이름은 다른 클래스와 식별할 목적으로 사용되므로 자바의 식별자 작성 규칙에 따라 만든다.

 

번호 작성규칙
1

하나 이상의 문자로 이루어져야 한다|

Car, SportsCar
2 첫 번째 글자는 숫자가 올 수 없다. Car, 3Car(x)
3 ’$’,’_’외의 특수 문자는 사용할 수 없다. $Car,_Car,@Car(x),#Car(x)
4 자바 키워드는 사용할 수 없다. int(x),for(x)

 

추가적으로 다음과 같은 사실을 알아두자.

 

- 클래스 이름은 영어 대소문자를 구분한다.

- 관례적으로 클래스 이름이 단일 단어라면 첫 자를 대문자로 하고 나머지는 소문자로 작성한다. 서로 다른 단어가 혼합된 이름을 사용하면 각 단어의 글자는 대문자로 작성하는 것이 관례이다.

- 일반적으로 소스 파일당 하나의 클래스를 선언하지만, 두 개 이상의 클래스 선언도 가능하다.

- 두 개 이상의 클래스가 선언된 소스 파일을 컴파일하면 바이트 코드 파일은(.class) 클래스를 선언한 개수 만큼 생긴다.

 

class Car{

}

class Tire{

}

 

 

객체를 만드는 방법(new 키워드 이해하기)

 

클래스를 선언한 다음 컴파일을 했다면(이클립스, 인텔리제이 등의 IDE에서의 저장) 객체를 생성할 설계도가 만들어진 것이다. 클래스로부터 객체를 생성하는 방법은 new 연산자를 사용하면 된다.

 

new 클래스();

 

new 연산자 뒤에는 생성자가 온다. 생성자는 클래스() 형태를 가지고 있다. new 연산자는 객체를 메모리 힙 영역에 생성시킨 후, 객체의 주소를 리턴한다. 이 주소를 참조 타입인 클래스 변수에 저장해 두면, 변수를 통해 객체를 사용할 수 있다.

 

클래스 변수;
변수 = new 클래스();
클래스 변수 선언과 객체 생성을 한 개의 실행문으로 작성할 수도 있다.
클래스 변수 = new 클래스();

 

클래스의 구성 멤버

 

클래스에는 객체가 가져야 할 구성 멤버가 선언된다. 구성 멤버에는 필드(Field), 생성자(Constructor), 메소드(Method)가 있다. 멤버들은 생략되거나 복수 개를 작성할 수 있다.

 

public class ClassName {
    //필드 - 객체의 데이터가 저장되는 곳
    int fieldName;
    
    //생성자 - 객체 생성 시 초기화 역할 담당
    ClassName() {}
    
    //메소드 - 객체의 동작에 해당하는 실행 블
    void methodName() {}
}

필드를 정의, 사용하는 방법

필드는 객체의 고유 데이터, 부품 객체, 상태 정보를 저장하는 곳이다. 선언 형태는 로컬 변수와 비슷하지만 로컬 변수는 생성자와 메소드 내부에 선언되고, 필드는 클래스 내부이면서 생성자와 메소드 외부에 선언된다. 때문에 필드를 클래스 멤버 변수라고도 말한다.

 

 class Car {
   /* 고유 데이터 */
   String company;  //제작사   
   String model;    //모델    
   String color;    //색상    
   int maxSpeed;    //최고속도
   
   /* 상태 */
   int speed;   //현재 속도
   int rpm;     //엔진 회전 수
   
   /* 부품 */
   Body body;       //차체
   Engine engine;   //엔진
   Tire tire;       //타이어
 }

 

필드 선언은 클래스 중괄호 {} 블록 어디서든 존재할 수 있다. 생성자 선언과 메소드 선언의 앞과 뒤 어떤 곳에서도 필드 선언이 가능하다. 필드의 선언 모습은 아래와 같다.

 

타입 필드 [ = 초기값];

 

타입은 필드에 저장할 데이터의 종류를 결정한다. 타입에는 기본 타입(byte, short, int, long, float, double, boolean)과 참조 타입(배열, 클래스, 인터페이스)가 올 수 있다. 필드의 초기값은 필드 선언 시 주어질 수도 있고, 생략될 수도 있다.

 

public class Car {

String company = "테슬라";
String model = "S";
int maxSpeed = 300;
boolean engineStart ;

}

 

초기값이 지정되지 않은 필드들은 객체 생성 시 자동으로 기본 초기값으로 설정된다. 아래와 같이 필드의 타입에 따라 초기값이 다르다.

 

분류 데이터 타입 초기값
기본 타입 정수 byte 0
char '\u0000'
short 0
int 0
long 0L
실수 float 0.0f
double 0.0d or 0.0
논리 boolean false
참조 타입 배열
클래스
인터페이스
null
null
null

 

생성자와 메소드가 실행 종료되면 자동 소멸된다. 하지만 필드는 생성자와 메소드 전체에서 사용되며 객체가 소멸되지 않는 한 객체와 함께 존재한다.

 

클래스 내부의 생성자나 메소드에서 사용할 경우 단순히 필드 이름으로 읽고 변경한다. 하지만 클래스 외부에서 사용할 경우 우선적으로 클래스부터 객체를 생성한 뒤 필드를 사용해야 한다. 필드는 객체에 소속된 데이터이므로 객체가 존재하지 않으면 필드도 존재하지 않는다.

 

 class Car {
     //필드
     int speed;
     
     //생성자
     Car(){
         speed = 0; //값 변경
     }
     
     //메소드 
     void method(){
         speed = 10; //값 변경 
     }
 }

public class Person {
    void method(){
        //Car 객체 생성
        Car myCar = new Car();

        //필드 사용
        myCar.speed  = 60;  // 값 변경
    }
}

 

사용 방법은 로컬 변수와 동일한데, 차이점은 로컬 변수는 자신이 선언된 생성자 또는 메소드 블록 내부에서만 사용할 수 있는 반면 필드는 생성자와 모든 메소드에서 사용이 가능하는 점이다.

 

객체를 사용하기 위해서는 우선 객체를 생성해야 한다. car 변수가 Car 객체를 참조하게 되면 도트(.) 연산자를 사용해서 speed 필드에 접근할 수 있다. 도트 연산자를 통해 객체 접근 연산자로 객체가 가지고 있는 필드나 메소드를 사용할 수 있다.

 

public class Car {

	//필드
	String company = "테슬라";
	String model = "S";
	int maxSpeed = 300;
	boolean engineStart;

}

public class Main {

	public static void main(String[] args){

	//객체 생성
	Car car = new Car();

	//필드값 읽기
	System.out.println("제작회사:"+car.company);
	System.out.println("제작회사:"+car.model);
	System.out.println("최고속도:"+car.maxSpeed);

	//필드값 변경
	car.maxSpeed = 320;
	System.out.println("수정된 최고속도:"+car.maxSpeed);

	}

}

 

생성자를 정의, 사용하는 방법

 

생성자는 new 연산자로 호출되는 중괄호 {} 블록이다. 생성자의 역할은 객체 생성 시 초기화를 담당한다. 필드를 초기화하거나, 메소드를 호출해서 객체를 사용할 준비를 한다.

 

new 연산자에 의해 생성자가 실행되면 힙 영역에 객체가 생성되고 객체의 주소가 리턴된다. 리턴된 주소는 클래스 타입 변수에 저장되어 객체에 접근할 때 이용된다.

 

기본 생성자

 

모든 클래스는 생성자가 반드시 존재하며, 하나 이상을 가질 수 있다. 클래스 내부에 생성자 선언을 생략하면 컴파일러는 중괄호 {} 블록 내용이 비어있는 기본 생성자(Default Constructor)를 바이트 코드에 자동 추가한다.

 

때문에 클래스에 생성자를 선언하지 않아도 다음과 같이 new 연산자 뒤에 기본 생성자를 호출해서 객체를 생성시킬 수 있다.

 

Car car = new Car();

 

명시적인 생성자

클래스에 명시적으로 선언한 생성자가 한 개라도 있으면, 컴파일러는 기본 생성자를 추가하지 않는다. 명시적으로 생성자를 선언하는 이유는 객체를 다양하게 초기화하기 위해서이다.

 

생성자를 명시적으로 선언하려면 다음과 같은 형태로 작성하면 된다.

 

클래스 (매개변수1, 매개변수2 ...){

	//객체의 초기화 코드

}

 

생성자는 메소드와 비슷하게 생겼지만, 클래스 이름으로 되어 있고 리턴 타입이 없다. 생성자 블록 내부에는 객체 초기화 코드가 작성되며, 일반적으로 필드에 초기값을 저장하거나 메소드를 호출하여 객체 사용 전에 필요한 준비를 한다.

 

매개 변수는 생략하거나 여러 개를 선언할 수 있다. 매개 변수는 new 연산자로 생성자를 호출할 때 외부의 값을 생성자 블록 내부로 전달하는 역할을 한다. 아래 예제는 생성자를 호출할 때 네 개의 외부 값을 통해 필드 값을 초기화하는 예제다.

 

명시적으로 선언된 생성자가 있으면 기본 생성자(Car())를 호출하여 객체를 생성할 수 없다.

 

class Car {

	//필드
	String company;
	String model;
	int maxSpeed ;
	boolean engineStart;

	Car(String c, String m, int mS, boolean eS){
		company = c;
		model = m;
		maxSpeed = mS;
		engineStart = eS;
	}

}

public class Main {

	public static void main(String[] args){

	//생성자 호출
	Car car = new Car("테슬라","S", 300, false);
	//Car car = new Car(); (x) 기본 생성자 호출 불가

	}

}

 

메소드를 정의, 사용하는 방법

메소드는 객체의 동작에 해당하는 중괄호 {} 블록을 말한다. 중괄호 블록은 이름을 가지고 있는데, 이것이 메소드 이름이다. 메소드를 호출하면 중괄호 블록에 있는 모든 코드들이 일괄적으로 실행된다.

 

메소드는 객체 간의 데이터 전달의 수단으로 사용된다. 외부로부터 매개값을 받을 수도 있고, 실행 후 어떤 값을 리턴할 수도 있다.

 

메소드 선언은 선언부(리턴타입, 메소드이름, 매개변수선언)와 실행 블록으로 구성된다. 메소드 선언부를 메소드 시그니처라고 한다.

 

리턴타입 메소드이름 (매개변수1, 매개변수2, ...){

	//실행할 코드를 작성하는 곳

}

 

리턴 타입

리턴 타입은 메소드가 실행 후 리턴하는 값의 타입을 말한다. 메소드는 리턴값이 있을 수도 있고 없을 수도 있다. 메소드가 실행 후 결과를 호출한 곳에 넘겨줄 경우에는 리턴값이 있어야 한다.

 

리턴 값이 없는 메소드는 리턴 타입에 void가 와야 하며 return값이 있는 메소드는 리턴값의 타입이 와야한다. 리턴 값은 다음과 같이 사용하고, 리턴문이 메소드 내부에서 호출되면 메소드는 즉시 종료된다.

 

return 리턴값;

 

public class Main {

	void powerOn(){
		System.out.println("전원");
	}

	double divide(int x, int y){
		return x / y;
	}

	public static void main(String[] args){
		Main main = new Main();
		main.powerOn(); //리턴값 없는 메소드 호
		double result = main.divide(10,20); //리턴값 있는 메소드출 호출
	}

}

 

메소드 이름

 

메소드 이름은 자바 식별자 규칙에 맞게 작성한다. 다음 사항에 주의하자.

 

- 숫자로 시작하면 안 되고, $와 _를 제외한 특수 문자를 사용하지 말아야 한다.

- 관례적으로 메소드명은 소문자로 작성한다.

- 서로 다른 단어가 혼합된 이름이라면 뒤이어 오는 단어의 첫머리 글자는 대문자로 작성한다.

 

void powerOn(){}
double divide(int x, int y){}

추가적으로 메소드 이름은 해당 메소드가 어떤 기능을 수행하는지 쉽게 알 수 있도록 기능 이름으로 지어주는 것이 좋다.

 

매개 변수

 

매개 변수는 메소드가 실행할 때 필요한 데이터를 외부로부터 받기 위해 사용된다. 매개 변수는 생략하거나 여러 개를 사용할 수 있다. 메소드를 호출할 때는 메소드를 선언할 때 작성한 타입과 개수에 맞는 매개변수를 꼭 넣어 주어야 한다.

 

double divide(int x, int y){
	return x / y;
}


double result = divide(10, 20);

 

메소드 호출

 

메소드는 클래스 내, 외부의 호출에 의해 실행된다. 클래스 내부의 다른 메소드에서 호출할 경우에는 단순한 메소드 이름으로 호출한다. 클래스 외부에서 호출할 경우 우선 클래스로부터 객체를 생성한 뒤, 참조 변수를 이용해서 메소드를 호출해야 한다.

 

public class Calculator {

	void msgPrint(String msg){
    
   		System.out.println(msg);
	}

	void divide(int x, int y){

		double result = x / y;
		String msg = x+"과 "+y+"을 나눈 결과: "+result;
		msgPrint(msg); //객체 내부 호출
	}
}

public class Main {

	public static void main(String[] args){
		Calculator main = new Calculator();
		main.divide(20,10); //객체 외부 호출
	}
}

 

인스턴스 멤버

 

인스턴스 멤버란 객체(인스턴스)를 생성한 후 사용할 수 있는 필드와 메소드를 말하는데, 이들을 각각 인스턴스 필드, 인스턴스 메소드라고 한다.

 

앞서 설명한 모든 필드와 메소드는 인스턴스 멤버들이다. 인스턴스 멤버를 외부 클래스에서 사용하기 위해서는 인스턴스를 생성하고 참조 변수를 통해 접근해야 한다.

 

class Car {

	//필드
	int gas;

	//메소드
	void setSpeed(int speed){}
}	

public class Main {

	public static void main(String[] args){
		Car car1 = new Car();
		car1.gas = 10;
		car1.setSpeed(100);
        
		Car car2 = new Car();
		car2.gas = 20;
		car2.setSpeed(200);
	}
}

 

위 코드가 실행된 후 메모리 상태를 그림으로 표현하면 아래와 같다. 인스턴스 필드(gas)는 객체마다 따로 존재하고, 인스턴스 메소드(setSeed)는 객체마다 존재하지 않고 메소드 영역에 저장되고 공유된다.

this 키워드

 

객체 내부에서 인스턴스 멤버에 접근하기 위해 this 키워드를 사용할 수 있다. 객체는 자신을 ‘this’라고 한다. this는 주로 생성자의 메소드의 매개 변수 이름이 필드와 동일한 경우 인스턴스 멤버인 필드임을 명시하고자 할 때 사용된다.

 

class Car {

	//필드
	int speed;
    String color;

	//메소드
	void Car(int speed, String color){
    		this.speed = speed;
            	this.color = color;
	}
}

 

this()는 해당 클래스 생성자를 호출할 수 있어, 생성자를 재사용하는 데 사용할 수 있다.

 

class Car {

	//필드
	int speed;
    	String color;
    	int price;

	//메소드
    void Car(int speed, String color){
    	this.speed = speed;
        this.color = color;
	}
    
    void Car(int speed, String color, int price){
    	this(speed,color);
        this.price = price;
    }
    
}

 

 

 

출처: 이것이 자바다

반응형

댓글