객체의 고유 데이터, 부품 객체, 상태 정보를 저장하는 곳이다. 선언 형태는 변수와 비슷하지만 필드를 변수라고 부르지 않는다.
변수는 생성자와 메소드 내에서만 사용되고 생성자와 메소드가 종료되면 자동 소멸되지만 필드는 생성자와 메소드 전체에서 사용되며 객체가 소멸되지 않는 한 객체와 함께 존재한다.
[생성자]
new 연산자로 호출되는 특별한 {} 블록이다.
생성자는 객체 생성 시 초기화를 담당하는데, 필드를 초기화하거나 메소드를 호출해서 객체를 사용할 준비를 한다.
생성자는 메소드와 비슷하게 생겼지만, 클래스 이름으로 되어 있고 리턴 타입이 없다.
[메소드]
객체의 동작에 해당하는 {} 블록이다.
이 때 {} 블록의 이름이 메소드 이름이다.
메소드를 호출하게 되면 { ... } 안의 모든 코드들이 일괄적으로 실행된다.
메소드는 필드를 읽고 수정하는 역할도 하지만 다른 객체를 생성해서 다양한 기능을 수행한다. 또한 객체 간의 데이터 전달의 수단으로도 사용되며 외부로부터 매개값을 받을 수 있고 실행 후 어떤 값을 리턴할 수도 있다.
필드
객체의 고유 데이터, 객체가 가져야 할 부품, 객체의 현재 상태 데이터를 저장하는 곳이다.
오늘도 많이 본 자동차를 예로 들어보자.
자동차 객체
자동차 클래스 | public class Car { ... }
[고유 데이터]
제작회사
고유 데이터 클래스
String company;
모델
String model;
색깔
String color;
최고속도
int maxSpeed;
[상태]
현재속도
상태 클래스
int speed;
엔진 회전 수
int rpm;
[부품]
차체
부품 클래스
Body body;
엔진
Engine engine;
타이어
Tire tire;
필드의 초기값은 필드 선언 시 주어질 수도 있고 생략될 수도 있다.
위의 표에 나온 '자동차 클래스'는 생략된 케이스이다.
[필드 선언 예시]
public class Car {
// 필드 초기값 선언
String company = "현대자동차";
String model = "그랜저";
int maxSpeed = 300;
// 필드 초기값 생략
int productionYear;
int currentSpeed;
boolean engineStart;
}
[필드 타입별 초기값]
분류
데이터 타입
초기값
기본
정수
- byte - char - short - int - long
- 0 - ' ' (공백) - 0 - 0 - 0L
int와 long의 차이: L의 유무
실수
- float - double
- 0.0F - 0.0
float과 double의 차이: F의 유무
논리
- boolean
false
참조
- 배열 - 클래스 (String 포함) - 인터페이스
- null - null - null
생성자
new 연산자와 같이 사용되어 클래스로부터 객체를 생성할 때 호출되어 객체의 초기화를 담당한다.
객체 초기화란, 필드 초기화 또는 메소드를 호출해서 객체를 사용할 준비를 하는 것을 말한다.
생성자를 실행시키지 않고는 클래스로부터 객체를 만들 수 없다.
[기본 생성자 (디폴트 생성자, default Constructor)]
모든 클래스는 생성자가 반드시 존재하며, 하나 이상을 가질 수 있다.
+++
[오답노트]
프로그래밍 언어 활용 시험 5번문제 - 디폴트 생성자를 생성하시오.
기본 생성자는 매개변수를 하나도 가지지 않으며, 어떤 명령어도 포함하지 않는다. 문법으로는 클래스명을 따 온다.
클래스명() {}
+++
클래스가 public class로 선언되면 기본생성자에서도 public이 붙지만
클래스가 public 없이 선언되면 기본생성자에도 public이 붙지 않는다.
[public] 클래스() { ... }
[생성자 선언]
// 생성자블록
클래스(매개변수선언) {
// 객체의 초기화 코드
}
// 객체의 초기화 코드에는 필드에 초기값을 작성하거나 메소드를 호출하여 객체 사용 전 필요한 준비를 한다.
매개변수선언은 생략할 수도 있고, 여러 개를 선언할 수도 있다.
매개변수는 new 연산자를 통해 외부의 값을 생성자 블록 내부로 전달하는 역할을 한다.
Car myCar = new Car("그랜저", "검정", 300);
========
public class Car {
// 생성자
Car(String model, String color, int maxSpeed) { ... }
}
Car 클래스에 생성자 선언이 있기 때문에
기본생성자 [Car()]를 호출해서 객체를 생성할 수 없고
Car(String color, int cc)를 호출해서 객체를 생성해야 한다.
[필드 초기화]
클래스로부터 객체가 생성될 때 필드는 기본 초기값으로 자동설정된다.
이때 만약 다른 값으로 주고 싶다면 '필드를 선언할 때 초기값을 주는 방법'과 '생성자에서 초기값을 주는 방법'이 있다.
(1) 필드 선언 시 부여 (String nation;)
동일한 클래스로부터 생성되는 객체들은 모두 같은 데이터를 갖게 된다.
객체 생성 후 변경할 수 있지만, 객체 생성 시점에는 필드의 값이 모두 같다.
(2) 생성자 초기값 부여 (String name; / String birth;)
객체 생성 시점에 외부에서 제공되는 다양한 값들로 초기화되어야 할 때 사용한다.
name과 ssn의 필드값은 클래스를 작성할 때 초기값을 줄 수 없고 객체 생성 시점에 다양한 값을 가져야 한다.
11번째 줄을 보면 String n, s를 사용한 것을 볼 수 있다.
하지만 실제 코드를 작성할 때는 확 줄여서 그 의미를 모르게 하는 것보다 필드명을 그대로 사용함으로
매개변수가 무엇을 의미한 것인지를 표시해주는 것을 추천한다.
우리가 스스로를 '나'라고 칭하듯이 객체가 객체 자신을 스스로 칭하는 것을 'this'라고 한다.
"this.필드"는 this라는 참조 변수로 필드를 사용하는 것과 동일하다.
this.name = name; 에서
앞의 name은 필드이고, 뒤의 name은 매개변수이다.
객체의 필드는 하나가 아니라 여러개 가 있고, 이 필드들을 모두 생성자에서 초기화한다면
생성자의 매개 변수의 수는 객체의 필드 수만큼 선언되어야 한다.
하지만 실제로는 중요 몇 개 필드만 매개 변수를 통해 초기화되고 나머지는 필드 선언 시 초기화하거나
생성자 내부에서 임의의 값 또는 계산된 값으로 초기화한다.
[생성자 오버로딩]
Car 객체를 생성할 때 외부에서 제공되는 데이터가 없다면 기본 생성자로 Car 객체를 생성해야 하고
외부에서 model 데이터가 제공되거나 model, color가 제공될 경우에도 Car 객체를 생성할 수 있어야 한다.
이에 자바는 다양한 방법으로 객체를 생성할 수 있도록 생성자 오버로딩(Overloading)을 제공한다.
'오버로딩'이란, 매개 변수를 달리하는 생성자를 여러 개 선언하는 것을 말한다.
생성자 오버로딩
주의할 점이 있다면, 아래와 같이 다른 건 다 같으나 순서가 바뀐 것은 오버로딩이라고 볼 수 없다.
생성자 오버로딩 시 주의할 점
생성자가 오버로딩 되어 있을 경우 new 연산자로 생성자를 호출할 때 제공되는
매개값의 타입과 수에 의해 호출될 생성자가 결정된다.
생성자 선택 예시
[생성자 호출 this()]
생성자 오버로딩이 많아질 경우 생성자 간의 중복된 코드가 발생할 수 있다.
이런 현상은 매개 변수의 수만 달리하고 필드 초기화 내용이 비슷한 생성자에서 많이 목격된다.
이 때 필드 초기화 내용은 한 생성자에만 집중적으로 작성하고 나머지에서는 초기화 내용을 가지고 있는 생성자 호출방법을 사용한다.
다음은 생성자에서 다른 생성자를 호출할 때에 쓰이는 코드와 사용방법이다.
클래스 ( [매개변수선언] ) {
this( 매개변수, ..., 값, ...); // 클래스의 다른 생성자 호출
실행문;
}
this() 는 자신의 다른 생성자를 호출하는 코드로 반드시 생성자의 첫줄에서만 허용된다.
this() 다음에는 추가적인 실행문들이 올 수 있다.
--> 호출되는 생성자의 실행이 끝나면 원래 생성자로 돌아와서 다음 실행문을 진행한다는 뜻이다.
아래는 중복코드와 변화된 코드이다.
생성자 호출 this()
왼쪽의 CarThis 클래스를 적으면서 느낀 점은 이걸 이렇게 쓰기는 할까? 라는 의문인데
아직 이렇다 할 경험이 없으니 일단 적고 넘어가겠다.
아무튼 왼쪽의 CarThis를 오른쪽의 CarThis2로 변화시켜 보았다. 확실히 줄은 줄었으나
new 연산자 뒤에는 생성자가 따라오며, 생성자의 형태는 "클래스()" 형태를 가지고 있다.
현실세계에서 물건의 위치를 모르면 물건을 사용할 수 없듯이
객체 지향 프로그램에서도 메모리 내 생성된 객체의 위치를 모르면 객체를 사용할 수 없다.
new 연산자는 힙 영역에 객체를 생성시킨 후 객체의 주소를 리턴하도록 되어 있으며
이 주소를 참조 타입인 클래스 변수에 저장 후 변수를 통해 객체를 사용할 수 있게 한다.
// 자동차 클래스 선언
public class Car {
}
public class CarExam {
public static void main(String[] args) {
// 표현1
// Car car;
// car = new Car();
// 표현2
Car car = new Car();
}
}
표현 1과 표현2는 둘 다 클래스 변수 선언과 객체 생성을 하는 것이지만 보통 표현2를 더 자주 쓴다.
Car와 CarExam의 차이는 Car의 경우 라이브러리(API : Application Program Interface) 용이고CarExam의 경우 실행용이다.
프로그램 전체에 사용되는 클래스가 n개라면, 1개는 실행용이고, n-1개는 모두 라이브러리라고 보면 된다.
실행 클래스는 main() 메소드를 가지고 있다.물론 main() 메소드가 있는 곳에서도 라이브러리를 만들 수 있다.
public class Car {
String name;
int maxSpeed;
int releaseYear;
public static void main (String[] args) {
Car car1 = new Car();
Car car2 = new Car();
}
}
물리적으로 존재하거나 추상적으로 생각할 수 있는 것 중에서 자신의 속성을 가지고 있고 다른 것과 식별 가능한 것을 말한다. 물리적으로 존재하는 것 : 자동차, 자전거, 책, 사람 등등 추상적으로 생각할 수 있는 것 : 학과, 강의, 주문 등등
객체는 속성과 동작으로 구성되어 있다.
사람은이름과 나이라는 속성이 있고걷다, 뛰다등의 동작이 있다.
자동차는모델명, 색상이라는 속성이 있고,달린다와 멈춘다는 동작이 있다.
자바에서는 속성을필드, 동작을메소드라고 부른다.
(1) 객체 모델링(Object Modeling)
현실 세계의 객체를 소프트웨어 객체로 설계하는 것을 의미한다. 현실 세계 객체의 속성과 동작을 추려서 소프트웨어 객체의 필드와 메소드로 정의하는 과정이라고 볼 수 있다.
2. 객체의 상호작용
현실 세계에서 일어나는 모든 현상은 객체와의 상호작용으로 이루어진다.
계산기로 예를 들어보자. 사람이 계산기에 어떤 값을 입력하여 주면 계산기는 그에 맞는 결과값을 사람에게 보여준다.
소프트웨어에 적용시켜보자.
객체들은 각각 독립적으로 존재하고 타 객체와 상호작용하면서 동작한다.
객체들 사이의 상호작용 수단은 '메소드'이다.
객체가 타 객체의 기능을 이용하는 것을 '메소드 호출'이라고 한다.
메소드 호출을 해보기 전에 계산기의 속성과 동작을 간단하게 알아보자.
계산기의 속성은 모델명과 회사명으로 하고 동작은 더하기와 빼기로 해보자.
원하는 결과가 나왔으니 패스한다.
메소드 호출은 맨 아래에 보이듯
객체명.메소드명(매개값1, 매개값2)로 표현한다.
3. 객체 간의 관계
객체는 개별적으로 사용될 수도 있지만 대부분 다른 객체와 관계를 맺고 있다.
이런 관계의 종류에는 집합, 사용, 상속 관계가 존재한다.
[집합 관계 : 집약 + 합성]
집합관계
특징
집약(Aggregation)
- 전체 객체의 부분 객체의 생명 주기가 다르다. - 부분 객체를 여러 전체 객체가 공유할 수 있다.
합성(Compositon)
- 전체 객체가 없어지면 부분 객체도 없어진다. - 부분 객체를 여러 전체 객체가 공유할 수 없다.
[사용 관계 / Use A]
가장 일반적이다.
다른 클래스의 객체를 메소드 인자로 받아 사용하거나 메소드 내에서 다른 클래스의 객체를 생성하여 사용한다.
사용 관계이지만 사용하는 객체를 멤버 변수로 유지할 수 있다.
사용 관계이면서 포함 관계도 가능하다.
예를 들어, 사람은 자동차를 사용하므로 사람과 자동차는 사용관계라고 볼 수 있다.
[상속 관계 / Is A]
BMW is a car.
Audi is a car.
Child class is a Parent class.
개념 상위(부모) 객체를 기반으로 하위(자식) 객체를 생성하는 관계를 말한다. 일반적으로 상위 객체는 종류를, 하위 객체는 구체적인 사물에 해당한다.
장점 (1) 코드의 재사용이 가능하다. → 자식 클래스를 만들 때 편하다.
(2) 다양한 객체를 처리할 수 있는 공통 리모컨이 생긴다.
[객체 지향 프로그래밍(OOP, Object Oriented Programming)]
만들고자 하는 완성품인 객체를 모델링하고
집합 관계에 있는 부품객체와 사용관계에 있는 객체를 하나씩 설계 후
조립하는 방식으로 프로그램을 개발하는 기법이다.
4. 객체 지향 프로그래밍의 특징
객체 지향 프로그램의 특징으로는 캡슐화, 상속, 다형성이 있다.
(1) 캡슐화 : 정보은닉
객체의 필드와 메소드를 하나로 묶고 실제 구현 내용을 감추는 것을 말한다.
목적으로는 외부의 잘못된 사용으로 인해 객체가 손상되지 않도록 한다. 자바는 접근제한자를 사용하여 캡슐화된 멤버를 노출시킬지, 숨길지를 결정한다.
즉, 접근 제한자는 객체의 필드와 메소드의 사용 범위를 제한함으로써 외부로부터 보호한다.
[접근제어자]
접근제어자는 클래스 접근제어자와 메소드 접근제어자로 나뉜다.
클래스 접근제어자
default
- 동일 패키지의 클래스(class)에만 인스턴스(객체)를 생성가능
public
- 다른 패키지에서 인스턴스(객체)를 생성가능
메소드 접근제어자
public
- 모든 객체에서 접근 가능하다.
private
- 동일한 클래스 안에서만 접근이 가능하고, this를 사용하는 것들은 외부에서 접근 불가능하고 상 속도 안 된다.
default
- 접근제어자가 없는 형태로 동일한 패키지 안에서만 접근이 가능하다.
protected
- 동일한 패키지 안에서 사용가능하고, 다른 패키지라도 상속받은 클래스에는 접근이 가능하다.
(2) 상속
일반적으로 상속이라 했을 때 자식이 부모의 재산을 물려받는다라는 개념을 떠올린다.
객체 지향 프로그래밍에서도 부모 역할의 상위 객체와 자식 역할의 하위 객체가 있다.
상위 객체는 자기가 갖고 있는 필드와 메소드를 하위 객체에게 물려주어 하위 객체가 사용할 수 있도록 해준다.
상속은 상위 객체를 재사용하여 하위 객체를 쉽고 빨리 설계할 수 있도록 도와주고
이미 잘 개발된 객체를 재사용하여 새로운 객체를 만들기 때문에 반복된 코드의 중복을 줄여준다.
게시글 상속 응용
코드를 보면 Board 클래스 안에 변수들 4개를 선언할 걸 볼 수 있다.
그에 반해 Gallery 클래스와 Notice 클래스에는 그림파일 첨부값만 있거나
아무 내용이 없다는 것을 볼 수 있다.
Board 클래스로부터 상속받아 오기에 Gallery 클래스는 기존에 이미지파일 첨부 값만 넣어준 것이며
Notice 클래스는 받아오기만 하고 아무것도 입력 안 한 모습을 볼 수 있다.
상속을 받아올 때는 '자식클래스명 extends 부모클래스명'이라고 입력하면 된다.
(3) 다형성
같은 타입이지만 실행 결과가 다양한 객체를 이용할 수 있는 성질을 말한다.
코드 측면에서 보면 다형성은 하나의 타입에 여러 객체를 대입함으로써 다양한 기능을 이용할 수 있도록 해 준다.
타이어를 예로 들면, 타이어의 규격이 정해져 있다고 하면 타이어 사는 규격에 맞춰서 자신들만의 타이어를 제품으로 내 놓는다고 생각하면 된다.
[참조변수의 다형성]
class Samsung {...}
class Samsung extends Company {...}
...
Company com = new Company(); // 허용
Samsung ss = new Samsung(); // 허용
Company co = new Samsung(); // 허용
Samsung sam = new Company(); // 오류.
[참조 변수의 타입 변환]
서로 상속 관계에 있는 클래스 사이에만 타입 변환을 할 수 있다.
자식 클래스 타입에서 부모 클래스 타입으로서 타입 변환은 생략할 수 있다.
부모 클래스 타입에서 자식 클래스 타입으로의 변환은 반드시 명시해야 한다.
class Samsung {...}
class Posco {...}
class Samsung extends Company {...}
...
Company com1 = null;
Samsung ss = new Samsung();
Company com2 = new Company();
Posco po = null;
com1 = ss; // com1 = (Company) ss; 와 같으며, 타입변환 생략가능.
po = (Posco) com2; // 타입변환 생략불가.
po = (Posco) ss; // 직접적인 상속관계가 아니므로 오류 발생
// 입력 매개변수 == (int a, int b)
int running (int a, int b)
{
int c = a * b;
...
return c;
}
// 입력 매개변수가 없는 경우 == ()
int running()
{
int c = a * b;
...
return c;
}
(6) main() 메소드
프로그램의 시작 메소드
클래스 내부에 정의되지만 멤버 메소드는 아니다.
class SmartPhone {
public static void main (String[] args) {
}
}
(7) 객체 생성하기
main() 메소드에서 생산한다.
class SmartPhone {
public static void main (String[] args) {
// 객체 생성
SmartPhone g = new SmartPhone();
SmartPhone i = new SmartPhone();
}
}
(8) 멤버 변수와 메소드 사용하기
멤버 변수는 객체 생성 시 자동 초기화 됨
수치관련 변수는 0, 문자 관련 변수는 null
멤버 변수와 메소드는 객체 생성 후 사용
class SmartPhone {
public static void main (String[] args) {
SmartPhone g = new SmartPhone();
SmartPhone i = new SmartPhone();
g.modelName = "galaxy s21+";
i.modelName = "iPhone 11";
g.turnOn();
g.turnOff();
i.turnOn();
i.turnOff();
}
}