4.1 객체 지향과 자바
세상 모든 것이 객체다.
자바의 객체 지향 특성
▶ 캡슐화(encapsulation): 객체를 캡슐로 싸서 그 내부를 보호하고 볼 수 없게 만든 것
- 클래스(class): 객체의 모양을 선언한 틀
- 실체(instance): 객체
▶ 상속(inheritance): 상위 객체의 속성이 하위 객체에 물려져서, 하위 개체가 상위 개체의 속성을 모두 가지는 관계
- 확장(extends): 자식 클래스가 부모 클래스의 속성을 물려받아 부모 클래스에 기능을 확장하는 것
- 슈퍼 클래스(super class): 부모 클래스
- 서브 클래스(sub class): 자식 클래스
: 상속은 슈퍼클래스에 만들어진 필드와 메소드를 물려받음으로써 코드의 중복 작성을 방지하고, 코드를 재사용함으로써 코드 작성에 드는 시간과 비용을 줄인다.
▶ 다형성(polymorphism): 같은 이름의 메소드가 클래스 혹은 객체에 따라 다르게 구현되는 것
- 메소드 오버라이딩(overriding): 슈퍼클래스에서 구현된 메소드를 서브클래스에서 자신의 특징에 맞게 동일한 이름으로 다시 구현하는 것
- 메소드 오버로딩(overloading): 클래스 내에서 같은 이름의 메소드를 여러 개 만드는 것
객체 지향 언어의 목적
- 소프트웨어의 생산성 향상
- 실세계에 대한 쉬운 모델링
절차 지향 프로그래밍 & 객체 지향 프로그래밍
- 절차 지향 프로그래밍: C언어처럼 실행하고자 하는 절차를 정하고, 이 절차대로 프로그래밍하는 방법
- 객체 지향 프로그래밍: 실세상의 물체를 객체로 표현하고, 이들 사이의 관계, 상호작용을 프로그램으로 나타내는 방법
--> 객체를 추출하고, 객체들의 관계를 결정하고, 이들의 상호작용에 필요한 함수(메소드)와 변수(필드)를 설계 및 구현한다.
클래스와 객체
- 클래스: 객체를 만들어내기 위한 설계(틀)
- 인스턴스(instance): 클래스에 선언된 모양 그대로 생성된 실체 (= 객체)
4.2 자바 클래스 만들기
자바 클래스 구성
- 클래스 멤버
- 필드(field): 객체의 상태 값을 저장할 멤버 변수
- 메소드(method): 실행 가능한 함수
- 접근 지정자: 클래스에 대한 접근 권한 설정
객체 생성과 활용
// 예제 4-1
// 반지름과 이름을 가진 Circle 클래스를 작성하고, Circle 클래스의 객체를 생성하라.
public class Circle {
int r; // 원의 반지름 필드
String name; // 원의 이름 필드
public double getArea() { // 멤버 메소드
return 3.14*r*r;
}
public static void main(String[] args) {
// 피자
Circle pizza = new Circle(); // 객체에 대한 레퍼런스 변수 pizza
pizza.r = 10;
pizza.name = "자바피자";
double area = pizza.getArea();
System.out.println(pizza.name + "의 면적은 " + area);
// 도넛
Circle donut = new Circle();
donut.r = 3;
donut.name = "자바도넛";
area = donut.getArea();
System.out.println(donut.name + "의 면적은 " + area);
}
}
// 예제 4-2
// 너비와 높이를 입력받아 사각형의 면적을 출력하는 프로그램
import java.util.Scanner;
class Rectangle{
int w;
int h;
public int getArea() {
return w*h;
}
}
public class RectangleApp {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
Rectangle rect = new Rectangle();
System.out.print(">>");
rect.w = scanner.nextInt();
rect.h = scanner.nextInt();
System.out.println("사각형의 면적은 " + rect.getArea());
scanner.close();
}
}
4.3 생성자
생성자의 개념과 목적
- 생성자: 객체가 생성될 때 초기화를 위해 실행되는 메소드
생성자 작성 및 활용
// 예제 4-3
// 두 개의 생성자를 가진 Circle_ 클래스
public class Circle_ {
int radius;
String name;
// 생성자 이름 = 클래스 이름
public Circle_() { // 매개변수가 없는 생성자
radius = 3; // r의 초기값은 1
name = " ";
}
public Circle_(int r, String n) { // 매개변수를 가진 생성자
radius = r;
name = n;
}
public double getArea() {
return 3.14*radius*radius;
}
public static void main(String[] args) {
Circle_ pizza = new Circle_(10, "자바피자");
double area = pizza.getArea();
System.out.println(pizza.name + "의 면적은 " + area);
Circle_ donut = new Circle_();
donut.name = "자바도넛";
area = donut.getArea();
System.out.println(donut.name + "의 면적은 " + area);
}
}
// 예제 4-4
// title과 author 필드를 가진 Book 클래스를 작성하고, 생성자를 작성하여 필드를 초기화하라.
public class Book {
String title;
String author;
// 생성자1
public Book(String t) {
title = t;
author = "작자미상";
}
// 생성자2
public Book(String t, String a) {
title = t;
author = a;
}
public static void main(String[] args) {
Book littlePrince = new Book("어린왕자", "생텍쥐페리");
Book loveStory = new Book("춘향전");
System.out.println(littlePrince.title +", " + littlePrince.author);
System.out.println(loveStory.title + ", " + loveStory.author);
}
}
기본 생성자(dafault constructor)
- 기본 생성자(default constructor): 매개변수가 없고, 실행코드가 없어서 아무 일도 하지 않고 단순 리턴하는 생성자
this 레퍼런스
- this: 객체 자신에 대한 레퍼런스
this()로 다른 생성자 호출
// 예제 4-5
// this()로 다른 생성자 호출
public class Book_ {
String title;
String author;
void show() {
System.out.println(title + ", " + author);
}
public Book_() {
this(" ", " ");
System.out.println("생성자 호출됨");
}
public Book_(String title) {
this(title, "작자미상");
}
public Book_(String title, String author) {
this.title = title;
this.author = author;
}
public static void main(String[] args) {
Book_ littlePrince = new Book_("어린왕자", "생텍쥐페리");
Book_ loveStory = new Book_("춘향전");
Book_ emptyBook = new Book_();
loveStory.show();
}
}
4.4 객체 배열
객체 배열
- 객체 배열: 객체에 대한 레퍼런스를 원소로 갖는 배열
객체 배열 선언 및 생성
배열의 원소 객체 접근
// 예제 4-6
// 반지름이 0~4인 Circle 객체 5개를 가지는 배열을 생성하고, 배열에 있는 모든 Circle 객체 면적을 출력하라.
class Circle{
int radius;
public Circle(int radius) {
this.radius = radius;
}
public double getArea() {
return 3.14*radius*radius;
}
}
public class CircleArray {
public static void main(String[] args) {
Circle[] c = new Circle[5]; // Circle 배열에 대한 레퍼런스 배열
for(int i=0; i<c.length; i++)
c[i] = new Circle(i); // i번째 원소 객체
for(int i=0; i<c.length; i++)
System.out.print((int)(c[i].getArea()) + " ");
}
}
// 예제 4-7
// 2개짜리 객체 배열을 만들고, 사용자로부터 책의 제목과 저자를 입력받아 배열을 완성하라.
import java.util.Scanner;
class Book{
String title;
String author;
public Book(String title, String author) {
this.title = title;
this.author = author;
}
}
public class BookArray {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
Book[] mybook = new Book[2];
for(int i=0; i<mybook.length; i++) {
System.out.print("제목>>");
String title = scanner.nextLine();
System.out.print("저자>>");
String author = scanner.nextLine();
mybook[i] = new Book(title, author); // 배열 원소 객체 생성
}
for(int i=0; i<mybook.length; i++)
System.out.print("(" + mybook[i].title + ", " + mybook[i].author + ") ");
scanner.close();
}
}
4.5 메소드 활용과 객체 치환
메소드 형식
▶ 접근 지정자
: 자바에서 메소드는 반드시 접근 지정자와 함께 선언되어야 한다.
- public: 클래스 내부/외부에서 모두 호출 가능
- private: 클래스 멤버들만 호출 가능
- protected: 동일한 패키지의 클래스들, 상속받은 서브 클래스에서 호출 가능
- 디폴트 접근 지정: 동일한 패키지 내의 모든 클래스에서 호출 가능
▶ 리턴 타입
: 메소드가 호출자에게 리턴할 값의 타입
인자 전달
- 메소드 호출 시 인자 전달 방식(argument passing) - 값에 의한 호출(call-by-value)
: 호출하는 값이 복사되어 메소드의 매개 변수에 전달된다.
// 예제 4-8
// char[] 배열을 전달받아 배열 속의 공백(' ') 문자를 ','로 대치하는 메소드
public class ArrayPassing {
static void replaceSpace(char a[]) {
for(int i=0; i<a.length; i++)
if(a[i] == ' ')
a[i] = ',';
}
static void printCharArray(char a[]) {
for(int i=0; i<a.length; i++)
System.out.print(a[i]);
System.out.println();
}
public static void main(String[] args) {
char c[] = {'L', 'e', 'e', ' ', 'J', 'i', 'W', 'o', 'n'};
printCharArray(c);
replaceSpace(c);
printCharArray(c);
}
}
메소드 오버로딩
: 클래스 내에 이름이 같지만 매개 변수의 타입이나 개수가 서로 다른 여러 개의 메소드를 작성하는 것
객체 치환 시 주의할 점
- 객체의 치환은 객체를 복사하는 것이 아니며, 레퍼런스의 복사이다.
4.6 객체의 소멸과 가비지 컬렉션
객체의 소멸
: new에 의해 할당 받은 객체와 배열 메모리를 자바 가상 기계로 되돌려 주는 행위
가비지
: 가리키는 레퍼런스가 하나도 없는 객체 --> 더 이상 접근할 수 없어 사용될 수 없게 된 메모리
가비지 컬렉션(garbage collection)
: 자바 가상 기계가 가비지 자동 회수
가비지 컬렉션 강제 수행
: System 또는 Runtime 객체의 gc() 메소드 호출
System.gc(); // 가비지 컬렉션 작동 요청
4.7 접근 지정자
자바의 패키지 개념
- 패키지: 상호 관련 있는 클래스 파일(컴파일된 .class)을 저장하여 관리하는 디렉터리
접근 지정자(access specifier)
: 클래스나 멤버들을 다른 클래스에서 접근해도 되는지의 여부를 선언하는 지시어
- private, protected, public, 디폴트(접근지정자 생략)
클래스 접근 지정
: 다른 클래스에서 사용하도록 허용할 지 지정
- public 클래스: 패키지에 상관없이 다른 어떤 클래스에게도 사용이 허용됨
- 디폴트 클래스(접근 지정자 생략): 같은 패키지 내에 있는 클래스들에게만 사용이 허용됨
멤버 접근 지정
- public 멤버: 패키지를 막론하고 모든 클래스들이 접근 가능함
- private 멤버: 비공개 - 클래스 내의 멤버들에게만 접근 허용됨
- protected 멤버: 보호된 공개 - 패키지 내의 모든 클래스에서 접근 가능함, 다른 패키지에 있더라도 자식 클래스의 경우 접근 허용됨
- 디폴트 멤버: 동일한 패키지에 있는 클래스 내의 멤버들에게만 접근 허용됨
4.8 static 멤버
static 멤버 선언
static 멤버의 특성
- static 멤버는 클래스당 하나만 생성됨
- 객체들에 의해 공유됨
static 멤버 사용
static의 활용
- 전역변수, 전역함수
- 공유 멤버
// 예제 4-11
// 전역함수로 작성하고자 하는 abs, max, min의 3개 함수를 static 메소드를 작성하고 호출하는 사례
class Calc{
public static int abs(int a) {
return (a>0)?a:-a;
}
public static int max(int a, int b) {
return (a>b)?a:b;
}
public static int min(int a, int b) {
return (a>b)?b:a;
}
}
public class CalcEx {
public static void main(String[] args) {
System.out.println(Calc.abs(-5));
System.out.println(Calc.max(10,8));
System.out.println(Calc.min(-3, 8));
}
}
static 메소드의 제약 조건
- static 메소드는 오직 static 멤버만 접근 가능하다.
- static 메소드에서는 this를 사용할 수 없다.
4.9 final
final 클래스
: final이 클래스 이름 앞에 사용되면, 클래스를 상속받을 수 없음을 지정한다.
final 메소드
: 메소드 앞에 final이 붙으면, 이 메소드는 더 이상 오버라이딩할 수 없음을 지정한다.
final 필드
: 자바에서 final로 필드를 선언하면, 필드는 상수가 된다.
'Programming > Java프로그래밍및실습' 카테고리의 다른 글
[자프실] 6. 모듈과 패키지 개념, 자바 패키지 활용 (1) | 2024.01.05 |
---|---|
[자프실] 5. 상속 (1) | 2024.01.05 |
[자프실] 3. 반복문과 배열 그리고 예외 처리 (1) | 2024.01.02 |
[자프실] 2. 자바 기본 프로그래밍 (1) | 2023.12.28 |
자바에서 상수 키워드 final을 사용하는 이유: constant folding (0) | 2023.12.28 |