[혼공자] chapter06 - 클래스

나봉·2025년 2월 7일
0

13기 혼공자

목록 보기
9/14

06-1 객체 지향 프로그래밍

객체 지향 프로그래밍(OOP: Object-Oriented Programming) : 객체를 하나씩 조립해서 완성된 프로그램을 만드는 기법

객체(object) : 물리적으로 존재하거나 추상적으로 생각할 수 있는 것 중에서 자신의 속성을 가지고 있으면서 식별 가능한 것

  • 객체는 속성(field)과 동작(method)으로 구성
  • 객체 모델링(object modeling) : 현실 세계의 객체를 소프트웨어 객체로 설계하는 것
    • 물리적인 객체 : 자동차, 자전거, 책, 사람
    • 추상적인 객체 : 학과, 강의, 주문
      => 사람 : 속성(이름, 나이) / 동작(웃다, 먹다)
      => 자동차 : 속성(색깔, 속도) / 동작(달린다, 멈춘다)

객체의 상호작용

  • 객체들은 독립적으로 존재

  • 다른 객체와 서로 상호작용하여 동작(=메서드 호출)

객체 간의 관계

1. 집합 관계 : 하나의 객체는 부품, 하나의 객체는 완성품
=> 부품과 자동차는 집합 관계

2. 사용 관계 : 객체 간의 상호작용
=> 사람과 자동차는 사용 관계

3. 상속 관계 : 부모 객체를 기반으로 자식 객체를 생성하는 관계
=> 기계와 자동차는 상속 관계

객체와 클래스

  • 설계도 = 클래스

  • 클래스로 만든 객체는 인스턴스

클래스 선언

  • 클래스의 이름은 다른 클래스와 식별할 목적으로 사용
  • 클래스 이름도 대소문자를 구분 , 첫 글자는 보통 대문자로 혼합된 이름을 사용한다면 각 단어의 첫 글자는 대문자로 작성

    식별자 작성 규칙

    1. 하나 이상의 문자로 이루어져야 함
    2. 첫 글자에는 숫자 불가
    3. '$', '_' 외의 특수 문자 사용 불가
    4. 자바 키워드 사용 불가

클래스 선언 예시

    public class Car {

    }
    
    public class Tire{
    
    }

객체 생성과 클래스 변수

  • new는 클래스로부터 객체를 생성시키는 연산자, 메모리 힙영역에 생성
    // 클래스 선언
	public class Student {

	}
	public static void main(String[] args) {
		
        // 객체 생성
		Student s1 = new Student();
		System.out.println("s1 변수가 Student 객체를 참조합니다.");
		
        // 객체 생성
		Student s2 = new Student();
		System.out.println("s2 변수가 또 다른 Student 객체를 참조합니다.");
	}

클래스의 구성 멤버

1. 필드(Field)

  • 객체의 데이터가 저장되는 곳

  • 생성자와 메서드 전체에서 사용되며 객체가 소멸되지 않는 한 객체와 함께 존재

2. 생성자(Constructor)

  • 객체 생성 시 초기화 역할 담당

  • new 연산자로 호출되는 특별한 중괄호 {}블록

  • 클래스 이름으로 되어 있고 리턴 타입이 없음

3. 메서드(Method)

  • 객체의 동작에 해당하는 실행 블록

  • 메서드를 호출 하면 중괄호 블록에 있는 모든 코드들아 알괄적으로 실행

  • 객체 간의 데이터를 전달하는 수단

	public class ClassName{
    
    	// 필드
        int fieldName;
        
        // 생성자
        ClassName(){
        
        }
        
        // 메서드
        void methodName(){
        
        }
    }

06-2 필드

  • 필드(field) : 데이터를 저장하는 곳

필드 선언

  • 클래스 중괄호 {} 블록 어디서든 존재

  • 초기값이 지정되지 않은 필드는 객체 생성 시 자동으로 기본 초기값 설정
    => 정수 타입 : 0 , 실수 타입 : 0.0, boolean 타입 : false, 참조 타입 : null

필드 선언 예시

	String company = "현대자동차";
    String model = "그랜저";
    int maxSpeed = 300;
    int productionYear;
    boolean engineStart;

필드 사용

  • 필드값을 읽고 변경 하는 작업

  • 클래스 내부에서 사용 시 필드 이름으로 읽고 변경, 클래스 외부에서 사용 시 클래스로부터 객체 생성한 뒤 사용 가능

	public class Car {

        // 필드
        String company = "현대자동차";
        String model = "그랜저";
        String color = "검정";
        int maxSpeed = 350;
        int speed; // 0, 초기값 지정하지 않았기 때문에 자동으로 기본 초기값 설정
    }
	public static void main(String[] args) {
		// 객체 생성
		Car myCar = new Car();
		
		// 필드값 읽기
		System.out.println("제작 회사: " + myCar.company);
		System.out.println("모델명: " + myCar.model);
		System.out.println("색깔: " + myCar.color);
		System.out.println("최고속도: " + myCar.maxSpeed);
		System.out.println("현재속도: " + myCar.speed);
		
		// 필드값 변경
		myCar.speed = 60;
		System.out.println("수정된 속도: " + myCar.speed);
	}

