객체지향 프로그래밍을 지원하는 언어는 대표적으로 Java, C#, C++ 등이다. 객체 지향 프로그래밍은 다음과 같이 몇 가지의 특징을 갖는다.
- 추상화란 불필요한 정보의 노출을 최소화하고 꼭 필요한 정보만 노출하는 기법으로 캡슐화, 은닉화 등의 용어와 관련이 있다. 자료의 추상화를 위해 구현한 것이 클래스이다.
- 상속이란 기존에 만들어놓은 클래스의 기능을 그대로 물려받아서 사용하는 것이다. 이렇게 하면 기존 코드가 재사용되기 때문에 상당히 효율적인 프로그래밍이 가능하다.
- 다형성이란 같은 이름의 기능을 하는 요소를 여러 개 만드는 것을 말한다. 예를 들어 A라는 이름의 메소드 여러 개가 각각 다른 기능을 하도록 만들 수 있다.
- 동적 바인딩이란 실행할 시점에 동작이 변경될 수 있는 것을 의미하며, 컴파일할 때 동작이 결정되는 정적 바인딩과 반대되는 개념이다.
1. 클래스(Class)
클래스는 현실의 '사물'을 컴퓨터 안에서 구현하기 위해 고안된 개념이다. 예를 들면 자동차는 색상이나 속도와 같은 속성을 가지고 속도를 내거나 줄이는 기능을 가진다. 이 때 속성은 필드로 기능은 메소드로 구현하면 된다.
class Car{
String color;
int speed;
void upSpeed(int value){
speed = speed + value;
}
void downSpeed (int value){
speed = speed - value;
}
}
이렇게 객체에 대한 정의를 내렸다면 이를 토대로 실제 인스턴스 (각 객체)를 만들 수 있다. 예를 들면 다음과 같다.
Car myCar1 = new Car();
Car myCar2 = new Car();
Car myCar3 = new Car();
//혹은 다음과 같이 작성해도 된다.
Car myCar4, myCar5, myCar6;
myCar4 = new Car();
myCar5 = new Car();
myCar6 = new Car();
인스턴스의 필드에 각 값을 대입할 수도 있다.
myCar1.color = "Red";
myCar1.speed = 0;
myCar2.color = "Yellow";
myCar2.speed = "0";
myCar1.upSpeed(30);
myCar2.upSpeed(60);
※private 접근 제어 수식어
자바에서는 필드에 직접 접근하지 못하도록 private 접근 제어 수식어를 제공한다. 필드 앞에 private를 붙이면 클래스 안의 메소드에서는 접근이 가능하지만, 인스턴스를 통해 직접 필드에 접근할 수는 없다. 다음과 같은 코드에서 myCar1.color 과 같은 방식으로 접근하면 에러가 뜬다.
class Car{
private String color;
private int speed;
void upSpeed(int value) {
if (speed + value < 200) {
speed = speed + value;
}
else {
speed = 200;
}
}
void downSpeed(int value) {
speed = speed - value;
}
String getColor() {
return color;
}
int getSpeed() {
return speed;
}
void setColor(String color) {
this.color = color;
}
void setSpeed(int speed) {
this.speed = speed;
}
}
public class Ex11_02 {
public static void main(String[] args) {
// TODO Auto-generated method stub
Car myCar1 = new Car();
myCar1.setColor("Red");
myCar1.setSpeed(0);
myCar1.upSpeed(30);
System.out.printf("자동차1의 색상은 "+ myCar1.getColor()+ "이며, 현재 속도는 " + myCar1.getSpeed()+"km입니다.");
}
}
※public 접근 제어 수식어
public 접근 제어 수식어는 private과 반대로 외부(모든 클래스)에서 접근이 가능하도록 하는 예약어이다. 일반적으로 private는 필드 앞에 붙여서 사용하고, public은 메소드 앞에 붙여서 사용한다. 따라서 필드는 외부에서 함부로 변경할 수 없도록 하고, 외부에 공개된 메소드를 통해 접근하도록 하는 것이다. 보통은 필드에는 private을, 메소드는 public을 붙인다.
이외에도 default와 protected 접근 제어 수식어가 존재한다. 이들의 차이는 한 눈에 보면 다음과 같다.
필드에 private을 추가하면 잘못된 값이 입력되는 것을 막을 수 있다. 예를 들어 speed 필드에 private 지정자가 없으면 자동차의 속도가 0 이하로 떨어지거나 200km가 넘는 경우를 막을 수 없다. 하지만 upSpeed()나 downSpeed() 메소드에서 값을 확인하면 이러한 오류를 피할 수 있다.
2. 생성자
생성자는 클래스의 이름과 동일한 메소드를 말하며 주로 초기화할 때 사용한다. 인스턴스를 생성하면서 동시에 각 필드의 초기값을 설정할 수 있도록 한다. 이렇게 하면 코드를 간결하게 유지할 수 있고 초기값 설정을 잊는 일도 없게 된다.
다음은 생성자를 통해 초기화된 예이다.
class Car1{
private String color;
private int speed;
Car1(String color, int speed) {
this.color = color;
this.speed = speed;
}
public String getColor() {
return color;
}
public int getSpeed() {
return speed;
}
}
public class Ex11_05 {
public static void main(String[] args) {
// TODO Auto-generated method stub
Car1 myCar1 = new Car1("Red", 0);
Car1 myCar2 = new Car1("Blue", 30);
System.out.printf("myCar1 color is " + myCar1.getColor());
}
}
만약 Car1(String color, int speed) 이 부분에서 어떠한 파라미터(매개변수)도 넘겨주지 않고 ()로 넘겨준다면 하나의 고정된 값으로 초기화를 시켜 줄 수 있다. 번외로 주의할 점은 여러 자바 파일을 한 디렉토리 src 폴더 안에서 진행했더니 겹치는 class (여기서는 Car)이 생겨 (에러 : The type Car is already defined) 에러가 났다. 그래서 새로 만드는 파일에서는 Car1이라고 명칭해줬다.
메소드 오버로딩은 같은 클래스 안에서 메소드의 이름이 같아도 파라미터의 개수나 데이터 형식만 다르면 여러 개를 선언할 수 있는 것을 말한다. 생성자 역시도 메소드이므로 메소드 오버리딩이 가능하다. 예를 들면 다음과 같다.
Car(){
}
Car(String color){
this.color = color;
}
Car(String color, int speed){
this.color = color;
this.speed = speed;
}
...
Car myCar1 = new Car();
Car myCar2 = new Car("Red");
Car myCar3 = new Car("Blue", 50);
이는 일반 메소드에서도 가능하다. 예를 들면 두 수를 더하는 클래스에 메소드를 만들었다면 같은 이름의 메소드더라도 하나는 double형 매개 변수 2개를, 하나는 int형 매개변수 2개를 인자로 받을 수 있다.
클래스의 인스턴스들 전체를 group으로 봐야 할 때가 존재한다. 그럴 때 굉장히 애매해지는 것이 인스턴스 변수는 저장공간을 따로 부여하지만 클래스 변수는 딱히 저장공간이 없다. 만약 각 인스턴스가 같은 값을 공유하는 필드의 변수, 즉 클래스 변수가 존재한다면 static 키워드를 이용해서 클래스 변수를 만들어 줄 수 있다. 다음 예를 보면 조금 더 이해하기가 쉽다.
class Car1{
private String color;
private int speed;
static private int count = 0; //count는 생산된 자동차의 총 대수를 의미
Car1() {
count ++;
}
public int getCount() {
return count;
}
}
public class Ex11_05 {
public static void main(String[] args) {
// TODO Auto-generated method stub
Car1 myCar1 = new Car1();
System.out.println("현재 생산된 자동차의 수 ==>" + myCar1.getCount());
Car1 myCar2 = new Car1();
System.out.println("현재 생산된 자동차의 수 ==>" + myCar2.getCount());
Car1 myCar3 = new Car1();
System.out.println("현재 생산된 자동차의 수 ==>" + myCar3.getCount());
}
}
위의 코드에서 클래스 메소드를 생성해 볼 수 있다. 메소드에는 인스턴스 메소드와 클래스 메소드가 있다. 우리가 사용했던 것처럼 '인스턴스이름.메소드이름()'의 형태를 가진 것들은 모두 인스턴스 메소드이다. 이는 각 인스턴스에 영향을 미친다. 반면 클래스 메소드는 역시 static을 이용해서 전체 클래스 변수에 영향을 미친다. 즉, 인스턴스 메소드는 인스턴스를 생성한 이후에야 호출이 가능하지만 클래스 메소드는 인스턴스를 생성하기 전에도 '클래스이름.메소드이름()' 형태로 호출할 수 있다.
class Car1{
private String color;
private int speed;
static private int count = 0; //count는 생산된 자동차의 총 대수를 의미
Car1() {
count ++;
}
static int getCount() {
return count;
}
}
public class Ex11_05 {
public static void main(String[] args) {
// TODO Auto-generated method stub
Car1 myCar1 = new Car1();
System.out.println("현재 생산된 자동차의 수 ==>" + Car1.getCount());
Car1 myCar2 = new Car1();
System.out.println("현재 생산된 자동차의 수 ==>" + Car1.getCount());
Car1 myCar3 = new Car1();
System.out.println("현재 생산된 자동차의 수 ==>" + myCar3.getCount());
}
}
클래스 메소드로 사용하기 위해 static으로 지정해둔 메소드들은 마찬가지로 인스턴스 메소드로도 사용할 수 있다.
'TIL > Java | Spring Boot' 카테고리의 다른 글
2022.1.1 TIL : [Java] 컬렉션과 제네릭 (Collection & Generic) - 마무리 (0) | 2022.01.01 |
---|---|
2021.12.31 TIL : [Java] 컬렉션과 제네릭 (Collection & Generic) - 2 (0) | 2022.01.01 |
2021.12.30 TIL : [Java] 컬렉션과 제네릭 (Collection & Generic) - 1 (0) | 2021.12.30 |
2021.8.12 TIL : [Java] 기초 문법2 - 객체지향 프로그래밍 응용(2) (0) | 2021.08.12 |
2021.8.3 TIL : [Java] 기초 문법2 - 객체지향 프로그래밍 응용(1) (0) | 2021.08.03 |
댓글