본문 바로가기

복습

[Java 복습] 클래스와 메서드

자바란?

  • 프로그래밍 언어
  • 컴퓨터 프로그램(애플리케이션)을 만드는데 사용
  • 실행환경(JRE) + 개발도구(JDK) + 라이브러리(API)

 


어디에 쓰일까?

  • PC 애플리케이션 <- 인텔리제이, 이클립스
  • 웹 애플리케이션 <- 웹사이트, 스프링
  • 모바일 애플리케이션(안드로이드) 
  • 빅데이터
  • 게임, 과학, 소형기기 등

 

왜 자바일까?

  • 다양한 분야에서 활발히 사용
  • 20년 동안 프로그래밍 언어 1,2 위(현재는 파이썬, 자바 스크립트)
  • 자바를 배우면 컴퓨터에 대한 일반적인 지식
  • 모던 프로그래밍 언어(객체지향 + 자바8. 함수형)
  • 넓은 생태계 

  • JAVA SE -> 일반적인
  • JAVA ME -> 소형
  • JAVA EE -> 대기업


자바의 특징

  1.  배우기 쉬운 객체지향 언어 = 프로그래밍 언어 + 객체지향개념(C++, JAVA, PYTHON, JS)
  2.  자동 메모리 관리(GC)
  3. 멀티 쓰레드 지원(채팅 + 문서 보내기)
  4.  풍부한 라이브러리로 쉽게 개발가능
  5. 운영체제에 독립적(WINDOWS, LINUX)



자바 가상 머신(JVM)

  • 자바 프로그램이 실행되는 가상 컴퓨터(VM)
  • 한번 작성하면 어디서든 실행

 


객체지향 언어

  1. 80년대 초 소프트웨어의 위기 - 빠른 변화를 쫒아가기 힘듬
  2. 해결책으로 객체지향 언어를 도입(절차적 -> 객체지향)
  3. 코드의 재사용성이 높고, 유지보수 용이(빠른 변화에 쫒아갈 수 있음), 중복 코드 제거
  4. 객체지향 언어 = 프로그래밍 언어 + 객체지향개념(개념, 규칙) <-규칙은 외우자

 


OOP의 핵심개념

  1. 캡술화
  2. 상속
  3. 추상화
  4. 다형성 <- 제일 중요!!


클래스와 객체

  • 클래스 정의: 클래스란 객체를 정의해 놓은 것
  • 클래스의 용도: 클래스는 객체를 생성하는데 사용

 

  • 객체의 정의: 실제로 존재하는 것, 사물 또는 개념
  • 객체의 용도: 객체가 가지고 있는 기능과 속성에 따라 다름

 

객체의 구성요소 - 속성과 기능

객체 = 속성(변수) + 기능(메서드)
하드웨어 -> 소프트웨어화



TV

  • 속성: 크기, 길이, 높이, 색상, 볼륨, 채널 등
  • 기능: 켜기, 끄기, 볼륨 높이기, 볼륨 낮추기, 채널 변경하기 등

 

객체: 모든 인스턴스를 대표하는 일반적 용어
인스턴스: 특정 클래스로부터 생성된 객체(TV 인스턴스)


(설계도)    (인스턴스화)       (제품) - 사용
클래스 ---------------------> 인스턴스(객체)


Q. 클래스(설계도)가 왜 필요할까?
A. 객체(제품)를 생성하기 위해서

Q. 객체가 왜 필요한가?
A. (제품)우리가 사용하기 위해서

Q. 객체를 사용한다는 것은?
A. 객체가 가진 속성(변수)과 기능(메서드)을 사용하려고!


클래스 

 

  1. 설계도
  2. 데이터 + 함수 - 관련 있는 서로 다른 타입을 묶어둘 수 있다.
  3. 사용자 정의 타입 - 원하는 타입을 직접 만들 수 있다.
  • 변수: 하나의 데이터를 저장할 수 있는 공간
  • 배열: 같은 종류의 여러 데이터를 하나로 저장할 수 있는 공간
  • 구조체: 서로 연관된 여러 데이터(종류 관계X) 를 하나로 저장할 수 있는 공간
  •  클래스: 데이터와 함수의 결합(구조체 + 함수)



선언 위치에 따른 변수의 종류

  • 영역:
  • 클래스 영역
  • 메서드 영역 
{ 
     1.int iv;             // 인스턴스 변수                      ] (선언문만 가능)
     2.static int cv;    // 클래스 변수(static 변수, 공유 변수)   ]  클래스 영역

      void method() {
      3. int lv = 0; // 지역 변수                               ]  메서드 영역 (메서드 선언문)
    }
}

 

변수의 종류      

선언 위치      

 생성시기

클래스 변수 

