[혼공자] 3주차_클래스

jini·2025년 7월 20일
0

혼자공부하는자바

목록 보기
3/6

한빛미디어의 <혼자 공부하는 자바>를 요약 정리했습니다.

 

🧊 3주차 미션

기본: 어렵거나 중요하다고 생각하는 용어를 혼공 용어 노트에 정리하고 공유하기

필드(field)
객체의 고유 데이터, 부품 객체, 상태 정보를 저장하는 곳

  • 선언 형태는 변수와 비슷하지만, 필드를 변수라고 부르지는 않음
  • 변수 : 생성자와 메소드 내에서만 사용되고 생성자와 메소드가 실행 종료되면 자동 소멸
  • 필드 : 생성자와 메소드 전체에서 사용되며 객체가 소멸되지 않는 한 객체와 함께 존재

 

생성자(constructor)
new 연산자로 호출되는 특별한 중괄호 {} 블록

  • 객체 생성 시 초기화를 담당
  • 필드를 초기화 하거나 메소드를 호출해서 객체를 사용할 준비
  • 메소드와 비슷하게 생겼지만, 클래스 이름으로 되어 있고 리턴 타입이 없음

 

메소드(method)
객체의 동작에 해당하는 중괄호 {} 블록

  • 메소드를 호출하게 되면 중괄호 블록에 있는 코드들이 일괄적으로 실행
  • 객체 간의 데이터를 전달하는 수단
  • 외부(호출한 곳)로부터 매개 값을 받아 실행에 이용하고, 실행 후 결과 값을 외부로 리턴할 수 있음

 

싱글톤(Singleton) 패턴
하나의 클래스에 오직 하나의 인스턴스만 가지는 패턴
하나의 인스턴스를 만들어 놓고 다른 모듈들이 공유

  • 데이터베이스 연결 모듈
    • 데이터베이스에 접속하는 작업은 그 자체로 무거운 작업이며, 여러번 생성할 필요가 없음
  • 디스크 연결, 네트워크 통신, DBCP 커넥션풀, 스레드풀, 캐시, 로그 기록 객체

장점

  • 인스턴스 생성 비용이 줄어듬

단점

  • 모듈간 의존성이 높아짐
  • TDD(Test Driven Development) 단위 테스트에 문제 발생

→ 단위 테스트를 할 때, 테스트가 서로 독립적이어야 하며 테스트를 어떤 순서로든 실행할 수 있어야 하는데, 싱글톤 인스턴스는 자원을 공유하고 있기 때문에 테스트가 결함없이 수행되려면 매번 인스턴스의 상태를 초기화시켜주어야 함

class Singleton {
	constructor() {
		if (!Singleton.instance) {
			Singleton.instance = this
		}
		return Singleton.instance
	}
	
	getInstance() {
		return this
	}
}

const a = new Singleton()
const b = new Singleton()
console.log(a === b)  // true

 

선택: 객체 지향 프로그래밍의 개념 정리하기

 

🧊 객체 지향 프로그래밍

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

  • 속성(= 필드) : 사람(이름, 나이), 자동차(색깔, 속도)
  • 동작(= 메소드) : 사람(웃다, 먹다), 자동차(달린다, 멈춘다)

-> 현실 세계의 객체를 소프트웨어 객체로 설계하는 것을 객체 모델링(object modeling)이라고 함

 

메소드 호출

리턴값 = 객체.메소드(매개값1, 매개값2, ...);

// 계산기 호출 예제
int result = Calculator.add(10, 20);

 

객체 간의 관계

  • 집합 관계 : 하나는 부품이고 나하는 완성품
  • 사용 관계 : 객체는 다른 객체의 메소드를 호출하여 원하는 결과를 얻어냄
  • 상속 관계 : 상위(부모) 객체를 기반으로 하위(자식) 객체를 생성하는 관계

 

객체와 클래스

  • 클래스 : 객체를 생성하기 위한 필드와 메소드를 정의
  • 인스턴스 : 클래스로부터 만들어진 객체
    • 하나의 클래스로부터 여러 개의 인스턴스를 만들 수 있음

 

[1] 클래스 선언

식별자 작성 규칙

  • 하나 이상의 문자로 이루어져야 함 -> Car, SportsCar
  • 첫 글자에는 숫자가 올 수 없음 -> Car, 3Car(x)
  • '$', '_' 외의 특수 문자는 사용할 수 없음 -> $Car, _Car, @Car(x), #Car(x)
  • 자바 키워드는 사용할 수 없음 -> int(x), for(x)
  • 단일 단어라면 첫 글자를 대문자로 하고 나머지는 소문자로 작성
  • 서로 다른 단어가 혼합된 이름을 사용한다면, 각 단어의 첫 글자는 대문자로 작성

 

