티스토리 뷰

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;
    }
}

 

 

최근에 올라온 글