클래스 영역     

클래스가
메모리에 올라갈 때

인스턴스 변수

클래스 영역      

인스턴스(객체)가
생성되었을 때 ★

지역 변수

클래스 영역 이외의 영역

변수 선언문이
수행되었을 때

 


차이점

  • CV(static)는 자동 아무때나 사용가능(객체 생성X  ram (로딩) -> cpu)
  • IV는 객체를 만들어야 사용가능(객체 생성O)
  • LV는 메서드 호출되서 메서드가 끝날 때까지 후에는 자동제거

 

정리

  • 객체는 iv 변수의 묶음
  • iv는 참조변수가 없어지면 GC에 의하여 사라짐

 


클래스 변수와 인스턴스 변수의 차이점

속성 - 예시: 포커 카드

  • 무늬, 숫자(개별 속성) - 인스턴스 변수(인스턴스 속성이 개별적인 것)
  • 카드폭, 높이 (공통 속성) - 클래스 변수(모든 인스턴스가 가지는 속성)
class Card {
    String kind; // 무늬    >
    int number; // 숫자     > 개별 iv

    static int width = 100; // 폭      >
    static int height = 250; // 높이   > 공통 cv
}


Card 객체 사용

Card c = new Card(); // 객체 생성

c.kind = "HEART"  ]   
c.number = 5;  ]   객체 사용
 
c.width = 200;    권장 x]               Card.width = 200;  
c.height = 300;   권장 x]   객체 사용 -> Card.height = 300;



static <- 인스턴스 변수와 같은 공간에 있으면 메모리 낭비
왜? -> 어차피 같은 모든 객체에 같은 값이 들어있을텐데 ?
-> 그래서 클래스 변수를 건들지 말라고 final로 막는 것 같음
어떻게? -> final static -> cv(클래스 변수)는 다른 공간에 한개만 만들어진다!

  • + 객체는 힙영역에 저장되는 것 같다. 
  • + static은 클래스 영역

-> static을 바꾼다면 굳이 cv로 만들필요가 없을 것 같다. 걍 인스턴스 변수로 만들지..
모든 객체가 공유하는 것이 클래스 변수(static 변수)

 

return문 

  • 실행 중인 메서드를 종료하고 호출한 곳으로 되돌아간다.
  • 반환타입이 void가 아닌 경우, 반드시 return문 필요
  • 메서드가 작업을 마쳤을 때 반환 타입이 void이면 생략 가능(컴파일 자동추가)

 

호출 스택(call stack)

  • 스택(stack): 밑이 막힌 상자. 위에 차곡차곡 쌓인다.
  • 메서드가 수행에 필요한 메모리가 제공되는 공간
  • 메서드가 호출되면 호출스택에 메모리 할당, 종료되면 해제

아래 있는 메서드가 위의 메서드를 호출한 것
맨 위의 메서드 하나만 실행 중, 나머지는 대기중

 

 

 

static 메서드와 인스턴스 메서드


인스턴스 메서드

  • 인스턴스 생성후, '참조변수. 메서드이름( )' 으로 호출
  • 인스턴스 멤버(iv, im)와 관련된 작업을 하는 메서드
  • 메서드 내에서 인스턴스 변수(iv) 사용가능

 

static 메서드(클래스 메서드)

  • 객체 생성없이 '클래스이름.메서드이름( )' 으로 호출
  • 인스턴스 멤버(iv, im)와 관련없는 작업을 하는 메서드
  • 메서드 내에서 인스턴스 변수(iv) 사용불가

 

그렇다면 메서드를 생성할 때 static 키워드를 사용유무를 정할까?

  • 메서드 내에서 인스턴스 변수(iv) 사용여부
  • 이건 전에 공부하다 놓친 것 같다.
  • 리터럴 값을 넣어도 마찬가지
  • static 메서드는 인스턴스 변수, 메서드를 쓸 수 없다!  
  • 공통 속성이여서 static을 붙이는게 아니다.
  • 인스턴스 변수를 안 쓸때 (im은 iv를 사용하는 메서드) static을 사용한다.

 

인스턴스 메서드도 사용하지 못한다. 멤버(iv, im)를 사용하지 못한다.

 

그럼 어떻게 쓸 수 있을까? =====> 이런 식으로 인스턴스 변수가 아닌 지역 변수로 사용할 수 있다.

public class isUseIv {

    int iv; // 인스턴스 변수
    static int cv; // 클래스 변수

    void instanceMethod() { // 인스턴스 메서드
        System.out.println(iv);
        System.out.println(cv);
    }

    static void staticMethod() { // static 메서드
        System.out.println(iv); // 에러!!! 인스턴스 변수를 사용할 수 없다.
        System.out.println(cv); // 클래스 변수는 사용할 수 있다.
    }
}

 