클래스 이름.java로 소스 파일 생성

public class 클래스이름 {

}
  • 중괄호는 클래스 선언의 시작과 끝을 알려줌
  • 소스 파일을 컴파일하면 바이트 코드 파일(.class)이 생김 (클래스를 선언한 개수만큼)

 

[2] 객체 생성과 클래스 변수

클래스로부터 객체를 생성하려면 new 연산자 사용

  • new 연산자 뒤에는 생성자가 오는데, 생성자는 클래스() 형태를 가지고 있음
  • new 연산자로 생성된 객체는 메모리 힙 영역에 생성
new 클래스();

 
객체를 생성시킨 후 객체의 번지를 리턴
-> 참조 타입인 클래스 변수에 저장해두면 변수를 통해 객체를 사용 가능

클래스 변수;
변수 = new 클래스();

// 1개의 실행문으로 작성
클래스 변수 = new 클래스();

 

클래스의 두 가지 용도

  • 라이브러리(API: Application Program Interface)용
    • 다른 클래스에서 이용할 목적으로 설계
  • 실행용
    • 프로그램의 실행 진입점인 main() 메소드를 제공하는 역할
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 객체를 참조합니다.");
	}
}

 

[3] 클래스의 구성

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

필드(field)
객체의 고유 데이터, 부품 객체, 상태 정보를 저장하는 곳

  • 선언 형태는 변수와 비슷하지만, 필드를 변수라고 부르지는 않음
  • 변수 : 생성자와 메소드 내에서만 사용되고 생성자와 메소드가 실행 종료되면 자동 소멸
  • 필드 : 생성자와 메소드 전체에서 사용되며 객체가 소멸되지 않는 한 객체와 함께 존재

 

생성자(constructor)
new 연산자로 호출되는 특별한 중괄호 {} 블록

  • 객체 생성 시 초기화를 담당
  • 필드를 초기화 하거나 메소드를 호출해서 객체를 사용할 준비
  • 메소드와 비슷하게 생겼지만, 클래스 이름으로 되어 있고 리턴 타입이 없음

 

메소드(method)
객체의 동작에 해당하는 중괄호 {} 블록

  • 메소드를 호출하게 되면 중괄호 블록에 있는 코드들이 일괄적으로 실행
  • 객체 간의 데이터를 전달하는 수단
  • 외부(호출한 곳)로부터 매개 값을 받아 실행에 이용하고, 실행 후 결과 값을 외부로 리턴할 수 있음

 

🧊 필드

객체 고유의 데이터, 객체가 가져야 할 부품, 객체의 현재 상태 데이터를 저장하는 곳
ex. 자동차 객체

  • 고유 데이터: 제작회사, 모델, 색깔, 최고 속도
  • 상태 데이터: 현재 속도, 엔진 회전 수
  • 부품: 차체, 엔진, 타이어

 

[1] 필드 선언

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

  • 생성자와 메소드 중괄호 {} 블록 내부에는 선언 불가 -> 로컬 변수
타입 필드 [ = 초기값];
  • 타입 : 필드에 저장할 데이터의 종류 결정
    • 기본 타입(byte, short, int, long, float, double, boolean)
    • 참조 타입(배열, 열거, 인터페이스)
String company = "현대자동차";
String model = "그랜저";
int maxSpeed = 300;
int productionYear;
boolean engineStart;

 

[2] 필드 사용

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

  • 클래스 내부의 생성자나 메소드에서 사용할 경우 필드 이름으로 읽고 변경 가능
  • 클래스 외부에서 사용할 경우 클래스로부터 객체를 생성한 뒤 필드 사용
public class Car {
   // 필드
   String company = "현대자동차";
   String model = "그랜저";
   int maxSpeed = 350;
}