06-3 생성자

  • 생성자(Constructor) : 클래스로 부터 객체를 생성할 때 호출되어 객체의 초기화를 담당
    => new 연산자에 의해 생성자가 성공적으로 실행되면 힙영역에 객체가 생성되고
    객체의 번지가 스택영역에 리턴

기본 생성자

  • 모든 클래스는 생성자가 반드시 존재

  • 클래스 내부에 생성자 선언을 생략하여도 컴파일러는 기본 생성자를 바이트 코드에 자동 추가

  • but, 명시적으로 선언한 생성자가 하나라도 있다면 컴파일러는 기본 생성자를 추가하지 않음

	public class Car{
 //     기본 생성자  
 //   	public Car(){ // 이 부분을 생략하고 작성 하여도 기본 생성자는 자동으로 추가 됨
 //     
 //       }
    }

생성자 선언

  • 리턴 타입이 없고 클래스 이름과 동일

  • 매개 변수 선언은 생략도 가능하며 여러 개 선언도 가능
    => 매개 변수는 생성자를 호출할 때 외부의 값을 생성자 블록 내부로 전달하는 역할

public class Car {
	
	// 명시적 생성자
	Car(String color, int cc){
		System.out.println(color);
		System.out.println(cc);
		System.out.println(color + "색의 " + cc + "cc 자동차가 생성");
	}
}

public class CarExample {

	public static void main(String[] args) {

		// 생산자를 명시적으로 사용할 경우 기본 생성자 자동으로 설정되지 않는다.
		Car myCar = new Car("검정", 3000);
	}
}

필드 초기화

  1. 필드 선언시 초기값을 줌
    => 클래스로 부터 객체가 생성될 때 필드는 기본 초기값으로 자동 설정

  2. 생성자에서 초기값을 줌
    => 객체 생성 시 외부에서 제공되는 다양한 값들로 초기화 될 경우 사용
    => 필드와 매개 변수의 이름이 동일한 이름을 사용하는 것이 일반적이다. 헷갈릴 수 있으므로 필드앞에 this를 붙여 매개변수와 구분할 수 있다.

public class Korean {

	// Field
	String nation = "대한민국"; // 국적, 필드 선언 시 초기값을 줌
	String name; // 이름       // 생성자에서 초기값을 줌 
	String ssn; // 주민번호    // 생성자에서 초기값을 줌 
	
	// 생성자
	public Korean(String name, String ssn) {
		this.name = name; // this.name은 필드, name은 생성자의 매개 변수
		this.ssn = ssn;
	}
}

public class KoreanExample {

	public static void main(String[] args) {

		Korean k1 = new Korean("박자바", "011225-1234567");
		System.out.println(k1.nation); // 대한민국, 초기값에서 설정
		System.out.println(k1.name);   // 박자바, 생성자에서 초기값 설정
		System.out.println(k1.ssn);    // 011225-1234567, 생성자에서 초기값 설정
	}
}

생성자 오버로딩

  • 매개 변수를 달리하는 생성자를 여러 개 선언하는 것

  • 매개 변수의 타입과 개수 그리고 선언된 순서가 똑같을 경우 매개 변수의 이름만 바꾸는 것은 생성자의 오버로딩이 아님

	public class Car(){
    	Car(){}
        Car(String model){}
        Car(String model, String color){}
        Car(String model, String color, int maxSpeed){}
    }

다른 생성자 호출:this()

  • 같은 클래스 내에서 다른 생성자를 호출하는 역할

  • 생성자의 첫줄에만 허용

	Car(String model){
		this(model, null, 0); // this 생성자의 첫 줄에만 허용
	}
    
    Car(String model, String color, int maxSpeed) {
		this.model = model;
		this.color = color;
		this.maxSpeed = maxSpeed;
	}

06-4 메서드

  • 메서드는 객체의 동작에 해당하는 {} 블록

메서드 선언선언부(=메서드 시그니처)와 실행 블록으로 구성

리턴 타입 : 메서드가 리턴하는 결과의 타입을 표시
메서드 이름 : 기능이 드러나도록 식별자 규칙에 맞게 이름을 지어준다
매개 변수 선언 : 필요한 데이터를 받기 위한 변수 선언
메서드 실행 블록 : 실행할 코드 작성

메서드 선언

