아니 벌써 금요일!???

image

시간이 이렇게 빨리가다니요번주는 진짜 엄청 빨리 시간이 지났던 것 같다.
아무래도 문법공부와 문제풀이를 해서 그런가? 벌써 금요일이다…

어제는 배열에 대해 공부했고여러방을이용해 같은 계열의
데이터들은한군데 저장할 수 있는 것을 알아보았다.
오늘은 자바의 심장… 자바의 꽃이라고 많이들하는객체지향에대해 공부해보는 날이다.

오늘도 화이팅!!


객체지향 프로그래밍 (Object-Oriented Programming)

객체 개념에 기반한 프로그램패러다임, 객체 간 관계 및 유기적인 협력.
실제 사물의 속성기능을 분석한 후에 이것을 프로그래밍의 변수와 함수로
정의함으로 실제 세계를 최댛나 컴퓨터 프로그래밍에 반영하고자 하는 시도라 설명할 수 있다.

가장 많이 드는 예로 자동차를 생각해보면
속성에는 자동차의 색깔, 자동차 바퀴의 크기, 자동차 내부 디자인 등 이있고
기능에는 주행(엑셀을 밟으면 차가 움직인다), 라디오 (라디오를 키면 음성이나온다) 등 이있다.

자동차라는 설계도 안에
여러가지 속성과 기능을 합쳐서 자동차라는 것을 만들 듯이
객체지향 프로그래밍도 속성과 기능을 프로그래밍의 변수와 함수로 정의해
하나의 설계도를 완성하는 것이라 생각할 수 있는 것 같다.

이제 객체지향이라는 것이 어떤 느낌인지 대략 파악하였으니
실제 Java 언어로 객체지향 프로그래밍을 하기위해서

어떤 것을 배워야하는지 알아보자!!


클래스(Class)

클래스는 객체를 정의한 ‘설계도’, ‘‘이라는 말로 많이 정의하는 것으로 들었다.
즉, 클래스는 객체를 생성하는데 사용된다.
반대로 객채는 클래스에 정의되고 설계된 내용 그대로 생성된다.

❗️클래스는 객체 그자체가 아니다!   단지 객체를 생성하는 데 사용되는 하나의 틀!

image
출처 - wikidocs 레퍼런스

가장 많이 드는 예로, 붕아빵 틀과 붕어빵이 있다.
Class 즉 설계도,틀 이라고했는데
위에서 보면 붕어빵을 만들 수 있는 틀이다. 수백번 수천번을 만들던
기계가 고장나지 않는 이상 항상 같은 모양으로 만들어 질 수 있다.
그 틀안에서 만들어진 붕어빵을 즉, 클래스를 통행 생성된 객체를
인스턴스(Instance)라고 한다.

객체와 인스턴스는 같은 말이라 차이를 두는 것에 큰 의미는 없고
엄격히 구분하자면 객체 > 인스턴스 의 의미를 가지고 있다.
이렇게 생성된 인스턴스들은 여러가지 속성을 가질 수 있다.
붕어빵에 팥만 들어가냐? 아니다.
슈크림도 들어가고 만드는 사람이 원하면 무었이든 넣을 수 있다.
이렇게 클래스에서 만들어진 인스턴스들은 같은 틀에서
만들어졌지만 서로 다르다고 볼 수 있다.

이제 프로그램적으로 접근해서
설계도,틀을 즉 Class를 구성하는 여러요소와 문법이있다.

1).필드 (field)
-. 클래스의 속성을 나타내는 변수이다.
ex) int x = 10;

2).메서드 (method)
-. 클래스의 기능을 나타내는 함수이다.
ex) public void carDrive();

3).생성자 (constructor)
-. 클래스의 객체를 생성하는 역할이다.
-. 클래스와 동일한 이름으로 만든다.

4).이너 클래스 (inner class)
-. 클래 내부의 클래스를 의미한다.

public class ExampleClass {
	int x = 10; // (1)필드
	public int carDrive() {...} // (2)메서드
	public ExampleClass {...} // (3)생성자
	class ExampleClass2 {...} // (4)이너 클래스
}

위에서 필드,메서드,이너클래스는 멤버(member)라고 부른다.
생성자나 메서드, 이너클래스 등 오늘말고 다른날에 심화학습할 것 같다.
오늘은 이런 것들이 있다 정도만 알면 될 것 같다.


객체(Object)

앞에서 엄격하게 나누자면 얘기했듯이 개별객체는 인스턴스
좀 더 큰범위는 객체이다.
객체를 생성과 활용을 할 수 있는 방법을 알아보자


선언방법