public class CarExample {
	public static void main(String[] args) {
    	// 객체 생성
        Car myCar = new Car();
        
        // 필드값 읽기
        System.out.println("제작회사: " + myCar.company);
        System.out.println("모델명: " + myCar.model);
        System.out.println("최고속도: " + myCar.maxSpeed);
        
        // 필드값 변경
        myCar.maxSpeed = 60;

 

🧊 생성자

new 연산자로 클래스로부터 객체를 생성할 때 호출되어 객체의 초기화를 담당

  • 객체 초기화 : 필드를 초기화하거나 메소드를 호출해서 객체를 사용할 준비를 하는 것을 말함
  • 생성자를 실행하지 않고는 클래스로부터 객체를 만들 수 없음
  • 생성자가 실행되면 힙 영역에 객체가 생성되고, 객체의 번지가 리턴

 

[1] 기본 생성자

모든 클래스는 생성자가 반드시 존재하며, 하나 이상 가질 수 있음

  • 생성자 선언을 생략하면, 컴파일러는 중괄호 블록 내에 기본 생성자를 바이트 코드에 자동 추가
[public] 클래스() { }

 

[2] 생성자 선언

생성자는 리턴 타입이 없고 클래스 이름과 동일

  • 매개 변수 선언은 생략하거나 여러 개를 선언할 수 있음
클래스(매개변수선언, ...) {
  // 객체의 초기화 코드
}

// Car 예제
public class Car {
  // 생성자
  Car(String color, int cc) { ... }
}

public class CarExample {
	public static void main(String[] args) {
    	Car myCar = new Car("검정", 3000);
        Car myCar = new Car();  // x: 기본 생성자 호출 불가능
    }
}

 

[3] 필드 초기화

클래스로부터 객체가 생성될 때 필드는 기본 초기값으로 자동 설정

  • 필드를 선언할 때 초기값을 주는 방법
    • 동일한 클래스로부터 생성되는 객체들은 모두 같은 값을 갖게 됨
  • 생성자에서 초기값을 주는 방법
public class Korean {
	// 필드
    String nation = "대한민국";
    String name;
    String ssn;
    
    // 생성자
    public Korean(String n, String s) {
    	name = n;
        ssn = s;
    }
}

Korean k1 = new Korean("박자바", "011225-1234567");

필드와 매개 변수 이름이 동일한 경우, 필드 앞에 this.를 붙여 구분

public Korean(String name, String ssn) {
	this.name = name;
    this.ssn = ssn;
}

 

[4] 생성자 오버로딩

외부에서 제공되는 다양한 데이터들을 이용해서 객체를 초기화하려면 생성자도 다양해야 함
-> 생성자 오버로딩 : 매개 변수를 달리하는 생성자를 여러 개 선언하는 것

public class 클래스 {
	클래스 ([타입 매개변수, ... ]) { ... }
    
    클래스 ([타입 매개변수, ... ]) { ... }
}

public class Car {
	Car() { ... }
    Car(String model) { ... }
    Car(String model, String color) { ... }
}

 

[5] 다른 생성자 호출: this()

생성자 오버로딩이 많아질 경우 생성자 간의 중복된 코드 발생 가능
-> 필드 초기화 내용은 한 생성자에만 집중적으로 작성하고 나머지 생성자는 초기화 내용을 가지고 있는 생성자를 호출

클래스([매개변수, ...]) {
	this(매개변수, ...,, ...);  // 클래스의 다른 생성자 호출
    실행문;
}

 
this()는 자신의 다른 생성자를 호출하는 코드로 반드시 생성자의 첫 줄에서만 허용

Car(String model) {
	this.model = model;
    this.color = "은색";
    this.maxSpeed = 250;
}

Car(String model, String color) {
	this.model = model;
    this.color = color;
    this.maxSpeed = 250;
}

Car(String model, String color, int maxSpeed) {
	this.model = model;
    this.color = color;
    this.maxSpeed = maxSpeed;
}

// this() 사용
Car (String model) {
	this(model, "은색", 250)
}

Car (String model, String color) {
	this(model, color, 250);
}

Car(String model, String color, int maxSpeed) {
	this.model = model;
    this.color = color;
    this.maxSpeed = maxSpeed;
}

 

🧊 메소드

[1] 메소드 선언

메소드 선언은 선언부와 실행 블록으로 구성: 메소드 시그니처

리턴타입 메소드이름([매개변수선언, ...]) {
	실행 코드 작성
}

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

powerOn();
double result = divide(10, 20);

// 매개 변수를 배열 타입으로 선언
int sum1(int[] values) { }

int[] values = {1, 2, 3};
int result = sum1(values);
int result = sum1(new int[] {1, 2, 3, 4, 5});

// 매개 변수를 ··· 으로 선언
int sum2(int ··· values) { }

int result = sum2(1, 2, 3);
int result = sum2(1, 2, 3, 4);
  • 리턴 타입: 메소드가 리턴하는 결과의 타입 표시(없을 수도 있음)
  • 메소드 이름: 메소드의 기능이 드러나도록 식별자 규칙에 맞게 이름을 지어줌
    • 숫자로 시작하면 안되고, $와 _를 제외한 특수 문자를 사용하지 말아야 함
    • 관례적으로 메소드 이름은 소문자로 작성
    • 서로 다른 단어가 혼합된 이름이라면 뒤이어 오는 단어의 첫 글자는 대문자로 작성
  • 매개 변수 선언: 메소드를 실행할 때 필요한 데이터를 받기 위한 변수 선언
    • 매개 변수의 개수를 모를 경우: 매개 변수를 배열 타입으로 선언 or ··· 사용
  • 메소드 실행 블록: 실행할 코드를 작성

 

[2] return문

리턴값이 있는 메소드
리턴 타입이 있는 메소드는 반드시 리턴문을 사용해서 리턴값을 지정

  • return문이 없다면 컴파일 에러가 발생하고, return문이 실행되면 메소드는 즉시 종료
return 리턴값;

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

 

리턴값이 없는 메소드: void
void로 선언된 메소드에서도 return문을 사용 가능

  • 메소드 실행을 강제 종료시키는 역할
return;

// example
void run() {
	while(true) {
    	if(gas > 0) {
			gas -= 1;
        } else {
        	return;  // run() 메소드 실행 종료
        }
    }
}

 

[3] 메소드 호출

메소드는 클래스 내/외부의 호출에 의해 실행

  • 내부: 단순한 메소드 이름으로 호출
  • 외부: 클래스로부터 객체를 생성한 뒤 참조 변수를 이용해서 메소드를 호출

 

객체 내부에서 호출

메소드(매개값, ...);

// example
public class ClassName {
	void method1(String p1, int p2) { }
    
    void method2() {
    	method1("홍길동", 100);
    }
}

 

리턴 값을 받고 싶은 경우

public class ClassName {
	int method1(int x, int y) {
    	int result = x + y;
        return result;
    }
    
    void method2() {
    	int result1 = method1(10, 20);  // 30
        double result2 = method2(10, 20);  // 30.0
    }
}

 

객체 외부에서 호출
외부 클래스에서 메소드를 호출하려면 클래스로부터 객체를 생성

클래스 참조변수 = new 클래스(매개값, ...);

참조변수.메소드(매개값, ...);  // 리턴값이 없거나 리턴값을 받지 않을 경우
타입 변수 = 참조변수.메소드(매개값, ... );  // 리턴값이 있고, 리턴값을 받고 싶을 경우

//example
Car myCar = new Car();
myCar.keyTurnOn();
int speed = myCar.getSpeed();

 

[4] 메소드 오버로딩

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

  • 매개 변수의 타입, 개수, 순서 중 하나가 달라야 함
class 클래스 {
	리턴 타입 메소드이름(타입 변수, ...) { ... }
    리턴 타입 메소드이름(타입 변수, ...) { ... }
}

// example
public class Calculator {
	// 정사각형의 넓이
    double areaRectangle(double width) {
    	return width * width;
    }
    
    // 직사각형의 넓이
    double areaRectangle(double width, double height) {
    	reutrn width * height;
    }
}

 

🧊 인스턴스 멤버와 정적 멤버

  • 인스턴스 멤버 : 객체마다 가지고 있는 멤버
  • 정적 멤버 : 클래스에 위치시키고 객체들이 공유하는 멤버

 

[1] 인스턴스 멤버와 this

인스턴스 멤버는 객체(인스턴스)를 생성한 후 사용할 수 있는 필드ㅘ 메소드

인스턴스 멤버 선언

public class Car {
	// 필드
    int gas;
    
    // 메소드
    void setSpeed(int speed) { ... }
}

Car myCar = new Car();
myCar.gas = 10;
myCar.setSpeed(60);

 

this
객체 내부에서 인스턴스 멤버에 접근하기 위해 사용

  • 주로 생성자와 메소드의 매개 변수 이름이 필드와 동일한 경우 사용
Car(String model) {
	this.model = model;
}

void setModel(String model) {
	this.model = model;
}

 

[2] 정적 멤버와 static

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

  • 객체가 없이도 실행되기 때문에 내부에 인스턴스 필드나 인스턴스 메소드 사용 불가능
  • 객체 자신의 참조인 this 키워드도 사용 불가능

 

정적 멤버 선언
정적 필드와 정적 메소드를 선언하려면 필드와 메소드 선언 시 static 키워드를 붙여줌

  • 클래스 로더가 클래스(바이트 코드)를 로딩해서 메소드 메모리 영역에 적재할 때 클래스별로 관리
public class 클래스 {
	// 정적 필드
    static 타입 필드 [=초기값];
    
    // 정적 메소드
    static 리턴 타입 메소드(매개변수선언, ...) { ... }
}

 

정적 멤버 사용
클래스가 메모리로 로딩되면 정적 멤버를 바로 사용 가능

클래스.필드;
클래스.메소드(매개값, ...);

// example
public class Calculator {
	static double pi = 3.14159;
    static int plub(int x, int y) { ... }
}

double result1 = 10 * 10 * Calculator.pi;
int result2 = Calculator.plus(10, 5);

 

[3] 싱글톤

전체 프로그램에서 단 하나의 객체만 만들도록 보장해야 하는 경우

  • 외부에서 new 연산자로 호출할 수 없도록 막아야 함
  • 생성자 앞에 private 접근 제한자를 붙여 줌
public class 클래스 {
	// 정적 필드
    private static 클래스 singleton = new 클래스();
    
    // 생성자
    private 클래스() {}
    
    // 정적 메소드
    static 클래스 getInstance() {
    	return singleton;
    }
}

// getInstance 호출
클래스 변수1 = 클래스.getInstance();

 

[4] final 필드와 상수

final 필드
초기값이 저장되면, 프로그램 실행 도중에 수정할 수 없다는 것

  • 필드 선언 시에 주는 방법
  • 생성자에 주는 방법
final 타입 필드 [=초기값];

 

상수(static final)
객체마다 존재하지 않고 클래스에만 존재하며, 한 번 초기값이 저장되면 변경할 수 없음

  • 모두 대문자로 작성
  • 여러 단어가 혼합된 이름이라면 언더바(_)로 단어들을 연결해 줌
static final 타입 상수 = 초기값;

// example
static final double PI = 3.14159;
static final double EARTH_RADIUS = 6400;

 

🧊 패키지와 접근 제한자

패키지의 물리적인 형태는 파일 시스템의 폴더

  • 클래스를 유일하게 만들어주는 식별자 역할
  • 클래스는 이름이 동이하더라도 패키지가 다르면 다른 클래스로 인식
  • 클래스 : 패키지 이름 + 클래스 이름 -> 상위패키지.하위패키지.클래스

 

[1] 패키지 선언

해당 클래스가 어떤 패키지에 속할 것인지를 선언

  • 패키지는 클래스의 일부로, 클래스만 따로 복사해서 다른 곳으로 이동하면 클래스를 사용할 수 없음
package 상위패키지.하위패키지;

public class ClassName { ... }

패키지 명명 규칙

  • 숫자로 시작해서는 안되고 _, $ 를 제외한 특수 문자를 사용하면 안됨
  • java로 시작하는 패키지는 자바 표준 API에서만 사용하므로 사용하면 안됨
  • 모두 소문자로 작성하는 것이 관례

 

import문
사용하고자 하는 클래스 또는 인터페이스가 다른 패키지에 소속되어 있다면, import문으로 해당 패키지의 클래스 또는 인터페이스를 가져와 사용할 것임을 컴파일러에게 알려주어야 함

  • 패키지 선언과 클래스 선언 사이에 작성
  • 상위 패키지를 import 했다고 해서 하위 패키지까지 import 되는 것은 아님
  • 자바는 패키지 전체 이름으로 패키지를 식별
    -> com.hankookcom.hankook.project는 서로 다른 패키지
import 상위패키지.하위패키지.클래스이름;
import 상위패키지.하위패키지.*;

 

[2] 접근 제한자(Access Modifier)

접근을 제한하기 위해 사용(클래스 및 인터페이스, 이들이 가지고있는 멤버의 접근)

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

 

1) 클래스의 접근 제한: public, default

클래스를 선언할 때 해당 클래스를 같은 패키지 내에서만 사용할 것인지 다른 패키지에서도 사용할 수 있도록 할 것인지 결정

