Posts ☕️ [Java] 유튜브 주간컴공 학습자료
Post
Cancel

☕️ [Java] 유튜브 주간컴공 학습자료

◻️ Java 나중에 살펴볼 자료


본 자료는 유튜브 주간컴공의 프로그래밍 언어 활용(Java)을 정리한 내용이다.
지금은 언어를 잘 몰라서 이해가 되지 않지만 나중에 돌아와서 살펴보기 위해 작성해 놓았다.



◻️ Java


  • 클래스와 객체
    1) Java에서의 클래스

    • Java는 모든 코드가 클래스이다
    • main 메소드를 포함하는 클래스를 가장 먼저 실행한다
    • 멤버(member): 클래스에 포함되는 요소
    • 데이터는 객체 생성을 통하여 확보한다
1
2
3
4
5
6
7
8
9
10
11
// Circle 클래스 정의
class Circle{
    ...
}

// Hello World 클래스 정의(프로그램 시작지점)
public class HelloWorld{
    public static void main(String[] args){
        ...
    }
}


2) 클래스의 구성

1️⃣ 멤버 변수

  • 객체가 가지는 모든 상태, 수치, 성질
  • C언어에서의 구조체(사용자 정의 자료형)과 유사
  • 다른 객체에서 접근할 수 없도록 정보은닉하여 사이드 이펙트 최소화

2️⃣ 멤버 메소드

  • 객체에서 발생하는 모든 연산 및 제어, 요청행위
  • C언어에서의 함수와 유사
1
2
3
4
5
6
7
8
9
10
11
12
// Circle 클래스 정의
class Circle{
    // 멤버 변수 정의
    double pi = 3.141592;
    double radius;

    // 멤버 메소드 정의
    void volume(){
        // 원의 부피 출력
        System.out.println(radius * radius * pi);
    }
}
  • Java의 출력 메소드 print는 그냥 출력만하는 print,
  • 줄바꿈까지 해주는 println이 있고
  • 서식 지정이 가능한 printf까지 총 3가지가 대표적이다


3) 접근 지정자

1️⃣ 접근 지정자의 정의

  • 클래스 내 멤버들의 접근 수준을 결정하는 토큰
  • 프로그램, 패키지, 하위 클래스, 자신의 순서

2️⃣ 접근 지정자의 종류

  • public: 프로그램 내 모든 객체에서 접근 가능
  • default(생략): 같은 패키지 안에서만 접근 가능
  • protected: 자신과 하위 클래스에서만 접근 가능
  • private: 자신의 클래스에서만 접근 가능
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
// 접근 지정자를 생략하면 default로 인식
class Circle{
    // 멤버 변수는 외부 접근 불가능
    private double pi = 3.141592;
    private double radius;

    // 같은 패키지 안에서만 접근 가능
    void volume(){
        System.out.println(radius * radius * pi);
    }
    // private 멤버 접근을 위한 public 메소드 정의
    public void set_radius(double r){
        radius = r;
    }
}


4) 생성자(Constructor) 메소드

1️⃣ 생성자 메소드의 정의

  • 클래스 내부에 존재하며 객체 생성시 자동으로 실행
  • 객체가 생성될 때 외에는 별도로 실행 불가
  • 정의되어 있지 않으면 자바에서 자동 생성
  • 객체 생성시 멤버 변수 초기화 처리
  • 생성자 메소드명은 클래스명과 동일, 리턴 타입 없음

    2️⃣ this
  • 클래스 자신에 포함된 멤버 변수에 접근하기 위한 토큰
  • 메소드 명이 같아도, 매개변수의 개수나 타입이 다르면 사용 가능
  • 이름이 동일한 다른 지역 변수와 구분을 위한 사용

    3️⃣ Overloading
  • 동일한 이름을 가진 여러 메소드를 사용하는 기술
  • 같은 메소드명으로 서로 다른 기능을 정의할 수 있는 오버로딩
  • 메소드의 인수 유형과 개수의 차이로 각 메소드 구별
  • 생성자 메소드 뿐 아니라 모든 메소드에 적용 가능

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
class Circle{
    private double pi = 3.141592;
    private double radius;
    // 실수 인수를 전달하여 객체 생성시 자동실행
    Circle(double radius){
        this.radius = radius;
        System.out.println("객체가 생성되었습니다.");
    }
    // 인수 전달 없이 객체 생성시 자동실행
    Circle(){ // 같은 메소드 명으로 서로 다른 기능을 정의하는 오버로딩
        this radius = 3.0;
        System.out.println("기본 객체가 생성되었습니다");
    }
}
    public class HelloWorld{
        public static void main(String[] args){
            Cicle c1 = new Cicle(5.0);  // 인수를 전달하여 객체 생성시 호출
            Cicle c2 = new Cicle();     // 인수 없이 객체 생성시 호출
        }
    }

