자바스터디 챕터 6 객체지향 프로그래밍1
- 클래스 : 객체를 정의해두는 설계도
- 객체 : 클래스를 기반으로 실제 생성된 것
- 인스턴스 : 어떤 클래스로부터 만들어진 객체를 그 클래스의 인스턴스라고 한다. 어떤 클래스로부터 만들어진 것인지 강조하는 구체적 의미.
배열의 생성과 유사하게
1. 참조할 참조변수 선언
2. 클래스 객체 생성 -> 참조변수에 객체주소 저장
순서로 이루어짐클래스명 참조변수명 = new 클래스명(); // 동시에도 가능, 참조변수와 인스턴스의 타입은 항상 일치
인스턴스에 접근해 멤버변수, 메소드를 사용하는 것은 참조변수를 통해서만 가능하다.
: 참조변수.멤버변수 // 참조변수.메소드()
같은 타입의 객체들을 배열로 묶어 다룰 수 있음
-> 객체의 주소들을 저장한 참조변수 배열
일반 배열을 선언 할 때와 마찬가지로
java타입명[] 참조변수명 = new 타입명[개수];
로 선언해주면 되지만,
객체들의 참조변수만 생성된 것이고 실제 객체를 생성하지 않았으므로,
배열의 각 요소에 객체를 생성해서 할당하는 일을 꼭 해야함
- 실제로 하나씩 저장
tvArr[0] = new Tv(); tvArr[1] = new Tv(); tvArr[2] = new Tv();
- 수가 많은 경우엔 반복문으로
Tv[] tvArr = new Tv[100]; for( int i = 0 ; i < Tv.length ; i++ ) { tvArr[i] = new Tv(); }
1. 지역변수
-선언위치 : 클래스 영역 이외 (메소드, 생성자, 초기화 블럭 내부, ... )
-생성시기 : 변수 선언문이 실행 됐을 때 생성
-소멸 : 선언된 메소드가 종료되어 소멸 된 경우, 가장 가까운 중괄호가 닫힐 때
2. 클래스변수
-선언위치 : 클래스 영역
-생성시기 : 클래스가 메모리에 올라갈 떼
-특성 : 클래스의 모든 인스턴스가 공통된 저장공간을 공유하게 된다.
인스턴스들이 공통적인 값을 유지해야 할 때 사용되며,
인스턴스를 생성하지 않고도'클래스.클래스변수' 형태로 바로 사용
가능하다.
인스턴스 변수 앞에 static을 붙여 선언
-소멸시기 : 프로그램이 종료 될 때
- 인스턴스변수
-선언위치 : 클래스영역
-생성시기 : 인스턴스가 생성되었을 때
-특성 : 인스턴스마다 독립적인 저장공간, 값을 가질 수 있음
메소드는 선언부, 구현부로 이루어져있다
int add (int x, int y) { // 선언부 int result = x + y; // 구현부 return result; }
- 선언부
반환타입 이름 (매개변수선언) int add (int x, int y)
구현부 : 메소드 호출 시 수행 될 문장들
리턴타입이 void인 경우를 제외하면 반드시 'return 반환값' 이 포함되어야 함지역변수 : 메소드 내부에서 선언된 변수는 내부에서만 사용 가능
메소드이름( 값1, 값2, ...)
호출할 때 괄호 안에 지정해 주는 값들이 '인자'
-> 메소드가 호출되며 인자가 매개변수에 대입 됨 : 타입일치 필요 or 자동형변환이라도 가능하게 해야 함
모든 메소드는 항상 return 을 포함해야 함
(리턴타입이 void인 경우는 컴파일러가 마지막에 return; 을 자동으로 추가)
return의 반환값으로는 변수뿐만 아니라, 수식도 올 수 있다.
return abs(x-y); return x>=0 ? x : -x; return result ...
- return문을 사용한 유효성 검사
인자로 받은 값의 유효성을 조건문으로 검사하고
적절하지 않은 값의 경우 return문으로 작업을 중단하고 돌아가야 함float divide(int x, int y) { if(y==0) { System.out.println("0으로 나눌 수 없음"); return 0; //메소드 종료 : 값이 유효하지 않음 } return x/(float)y; }
- 메모리구조의 3가지 주요 영역
1. 메소드 영역 : 프로그램 실행 중 어떤 클래스가 사용되면, 해당 클래스파일을 분석한 클래스 데이터를 저장하는 영역 ( 클래스 변수 포함 )2. 힙 : 인스턴스가 생성되는 공간 ( 인스턴스 변수 포함 )
3. 호출 스택 : 메소드 호출 시 메소드 작업에 필요한 메모리 공간 ( 지역변수, 연산의 중간결과, ... )을 제공하는 공간
- 메소드 호출 시 스택 할당 받음 -> 수행 끝나면 메모리 반환
- 스택 구조이므로 제일 위에 있는 메소드 : 현재 실행중인 메소드
, 아래 있는 메소드가 위의 메소드를 호출한 구조
- 참조형 매개변수는 기본형 매개변수와 달리 값의 주소를 넘겨주므로
값을 읽고 변경도 할 수 있다.
- 참조형 반환타입 : 메소드가 '객체의 주소'를 반환하는 것
, 호출 결과를 저장하는 변수도 같은 타입의 참조변수여야 함
메소드 내부에서 메소드 자기 자신을 다시 호출하는 것
1. 종료조건이 반드시 필요하다
2. 반목문으로도 같은 내용을 작성하는 것이 가능하다.
3. 재귀호출은 함수의 호출이므로 반복문보다 몇 가지 과정(매개변수 복사, 복귀주소 저장, ...)이 추가로 필요하다.
하지만 재귀호출이 반복문보다 논리적 간결함이 큰 경우에 사용한다.
- 재귀함수 대표적 예시 : 팩토리얼 계산
public class FactorialTest { public static void main(String args[]) { System.out.println(factorial(4)); } static int factorial(int n) { if(n<=0 || n>12 ) return -1; //유효성 검사 // n<=0인 경우 종료조건에 맞지않아 무한루프 -> 스택오버플로우 에러 if(n==1) return 1; //종료조건! return n*factorial(n-1); //재귀적 호출 } }
변수와 마찬가지로, 메소드 앞에 static이 붙어있으면 클래스(static) 메소드이다.
- 객체를 생성하지 않고도 '클래스이름.메소드이름' 으로 호출 가능
: 클래스가 메모리에 올라갈 때 자동으로 생성되기 때문- 클래스메소드는 인스턴스 변수를 사용할 수 없다
- 인스턴스와 관계없는, 즉 인스턴스 변수나 인스턴스 메소드를 사용하지 않는 메소드를 static메소드로 정의하자 : 호출시간을 줄일 수 있다.
클래스 멤버는 언제나 참조, 호출이 가능
/ 인스턴스 멤버는 해당 객체가 생성된 후에만 참조, 호출이 가능
이 점으로 기억하면 됨
1. 클래스, 인스턴스 -> 클래스 멤버
클래스 멤버를 호출 하는 것은 언제나 가능
2. 클래스 -> 인스턴스
인스턴스 멤버가 존재하는지 보장할 수 없으므로 같은 클래스 내부의 멤버라고 해도 클래스 멤버 -> 인스턴스 멤버 호출은 x
3. 인스턴스 -> 인스턴스 멤버
한 쪽의 인스턴스 멤버가 존재 한다는 것은 해당 객체가 생성되었다는 의미
- 메소드 이름이 같아야 한다
- 매개변수의 개수 혹은 타입이 달라야한다
리턴타입은 오버로딩을 구현하는데 아무 영향을 주지 못한다!
메소드의 매개변수 개수를 동적으로 다룰 수 있다.
//'타입... 변수명' 형식으로 사용 public PringStream printf(String format, Object... args)
-> 내부적으로 배열을 이용해 처리함
하지만 가변인자를 선언한 메소드를 오버로딩하면 메소드를 호출했을 때 둘을 구별하지 못하는 경우가 발생할 수 있다.
-> 가능한 가변인자를 사용한 메소드는 오버로딩 하지 않는 것이 좋다.
인스턴스가 생성될 때 인스턴스의 초기화에 사용되는 메소드
- 이름이 클래스와 같다
- 리턴값이 없으며 선언 시 void는 생략한다
- 오버로딩이 가능하여 하나의 클래스에 여러 생성자가 존재할 수 있다.
- 지금까지 인스턴스 생성시 new 클래스명();에서 '클래스명()' 부분이 생성자 였던셈이다.
모든 클래스에는 반드시 하나 이상의 생성자가 정의 돼 있어야 함
-> 정의하지 않은 경우, 컴파일러가 자동으로 빈 기본 생성자를 추가해준다.
-> 다른 생성자를 하나라도 정의했을 경우, 기본생성자는 만들어지지 않는 것을 주의
생성자를 통해 매개변수를 넘겨받아
인스턴스의 생성과 동시에 멤버변수를 초기화 하는 것이 가능하다.
Car c = new Car(); c.color = "white"; c.gearType="auto"; c.door = 4;
생성 후 멤버변수들을 각각 초기화
Car c = new Car("white", "auto", 4);
생성자로 생성과 동시에 초기화
생성자 간 호출 시의 조건
- 생성자의 이름으로 클래스 대신 this를 사용
- 한 생성자에서 다른 생성자를 호출 할 때는 반드시 첫 줄에서만 가능
사용 예제
class Car() {
String color;
String gearType;
int door;
Car() {
this("white","auto",4); //생성자 내부에서 생성자 호출
}
Car(String color, String gearType, int door) {
this.color = color;
this.gearType = gearType;
this.door = door;
}
이 경우에서
Car();
로 인스턴스를 생성한다면 해당 생성자가 다른 생성자를 호출하므로 "white", "auto", 4 로 초기화 될 것이다.
이처럼 아무런 옵션을 주지 않고 생성한 경우에 기본값을 주는 용도로도 사용할 수 있다.
this : 인스턴스 자기 자신의 주소값을 다진 참조변수
this(), this(매개변수) : 생성자, 같은 클래스의 다른 생성자를 호출할 때만 사용
생성자의 매개변수로 클래스의 참조변수를 주기
Car(Car c) {
Car(c.color, c.gearType, c.door);
}
이 생성자로 새 인스턴스를 생성하면 값은 똑같이 갖지만 별도의 메모리공간에 존재하는 별도의 인스턴스가 된다.
별도의 인스턴스이므로 서로의 값 변화는 영향을 주지 않는다.
- 멤버변수, 배열 : 초기화 하지 않아도 자동으로 변수타입에 맞는 기본값으로 초기화 됨
- 지역변수 : 반드시 초기화해야 함
변수를 선언함과 동시에 초기화하는 것
int door = 4;
- 클래스 초기화 블럭 : 클래스변수의 초기화에 사용
클래스가 메모리에 로딩 될 때 한 번만 수행됨- 인스턴스 초기화 블럭 : 인스턴스 변수의 초기화에 사용
인스턴스를 생성 할 때마다 수행됨
클래스의 모든 생성자에 공통으로 수행되어야 하는 문장을 넣는데 사용
class InitCar() {
static { //클래스초기화블럭 }
{//인스턴스 초기화 블럭}
}