1. 리턴 타입

  • 메서드를 실행한 후의 결과값의 타입을 말한다.
	void powerOn() {} // void로 리턴값이 없음
    powerOn(); // 리턴값이 없으므로 단순히 메서드만 호출
    
    double divided(int x, int y) {} // double이라는 리턴값이 있음
    double result = divided(10, 20); // 리턴값이 있으므로 저장할 변수가 필요

2. 메서드 이름

  • 숫자로 시작 x, $와 _를 제외한 특수 문자 사용 x

  • 메서드 이름은 소문자로 작성

  • 서로 다른 단어가 혼합된 이름은 단어의 첫 글자는 대문자로 작성

	void run() {}
    void startEngine() {}
    String getName() {}

3-1. 매개 면수 선언

  • 메서드 실행 시 필요한 데이터를 외부로부터 받기 위해 사용

  • 매개 변수가 필요한 경우도 있고 필요 없는 경우도 있다

  • 매개 변수가 있는 매서드 선언 시 메서드를 호출 시 반드시 매개값을 주어야 함

	double divided(int x, int y) {} // 매개 변수가 있는 메서드 선언
    double result = divided(10, 20); // 매서드 호출 시 매개값 주어야 함

3-2. 매개 변수의 개수를 모를 경우

1. 배열 타입 방법

	int sum1(int[] values) { }

2. 값의 목록만 넘겨주는 방법

	int sum2(int ... values) { }

return문

1. 리턴값이 있는 메서드

  • return값을 지정해야 함

  • return문이 없다면 컴파일 에러 발생, return문 실행되면 메서드는 즉시 종료

	int plus(int x, int y) {
    	int result = x + y;
        return result;
    }

2. 리턴값이 없는 메서드 : void

  • 리턴값이 없는 메서드는 void로 작성

  • void로 선언된 메서드도 return문을 사용 가능
    => 메서드 실행을 강제 종료

void run() {
	while (true) { // 무한반복
    	if (gas > 0) {
        	System.out.println("달립니다.(gas 잔량:" + gas + ")" );
				gas -= 1;
        } else {
        	System.out.println("멈춥니다.(gas 잔량:" + gas + ")" );
				return; // 메서드 종료
        }
		}
 
 
 }

메서드 호출

1. 객체 내부에서 호출

  • 메서드 이름으로 호출

  • 리턴값이 있는 메서드를 호출하고 리턴값을 받고 싶다면 변수를 선언하고 리턴값을 대입

	public class ClassName{
    	void method1(String p1, int p2) {
        
        }
        
        void method2() {
        	method1("홍길동", 100); // 메서드 이름으로 호출
        }
    }

2. 객체 외부에서 호출

  • 클래스로부터 객체를 생성 후 호출 가능
public class Car {
	
	void keyTurnOn() {
		System.out.println("키를 돌립니다.");
	}
}
public class CarExample {

	public static void main(String[] args) {

		Car myCar = new Car(); // 객체 생성
		
		myCar.keyTurnOn(); // 객체 생성으로 메서드 호출 가능
	}
}

메서드 오버로딩

  • 클래스 내에 같은 이름의 메서드를 여러 개 선언하는 것

  • 매개 변수의 타입, 개수, 순서 중 하나가 달라야 함

public class Calculator {
	
	double areaRectangle(double width) {
		return width * width;
	}
	
	double areaRectangle(double width, double height) {
		return width * height;
	}
}

06-5 인스턴스 멤버와 정적 멤버

  • 인트턴스 멤버 : 객체마다 가지고 있는 멤버

  • 정적 멤버 : 클래스에 위치시키고 객체들이 공유하는 멤버

인스턴스 멤버와 this

  • 인스턴스 멤버 : 객체를 생성한 후 사용 가능한 필드와 메서드

1. 인스턴스 멤버 선언

	public class Car{
    	// 인스턴스 필드
        int gas;
        
        // 인스턴스 메서드
        void setSpeed(int speed) {
        
        }
    }

2. this

  • 객체 자신을 가리키는 것

  • 생성자와 메서드의 매개 변수의 이름이 필드와 동일한 경우, 인스턴스 멤버인 필드임을 명시 할 때 사용

public class Car {

	// 인스턴스 필드
	String model;
	int speed;
	
	// 생성자
	Car(String model){
		this.model = model;
	}
	
	// 메서드
	void setSpeed(int speed) {
		this.speed = speed;
	}
}

정적 멤버와 static

  • 정적 멤버 : 클래스에 고정된 멤버로서 객체를 생성하지 않고 사용할 수 있는 필드와 메서드

  • 객체마다 가지고 있을 필요가 없는 공용 데이터라면 정적 필드로 선언하는 것이 좋음

1. 정적 멤버 선언 : static 키워드를 사용

public class Calculator {
	
	// 정적 필드
	static double pi = 3.14159;
	
	// 정적 메서드
	static int plus(int x, int y) {
		return x + y;
	}
	