그렇다면 왜 인스턴스 변수를 사용할 수 없을까?

  • 클래스(static) 변수는 객체 생성 없이 호출이 가능하다. (항상 호출 ok)
  • 인스턴스 변수는 객체 생성 후 호출이 가능하기 때문이다.
  • 마찬가지로 인스턴스 메서드도 호출할 수 없다. => (인스턴스로 작업하는 메서드 이기 때문에)
  • 물론 객체를 생성후에 접근해서 호출할 수는 있다.
public class isUseIv {

    int iv; // 인스턴스 변수
    static int cv; // 클래스 변수

    void instanceMethod() { // 인스턴스 메서드
        System.out.println(iv);
        System.out.println(cv);
    }

    static void staticMethod() { // static 메서드
        isUseIv useIv = new isUseIv(); // 객체 생성
        System.out.println(useIv.iv); // 객체 생성 후에는 호출할 수 있다.
        System.out.println(cv); // 클래스 변수는 사용할 수 있다.
    }
}

Q. static 메서드는 static 메서드 호출가능?
A. OK

Q. static 메서드는 인스턴스 변수 사용가능?
A. NO (인스턴스 변수는 객체 생성해야 사용가능)  객체 = 인스턴스 변수 묶음

Q. static 메서드는 인스턴스 메서드 사용가능?

A. NO (인스턴스 메서드는 인스턴스 메서드를 필요로 하기 때문에)

 

Q. static 메서드는 인스턴스 멤버를 쓸 수 없나요?

A. static 메서드 호출시 객체(iv 묶음)가 없을 수도 있어서 <- static 메서드는 항상 호출 가능하기 때문에

 

정리

인스턴스 변수를 호출하기 위해서는 객체가 생성되어야 하는데 static 메서드는 항상 호출이 가능하기 때문에

객체(인스턴스 변수 묶음)가 없을 수 도 있다. => 생성시기가 다르기 때문에

 

 

메서드 오버로딩(과적)

한 클래스 안에 같은 이름의 메서드 여러 개를 정의하는 것

 

 

예시

  • 만약 오버로딩을 지원하지 않는다면.. 이름이 다 달라졌을거다.. 과연 다 외울 수 있었을까?

 

오버로딩이 성립하기 위한 조건 3가지

  1. 메서드 이름이 같아야 한다.
  2. 매개변수의 개수 또는 타입이 달라야 한다.
  3. 반환 타입은 영향없다.

 

 

생성자

  • 인스턴스가 생성될 때마다 호출되는 '인스턴스 초기화 메서드'
  • 인스턴스 생성시 수행할 작업(iv 초기화)에 사용
Time t = new Time(); // new: 객체생성(참조값), Time(): 기본생성자 호출
t.hour = 12;
t.minute = 34;
t.second = 56;

Time t = new Time(12, 34, 56); // 생성자 호출

 

생성자 규칙

  • 이름이 클래스 이름과 같아야 한다.
  • 리턴 값이 없다. (void 안 붙임)
  • 모든 클래스는 반드시 한개 이상의 생성자를 가져야 한다.

 

 

기본 생성자

  • 매개변수가 없는 생성자
  • 생성자가 하나도 없을 때만, 컴파일러가 자동 추가

 

 

생성자 this

  • 생성자에서 다른 생성자 호출할 때 사용
  • 다른 생성자 호출시 첫 줄에서만 사용가능
public class Human {

    String name;
    String job;
    int age;

    Human() {
        /*name = "홍길동";
        job = "취준생";        <----- 코드 중복 제거
        age = 0;
         */
        this("홍길동", "취준생", 0); // Human(String name, String job, int age)를 호출
    }
    public Human(String job) {
        this("홍길동", job, 0); // Human(String name, String job, int age)를 호출
    }

    Human(String name, String job, int age) {
        name = name;
        job = job;
        age = age;
    }
}

 

 

참조 변수 this

  • 인스턴스 자신을 가리키는 참조 변수
  • 인스턴스 메서드(생성자 포함) 에서 사용가능
  • 클래스 메서드 사용X
  • 지역 변수와 인스턴스 변수를 구별할 때 사용
public class Human {

    String name;
    String job;
    int age;

    Human() {
        this("홍길동", "취준생", 0); // Human(String name, String job, int age)를 호출
    }
    public Human(String job) {
        this("홍길동", job, 0); // Human(String name, String job, int age)를 호출
    }

    Human(String name, String job, int age) {
         //iv       //lv     this: 생략 가능하지만 사용 권장
        this.name = name;
        this.job = job;
        this.age = age;
    }
}

 

 

참조변수 this( )와 생성자 this( )

