현실에서 제품을 만드는 과정과 유사하여 제품을 만들기 위해 부품을 먼저 만들고 부품들을 조립해서 제품을 완성하는 방식
소프트웨에서도 부품에 해당하는 객체들을 만들어 하나의 완성된 프로그램을 만드는 기법을 객체 지향 프로그래밍(OOP)라 한다.
공장에서 설계도를 가지고 부품을 조립하여 제품을 출하하는 개념과 유사하다.
클래스란?
공장에서 부품과 제품을 만들기 위한 설계도이다.
실제하지 않지만 객체를 만들기 위해서 미리 정의해둔 필드와 메서드들이다.
객체란?
공장에서 설계로를 가지고 만든 부품과 제품이다.
실제하고 설계도를 기반으로 필드와 메서드들이 실제 동작한다.
객체 프로그래밍의 특징
캡슐화 : 객체의 필드, 메서드를 하나로 묶고, 실제 구현 내용을 감추는 것을 말한다. 외부 객체는 객체 내부의 구조를 알지 못하며 객체가 노출해서 제공하는 필드와 메서드만 이용할 수 있다.
상속 : 부모(조상)이 가진 재산을 자식에게 물려주는 것으로 상위 객체가 가진 필드와 메서드를 자식이 사용할 수 있고 다시 재정의할 수도 있다.
다형성 : 같은 타입이지만 실행 결과가 다양한 객체를 이용하는 성질을 말한다. 부모 타입에는 모든 자식 객체가 대입될 수 있고 인터페이스 타입에는 모든 구현 객체가 대입될 수 있다.
객체와 클래스
클래스를 설계하고 설계 된 클래스를 가지고 사용할 객체를 생성한 후 생성된 객체를 사용한다.
관례적으로 클래스 이름이 단일 단어라면 첫 자를 대문자로 하고 나머지는 소문자로 작성한다.
파일 이름과 동일한 이름의 클래스 선언에만 public 접근 제한자를 붙일 수 있고 가급적 소스 파일 하나당 동일한 이름의 파일 클래 하나를 선언하는게 좋다.
// Car.javapublicclassCar{
String name; // 클래스 필드 : 객체의 속성을 의미하며 데이터 저장
int speed; // 클래스 필드
int val;
publicCar() { // 기본 생성자 : 생성자는 프로그래머가 만들지 않으면 컴파일러가 자동으로 하나 만들어준다.// 객체 생성 시 초기화 역할
}
publicCar(String name) { // 매개변수를 받는 생성자 this.name = name // this는 해당 객체를 의미함 : name이 같으므로 어떤 name을 의미하는지 명시
}
publicCar(String name, int speed) {
this(name); // 중복 코드를 없애기 위해 name은 다른 생성자 호출 : this와 this()는 다르다.this.speed = speed;
}
publicvoidopen() { // 메서드 : 객체의 기능을 의미하며 CRUD 조작을 함
}
public int value(int ... values) { // 매개 변수의 수를 모를 때 받는 가변인자이고 배열([])로 전달 받아진다.for (int i = 0; i < values.length; i++) {
this.val += values[i];
}
returnthis.val; // 객체가 가지고 있는 val을 return 함
}
}
// Test.javapublicclassTest{
publicstaticvoidmain(String args[]) {
Car c = new Car(); // 객체 생성
c.value(1,2,3,4); // 가변인자를 가진 value 호출
c.value(1,2,3,4, 5); // 가변인자를 가진 value 호출
}
}
객체의 메서드 호출
객체 내부에서의 호출 : method2() -> method1()
객체 외부에서의 호출 : c.method2()
메서드 오버로딩
같은 이름을 가진 메서드의 매개 변수의 타입, 개수, 순서에 따라 호출하는 메서드가 달라짐
intplus(int x, int y){ }
intplus(double x, int y){ }
intplus(int x, int y, int z){ }
정적 멤버와 static
정적은 고정되어 있다는 의미로 정적 멤버는 클래스에 고정된 멤버로서 객체를 생성하지 않고 사용할 수 있는 필드와 메서드를 말한다.
프로그램이 시작하고부터 종료될 때까지 공유 메모리 영역에 정적 멤버를 올려두고 어디서든 참고해서 쓸 수 있다.
필드의 경우 객체가 가지고 있어야 할 데이터라면 인스턴스 필드로 선언하고, 객체마다 가지고 있을 필요성이 없는 공용적인 데이터라면 정적 필드로 선언하는 것이 좋다. => PI같은 데이터
메서드의 경우 인스턴스 필드를 이용해서 실행해야 한다면 인스턴스 메서드로 선언하고, 인스턴스 필드를 이용하지 않는다면 정적 메서드로 선언한다. => 덧셈, 뺄셈의 기능은 정적 메서드로 선언하는게 좋다.
publicclassTest{
// 정적 필드staticint x = 10;
// 정적 메소드staticintplus(int x, int y){}
int field1;
voidmethod1(){}
staticint field2;
staticvoidmethod2(){}
static { // 정적 블록
field1 = 10; // 컴파일 에러
method1(); // 컴파일 에러
field2 = 10; // 같은 정적만 가능
method2(); // 같은 정적만 가능
}
staticvoidMethod3(){
this.field1 = 10; // 컴파일 에러this.method1(); // 컴파일 에러
field2 = 10; // 같은 정적만 가능
method2(); // 같은 정적만 가능
}
publicvoidstaticmain(String args[]){ // main도 static이라 바로 field1에 접근할 수 없어서 객체를 생성하고 접근해야 한다.
Test t = new Test();
t.field1 = 20;
}
}
싱글톤
객체가 단 하나만 생성됨을 보장하는 객체를 싱글톤이라고 한다.
객체를 아무리 생성해도 같은 객체를 반환하여 같은 객체임을 보장한다.
public class Test {
// 정적 필드
private static Test singleton = new Test();
// 생성자
public Test() { }
// 정적 메서드
public Test getInstance() {
return singletone;
}
}
final 필드
최종의 마지막의 뜻으로 최종적인 필드, 메서드임을 의미하여 객체가 생성되고 한번 초기화 되면 바꿀 수 없음을 말한다.
final 필드는 객체마다 저장되고, 생성자의 매개값을 통해서 여러 가지 값을 가질수 있기 때문에 상수가 될 수 없다.
상수(static final)
불변의 값을 상수라고 하며 선언과 동시에 한번 초기값이 저장되면 변경할 수 없다.
패키지
클래스를 체계적으로 관리하기 위해 패키지를 사용하며 파일을 넣어두는 폴더라고 생각하면 된다.
package 상위패키지.하위패키지.클래스; 로 작성된다.
회사에서는 보통 도메인 이름을 패키지로 한다. => com.otrodevym.test
규칙
숫자로 시작해서는 안 되고, _, $를 제외한 특수 문자를 사용해서는 안 된다.
java로 시작하는 패키지는 자바 표준 API에서만 사용하므로 사용해서는 안 된다.
모두 소문자로 작성하는 것이 관례이다.
패키지 선언이 포함된 클래스 컴파일
java의 컴파일 된 class 파일 위치를 잡는 방법이다.
cmd 기준
javac -d . // 현재 폴더 내에 생성
javac -d ..\bin // 현재 폴더와 같은 위치의 bin 폴더에 생성
javac -d C:\Temp\bin // C:\Temp\bin 폴더에 생성
접근 제한자
접근 제한
적용 대상
클래스 내부
동일 패키지
하위 클래스
그 외 영역
public
클래스, 필드, 생성자, 메서드
O
O
O
O
protected
필드, 생성자, 메서드
O
O
O
X
default
클래스, 필드, 생성자, 메서드
O
O
X
X
private
필드, 생성자, 메서드
O
X
X
X
public : 제한 없이 접근 가능
protected : 본인과 하위(자식) 클래스와 동일 패키지에서 접근 가능
default : 본인과 동일 패키지에서만 접근 가능
private : 본인만 접근 가능
Getter와 Setter 메서드
일반적으로 객체 지향 프로그래밍에서 객체의 외부에서 객체의 데이터를 읽고 변경할 수 있으면 객체의 무결성 결점이 깨질 수 있기 때문에 객체의 데이터는 객체 외부에서 직접적으로 접근하는 것을 막는다.