  • default 접근 제한

    • 같은 패키지에서는 제한 없이 사용할 수 있지만, 다른 패키지에서는 사용할 수 없도록 제한
  • public 접근 제한

    • 같은 패키지뿐만 아니라, 다른 패키지에서도 제한 없이 사용 가능
    • 클래스를 라이브러리 클래스로 개발한다면 반드시 public 접근 제한을 갖도록 해야 함
package sec.exam.package1;

class A {}  // default 접근 제한

public class B {
	A a;  // A 클래스 접근 가능
}


package sec.exam.package2;

import sec.exam.package1.*;

public class C {
	A a;  // A 클래스 접근 불가(컴파일 에러)
    B b;  // B 클래스 접근 가능
}

 

2) 생성자의 접근 제한: public, protected, default, private

객체를 생성하기 위해서는 new 연산자로 생성자를 호출

  • public 접근 제한
    • 모든 패키지에서 아무런 제한 없이 생성자 호출 가능
  • default 접근 제한
    • 같은 패키지에서는 아무런 제한 없이 생성자 호출 가능하지만, 다른 패키지에서는 생성자 호출 불가능
  • protected 접근 제한
    • 같은 패키지에 속하는 클래스에서 생성자를 호출 가능
    • 다른 패키지에 속한 클래스가 해당 클래스의 자식 클래스라면 생성자 호출 가능
  • private 접근 제한
    • 동일한 패키지이건 다른 패키지이건 상관없이 생성자를 호출하지 못함
    • 오로지 클래스 내부에서만 생성자를 호출할 수 있고, 객체를 만들 수 있음
    • singleton 패턴에서 여러 개의 객체를 만들지 못하도록, 생성자를 private 접근 제한으로 선언하고, 자신의 유일한 객체를 리턴하는 getInstance() 정적 메소드를 선언
