클래스와 객체 (2)
1. 메소드, 가비지
1) 메소드
- 메소드는 C/C++의 함수와 동일
- 자바의 모든 메소드는 반드시 클래스 안에 있어야 함(캡슐화 원칙)
- 다른클래스에서메소드를접근할수있는지여부선언
- public, private, protected, 디폴트(접근 지정자 생략)
리턴 타입
- 메소드가 리턴하는 값의 데이터 타입
2) 인자 전달__기본 타입의 값이 전달되는 경우
매개 변수가 byte, int, double 등 기본 타입으로 선언되었을 때, 호출자가 건네는 값이 매개 변수에 복사되어 전달. 실인자 값은 변경되지 않음
public class CallByValue {
public static void main(String args[]) {
int n = 10;
increase(n); // 호출
System.out.println(n);
}
static void increase(int m) {
m = m + 1;
}
}
실행결과
10
3) 인자 전달__객체가 전달되는 경우
매개 변수가 실인자 객체 공유
public class ReferencePassing {
public static void main (String args[]) {
Circle pizza = new Circle(10);
increase(pizza); // 호출
System.out.println(pizza.radius);
}
static vodi increase(Circle m) {
m.radius++;
}
}
실행결과: 11
4) 인자 전달__배열이 전달되는 경우
- 배열 레퍼런스만 매개 변수에 전달 : 배열 통째로 전달되지 않음
- 객체가 전달되는 경우와 동일 : 매개 변수가 실인자의 배열 공유
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] + " ")
}
static void increase(int[] array) {
for( int i = 0; i < array.length; i++)
array[i]++;
}
}
}
실행결과
2 3 4 5 6
public class ArrayParameter {
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[] = {'T','h','i','s',' ','i','s',' ','a',' ','p','e','n','c','i','l','.'};
printCharArray(c);
replaceSpace(c);
printCharArray(c);
}
}
실행결과
This is a pencil.
This,si,a,pencil.
5) 메소드 오버로딩 (Overloading)
한 클래스 내에서 두 개 이상의 이름이 같은 메소드 작성
- 메소드 이름이 동일하여야 함
- 매개변수의개수가서로다르거나,타입이서로달라야함
- 리턴 타입은 오버로딩과 관련 없음
6) 오버로딩과 메소드 호출
매개변수의 개수와 타입이 서로 다른 3 함수 호출
public static void main(String args[]) {
MethodSmaple a = new MethodSample();
int i = a.getSum(1, 2);
int j = a.getSum(1, 2, 3);
int 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;
}
}
오류
class MethodOverloadingFail { // 메소드 오버로딩이 실패한 사례
public int getSum(int i, int j) {
return i + j;
}
public double getSum(int i, int j) {
return (double)(i + j);
}
}
7) 객체 치환 시 주의할 점
객체 치환은 객체 복사가 아니며, 레퍼런스의 복사이다.
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) {
Smap ob1 - new Samp(3);
Smap ob2 - new Samp(4);
Samp s;
s = ob2;
ob1 = ob2; // 객체의 치환
System.out.println("ob1.id=" + ob1.get());
System.out.println("ob2.id=" + ob1.get());
}
}
실행결과
ob1.id=4
ob2.id=4
8) 객체 소멸
- new에 의해 할당 받은 객체와 배열 메모리를 자바 가상 기계로 되돌려 주는 행위 소멸된 객체 공간은 가용 메모리에 포함
- 자바에서 사용자 임의로 객체 소멸 안됨
- 자바는 객체 소멸 연산자 없음 (객체 생성 연산자 : new)
- 객체 소멸은 자바 가상 기계의 고유한 역할
- 자바 개발자에게는 매우 다행스러운 기능
- C/C++에서는 할당 받은 객체를 개발자가 프로그램 내에서 삭제해야 함
- C/C++의 프로그램 작성을 어렵게 만드는 요인
- 자바에서는 사용하지 않는 객체나 배열을 돌려주는 코딩 책임으로부터 개발자 해방
9) 가비지
- 가리키는 레퍼런스가 하나도 없는 객체
- 더이상접근할수없어사용할수없게된메모리
- 가비지 켈렉션
- 자바 가상 기계의 가비지 컬렉터가 자동으로 가비지 수집, 반환
public class GarbageEx {
public static void main(Stringp[] args) {
String a = new String("Good");
String b = new String("Bad");
String c = new String("Normal");
String d, e;
a = null;
d = c;
c = null;
}
}
객체만 생성된 경우 (6라인까지) : a,b,c 에 문자열 할당되었음
코드 전체 실행후 a를 nil로 선언하여 "Good"은 가비지가 되었음
c는 null 이 되었지만 d가 있기때문에 Normal은 가비지가 되지 않는다.
9) 가비지 컬렉션
- 자바 가상 기계가 가비지 자동 회수
- 가용메모리공간이일정이하로부족해질때
- 가비지를 수거하여 가용 메모리 공간으로 확보
- 가비지 컬렉터(garbage collector)에 의해 자동 수행
- 강제 가비지 컬렉션 강제 수행
- System 또는 Runtime 객체의 gc() 메소드 호출
- 이코드는자바가상기계에강력한가비지컬렉션요청
- 그러나자바가상기계가가비지컬렉션시점을전적으로판단
2. 접근 지정자
1) 접근지정자
- private, protected, public, 디폴트(접근 지정자 생략)
- 접근 지정자의 목적
- 클래스나 일부 멤버를 공개하여 다른 클래스에서 접근하도록 허용
- 객체지향언어의캡슐화정책은멤버를보호하는것
- 접근지정은캡슐화에묶인보호를일부해제할목적
- 접근 지정자에 따른 클래스나 멤버의 공개 범위
2) 클래스의 접근 지정
다른 클래스에서 사용하도록 허용할 지 지정
public 클래스
- 다른 모든 클래스에게 접근 허용
- 디폴트 클래스(접근 지정자 생략)
- package-private라고도 함
- 같은 패키지의 클래스에만 접근 허용
3) 멤버 접근 지정
- public 멤버 : 패키지에 관계 없이 모든 클래스에게 접근 허용
- private 멤버 : 동일 클래스 내에만 접근 허용, 상속 받은 서브 클래스에서 접 근 불가
- protected 멤버 : 같은 패키지 내의 다른 모든 클래스에게 접근 허용, 상속 받은 서브 클래스는 다른 패키지에 있어도 접근 가능
- 디폴트(default) 멤버 : 같은 패키지 내의 다른 클래스에게 접근 허용
멤버에 접근하는 클래스 | 멤버의 접근 지정자 | |||
private | 디폴트 접근 지정 | protected | public | |
같은 패키지의 클래스 | X | O | O | O |
다른 패키지의 클래스 | X | X | X | O |
접근 가능영역 | 클래스 내 | 동일 패키지 내 | 동일 패키지와 자식 클래스 |
모든 클래스 |
class SampleClass {
public int field1;
protected int field2;
int field3;
private int field4;
}
public class AccessEx {
public static void main(String[] args) {
SampleClass s = new SampleClass(); s.field1 = 0;
s.field2 = 1;
s.field3 = 2;
s.field4 = 3; //field4는 SampleClass의 private 멤버이므로 SampleClass 외의 다른 클래스에서 접근할 수 없다.
}
}
Failure
Exception in thread "main" java.lang.Error: Unresolved compilation problem: The field s.field4 is not visible at AccessEx.main(AccessEx.java:14)
3. static 멤버, final 키워드
1) static 멤버
static 멤버 선언
class StaticSample {
int n; // non-static 필드
void g() {...} // non-static 메소드
static int m; // static 필드
static void f() {...} // static 메소드
}
객체 생성과 non-static 멤버의 생성
- non-static 멤버는 객체가 생성될 때, 객체마다 생긴다.
2) static 멤버의 생성
- static 멤버는 클래스당 하나만 생성
- 객체들에 의해 공유됨
n, f() 는 객체들에 의해 공유되는 static
멤버
3) static 멤버와 non-static 멤버 특성 정리
non-static 멤버 | static 멤버 | |
---|---|---|
공간적 특성 | 멤버는 객체마다 별도 존재 - 인스턴스 멤버라고 부름 |
멤버는 클라스당 하나 생성 - 멤버는 객체 내부가 아닌 별도의 공간에 생성 - 클래스 멤버라고 부름 |
시간적 특성 | 객체 생서 시에 멤버 생성됨 - 객체가 생길 때 멤버도 생성 - 객체 생성 후 멤버 사용 가능 - 객체가 사라지면 멤버도 사라짐 |
클래스 로딩 시에 멤버 생성 - 객체가 생기기 전에 이미 생성 - 객체가 생기기 전에도 사용 가능 - 객체 가 사라져도 멤버는 사라지지 않음 - 멤버는 프로그램이 종료될 때 사라짐 |
공유의 특성 | 공유되지 않음 - 멤버는 객체 내에 각각 공간 유지 |
동일한 클래스이 모든 객체들에 의해 공유됨 |
4. static 멤버 사용
클래스 이름으로 접근 가능
객체의 멤버로 접근 가능
StaticSample b1 = new StaticSample();
b1.m = 3; // 객체 이름으로 static 필드 접근
b1.f(); // 객체 이름으로 static 메소드 호출
non-static 멤버는 클래스 이름으로 접근 안 됨
5) static의 활용
- 전역 변수와 전역 함수를 만들 때 활용
- 공유 멤버를 만들고자 할 때
- static으로 선언한 멤버는 클래스의 객체들 사이에 공유
6) static 메소드의 제약 조건
static 메소드는 오직 static 멤버만 접근 가능
- 객체가 생성되지 않은 상황에서도 static 메소드는 실행될 수 있기 때문에, non-static 멤버 활용 불가
- non-static 메소드는 static 멤버 사용 가능
class StaticMethod {
int n;
void f1(int x) { n = x; } // 정상
void f2(int x) { m = x;} // 정상
statid int m;
static void s1(int x) { n = x; } // 컴파일 오류. static 메소드는 non-static 필드 사용 불가
static void s2(int x) { f1(3); } // 컴파일 오류. static 메소드는 non-static 메소드 사용 불가.
static void s3(int x) { m = x; } // 정상. static 메소드는 static 필드 사용가능
static void s4(int x) { s3(3); } // 정상. static 메소드는 static 메소드 호출 가능
}
static 메소드는 this 사용불가
- static 메소드는 객체 없이도 사용 가능하므로, this 레퍼런스 사용할 수 없음
static void f() { this.n = x; } // 오류. static 메소드에서는 this 사용 불가능
stativ ovid g() { this.m = x; } // 오류. static 메소드에서는 this 사용 불가능
7) final 클래스와 메소드
final 클래스 - 더 이상 클래스 상속 불가능
final 메소드 - 더 이상 오버라이딩 불가능
public class SuperClass {
protected final int finalMethod() {
...
}
}
class SubClass extends SuperClass {
protected int finalMethod() { ... } // 컴파일 오류, 오버라이딩 할 수 없음
}
3) final 필드
final 필드, 상수 선언 : 상수를 선언할 때 사용
class SharedClass {
public static final double PI = 3.14;
}
상수 필드는 선언 시에 초기 값을 지정하여야 한다.
상수 필드는 실행 중에 값을 변경할 수 없다.
```java
public class FinalFieldClass {
final int ROWS = 10; // 상수 정의, 이때 초기 값(10)을 반드시 설정
void f() {
int [] intArray = new int [ROWS]; // 상수 활용
ROWS = 30; // 컴파일 오류 발생, final 필드 값을 변경할 수 없다.
}
}