5) 객체 생성

1️⃣ 인스턴스 생성

  • 새로운 객체를 생성하여 적절한 타입의 변수에 할당
  • new 키워드를 이용하여 인스턴스를 생성 ➡ 생성자 호출
  • 일반적으로 인스턴스의 타입과 객체 변수의 타입이 동일함

2️⃣ 객체의 멤버 접근

  • 객체변수와 점(.)을 이용
  • 접근 지정자에 따라 직접 접근이 어려울 수 있음
  • 멤버 변수에 static 키워드를 붙여 생성하면, 모든 객체가 공유하는 데이터 생성 가능
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
class Circle{
    private double pi = 3.141592;
    private double radius;
    private static int cnt = 0;

    Circle(double radius){
        this.radius = radius;
        this.cnt++; // static 변수를 증가시켜줌
        System.out.println(this.cnt + "번 객체가 생성되었습니다.");
    }
    void created_cnt(){
        System.out.println("총 " + this.cnt + "개 도형이 존재합니다.");
    }
}
public class Helloworld{
    public static void main(String[] args){
        // Cicle 인스턴스 생성
        Circle c1 = new Circle(5.0); // static이기 때문에 +1
        Circle c2 = new Circle(4.0); //                  +1
        Circle c3 = new Circle(6.0); //                  +1 결과로 출력됨
        c1.created_cnt();
    }
}



상속


1) 상위 클래스

  • 상위 클래스는 대부분의 속성을 하위클래스에게 상속
  • 여러 하위 클래스가 사용할 공통된 속성을 구현
  • 상위 클래스 단독으로 인스턴스 생성 가능

2) 하위 클래스

  • 상속 받은 상위 클래스 대부분의 속성을 포함
  • extends 키워드를 사용하여 상속받을 상위 클래스 지정
  • 상위 클래스의 매소드를 재사용, 재정의하여 사용

3) Overriding

  • 상위 클래스의 메소드를 재정의하여 사용하는 기술
  • 상위 클래스와 동일한 메소드명과 매개변수 지정
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
class Espresso{
    int espresso = 20;
    void recipe(){
        System.out.println("에스프레소 " + espresso + "ml");
    }
}

class Americano extend Espresso{ //아메리카노 클래스에서 Espresso를 상속받음
    int water = 80; 
    // water 변수밖에 없지만, 상속을 받았기 때문에 Espresso 변수 역시 사용 가능
    // 따라서 recipe 메소드도 사용 가능
    void recipe(){
        // Espresso 클래스의 recipe 메소드를 재정의하여 사용할 수 있다
        // 이렇게 하면 Espresso 인스턴스의 레시피 메소드는 에스프레소 용량만,
        // 아메리카노 인스턴스의 레시피 메소드는 에스프레소와 물이 나온다!
        System.out.print("에스프레소 " + espresso + "ml + 물" + water + "ml");
    }
}

public class HelloWorld{
    public static void main(String[] args){
        Espresso e1 = new Espresso();
        e1.recipe();
        Americano a1 = new Americano();
        a1.recipe();
    }
}


4) 추상 클래스

1️⃣ 추상 클래스 개념

  • 클래스의 체계적인 설계를 위해 사용하는 클래스
  • 선언부만 있고 구현부가 없는 추상 메소드를 하나 이상 포함
  • 반드시 하위 클래스에서 상속하여 추상 메소드를 오버라이딩 해야 인스턴스 생성 가능
  • 상속된 클래스에서도 구현되지 않은 추상 메소드가 있다면 그 역시 추상 클래스이므로 인스턴스 생성 불가
  • 각각의 하위 클래스에서 수행되는 유사한 기능을 하나의 이름으로 통일 가능

2️⃣ 추상 클래스 구현

  • abstract 키워드를 사용하여 클래스와 매소드 구현
  • 메소드의 구현부(중괄호)를 생략하여 표현
  • 추상 클래스를 상속받은 후 해당 메소드를 오버라이딩
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
abstract class Shape{
    abstract void draw();
}
class Circle extends Shape{ //Circle과 Rectangle 클래스가 각각 상속받아 메소드 오버라이딩 진행
    void draw(){
        System.out.println("원을 그립니다");
    }
}
class Rectangle extends Shape{ 
    // Circle과 Rectangle은 같은 메소드명으로 각각 다른 일을 할 수 있게 됨(상속의 힘)
    void draw(){
        System.out.println("사각형을 그립니다")
    }
}
public class HelloWorld{
    public static void main(String[] args){
        Circle c1 = new Circle();
        Rectangle r1 = new Rectangle();
        c1.draw();
        r1.draw();
    }
}