this:

  • 인스턴스 자신을 가리키는 참조변수, 인스턴스의 주소가 저장되어 있다.
  • 모든 인스턴스 메서드에 지역변수로 숨겨진 채 존재한다.
public class Human {
    String name; // this.name
    String job; // this.job
    int age; // this.age
}

 

this( ), this(매개변수):

  • 생성자, 같은 클래스의 다른 생성자를 호출할 때 사용한다.
  • 클래스 이름 대신 this( )를 사용한다.

참고: this와 this는 비슷하게 생겼을 뿐 완전히 다른 것이다. this는 '참조변수' 이고, this( )는 '생성자' 이다.

 

 

변수의 초기화

  • 지역 변수는 수동 초기화 해야함(사용전 꼭!!!)
  • 맴버 변수는 자동 초기화 된다.
class initTest {
    int x;     // 인스턴스 변수
    int y = x; // 인스턴스 변수
    
    void method1() {
        int i;     // 지역변수
        int j = i; // 에러! 지역변수를 초기화하지 않고 사용
        }
    }

 

멤버 변수(iv, cv)의 초기화

1. 명시적 초기화(=)

class Car {
    int door = 4; // 기본형 변수의 초기화
    Engine e = new Engine(); // 참조형 변수의 초기화
}

 

2. 초기화 블럭

  • 인스턴스 초기화 블럭: { }
  • 클래스 초기화 블럭: static { }

 

3. 생성자(인스턴스 변수 초기화)

 Human(String name, String job, int age) {
        this.name = name;
        this.job = job;
        this.age = age;
    }

 

초기화 시점

  • 클래스 변수 초기화 시점: 클래스가 처음 로딩될 때(메모리에 올라갈 때) 단 한번
  • 인스턴스 변수 초기화 시점: 인스턴스가 생성될 때 마다
  • 초기화 순서: 클래스 변수 초기화 => 인스턴스 변수 초기화

 

오늘의 복습은 마쳤고, 아래는 복습하면서 간단하게 만들어봤다.

public class Card {

    public static int width = 200;
    public static int height = 300;
    private String kind;
    private int number;
    private String[] kinds = {"스페이스", "하트", "클로버", "다이아몬드"};
    
    Card() {
    // 기본 생성자
    }
    public void drawCard() {
        this.kind = kinds[shuffleKind()];
        this.number = shuffleNum();
    }

    public void show() {
        System.out.println("당신의 카드: " + kind);
        System.out.println("당신의 숫자: " + number);
    }

    private int shuffleKind() {
        double random = Math.random();
        int num = (int)Math.round(random * (kinds.length -1));
        return num;
    }

    private int shuffleNum() {
        double random = Math.random();
        int num = (int)Math.round((random * 9) + 1);
        return num;
    }
}
  • K,Q,J 문자를 제외한 카드뽑기 로직이다.
  • shuffleKind, shuffleNum을 통해 랜덤으로 카드종류와 숫자를 뽑아냈다.
  • 뽑은 문자열과, 숫자를 인스턴스 변수에 대입했다.
  • 넓이와 높이는 이후 Main 로직에서 Card.width, Card.height를 써보기 위해 접근제어자로public 을 선택했다.
  • shuffleKind에 0 ~ 3 랜덤 값을 리턴시켜 String 배열의 인덱스를 설정하고 뽑아냈다(ex. kinds[num]).
  • 굳이 밖에서 쓸 필요없는 내부로직은 접근제어자 private로 막았다.
  • 이를 통해 Main에서는 drawCard( ), show( ) 메서드를 이용해 랜덤한 카드를 뽑을 수 있다.
public class CardMain {

    public static void main(String[] args) {

        Card card = new Card();
        Scanner scanner = new Scanner(System.in);
        while (true){
            card.drawCard();
            card.show();
            if (scanner.nextLine().equals("e")) {
                break;
            }
        }
        System.out.println("현재 카드의 넓이는: " + Card.width);
        System.out.println("현재 카드의 높이는: " + Card.height);
    }
}
  • shuffleNum( ), shuffleKind( )가 정상적으로 숫자들을 뽑는지 검증하기 위해 while로 반복했다.
  • "e" 라는 문자를 치지 않는 이상 계속 반복해서 인스턴스 변수에 랜덤한 종류와 숫자를 대입할 것이다.

 

 

'복습' 카테고리의 다른 글

[Java 복습] 예외처리  (1) 2024.05.02
[Java 복습] 내부 클래스  (0) 2024.05.02
[Java 복습] 인터페이스의 장점  (0) 2024.05.02
[Java 복습] 다형성의 장점  (0) 2024.04.30
[Java 복습] 상속, 캡슐화, 다형성  (0) 2024.04.30