❗ src 기준 하위 폴더만 패키지 경로로 사용
.
으로 구분하고 소문자로 작성함이 관례public
으로 설정 선언된 패키지는 완전한 경로가 아니므로,
패키지 앞에 생략된 OS의 풀 경로는 classpath
에 등록해야함
import시 classpath
에 등록된 경로는 제외하고, 패키지명과 클래스명만 명시
(참고: classpath에는 bin
까지의 경로를 등록)
classpath 사용 이유 : Java가 플랫폼 중립적 언어인데,
(Java의 "Write Once, Run Anywhere"을 보면 알 수 있음)
class 코드 안에 풀경로를 넣어버리면 플랫폼 의존적인 코드가 되어 버리기 때문
import
: 다른 패키지에 있는 클래스 파일의 위치를 참조하는 선언문
❗ 같은 패키지 안에 있는 클래스들끼리는 import 없이도 서로 사용 가능
<다른 사람이 만든 클래스 파일 사용하기 >
누군가에게.class
파일을 받았다고 가정해보자,
그 안에 어떤 클래스와 메서드가 들어있는지 알아야 사용할 수 있을 것 아닌가?따라서 클래스를 제작한 사람은 반드시 설명서를 제공할 의무가 있다.
그래서 해당.class
파일에 대한 설명서인 API document(프로그래밍 사용설명서)가 필요하다!
javadoc
/**
로 시작해 */
로 끝나는 형식으로 작성
javadoc 파일명.java
// 현재 작업 중인 폴더(또는 파일이 있는 폴더)에 API 문서들이 생성
javadoc -d 디렉토리명 파일명.java
// -d 옵션을 사용하면 다른 디렉토리에 문서를 생성
<참고>
java 개발 시 사용되는 필수적이고 중요한 클래스들은
java.lang
패키지에 들어있고,
이 패키지는 개발자가 명시하지 않아도 이미 import
되고 있음
String
클래스,Object
클래스,Math
클래스 등...
public(접근제한자) | static(수식자) | void(반환타입) 메서드 이름(매개변수){...}
여기서 수식자를 알아보자
1️⃣ static
- 정적
클래스의 인스턴스와 관계없이 클래스 자체에 속하는 변수나 메서드를 의미
객체를 생성하지 않고도 클래스 이름을 통해 접근할 수 있음
static
이 붙은 변수는 클래스 변수static
이 붙은 메서드는 클래스 메서드2️⃣ final
- 마지막
final은 다양한 방식으로 사용되어, 주어진 요소를 변경 불가능하게 만듦
3️⃣ abstract
- 추상적
abstract는 구현되지 않은 메서드 또는 클래스를 정의할 때 사용됨
<참고> 오버로딩과 오버라이딩
구분 오버로딩 (Overloading) 오버라이딩 (Overriding) 정의 같은 이름의 메서드를 매개변수나 리턴 타입을 다르게 정의하는 것. 부모 클래스의 메서드를 자식 클래스에서 재정의하는 것. 목적 메서드 이름을 재사용하여 코드 중복을 줄이기 위해. 상속받은 메서드의 기능을 자식 클래스에서 변경하거나 확장하기 위해. 메서드 이름 동일 동일 매개변수 매개변수의 개수나 타입이 달라야 함 부모 클래스의 메서드와 매개변수가 동일해야 함 리턴 타입 리턴 타입도 동일하거나 달라도 됨 리턴 타입은 부모 메서드와 같아야 함 접근 제어자 자식 클래스에서 변경 가능, 부모 클래스의 접근 제어자보다 넓게 설정 가능 부모 클래스의 메서드보다 좁게 설정 불가
- 오버로딩은 메서드 이름은 같고, 매개변수가 다르거나 리턴 타입이 다르게 정의하는 것.
- 오버라이딩은 부모 클래스의 메서드를 자식 클래스에서 재정의하여 기능을 변경하는 것.
데이터를 private
으로 선언해 외부에서 그 데이터에 직접 접근하지 못하게 하고, 메서드를 통해 데이터를 읽거나 쓸 수 있게 하는 것
package use;
public class Account {
private String num = "110-409-513991"; // 계좌번호
private String bank = "신한은행"; // 은행명
private String owner = "HJ"; // 계좌 소유자
private int balance = 500000; // 잔액
// getter 메서드들
public int getBalance() { // 잔액 조회
return balance;
}
public String getBank() { // 은행명 조회
return bank;
}
public String getOwner() { // 계좌 소유자 조회
return owner;
}
public String getNum() { // 계좌번호 조회
return num;
}
// setter 메서드들
public void setBalance(int balance) { // 잔액 설정
this.balance = balance;
}
public void setBank(String bank) { // 은행명 설정
this.bank = bank;
}
public void setOwner(String owner) { // 계좌 소유자 설정
this.owner = owner;
}
public void setNum(String num) { // 계좌번호 설정
this.num = num;
}
}
메서드 접근은 나만 제어할 수 있음
ex) 잔액이 음수로 설정되지 않도록 하는 조건을 넣기
캡슐화(Encapsulation)와 은닉화(Encapsulation)는 거의 같은 개념으로 함께 이루어짐
둘은 아주 밀접하게 연결되어 있으며, 실질적으로 캡슐화를 구현하는 중요한 방법 중 하나가 은닉화임!
위 예제에서 엄밀하게 말하자면
getter
와setter
로 데이터와 메서드를 하나로 묶는 것은 캡슐화(Encapsulation)의 구현 방식
private
필드를 사용해 내부 데이터를 보호한 것은 은닉화(Encapsulation)의 구현 방식
날 멘붕에 빠뜨린..
생성자(Constructor): 생성자는 객체가 생성될 때 호출되는 특별한 메서드 객체의 초기 상태를 설정하고, 인스턴스를 생성하는 역할
생성자는 객체가 생성되는 시점에 초기화를 담당하기 때문에,
특히 "Has a" 관계로 포함된 다른 객체들을 함께 생성할 때 매우 유용
Has a 관계: "Has a" 관계는 객체가 다른 객체를 포함하고 있다는 관계를 나타냄
집합 관계로, 하나의 객체가 다른 객체를 속성으로 갖고 있다는 의미
현실에 존재하는 모든 사물은 단독으로 존재할 수 없으며, 객체와 객체 사이에 관련성을 맺으며 존재할 수 밖에 없다.
Java 언어에서는 특정 객체가 다른 객체를 멤버로 보유하고 있는, 즉 부품 관계를 가리켜 "Has a" 관계라고 한다.
자동차(Car)는 다음 부품을 가진다.
//현실의 핸들 부품객체 생성
package use;
public class Handle {
String name="파워핸들";
String color="핑크색";
public void rotate(){
System.out.println("핸들을 돌려요");
}
}
//현실의 바퀴 부품객체 생성
package use;
public class Wheel{
String brand="Hankook";
int price=170;
public void roll(){
System.out.println("굴러가요");
}
}
//현실의 문 부품객체 생성
package use;
public class Door{ // 현실의 문
String type="자동";
public void open(){
System.out.println("문이 열려요");
}
public void close(){
System.out.println("문이 닫혀요");
}
}
주 객체 Car.class
package use;
public class Car{
int price; //0
String name; //null
Handle handle; //null →객체 자료형
Wheel wheel; //null
Door door; //null
//생성자는 사물을 태어나게 하는 시점에 초기화에 관여하므로
//특히 has a car관계에 있는 객체의 인스턴스를 생성할 때 아주 유용
public Car(){
price=5000;
name="k9";
handle=new Handle(); // → 부품객체 생성
wheel=new Wheel();
door=new Door();
}
}
❗ has a 관계: 객체가 다른 객체를 멤버변수로 보유한 관계
Car
has a handle
Car
has a wheel
Car
has a door
Method | Stack | Heap |
---|---|---|
class Handle | main() frame | Handle @a → name: "파워핸들" |
class Wheel | └─ myCar → @d | color: "핑크색" |
class Door | Wheel @b → brand: "Hankook" | |
class Car | price: 170 | |
Door @c → type: "자동" | ||
Car @d → handle: @a | ||
wheel: @b | ||
door: @c | ||
price: 5000 | ||
name: "k9" |
🚗 UseCar.class
package use;
public class UseCar{
public static void main(String[] args) {
Car car=new Car(); //본체 (주 객체)
System.out.println(car.handle.color); //출력: 핑크색
System.out.println(car.wheel.brand); //출력: Hankook
car.door.open(); //출력: 문이 열려요
}
}
생성자 안(Car(){...}
)에서 handle, wheel, door를 new
해주면
👉 주석 내용은 틀린 것이고, 실행은 정상
생성자 안에서 아무것도 하지 않았다면
👉 주석이 맞고, 실행 시 오류
✅ 각 부품객체의 값을 변경하는 방법
방식 예 장점 단점 직접 접근 car.wheel.brand = "Michelin";
간단, 직관적 캡슐화 위반 위험 setter 사용 car.wheel.setBrand("Michelin");
안정성, 유지보수 용이 코드 좀 길어짐