객체 지향
- 컴퓨터가 수행하는 작업을 객체들 간의 상호작용으로 표현
- 클래스 혹은 객체들의 집합으로 프로그램 작성
캡슐화
- 객체를 캡슐로 싸서 그 내부를 보호하고 볼 수 없게 하는 것
상속
- 상위 개체의 속성을 하위 개체에 물려줌.
다형성
- 같은 이름의 메소드가 클래스나 객체에 따라 다르게 구현되는 것
- 메소드 오버로딩: 한 클래스 내에서 같은 이름이지만 다르게 작동하는 여러 메소드
- 메소드 오버라이딩: 슈퍼클래스의 메소드를 동일한 이름으로 서브 클래스마다 다르게 구현
클래스와 객체
- 클래스: 객체의 속성과 행위 선언. 객체를 만들어내기 위한 틀
- 객체를 클래스의 인스턴스라고 함.
- 객체들은 클래스에 선언된 동일한 속성을 가지지만 속성 값은 서로 다르다.
자바 클래스 만들기
클래스 구성
1. 클래스 구성
- class 키워드로 클래스 선언
2. 클래스 멤버
- 클래스의 구성 요소. 필드와 메소드
- 필드: 객체의 상태 값을 저장할 멤버 변수
- 메소드: 실행 가능한 함수이고 객체의 행위를 구현
3. 접근 지정자
- public: 다른 클래스에서 호출, 접근 가능하도록 공개
객체 생성과 활용
// 반지름과 이름을 가진 Circle 클래스를 작성하고,
// Circle 클래스의 객체 생성하기
public class Circle {
int radius; // 원의 반지름 필드
String name; // 원의 이름 필드
public double getArea() { // 멤버 메소드
return 3.14*radius*radius;
}
public static void main(String[] args) {
Circle pizza; // 객체에 대한 레퍼런스 변수 pizza 선언
pizza = new Circle(); // Circle 객체 생성
pizza.radius = 10; // 피자의 반지름을 10으로 설정
pizza.name = "자바피자"; // 피자의 이름 설정
double area = pizza.getArea(); // 피자의 면적 알아내기
System.out.println(pizza.name + "의 면적은 " + area);
Circle donut = new Circle(); // Circle 객체 생성
donut.radius = 2; // 도넛의 반지름을 2로 설정
donut.name = "자바도넛"; // 도넛의 이름 설정
area = donut.getArea(); // 도넛 면적 알아내기
System.out.println(donut.name + "의 면적은 " + area);
}
}
1. 레퍼런스 변수 선언
Circle pizza;
// 레퍼런스 변수 pizza 선언
2. 객체 생성
pizza = new Circle();
// new 연산자를 사용하여 Circle 객체 생성
3. 객체 멤버 접근
객체레퍼런스.멤버
pizza.radius = 10; // pizza 객체의 radius 값을 10으로 설정
pizza.name = "자바피자"; // pizza 객체의 name에 "자바피자" 대입
double area = pizza.getArea(); // pizza 객체의 getArea() 메소드 호출
생성자
- 객체가 생성될 때 초기화 목적으로 실행되는 메소드
- 객체가 생성되는 순간 자동 호출 (리턴값 X)
package test1;
public class Circle2 {
int radius;
String name;
public Circle2() { // 매개변수 없는 생성자
radius = 1; name= ""; // radius의 초기값은 1
}
public Circle2(int r, String n) { // 매개변수를 가진 생성자
radius = r; name = n; // radius와 name 필드 초기화
}
public double getArea() {
return 3.14 * radius * radius;
}
public static void main(String[] args) {
Circle2 pizza = new Circle2(10, "자바피자"); // Circle2 객체 생성, 반지름 10
double area = pizza.getArea();
System.out.println(pizza.name + "의 면적은 " + area);
Circle2 donut = new Circle2(); // Circle2 객체 생성, 반지름 1
donut.name = "도넛피자";
area = donut.getArea();
System.out.println(donut.name + "의 면적은 " + area);
}
}
- 생성자 이름은 클래스 이름과 동일하다.
- 생성자를 여러 개 작성할 수 있다.
- 생성자는 객체를 생성할 때 한 번만 호출된다.
- 생성자에 리턴 타입을 지정할 수 없다.
- 생성자의 목적은 객체가 생성될 때, 필요한 초기 작업을 위함이다.
기본 생성자
class Circle {
public Circle() { } // 기본 생성자
}
- 매개 변수가 없고 실행 코드가 없어 아무 일도 하지 않고 단순 리턴하는 생성자
- 디폴트 생성자라고도 부른다.
- 클래스에 생성자가 하나도 선언되어 있지 않은 경우, 컴파일러는 기본 생성자를 자동으로 생성한다.
this 레퍼런스
- 객체 자신에 대한 레퍼런스로서 메소드 안에서 사용된다.
- 현재 객체를 가리킨다.
- static 메소드에서는 사용할 수 없다.
class Circle {
int radius;
public Circle() { this.radius = 1; }
public Circle(int radius) { this.radius = radius; }
public double getArea() { return 3.14*this.radius*this.radius; }
...
}
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 littePrince = new Book("어린왕자", "생텍쥐페리");
Book loveStory = new Book("춘향전");
Book emptyBook = new Book();
loveStory.show();
}
}
객체 배열
- 객체에 대한 레퍼런스를 원소로 갖는 배열
// 5개의 Circle 객체 배열을 생성하고 활용하는 코드
Circle [] c; // Circle 배열에 대한 레퍼런스 변수 c 선언
c = new Circle[5]; // 레퍼런스 배열 생성
for (int i=0; i<c.length; i++)
c[i] = new Circle(i); // 각 원소 객체 생성
for (int i=0; i<c.length; i++)
System.out.print((int)(c[i].getArea()) + " "); // 배열의 원소 객체 사용
배열 선언 및 생성
1. 배열에 대한 레퍼런스 선언
- 레퍼런스 변수만 선언할 뿐 배열을 생성하는 것은 아니기 때문에 배열의 개수를 지정하면 안 된다.
Circle [] c;
2. 레퍼런스 배열 생성
c = new Circle[5]; // Circle 객체에 대한 레퍼런스 5개 생성
3. 객체 생성
- 다음 코드는 Circle 객체를 하나씩 생성하여 배열 c[]의 각 레퍼런스에 대입한다.
for (int i=0; i<c.length; i++)
c[i] = new Circle(i);
배열의 원소 객체 접근
- 다음과 같이 배열 c의 i번째 객체를 접근하기 위해서는 c[i] 레퍼런스를 사용한다.
for (int i=0; i<c.length; i++)
System.out.print((int)(c[i].getArea()) + " ");
메소드 활용과 객체 치환
메소드 형식
1. 접근 지정자
- public: 클래스 내부/외부에서 모두 호출 가능
- private: 클래스 멤버들만 호출 가능
- protected: 동일한 패키지의 클래스들과 상속받은 서브 클래스에서 호출 가능
- 디폴트 접근 지정(생략): 동일한 패키지 내의 모든 클래스에서 호출 가능
2. 리턴 타입
- 메소드가 호출자에게 리턴할 값의 타입
인자 전달
- 값에 의한 호출 (call-by-value)
- 호출하는 실인자의 값이 복사되어 메소드의 매개 변수에 전달된다.
1. 기본 타입의 값이 전달되는 경우
- 호출자가 건네는 값이 메소드의 매개 변수에 복사되어 전달
public class CallbyValue {
public static void main(String[] args) {
int n = 10;
increase(n); // increase 메소드 호출
System.out.println(n); // increase()가 끝나고 지역 변수 n의 값은 여전히 10
}
// 실행될 때, 매개 변수 m이 생기고 n의 값을 전달받아 10으로 초기화
static void increase(int m) {
m = m + 1; // m의 값을 1 증가시키지만, 변수 n의 값을 바꾸지는 못한다.
}
}
2. 객체가 전달되는 경우
- 객체의 레퍼런스 값이 전달된다.
public class ReferencePassing {
public static void main(String[] args) {
Circle pizza = new Circle(10);
increase(pizza); // increase 메소드 호출
System.out.println(pizza.radius); // 11 출력
}
// 매개변수 m이 생기고, pizza 변수에 저장된 값(레퍼런스)이 m에 복사되어,
// m은 pizza가 가리키는 객체를 함께 가리키게 된다.
static void increase(Circle m) {
m.radius++; // radius는 11로 변경되고 increase()가 종료해도 그대로 남는다.
}
}
3. 배열이 전달되는 경우
- 배열에 대한 레퍼런스만 전달된다.
public class ArrayPassing {
public static void main(String[] args) {
int a[] = {1, 2, 3, 4, 5};
increase(a);
for (int i=0; i<a.length; i++)
System.out.print(a[i] + " ");
}
// 매개변수 array는 정수형 배열에 대한 레퍼런스로서
// 배열 a를 가리키게 되어 두 레퍼런스는 하나의 배열을 공유한다.
static void increase(int[] array) {
for (int i=0; i<array.length; i++)
array[i]++;
}
}
메소드 오버로딩
- 클래스 내에 이름이 같지만 매개 변수의 타입이나 개수가 서로 다른 여러 개의 메소드
- 메소드의 리턴 타입은 상관없음.
public static void main(String args[]) {
MethodSample a = new MethodSample();
int i = a.getSum(1, 2);
int j = a.getSum(1, 2, 3);
double k = a.getSum(1.1, 2.2);
}
public class MethodSample {
public int getSum(int i, int j) {
return i + j;
}
public int getSum(int i, int j, int k) {
return i + j + k;
}
public double getSum(double i, double j) {
return i + j;
}
}
객체 치환 시 주의할 점
- 객체의 치환은 객체를 복사하는 것이 아니다.
public class Samp {
int id;
public Samp(int x) {this.id = x;}
public void set(int x) {this.id = x;}
public int get() {return this.id;}
public static void main(String[] args) {
Samp ob1 = new Samp(3);
Samp ob2 = new Samp(4);
Samp s;
s = ob2;
// 객체의 치환. s는 ob2의 객체를 가리킴
ob1 = ob2;
// 객체의 치환. ob1은 ob2의 객체를 가리키게 됨
// 원래 ob1이 가리키던 객체는 아무것도 가리키지 않게 되어,
// 더이상 프로그램에서 접근할 수 없는 상태가 된다. => 가비지
System.out.println("ob1.id="+ob1.get());
System.out.println("ob2.id="+ob2.get());
}
}
가비지
- 참조하는 레퍼런스가 하나도 없는 객체나 배열
- 프로그램에서 더이상 접근할 수 없다.
가비지 컬렉션
- 가비지가 많아지면 응용 프로그램에게 할당해줄 수 있는 가용 메모리의 양이 줄어든다.
- 가비지가 점점 늘어나 가용 메모리가 0이 되면, 자바 응용프로그램은 더이상 실행할 수 없다.
- 가용 메모리 공간이 일정 크기 이하로 줄어들면, 자바 가상 기계는 자동으로 가비지를 회수하여 가용 메모리 공간을 늘린다.
가비지 컬렉션 강제 수행
- System 또는 Runtime 객체의 gc() 메소드 호출
Systme.gc() // 가비지 컬렉션 자동 요청
접근 지정자
패키지
- 자바에서는 상호 관련 있는 클래스 파일들을 패키지에 저장하여 관리한다.
- 자바 프로그램은 하나 이상의 패키지로 구성된다.
접근 지정자
- private (외부로부터 완벽 차단)
- 디폴트 (동일 패키지 허용)
- protected (동일 패키지 + 자식 클래스 허용)
- public (모든 클래스)
static 멤버
특성
- 클래스당 하나만 생성되는 멤버
- 동일한 클래스의 모든 객체들이 공유
- 클래스 멤버라고 부름. (non-static 멤버는 인스턴스 멤버)
- 객체가 생성하기 전, 소멸된 후에도 static 멤버는 공간을 차지하고 있다. (외부에 별도로 존재)
사용
- 객체 이름이나 클래스 이름으로 모두 활용할 수 있다.
StaticSample.m = 3; // 클래스 이름으로 static 필드 접근
StaticSample.f(); // 클래스 이름으로 static 메소드 호출
활용
- 전역 변수와 전역 함수를 만들 때 활용
- 공유 멤버를 만들고자 할 때 활용
제약 조건
- static 메소드는 오직 static 멤버만 접근할 수 있다.
- static 메소드에서는 this를 사용할 수 없다.
final
final 클래스
- 더이상 클래스 상속 불가능
final 메소드
- 더이상 오버라이딩 불가능
final 필드
- 상수 선언
- 초기값 지정. 실행중 값 변경 X
'Language > Java' 카테고리의 다른 글
[Java] 상속 (0) | 2022.02.23 |
---|---|
[Java] 배열 / 예외처리 (0) | 2022.02.10 |
[Java] 자바 기본 프로그래밍 (프로그램 구조, 데이터 타입, 키 입력) (0) | 2022.02.05 |