    // 정적 메서드
	static int minus(int x, int y) {
		return x - y;
	}
}

2. 정적 멤버 사용

  • 클래스 이름과 함께 도트(.)연산자로 접근
		double result1 = 10 * 10 * Calculator.pi; // 정적 필드이기 때문에 클래스로 접근
		int result2 = Calculator.plus(10, 5);
		int result3 = Calculator.minus(10, 5);

3. 정적 메서드 선언 시 주의할 점

  • 정적 메서드 선언 시 인스턴스 필드나 인스턴스 메서드 사용 불가
    => 사용하고 싶다면 객체를 먼저 생성하고 참조 변수로 접근
public class Car {

	// 인스턴스 필드
	int speed;
	// 인스턴스 메서드
	void run() {
		System.out.println(speed + "으로 달립니다.");
	}
	
	public static void main(String[] args) {
		
		// static 안에 인스턴스 필드와 메서드를 사용하기 위해 객체 생성 후 접근
		Car myCar = new Car();
		myCar.speed = 60;
		myCar.run();
	}
}

싱글톤(Singleton)

  • 단 하나의 객체만 만들도록 하는 것

1. private 접근 제한자를 붙여준다.
=> 클래스 외부에서 new 연산자로 생성자 호출을 막음

2. 자신의 타입인 정적 필드를 하나 선언하고 자신의 객체를 생성해 초기화한다.
=> 클래스 내부에서는 new 연산자로 생성자 호출이 가능
=> 정적 필드도 private 접근 제한자를 붙여 외부에서 필드값 변경을 막음
3. 외부에서 호출할 수 있는 정적 메서드인 getInstance()선언하고 정적 필드에서 참조하는 자신의 객체를 리턴

public class Singleton {

	// 2. 자신의 타입인 정적 필드를 하나 선언하고 자신의 객체를 생성해 초기화한다.
	private static Singleton singleton = new Singleton();
	
    //1. private 접근 제한자를 붙여준다.
	private Singleton() {} 
	
    // 3. 외부에서 호출할 수 있는 정적 메서드인 getInstance()선언하고 정적 필드에서 참조하는 자신의 객체를 리턴
	static Singleton getInstance() {
		return singleton;
	}
}

final 필드와 상수

1. final 필드

  • 저장된 초기값이 최종값이므로, 수정이 불가능
  • final 필드의 초기값 주는 방법
  1. 필드 선언 시 초기값 주기
  2. 생성자에서 초기값 주기
public class Person {

	// 필드
	final String nation = "Korea"; // 필드 선언 시 초기값 주기
	final String ssn;
	String name;
	
	public Person(String ssn , String name) {
		this.ssn = ssn; //생성자에서 초기값 주기
		this.name = name;
	}
}

2. 상수(static final)

  • 불변의 값 ex) 원주율 파이, 지구의 무게 및 둘레

  • static이면서 final이어야 한다
    => static final 필드는 객체마다 존재하지 않고 클래스에만 존재, 변경 불가

  • 상수이름은 대문자로 작성

public class Earth {
	static final double EARTH_RADIUS = 6400;
	static final double EARTH_AREA = 4 * Math.PI * EARTH_RADIUS;
}

06-6 패키지와 접근 제한자

패키지 선언

  • 클래스 작성 시 어떤 패키지에 속할 것인지 선언
package sec06.exam01.com.mycompany;

public class Car {

}

패키지 이름 규칙

  1. 숫자로 시작 x, $와 _ 제외한 특수 문자 사용 x

  2. java로 시작하는 패키지는 사용 x

  3. 모두 소문자로 작성

import문

  • 클래스 또는 인터페이스가 다른 패키지에 속한다면 import문을 사용하여 컴파일러에게 알려줘야 한다.

  • 패키지 선언과 클래스 선언 사이에 작성

  • 서로 다른 패키지에 동일한 클래스 이름이 존재할 때 import문을 사용 시 패키지가 포함된 클래스 전체 이름을 기술하여 구분한다.

접근 제한자(Access Modifier)

  • 클래스, 인터페이스, 멤버의 접근을 제한

    접근 제한자 종류

    • public 접근 제한자 : 외부 클래스가 자유롭게 사용 가능
    • protected 접근 제한자 : 같은 패키지 또는 자식 클래스에서 사용 가능
    • private 접근 제한자 : 외부에서 사용 불가
    • default 접근 제한 : 같은 패키지에 소속된 클래스에서만 사용 가능

Getter와 Setter 메서드

  • Getter : 외부에서 객체의 데이터를 읽을 때 사용
    => 메서드로 필드값을 가공한 후 외부로 전달

  • Setter : 외부에서 메서드를 통해 필드에 접근하도록 유도
    => 메서드는 매개값을 검증해서 유효한 값만 객체의 필드로 저장하게 함

0개의 댓글

관련 채용 정보