📚 이것이 자바다 [개정판]
- 객체 = 속성(필드) + 동작(메소드)
- 물리적으로 존재하거나 개념적인 것 중에서 다른 것과 식별 가능한 것
- 캡슐화
- 필드와 메소드를 하나로 묶고 실제 구현 내용을 외부에 감추는 것이다
- 외부의 잘못된 사용으로 인해 객체가 손상되지 않도록 하기 위함이다
- 접근 제한자를 통해 노출할 것인지 숨길 것인지 결정한다
- 상속
- 코드의 재사용성을 높여준다
- 유지 보수 시간을 최소화시켜 준다
- 자식 객체는 부모 객체의 기능을 물려받고 기능을 추가하여 확장한다
- 다형성
- 사용 방법은 동일하지만 실행 결과가 다양하게 나오는 성질이다
- 클래스 ⇒ 인스턴스화 (클래스로부터 객체를 만드는 과정) ⇒ 인스턴스(객체)
- 하나의 클래스로부터 여러 개의 인스턴스를 만들 수 있다
// 클래스 선언
public class 클래스명 {
// 객체 생성
클래스 변수 = new 클래스();
// 스택에 저장된 객체의 주소를 힙에 생성된 객체가 참조
// 필드 선언
type fieldName;
// 생성자 선언 (클래스명과 동일)
ClassName() {...}
// 메소드 선언
type methodName() {...}
💡 하나의 소스 파일에 여러 개의 클래스를 선언하는 경우
파일명과 동일한 클래스만 공개(public) 클래스로 선언할 수 있다
💡 필드와 지역(로컬)변수의 차이점
필드 : 클래스 내에 선언, 객체 내부에 존재하며 객체 내/외부 어디든 사용 가능
변수 : 생성자나 메소드 내에서 선언되어 그 내부에서만 사용 가능
클래스 변수 = new 클래스();
- 클래스로부터 객체를 생성하려면 객체 생성 연산자인
new
가 필요하다- new 연산자는 객체를 생성시킨 후객체의 주소를 리턴한다
public class ClassName {
// 필드 선언
타입 fieldName;
// 생성자 선언
ClassName() {...}
// 메소드 선언
타입 methodName() {...}
필드
- 객체의 데이터를 저장하는 역할
생성자
- new 연산자로 객체를 생성할 때 객체 초기화 역할
- 메소드와 비슷하지만 리턴 타입이 없고, 클래스 이름과 동일하다
- 모든 클래스에는 생성자가 존재한다
메소드
- 객체가 수행할 동작
- 객체와 객체간의 상호 작용을 위해 호출된다
타입 필드명 = 초기값;
타입 필드명;
- 필드명은 첫 문자를 소문자로 하고 캐멀 스타일로 작성한다
- 초기값을 설정하지 않은 필드는 객체 생성 시 타입의 기본값으로 초기화된다
- 필드는 객체의 데이터이므로 객체가 존재해야만 사용할 수 있다
- 외부 객체에서 사용할 때는 도트 연산자(.)를 사용한다
class Car2 {
// 필드 선언
String model = "그랜저";
String color = "balck";
int maxSpeed = 350;
int speed;
}
public **class** CarMain2 {
public static void main(String[] args) {
// Car 객체 생성
Car2 myCar = new Car2();
// Car 객체의 필드값 읽기
System.out.println("모델명: " + myCar.model);
System.out.println("색상: " + myCar.color);
System.out.println("최고속도: " + myCar.maxSpeed);
System.out.println("현재속도: " + myCar.speed);
// Car 객체의 필드값 변경
myCar.speed = 60;
System.out.println("수정된 속도: " + myCar.speed);
}
}
클래스 변수 = new 클래스();
→ 생성자 호출- new 연산자는 객체를 생성한 후 객체를 초기화하는 역할을 한다
// 생성자 선언 ClassName(매개변수, ...) { // 객체 초기화 코드 } // 생성자 호출 ClassName 변수명 = new ClassName(매개변수);
- 매개값을 통해 객체의 필드를 다양하게 초기화하기 위한 방법
- 매개변수를 달리하는 생성자를 여러 개 생성하는 것이다
Car() {...} Car(String model) {...} Car(String model, String color) {...} Car(String model, String color, int maxSpeed) {...}
// model만 초기화하는 생성자
Car3(String model) {
this(model, "은색", 250); // #1 생성자 호출
}
// model과 color를 초기화하는 생성자
Car3(String model, String color) {
this(model, color, 250); // #1 생성자 호출
}
// #1 모든 필드를 초기화하는 생성자 (공통코드로 사용되는 생성자)
Car3(String model, String color, int maxSpeed) {
this.model = model;
this.color = color;
this.maxSpeed = maxSpeed;
}
- 메소드 선언: 객체의 동작을 실행 블록으로 정의하는 것
- 메소드 호출: 실행 블록을 실제로 실행하는 것
return문
: 메소드의 실행을 강제 종료하고 호출한 곳으로 돌아간다- 메소드명은 첫 문자를 소문자로 시작하고 캐멀 스타일로 작성한다
// 리턴값이 있는 메소드 선언
리턴타입 메소드명 (매개변수, ...) { 실행코드 };
// 리턴값이 없는 메소드 선언
void 메소드명 (매개변수, ...) { 실행코드 };
// 메소드 호출
타입 변수 = 메소드명();
- 인스턴스(instance) 멤버
- 객체에 소속되어 객체를 생성해야만 사용할 수 있는 멤버
- 객체를 생성하고 참조변수명으로 접근한다
- 정적(static) 멤버
- 클래스에 고정되어 객체 없이도 사용할 수 있는 멤버
- 클래스명으로 접근한다
- 정적 필드는 필드 선언과 동시에 초기값을 주는 것이 일반적이다
- 공용적인 필드는 정적 필드로 선언하는 것이 좋다
- 인스턴스 멤버 사용 불가, this 사용 불가
- → 객체 생성한 경우 가능
public class Car { // 인스턴스 필드 선언 int speed; // 인스턴스 메소드 선언 void run() { System.out.println(speed + "으로 달립니다."); } static void simulate() { // 객체 생성 Car myCar = new Car(); // 인스턴스 멤버 사용 myCar.speed = 200; myCar.run(); } public static void main(String[] args) { // 정적 메소드 호출 simulate(); // 객체 생성 Car myCar = new Car(); // 인스턴스 멤버 사용 myCar.speed = 30; myCar.run(); } }
final
초기값이 저장되면 이것이 최종값이 되어 수정할 수 없다- 필드 선언 시에 초기값을 대입하거나, 생성자에서 초기값을 대입한다
- 상수 이름은 모두 대문자로 작성하고, 언더바(_)로 단어를 연결한다
// 상수 선언 및 초기화
static final double EARTH_RADIUS = 6400;
// 상수 선언
static final double EARTH_SURFACE_AREA;
// 정적 블록에서 상수 초기화
static {
EARTH_SURFACE_AREA = 4 * Math.PI * EARTH_RADIUS * EARTH_RADIUS;
}
- 객체의 무결성을 유지하게 위해서는 객체의 필드를 외부에서 변경하거나 메소드를 호출할 수 없도록 막아야 한다
- 클래스, 멤버변수, 메서드, 생성자에서 사용될 수 있다
public
접근 제한이 없음protected
같은 패키지 내, 다른 패키지의 자손클래스에서 접근 가능(상속하는 경우)(default)
같은 패키지 내에서만 접근 가능, 아무것도 붙이지 않은 상태private
같은 클래스 내에서만 접근 가능
- 객체지향프로그래밍에서는 객체의 무결성이 중요하기 때문에 직접적인 필드 접근을 막고 메소드를 통해 접근하는 것을 선호한다
private
제어자를 사용하는 경우!!setter()
데이터를 검증하여 유효한 값만 필드에 저장한다 (데이터 접근, 수정)getter()
부적절한 데이터인 경우 적절한 값으로 변환하여 리턴한다 (변경한 데이터 읽기)
private 타입 fieldName;
// getter
public 타입 **getF**ieldName() {
return fieldName;
}
public boolean **isF**ieldName
// setter
public void setFieldName(타입 fieldName) {
this.fieldName = fieldName;
}
- 단 한 개의 객체만 생성해서 사용하고 싶은 경우에 적용할 수 있다
- 생성자를 private 접근 제한하여 외부에서의 생성자 호출을 막는 것이 핵심
- 싱글톤 패턴이 제공하는 정적 메소드를 통해 간접적으로 객체를 얻을 수 있다
public class 클래스 {
// private 접근 권한을 갖는 정적 필드 선언과 초기화
// 자신의 클래스 타입으로 정적 필드를 선언하고
// 미리 객체를 생성하여 초기화
private static 클래스 singleton = new 클래스();
// private 접근 권한을 갖는 생성자 선언
private 클래스() {}
// public 접근 권한을 갖는 정적 메소드 선언
// 정적 메소드를 public으로 선언하여 정적 필드값을 리턴할 수 있다
// -> 외부에서 객체를 얻는 유일한 방법
public static 클래스 getInstance() {
return singleton;
}
}