티스토리 뷰
6.1 객체지향 프로그래밍
객체지향 프로그래밍: 부품에 해당하는 객체들을 먼저 만들고 이 객체들을 하나씩 조립해서 만드는 프로그램
객체object
- 물리적으로 존재하거나 개념적인 것 중에서 다른 것과 식별 가능한 것
- 객체는 속성(필드)와 동작(메소드)로 구성되어 있음
- 객체 모델링: 현실 세계의 객체를 소프트웨어 객체로 설계하는 것
객체의 상호작용
- 현실 세계의 현상은 객체와 객체의 상호작용으로 이루어져 있음
- 객체들 사이의 상호작용 수단은 메소드
- 메소드 호출을 통해 객체들은 데이터를 주고 받음
메소드(매개값1, 매개값2...)
매개값: 메소드와 함께 전달하고자 하는 데이터
리턴값: 메소드의 실행 결과로 호출한 곳으로 돌려주는 값
객체 간의 관계
집합 관계
- 완성품과 부품의 관계
- 예를 들면 자동차는 엔진, 다이어, 핸들 등의 부품으로 구성된 완성품이다
사용 관계
- 다른 객체의 필드를 읽고 변경하거나 메소드를 호출하는 관계
- 예를 들면 사람과 자동차의 관계가 있음
상속 관계
- 부모와 자식 관계
- 자동차가 기계의 특징을 물려받는 다면 기계(부모)와 자동차(자식) 관계가 된다
객체지향 프로그래밍의 특징
캡슐화
- 실제 구현 내용을 외부에 감추는 것
- 외부 객체는 객체 내부의 구조를 알지 못 한다
- 외부의 잘못된 사용으로 인해 객체가 손상되지 않도록 하기 위해서 사용
- 접근제한자를 사용
상속
- 부모 객체는 자기가 가지고 있는 필드와 메소드를 자식 객체에서 물려주어 자식 객체가 사용할 수 있도록 함
- 코드의 재사용성을 높여준다 - 중복 코딩을 하지 않아도 된다
- 유지 보수 시간을 최소화한다
다형성
- 실행 결과가 다양하게 나오는 성칠
- 자동 타입 변환과 재정의 기술을 통해 구현
6.2 객체와 클래스
- 객체를 생성하려면 설계도에 해동하는 클래스가 필요
- 인스턴스: 클래스를 통해 생성된 객체
- 인스턴스화: 클래스로부터 객체를 만드는 과정
- 동일한 클래스에서 여러 개의 인스턴스를 만들 수 있음
6.3 클래스 선언
- 어떻게 객체를 생성(생성자)하고
- 객체가 가져야 할 데이터(필드)가 무엇이고
- 객체의 동작(메소드)는 무엇인지를 정의하는 내용이 포함된다
- 클래스 선언은 소스 파일명과 동일해야 함
- 하나의 소스 파일은 여러 개의 클래스 선언을 할 수 있음
- 이 때, 소스 파일명과 동일한 클래스만 public 클래스로 선언할 수 있음
- 바이트 코드 파일은 클래스 선언 수만큼 생성
package ch06.sec03; // 패키지 선언
public class SportsCar { // 클래스 선언
}
class Tire { // 파일 이름가ㅗ 다를 때는 public를 안 써준다
}
6.4 객체 생성과 클래스 변수
new 연산자: 객체로부터 클래스를 생성할 때 사용하는 연산자, 객체를 생성한 후 객체의 주소를 리턴
클래스 변수 = new 클래스();
- 라이브러리 클래스: 실행할 수 없으며 다른 클래스에서 이용하는 클래스
- 실행 클래스: main()메소드를 가지고 있는 실행 가능한 클래스
// 실행 클래스
public class FieldDemo {
public static void main(String[] args) {
// 객체 생성
// 클래스 변수 = new 클래스();
Car car1 = new Car();
}
}
// 라이브러리 클래스
class Car {
String model;
boolean start;
int speed;
}
6.5 클래스의 구성 멤버
- 구성 멤버: 생성자 + 필드 + 메소드
- 생성자: 객체 초기화 역할을 담당, 리턴 타입이 없고 이름은 클래스 이름과 동일
- 필드: 객체의 데이터를 저장
- 메소드: 객체가 수행할 동작
필드와 로컬 변수의 차이점
필드 | 로컬 변수 | |
선언 위치 | 클래스 선언 블록 | 생성자, 메소드 선언 블록 |
존재 위치 | 객체 내부에 존재 | 생성자, 메서드 호출 시에만 존재 |
사용 위치 | 객체 내, 외부에서 사용 가능 | 생성자, 메소드 블록 내부에서만 사용 가능 |
6.6 필드 선언과 사용
필드 선언
- 클래스 내부에서 선언해야 함
- 초기값을 제공하지 않을 경우 객체 생성 시 자동으로 기본값으로 초기화된다
정수 타입 | 0 |
실수 타입 | 0.0 |
boolean 타입 | false |
참조 타입 | null |
필드 사용
- 필드값을 읽고 변경한다는 것
- 클래스로부터 객체가 생성된 후에 필드를 사용할 수 있음
- 내부, 외부에서 사용 가능
public class FieldDemo {
public static void main(String[] args) {
// 객체 생성
Car car = new Car();
System.out.println(car.modelString); // 초기값 null
System.out.println(car.speed); // 초기값 0
System.out.println(car.start); // 초기값 false
// 외부에서 필드 사용
car.modelString = "현대";
}
}
class Car {
// 필드 선언
String modelString;
int speed;
boolean start;
// 내부 메서드에서 필드 사용
void upSpeed() {
speed = 100;
}
}
6.7 생성자 선언과 호출
- new 연산자를 객체를 생성한 후 연이어 생성자를 호출해서 객체를 초기화 하는 역할을 한다.
- 객체 초기화: 필드 초기화를 하거나 메소드를 호출해서 객체를 사용하라 준비를 하는 것
- 기본 생성자: 클래스에 생성자 선언이 없으면 컴파일러가 자동으로 생성자를 추가해줌
생성자 선언
- 개발자가 직접 선언할 수 있음
- 리턴 타입이 없고 클래스 이름과 동일
필드 초기화
- 객체마다 다른 값을 가져야 한다면 생성자에서 필드를 초기화하는 것이 좋다
- this 키워드는 현재 객체를 말한다
생성자 오버로딩
- 매개변수를 달리하는 생성자를 여러 개 선언하는 것
public class CarDemo {
public static void main(String[] args) {
// Car car = new Car(); 매개값이 있을 경우 기본 생성자는 사용할 수 없음
// 생성자를 호출해 객체 만들기
Car car = new Car("모델");
}
}
class Car {
String model;
int speed;
// 객체마다 동일한 값은 초기화 해주는 것이 좋다
String company = "자동차 회사";
// 객체마다 다른 값이 필요할 경우는 생성자를 통해 기본값을 대입
// 매개값이 있는 생성자
public Car(String model, int speed) {
this.model = model;
this.speed = speed;
}
// 생성자 오버로딩, 필요한 매개값만 사용할 수 있음
public Car(String model) {
// this는 현재 객체를 말함
this.model = model;
}
}
다른 생성자 호출
- 생성자가 많아질 경우 중복된 코드가 발생할 수 있음
- 공통 코드를 한 생성자에게만 집중적으로 작성하고 나머지는 this를 사용항 공통 코드를 가지고 있는 생성자를 호출하는 방법으로 개선할 수 있음
- this생성자는 생성자의 첫 줄에 작성
6.8 메소드 선언과 호출
- 메소드 선언: 객체의 독장을 실행 블록으로 정의
- 메소드 호출: 실행 블록을 실제로 실행
- 객체 내부에서도 호출되고, 다른 객체에서도 호출될 수 있음
메소드 선언
- 리턴타입: 리턴값이 없을 때는 void로 작성
- 메소드명: 소문자+캐멀스타일
- 매개변수
- 실행 블록
메소드 호출
- 객체 내부에서는 메소드명으로 호출
- 외부 객체에서는 참조 변수와 도트 연산자를 이용해 호출
class CaluclatorDemo {
public static void main(String[] args) {
Calculator caluclator = new Calculator();
// 메소드 호출
caluclator.powerOn();
int plus = caluclator.plus(3, 6);
System.out.println(plus);
}
}
class Calculator {
// 매개값이 없고 반환값이 없는 메서드
void powerOn() {
System.out.println("실행");
}
// 매개값이 있고 반환값이 있는 메서드
int plus(int x, int y) {
return x + y;
}
}
가변길이 매개변수
- 매개변수의 개수와 상관 없이 매개값을 줄 수 있음
- 매개값들은 자동으로 배열 항복으로 변환되어 사용되기 때문에 배열을 매개값으로 제공해도 된다
public class ComputerDemo {
public static void main(String[] args) {
Computer computer = new Computer();
int sum = computer.sum(1, 2, 3, 4, 5);
System.out.println(sum);
}
}
class Computer {
// 가변길이 매개변수를 갖는 메소드 선언
int sum(int...values) {
int sum = 0;
// 가변길이 매개변수는 배열 처럼 사용
for (int value : values) {
sum += value;
}
return sum;
}
}
return문
- 실행을 강제 종료하고 호출한 곳으로 돌아간다는 의미
- return문 이후의 실행문은 실행되지 않는다.
메소드 오버로딩
- 메소드 이름은 같되, 매개변수의 타입, 개수, 순서가 다른 메소드를 여러 개 선언하는 것
- 리턴 타입 무관
- 다양한 매개값을 처리하기 위해서 사용
class Calculator2 {
// 같은 이름이지만 매개값이 다르다
double areaRectangle(double width) {
return width * width;
}
double areaRetangle(double width, double height) {
return width * height;
}
}
6.9 인스턴스 멤버
인스턴스 멤버 | 객체에 소속된 멤버 객체를 생성해야만 사용할 수 있음 |
정적 멤버(static 멤버) | 클레스에 고저오딘 멤버 객체 없이도 사용할 수 있음 |
인스턴스 멤버 선언 및 사용
- 필드는 객체마다 따로 존재하고 메소드는 각 객체마다 존재하지 않고 메소드 영역에 저장되어 공유된다.
- 메소드는 코드 덩어리기 때문에 객체마다 저장하면 중복 저장으로 인해 메모리 효율이 떨어진다. 따라서 메소드 영역에 두고 공유해서 사용하되 객체 없이는 사용하지 못하도록 제한을 걸어둔 것.
this 키워드
- 객체 내부에서 인스턴스 멤버에 접근하기 위해 this 키워드를 사용
6.10 정적 멤버
정적 멤버: 메소드 영역의 클래스에 고정적으로 위치하는 멤버 -> 객체 생성 없이 사용 가능
정적 멤버 선언
- static 키워드를 추가
- 객체마다 가지고 있을 필요성이 없는 공용적인 필드를 정적 멤버로 선언하는 것이 좋음
- 인스턴스 필드를 사용하지 않는 메소드는 정적 메소드로 선언하는 것이 좋음
정적 멤버 사용
- 클래스 이름과 . 연산자로 접근
- 초기값을 주는게 일반적이지만 복잡한 초기화 작업은 정적 블록을 이용하는 것이 좋음
public class StaticDemo {
public static void main(String[] args) {
double result1 = 10 * Calculator.pi;
int result = Calculator.plus(10, 20);
System.out.println(Calculator.info);
}
}
class Calculator {
static double pi = 3.14;
static String info;
// 정적 블록
static {
info = "파이값은" + pi;
}
static int plus(int x, int y) {
return x + y;
}
}
인스턴스 멤버 사용 불가
- 정적 멤버는 객체 없이도 사용 가능하기 때문에 인스턴스 멤버를 내부에서 사용할 수 업음
- this도 사용 불가
- main() 메서드도 정적 메소드기 때문에 객체 생성 없이 인스턴스 필드와 메소드를 사용할 수 없음
6.11 final 필드와 상수
final 필드
- 값을 변경하는 것을 막고 읽기만 허용
- final필드는 프로그램 실행 도중 수정 불가
- 필드 선언 시 초기값 대입하거나 생정자에서 초기값을 대입
public class FinalDemo {
public static void main(String[] args) {
Korean korean = new Korean("123456789");
// 상수는 값 변경할 수 없
// korean.nation = "미국";
// korean.ssn = "987456";
}
}
class Korean {
// 필드 선언 시 초기값 대입
final String nation = "한국";
final String ssn;
//생성자에서 초기값 대입
public Korean(String ssn) {
this.ssn = ssn;
}
}
상수
- 상수는 불변의 값을 저장하는 필드로 객체마다 저장할 필요가 없고 여러 개의 값을 가져도 안되기 때문에 static+final
- 상수는 모두 대문자로 작성하며 언더바를 사용
public class EarthDemo {
public static void main(String[] args) {
// 상수값 사용
System.out.println(Earth.EARTH_RADIUS);
}
}
class Earth {
// 상수 선언 및 초기화
static final double EARTH_RADIUS = 6400;
// 상수 선언
static final double EARTH_SAURFACE_AREA;
// 정적 블록에서 상수 초기화
static {
EARTH_SAURFACE_AREA = 4 * EARTH_RADIUS;
}
}
6.12 패키지
- 패키지는 클래스의 일부분이며 클래스를 식별하는 요도로 사용
- 도멘인 이름의 역순으로 만든다.
- 상위 패키지와 하위 패키지를 도트(.)로 구분
- 클래스의 전체 이름에 포함
- com.mycompany패키지 에 Car 클래스가 있을 때 전체 이름은 com.mycompany.Car
패키지 선언
- 컴파일하는 과정에 자동으로 생성
- 소스 파일 최상단에 위치
- 소문자로 시작, 회사 도메인 역순, 마지막에는 프로젝트 이름 작성하는 것이 관례
import문
- 같은 패키지에선 조건 없이 사용 가능
- 하짐나 다른 패키지에 있는 클래스를 사용하려면 import문을 이용해서 명시해야 함
- 패키지 선언과 클래스 선언 사이에 위치
- 동일 패키이에 포함된 다수의 클래스를 사용해야 한다면 클래스 이름 생략 후 * 를 쓰면 된다.
6.13 접근 제한자
객체의 무결성을 유지하기 위해 사용
제한 대상 | 제한 범위 | |
public | 클래스, 필드, 생성자, 메소드 | 없음 |
protected | 필드, 생성자, 메소드 | 같은 패키지이거나 자식 객체만 사용 가능 |
(default) | 클래스, 필드, 생성자, 메소드 | 같은 패키지에서만 사용 가능 |
private | 필드, 생성자, 메소드 | 패키지 내부 |
클래스의 접근 제한
- public 접근 제한자를 생략했다면 (default) 접근 제한
- (default) 은 같은 패키지에서만 사요 가능
- public은 같은 패키지 뿐만 아니라 다른 패키지에서도 사용 가능
생성자의 접근 제한
public | 모든 패키지에서 생성자 호출 가능 = 모든 패키지에서 객체 생성 가능 |
(default) | 같은 패키지에서만 생성자 호출 가능 = 같은 패키지에서만 객체 생성 가능 |
private | 클래스 내부에서만 생성자 호출 가능 = 클래스 내부에서만 객체 생성 가능 |
필드와 메소드의 접근 제한
public | 모든 패키지에서 필드 및 메소드 사용 가능 |
(default) | 같은 패키지에서만 필드 및 메소드 사용 가능 |
private | 클래스 내부에서만 필드 및 메소드 사용 가능 |
6.14 Getter 와 Setter
- 객체의 필드를 외부에서 손쉽게 읽고 변경할 경우 객체의 무결성이 깨질 수 있음
- 따라서 멧드를 통해 필드에 접근하는 것을 선호
- 메소드가 데이터를 검증해서 유효한 값만 저장할 수 있도록 하기 때문이다.
- Setter: 값 저장
- Getter: 값 읽기
package beginnerJava.src.ch06.sec14;
class Car {
private int speed;
private boolean stop;
// get으로 시작하는 것이 관례
public int getSpeed() {
return speed;
}
public void setSpeed(int speed) {
this.speed = speed;
}
// boolean 일 때는 is로 시작하는 것이 관례
public boolean isStop() {
return stop;
}
public void setStop(boolean stop) {
this.stop = stop;
}
}
public class CarDemo {
public static void main(String[] args) {
Car myCar = new Car();
myCar.setSpeed(100);
System.out.println(myCar.getSpeed()); // 100 출력
myCar.setStop(true);
System.out.println(myCar.isStop()); // true 출력
}
}
6.15 싱글톤 패턴
- 애플리케이션 전체에서 단 한 개의 객체만을 생성해서 사용하고 싶을 때 사용하는 패턴
- 외부에서 new 연산자로 생성자를 호출할 수 없도록 private를 사용
- 외부에서는 마음대로 객체를 생성할 수 없고, 객체를 사용하기 위해서는 정적 메소드를 통해 얻을 수 있음
public class SingletoneDemo {
public static void main(String[] args) {
Singletone s1 = Singletone.getSingletone();
Singletone s2 = Singletone.getSingletone();
// 같은 객체를 참조하기 때문에 같은 객체입니다 가 출력
if (s1 == s2) System.out.println("같은 객체입니다");
else System.out.println("다른 객체입니다.");
}
}
class Singletone {
private static Singletone singletone = new Singletone();
public Singletone() {}
public static Singletone getSingletone(){
return singletone;
}
}
'도서 및 강의 > 이것이 자바다' 카테고리의 다른 글
이것이 자바다 3판 챕터 8 (2) | 2024.09.17 |
---|---|
이것이 자바다 3판 챕터 7 (0) | 2024.09.17 |
이것이 자바다 3판 챕터 5 (0) | 2024.08.25 |
이것이 자바다 3판 챕터 4 (0) | 2024.08.25 |
이것이 자바다 3판 챕터 3 (0) | 2024.08.25 |
최근에 올라온 글