5) 인터페이스

  • Java에서는 여러 클래스를 다중 상속 받을 수 없다. 상속관계가 복잡해지면 알 수 없는 부작용이 발생할 확률이 매우 높아지기 때문이다
  • 따라서 인터페이스를 사용하여 다중상속의 이점을 활용할 수 있다.

1️⃣ 다중 상속의 문제점

  • 다중 상속: 둘 이상의 상위 클래스를 상속받는 것
  • 상위클래스 A, B가 같은 클래스 C를 상속받는 경우와 같이 상속 관계가 복잡해지면 알 수 없는 부작용 발생할 확률 상승

2️⃣ 인터페이스의 특징

  • 모든 메소드가 추상 메소드로 정의되어 있는 추상 클래스
  • 상속을 받지 않기 때문에 다중 상속의 부정적 영향을 전혀 받지 않고 다중 상속의 장점 활용 가능
  • 상속은 기존 클래스의 속성을 확장하는 개념을 가지지만, 인터페이스는 하나의 확장된 클래스로 기능을 제한하거나 다른 기능을 수행하도록 변경(다형성)

3️⃣ 인터페이스 구현

  • class 대신 interface 키워드를 사용하여 구현하고, implements 키워드를 사용하여 상속
  • 확장된 클래스의 인스턴스를 상위 인터페이스 타입의 객체 변수에 할당하여 기능을 변경하거나 제한
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
interface Coffee{
    abstract void drink_coffee();
}

interface Cookie{
    abstract void eat_cookie();
}

class Cafe implements Coffee, Cookie
{
    public void drink_coffee(){
        System.out.println("커피를 마신다.");
    }
    public void eat_cookie(){
        System.out.println("쿠키를 먹는다.");
    }
    public void talk(){
        System.out.println("대화를 한다.");
    }
}
public class HelloWorld{
    public static void main(){
        Cafe k = new Cafe();
        k.drink_coffee();
        k.eat_cookie();
        k.talk();

        Coffee c = k;   //커피 객체 변수에 할당
        c.drink_coffee();

        Cookie x = k;   //쿠기 객체 변수에 할당
        x.eat_cookie();
    }
}

👀 위에서 Cafe 객체는 drink_coffee, eat_cookie, talk 까지,
3가지 메소드 사용이 가능한 상태가 된다. 따라서 객체를 생성하면 3가지 메소드 호출이 전부 가능하다

그런데 만약 3가지 기능이 가능한 카페 인스턴스를 일시적으로
drink_coffee만 가능하도록 제한을 걸어주고 싶다면, 해당 객체를 커피 객체 변수에 할당하면 된다.

이렇게 하면 새로이 커피 객체를 만들 필요 없이
커피 객체만으로도 커피 기능을 하는 객체역할을 수행할 수 있게 된다(쿠키도 마찬가지)

하나의 확장된 객체로 모든 기능, 또는 일부 기능만을 수행할 수 있는 형태로
변형이 가능한 상태, 이게 바로 다형성의 특징이며 객체지향 기술의 궁극적인 목표가 된다.


예외처리


1) 예외처리개념

  • 예외를 해결(처리)하는 코드를 구현하는 것이다
  • 문법 오류(Syntax Error): 괄호를 잘못 쓰거나, 함수명 오타 등으로 발생하는 문제
  • 예외: 문법이나 표현식에는 문제가 없지만 의도치 않은 작동 및 입력으로 문제가 발생하는 것

2) Java의 예외처리 방식

  • 예외가 발생할 수 있는 영역을 try 블록으로 감싸고
  • 예외처리를 위한 코드를 catch 블록으로 감싸둔다
  • catch 블록은 예외가 발생하지 않으면 실행되지 않는다
  • finally 블록은 무조건 실행하는 부분이다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
public class HelloWorld{
    public static void main(String[] args){
        // 멤버 변수 영역
        try{
            // 예외 감지 영역
        }
        catch{
            // 예외 감지시 실행 영역
        }
        finally{
            // 무조건 실행되는 영역
        }
    }
}
This post is licensed under CC BY 4.0 by the author.