클래스명 참조_변수명 = new 생성자();
Car avante = new Car();

자동차라는 설계도 Car의 생성자를 호출해
새로운 인스턴스인 avante라는 자동차라는 객체를 만든 모습이다.
이렇게 자동차라는 설계도로 생성자의 값을 변경해주면
무수히 많은 자동차 객체를 만들 수 있는 것이다.

여기서 new라는 키워드는 생성된 객체를 힙 메모리에 넣으라는 의미를 가지고 있다.
즉 여기서 생성된 참조 변수인 avante는 실제 데이터가 저장되어 있는 힙 메모리의 주소값을 가르킨다.
(JVM 메모리 구조에 대한 공부도 필요해보인다)


객채활용

이렇게 만들어진 avante라는 객체를 활용해야할 수 있다.

Car avante = new Car();

참조 변수명.필드명 // 필드값 불러오는 방법
System.out.println("내 차의 모델은 " + avante.model //필드에 있는 model이라 선언된 값 불러와 출력

참조 변수명.메서드명() // 메서드 호출하는 방법
avante.drive(); // drive으로 지정된 메서드를 호출해 운전기능실행
avante.stop(); // stop으로 지정된 메서드를 호출해 운전정지실행

첫번째로는 필드값을 불러와서 속성을 활용할 수 있고
메서드를 불러와서 기능을 활용할 수 있다.
이제 위에서 간단하게 설명한 필드와 메서드에 대한 내용들을 알아보자


필드(Field)

위에서 얘기했듯이 필드는 속성을 정의할 때 사용된다.
즉, 클래스에 포함된 변수를 의미한다.

자바 변수는 크게 3가지로 나뉜다.

  1. 클래스 변수 (class variable / cv)
  2. 인스턴스 변수 (instance variable / iv)
  3. 지역 변수 (local variable / lv)

이 세가지를 필드라부르고
static 키워드의 유무로 구분이 가능하다.

class Car{ 
    int carColor; // 인스턴스 변수
    static int carSzie // 클래스 변수
    
    void drive(){
    	int speed = 0; // 지역변수
    }

}


클래스변수 vs 인스턴스 변수

static이 있냐 없냐에 따라
인스턴수 변수냐, 클래스 변수냐의 차이를 나타난다고 하였는데

아래의 예제를 보며 살펴보자

public class example {
    int a = 1;
    static int b = 1;
}
public class Main{
    public static void main(String args[]) throws IOException {
    	//클래스명.인스턴스변수 = 오류
        System.out.println(example.a); //오류발생 
        
        //클래스명.클래스변수 = 정상
        System.out.println(example.b); //example 클래스의 클래스변수 b값이 출력됨
    }
}

example 클래스에 a라는 기본타입의 인스턴스 변수를 선언 및 할당하였고
b라는 기본타입의 클래스 변수를 선언 및 할당하였다.

*기본타입(정수타입,실수타입,문자타입,논리타입)
위에서 알 수 있는 사실은, 클래스명.클래스변수를 사용해야 값을 가져올 수 있다는 점

이 클래스의 인스턴스를 만들지 않고
호출할 수 있는 것은 클래스 변수이다.
인스턴스변수는 인스턴스를 만들고 선언이 가능하다.

public class Main{
    public static void main(String args[]) throws IOException {
    	example test = new example();
        System.out.println(example.a); //오류발생 기존 오류발생코드.
        
        System.out.println(test.a); // 인스턴스변수 값을 가져오는법
        System.out.println(example.b); //example 클래스의 클래스변수 b값이 출력됨
    }
}

위와 같이 test라는 인스턴스를 통해 인스턴스변수를 가져올 수 있다.


지역변수

지역변수는 메서드 내에 선언되며 메서드 내 {}블록에서만 사용이 가능한 변수다.

public class Car {
    int drive(){
        int a = 0;
        return a;
    }
    int speedChange(){
        return a; // 지역변수 a를 사용하지 못함
    }
}

예를들어 Car라는 클래스의
운전과, 속도변경의 기능은 메서드 2개가 있다고 가정할때.
int a 라는 지역변수를 drive() 메서드에 0이라는 값으로 할당하였다.
근데 이값을 speedChange() 메서드에 사용하고 싶어
위와 같이 return a를 하였을 경우 오류가 발생한다.
왜냐하면 a는 지역변수 이기때문에 메서드 내 {}블록에서만 사용가능한 변수이기 때문이다.

큰 특징은 멤버 변수와는 다르게 지역변수는 스택 메모리에 저장되어
메서드가 종료되는 것과 동시에 함께 소멸된다.

위에서 인스턴스 변수와 클래스 변수를 나눌때
static을 사용한다고 하였는데 이것에 대해 조금더 공부해보자


static

static은 클래스의 멤버에 사용하는 키워드이다.
*클래스의 멤버(필드,메서드,이너클래스)

멤버에 static 키워드가 붙어있으면 이것을 ‘정적 멤버(static member)‘라고 부른다.
기존에 new를 사용해 인스턴스를 만들어 인스턴스명.멤버명 이렇게 사용하면
힙 메모리에 생성되고 독립적인 저장공간을 가지게 된다.

반면 static으로 선언된 정적 멤버 클래스명.멤버명 이렇게 사용하게되면
클래스 내부에 저장 공간을 가지고 있기 때문에 객체 생성 없이 곧바로 사용이 가능하다.

이상 어려운 말은 끝났고
정말 간단 예제로 static의 사용법을 알아보자

public class Car {
        int seat = 4;
        static int tire  = 4;
}
public class Main{
    public static void main(String args[]) throws IOException {
        Car Hyundai = new Car();
        Car Kia  = new Car();

        Hyundai.seat = 5; // 현대는 자리가 5개!
        Kia.seat = 6; // 기아는 자리가 6개!
        System.out.println(Hyundai.seat); // 5
        System.out.println(Kia.seat); // 6

        Hyundai.tire = 5; // 현대는 바퀴가 5개!
        Kia.tire = 9; // 기아는 바퀴가 9개!
        System.out.println(Hyundai.tire); // 9
        System.out.println(Kia.tire); // 9
    }
}

간단하게 Car라는 클래스에
좌석수는 4개 int seat = 4;
바퀴가 4개 static int tire = 4;
로 설정해두었다고 가정하자

여기서 차이는 좌석은 인스턴스변수고 / 바퀴는 클래스 변수다.
이제 Car라는 Class로 각각 다른 자동차를 만들어보자
Car Hyundai = new Car();
Car Kia = new Car();
이렇게 2개의 인스턴스를 생성했고 각각 다른 객체이다.

여기서 먼저 해볼 것은. 인스턴스명.멤버명 으로 값을 변경해보는 것이다.
Hyundai.seat = 5; // 현대는 자리가 5개!
Kia.seat = 6; // 기아는 자리가 6개!
현대는 좌석을 5개, 기아는 좌석을 6개로 설정했을때

출력해보면 각각 인스턴스에 5개,6개의 좌석이 잘 생성된다.

하지만!
static을 사용한 정적멤버 변수인 tire를
Hyundai.tire = 5; // 현대는 바퀴가 5개!
Kia.tire = 9; // 기아는 바퀴가 9개!
이렇게 인스턴스명.멤버명 현대는 5개 , 기아는 9개로 바꾸어도

값을 공유하기 때문에 마지막에 저장한 9개가 출력되어진다.

Kia.tire = 9;
System.out.println(Hyundai.tire); // 9
System.out.println(Kia.tire); // 9

Car.tire = 20;
System.out.println(Hyundai.tire); // 20
System.out.println(Kia.tire); // 20

Hyundai.tire = 5;
System.out.println(Hyundai.tire); // 5
System.out.println(Kia.tire); // 5

Kia.tire = 10;
System.out.println(Hyundai.tire); // 10
System.out.println(Kia.tire); // 10

//새로운 인스턴스 토요타 등장!
Car Toyota = new Car();
System.out.println(Toyota.tire); // 10

결론!
결과적으론 static으로 설정한 멤버(필드,메서드,이너클래스)들을
값을 공유하기때문에 인스턴스를 새로생성해도 그값을 가지고 있다.


Static 변수와 instance 변수

public class Car {
        int seat = 4; // 인스턴스 변수
        static int tire  = 4; // 클래스 변수
        public static void abc(){ // 클래스 메서드
                System.out.println(seat); // 에러 발생
                System.out.println(tire);
        }
}

non-static variable this cannot be referenced from a static context
클래스 메서드인 abc()안에 인스턴스 변수를 사용했더니 위와 같은 알람이 발생한다.
Referenced(참조)를 하려면 메모리 어딘가에 인스턴스가 있어야함

check !! 클래스메서드에서는 클래스 변수만 접근이 가능하다!! 즉, 인스턴스 변수 접근불가


메서드(Method)

메서드는 특정 작업을 수행하는 일련의 명령문들의 집합이다.
앞에 얘기했던 것 처럼 기능에 속한다.
메서드는 크게 메서드 시그니처와 메서드 바디로 구분한다.

선언방법

자바제어자 반환타입 메서드명(매개 변수) { // 메서드 시그니처
	메서드 내용 // 메서드 바디
}

메서드명은 관련적으로 소문자로 표시하니 참고하자.

public static int add(int x, int y) { // 메서드 시그니처
	int result = x + y; // 메서드 바디
	return result;
}

접근제어자는(public,private)등 으로 이후에 배울 항목이니 우선 패스하자
static은 위에서 배웠듯이 클래스 메서드를 생성한 것이다.
여기서 int가 반환타입인데 반환타입이 없을 경우에는 void로 작성한다.
void가 아닌 경우에는 반드시 return이 있어야한다.


호출방법

메서드를 정의해놓아도 호출하지 않으면 아무런 일도 일어나지 않는다
메서드도 클래스의 멤버이므로 클래스 외부에서 메서드를 사용하기 위해서는
먼저 인스턴스를 생성해야하고 포인트 연산자(.)를 통해 메서드를 호출할 수 있다.
하지만, 클래스 내부에 있는 메서드끼리는 따로 객체를 생성하지 않고도 서로 호출가능!!!

클래스 내부에 있는 메서드끼리 호출방법.

메서드이름(매개변수1,매개변수2, ...); // 메서드 호출방법, 매개변수 없을 경우있음
public class Main{
    public static void main(String args[]) {
        int result = add(1,2);
        System.out.println(result);
    }
    public static int add(int x,int y){
        return x+y;
    }
}

같은 Main Class에 있는 메서드 끼리는
add(1,2); 이런식으로 인스턴스를 생성하지 않아도 호출이 가능하다.


외부 클래스에 있는 메서드끼리 호출방법.

public class Main{
    public static void main(String args[]) {
        Calculate plus = new Calculate();
        int result = plus.add(1,2);
        System.out.println(result);
    }
}
public class Calculate {
    public static int add(int x,int y){
        return x+y;
    }
}

이렇게 2개의 클래스가 있다고 가정해보자
함수를 호출하기위해선 인스턴스를 만들어주어야하고
위에서 Calculate라는 클래스를 이용해 plus라는 인스턴스를 만들었다.
여기서 plus.add(1,2); 인자를 입력해 함수를 호출했다.
여기서 plus.add(인자); 안에있는 값을 인자(argument)라고한다.
메서드를 정의할 때 선언된 매개변수와 일치가 되어야한다.


메서드의 오버로딩

메서드 오버로딩은 하나의 클래스 안에 같은 이름의 메서드를 여러개 정의하는 것이다.
쉽게말해 같은 메서드 이름이 여러개 있는데 메서드의 매개변수의 타입과 수가 달라지는 것이다.

오버로딩의 조건

  1. 메서드의 이름이 같아야한다.
  2. 매개변수의 개수 또는 타입이 달라야한다.

간단한 예제를 들어보자

public class Main {
    public static void main(String[] args) {
        Transfer taxi = new Transfer(); // 객체 생성
 
        taxi.fuel(); // 메서드 호출
        taxi.fuel(5); 
        taxi.fuel("Diesel",10);
    }
}

class Transfer {
    public void fuel() { // 메서드 오버로딩. 같은 이름의 메서드 3개.
        System.out.println("기름부족");
    }
    public void fuel(int remain) {
        System.out.println("기름부족:" + remain + "L");
    }

    public void fuel(String whatfuel, int remain) {
        System.out.println("연로:" + whatfuel + "기름부족:" + remain + "L");
    }
}

//기름부족
//기름부족:5L
//연로:Diesel기름부족:10L

fuel(연료)라는 같은 메서드 이름을가진 것들이 3개가 존재한다.
하지만 메서드마다 매개변수가 다르고
다른 것에따라 출력값도 달라지게된다.
이러한 경우를 오버로딩되었다고한다.



마치며…

오늘은 많은 개념과 내용을 배웠다.
솔직히 한번에 이해했다고 하면 거짓말일 것 같다.
객체지향의 Class에 해당하는 필드와 메서드에 대해
조금 중점적으로 공부해보았는데 머리가 터질 것 같다.

하지만 문제없다. 나에게는 주말과 복습이라는 친구가 있으니
대략적인 큰틀과 내용은 이해했지만 조금 더
개념에 대해 확실히 알아가고 생소한 이름들이 너무 많아
얘기할때 바로 이것이 무엇이다! 라고 정의가 되고 머릿속에서
그려지는 정도까지 숙달해야할 것같다!!

오늘 공부는 여기서 끝!!!


오늘의 커피량: ☕️ ☕️ ☕️ ☕️️️️
오늘의 점심: 뼈해장국, 햄계란부침, 공기밥