package sec.exam.package1;

public class A {
	// 필드
	A a1 = new A(true);
    A a2 = new A(1);
    A a3 = newA("문자열");
	
    // 생성자
    public A(boolean b) {}  // public 접근 제한
    A(int b) {}  // default 접근 제한
    private A(String s) {}  // private 접근 제한
}

public class B {
	// 필드
    A a1 = new A(str);  // public 생성자 접근 가능
    A a2 = new A(1);  // default 생성자 접근 가능
    A a3 = new A("문자열");  // private 생성자 접근 불가(컴파일 에러)


package sec.exam.package2;

import sec.sxam.package1.A;

public class C {
	// 필드
    A a1 = new A(str);  // public 생성자 접근 가능
    A a2 = new A(1);  // default 접근 불가(컴파일 에러)
    A a3 = new A("문자열");  // private 생성자 접근 불가(컴파일 에러)
}

 

3) 필드와 메소드의 접근 제한

필드와 메소드를 선언할 때 클래스 내부에서만 사용할 것인지, 패키지 내에서만 사용할 것인지, 다른 패키지에서도 사용할 수 있도록 할 것인지 결정

// 필드 선언
[public | protected | private] [static] 타입 필드;

// 메소드 선언
[publi | protected | private] [static] 리턴 타입 메소드(...) {...}
  • public 접근 제한
    • 모든 패키지에서 아무런 제한 없이 필드와 메소드 호출 가능
  • default 접근 제한
    • 같은 패키지에서는 아무런 제한 없이 필드와 메소드를 호출 가능하지만, 다른 패키지에서는 필드와 메소드를 호출 불가능
  • protected 접근 제한
    • 같은 패키지에 속하는 클래스에서 필드와 메소드를 호출 가능
    • 다른 패키지에 속한 클래스가 해당 클래스의 자식 클래스라면 필드와 메소드를 호출 가능
  • private 접근 제한
    • 동일한 패키지이건 다른 패키지이건 상관없이 필드와 메소드를 호출하지 못함

 

4) Getter와 Setter 메소드

객체의 필드를 객체 외부에서 직접적으로 접근하는 것을 막음
-> 외부에서 마음대로 변경할 경우 객체의 무결성이 깨질 수 있기 때문

필드는 private로 선언하여 외부에서 접근할 수 없도록 막고, 메소드는 공개해서 외부에서 메소드를 통해 필드에 접근하도록 유도

  • Setter: 메소드는 매개값을 검증해서 유효한 값만 객체의 필드로 저장
  • Getter: 메소드로 필드 값을 가공한 후 외부로 전달
private 타입 fieldName;  // 필드 접근 제한자: private

// Getter
public 리턴 타입 getFieldName() {  // 접근 제한자: Public
	return fieldName;
}

// Setter 
public void setFieldName(타입 fieldName) {  // 접근 제한자: public
	this.fieldName = fieldName;
}
  • 필드 타입이 boolean인 경우에는 Getter는 get으로 시작하지 않고 is로 시작하는 것이 관례

0개의 댓글