JAVA - 그림으로 배우는 자바2 (객체지향)

캉코딩·2022년 12월 26일
0

Java

목록 보기
2/2

그림으로 배우는 JAVA 입문내용을 수강 후 , 강사님의 뛰어난 강의력에 반해 2탄을 수강하게 됐다. OOP 는 들을 때마다 새로웠는데, 이번 강의를 통해 확실히 개념을 익혀보자 !

1. 객체지향 프로그래밍

  • oop란 ? Object Oriented Programming 즉 조립식 프로그래밍으로 부분적 기능을 만들고 이를 조립하여 전체를 완성하는 방식.
  • oop의 장점:
    1. 관리가 편하다 → 프로그램의 일부에 문제가 생긴 경우 해당 부분에 대해서만 문제를 해결하면 된다.
    2. 객체를 재사용할 수 있다 → 한번 객체를 만들어 놓으면 다른 프로그램에서도 쉽게 객체를 가져다 쓸 수 있다.
    3. 프로그램 확장이 편리하다 → 기존 프로그램에 무언가 새로운 기능을 추가하기 편리하다.
  • 클래스와 객체 : 객체는 클래스를 통해 만들 수 있다.
    - 클래스란, 객체를 만들기 위한 설계도이다. 해당 설계도를 통해 만들어진 무언가! 이를 객체 또 다른 표현으로 인스턴스(instance)라 한다.
  • 클래스 설계 및 구현
    • 클래스는 상태를 정의하는 필드와 동작을 정의하는 메소드로 나뉜다.

      [구현 예시]
  • 객체 생성 후 변수화
    • 생성된 객체는 연결된 변수와 닷(.) 연산으로 접근할 수 있다.
class Dog{
	String name;
    double weight;
    
    void bark(){
    	System.out.println("멍");
    }
}
Dog dog1 = new Dog();
dog1.name = "뽀삐";
dog1.weight = 3.0;
  • 객체 생성과 메소드 호출

    • 여러 객체 생성?
      • 하나의 잘 설계된 클래스로, 여러 개의 객체를 만들 수 있다. 마치, 붕어빵틀로 여러개의 붕어빵을 만드는 것과 같은 개념
    • 객체에게 명령하기?
      • 클래스를 통해 생성된 객체를 인스턴스(instance)라 한다.
      • 객체에 특정 동작을 수행시키는 것을 “인스턴스 메소드 호출”이라 함
        Cat cat1 = new Cat();
        cat1.meow(); // "야옹~"
  • 클래스 스코프(scope)

    • 필드의 활동 영역은 클래스 전체이다. 따라서 메소드 호출 시 필드를 사용할 수 있다.
      • 이러한 변수의 활동영역을 스코프라 한다. 따라서 필드의 활동영역은 클래스 스코프가 된다.
    class Dog {
    String name;
    int age;
    void bark() {
      // 필드 name을 사용
      System.out.println(name + "의 멍멍!");
    	}
     }
    
  • 메소드 스코드(scope)

    • 메소드 스코프?
      • 파라미터와 지역변수는 메소드 스코프를 가집니다. 다시 말해, 이들의 활동영역은 자신이 속한 메소드 내부
    • 지역변수?
      • 여기서 지역변수란, 메소드 내부에 선언된 변수
    class DrinkMachine {
     String output; // 필드 output 선언
     void pushButton(int num) { // 파라미터 num 선언
      // 지역변수 drinks 선언
      String[] drinks = {"콜라", "사이다", "맥주"};
      output = drinks[num];
    }
    void printOutput() {
      System.out.println(output);
        }
    }
    
  • 스코프 정리

    • 클래스 스코프: 필드
    • 메소드 스코프: 파라미터, 지역변수

2. 생성자

[요약]

  • 무엇?
    • 생성자란, 객체를 만드는 특별한 메소드 !
  • 예시: 앞서 이미 생성자를 사용했다. new Cat()
  • 역할
    • 생성자는 두가지 역할을 한다.
      1. 객체 생성 - 객체를 만든다.
      2. 객체 초기화 - 객체의 필드 값을 설정하는 것
        ※ 생성자를 몰랐을 때, 생성자는 객체를 만들기만 했다. 이후 초기화는 따로 진행했었다. 하지만 생성자를 활용한다면 코드를 간단히 할 수 있다.
        /* 1. 객체 생성 */
        			Cat c = new Cat();
        			/* 2. 필드 초기화 */
        			c.name = "네로";
        			c.weight = 3.78;
        			c.age = 3;
         /* 객체 생성과 동시에 초기화 */
        			Cat c = new Cat("네로", 3.78, 3);
  • 생성자 호출과 정의
    • 생성자는 호출과 정의로 나뉘어 사용된다.
  • 생성자 호출

       // 클래스_타입 변수명 = new 클래스_이름(전달 값);
    		Cat c = new Cat("네로", 3.78, 3);
  • 생성자 정의
    - 생성자 또한 메소드이므로 사용을 위해 먼저 정의되어야 한다. 일반 메소드와의 차이점은 리턴 타입이 없다는 점 !

    class Cat {
     String name;
     double weight;
     int age;
     /* 생성자 정의 */
     Cat (String s, double d, int i) {
       name = s;
       weight = d;
       age = i;
     }
    }```
  • String.format() 메소드

    • String.format() 메소드는 형식 문자열을 만들어 주는 메소드. 다만 출력을 하지 않고, 문자열만을 만들 뿐 !
      String name = "피자맛";
      int price = 1200;
      String str = String.format("Goroke { %s, %d원 }", name, price);
      System.out.println(str);
      // => "Goroke { 피자맛, 1200원 }" ```
  • 디폴트 생성자

    • 생성자가 없는 클래스의 경우 어떻게 객체를 만들어야 할까 ?
      • 디폴트 생성자: 정의된 생성자가 없을 때 , 어떻게 호출을 할까? 자바에서는 기본 생성자를 추가해준다. 디폴트 생성자는 파라미터 및 중괄호 내부가 없고, 생성자가 없는 경우에 자동 기입된다.
class Hero {
String name;
int hp;
  // 디폴트 생성자
  // - 파라미터 및 중괄호 내부 없음
  // - 생성자가 없는 경우, 자동 기입 됨
  Hero() { }
}

  • 객체 배열 만들기
    • 객체 또한 배열에 담을 수 있다.
      Book naruto = new Book("나루토");
      Book onepiece = new Book("원피스");
      Book slamdunk = new Book("슬램덩크");
      Book[] comics = { naruto, onepiece, slamdunk };
  • 파라미터로 객체 전달
    • 객체 또한 메소드의 파라미터로 전달이 가능하다.
    // 객체 생성
	Hero ironMan = new Hero("아이언 맨", 30);
	Hero captain = new Hero("캡틴 아메리카", 30);
	// 아이언 맨의 펀치 -> 캡틴 아메리카
	ironMan.punch(captain);
	// 캡틴 아메리카의 펀치 -> 아이언맨
	captain.punch(ironMan);
   
   	class Hero {
   	String name;
   	int hp;
   	Hero(String n, int h) {
    	name = n;
    	hp = h;
   	}
   	void punch(Hero enemy) {
    // 내용 생략
 	  }
 	}

3. 레퍼런스와 스태틱

  • 레퍼런스란 ?

    • 자바에서 변수의 타입은 레퍼런스형(references type) 기본형(primitives type)으로 나뉜다.

      • 레퍼런스형: 클래스타입, 사용자 정의형 타입 → 객체를 변수에 연결하기 위한 타입이다. 객체를 간접적으로 가리키는 형태.(대문자 시작)
      • 기본형: 값을 직접 갖는다.(소문자 시작)

  • Static 이란 ?

    • "공유" 의 개념이 담긴 키워드로 필드와 메소드에 적용될 수 있다. 필드에 적용되면 클래스 변수, 메소드에 적용되면 클래스 메소드가 된다.

    • 클래스 변수(Static fields): static 키워드가 필드에 적용된 경우. 객체 밖에 존재한다.

    • 인스턴스 변수(non-static fields): 객체 내부에 존재

    • 클래스 메소드: 클래스가 동작시키는 메소드로 static 적용된 메소드 이다.

    • 인스턴스 메소드: 주 객체가 수행하는 메소드로 static이 없다.

      • 위 두 메소드의 차이는 "주체 객체가 있는가?" 의 여부이다. 클래스 메소드의 경우 주체 없이 클래스명으로 호출된다.
        // Math의 클래스 메소드 random() 호출 예
        		double rand = Math.random();
         // 주체 객체 생성
        		Hero h1 = new Hero("닥터 스트레인지", 80);
        		// 주체 객체를 통한 인스턴스 메소드 호출
        		h1.teleport();

4.접근 제한자와 게터와 세터

  • 접근제한자: 외부 접근을 허용할지 말지를 정하는 키워드
    • getter와 setter를 통해 우회하여 private에 접근할 수 있다.
    • private 필드는 외부에서 직접 값을 가져올(read) 수 없다. 올바른 사용자가 외부에서 읽기 위해서는 게터(Getter) 메스드가 필요하며, 게터 메소드는 아래의 특징을 갖는다.
      • private 필드를 반환한다.
      • public 이다.
      • 메소드명은 "get+필드명" 으로 한다.
      class SmartPhone{
      	//private 필드 - 외부 접근 불가
         private int number;
      }
         // 게터 메소드 - number를 우회하여 반환
         public int getNumber(){
         	return number;
         }
       // 사용
       SmartPhone.getNumber()
    • private 필드는 외부에서 직접 값을 변경(write)할 수 없다. 이를 해결하기 위해서 세터(Setter) 메소드가 필요하며, 아래의 특징을 갖는다.
      • private 필드를 변경한다.
        • public 이다.
        • 메소드명은 반환하려는 private 필드명 앞쪽에 set을 붙인다.
        class SmartPhone{
        	//private 필드
            pirvate int number;
        }
        // 세터 메소드
        public void setNumber(int n){
        	number = n;
        }
      • 스코프(scope)란 , 변수의 활동 영역이다. 이러한 스코프는 메소드 스코프와 클래스 스코프로 나뉜다.
        • 메소드 스코프: 메소드 내부에서 활동(ex - 파라미터, 지역변수)
        • 클래스 스코프: 클래스 전역에서 활동(ex - 필드)
        • 이때 스코프와 관련하여 주의할 점은, 변수의 이름이 같은 경우이다.

          ※ 위와 같이 cool() 메소드와 great() 메소드 내부에 둘 다 score 및 result 변수를 가지고 있다. 이들은 같은 이름이지만 서로 스코프가 다르기에 각각 개별적인 변수입니다.
    • 클래스의 필드와 메소드의 파라미터 이름이 같은 경우에 문제가 발생할 수 있다. 필드의 값은 변경되지 않고, 파라미터 자신의 값을 그대로 대입할 뿐이다. 이유는 스코프가 중복되었기 때문 !
      		// 호출 영역
      		Cookie c = new Cookie("버터링", 1500);
      		// 정의 영역
      		class Cookie {
      		private String name;
      		private int price;
      		public Cookie(String name, int price) {
       			name = name; // 인스턴스 변수 name 초기화(X)
       			price = price; // 인스턴스 변수 price 초기화(X)
      			}
      		}
    • this 키워드
      - 파라미터와 필드의 이름이 같은 경우 this를 통해 이를 해결할 수 있다. this는 메소드 수행의 주체 객체를 가르키기 때문에 같은 이름의 파라미터와 구분할 수 있다.
      // 호출 영역
      Cookie c = new Cookie("버터링", 1500);
      c.setPrice(2000);
      // 정의 영역
      class Cookie {
       private String name;
       private int price;
       // 생성자
       public Cookie(String name, int price) {
         this.name = name;   // this.name -> 인스턴스 변수
         this.price = price; // this.price -> 인스턴스 변수
       }
       // 세터
       public void setName(String name) {
         this.name = name; // this.name -> 인스턴스 변수
       }
      }```

5.자바API

  • API란 프로그래밍을 위해 만들어진 도구, API는 패키지 형태로 제공된다. 패키지는 자바API가 담겨진 일종의 폴더라고 할 수 있다.

  • Random 클래스

    // java.util 패키지의 Random 클래스 불러옴
    import java.util.Random;
    //객체 생성
    Random random = new Random();
    
    // 난수 생성
    // 0이상N미만의 임의의 정수
    int n = 10;
    int randInt = random.nextInt(n); // 0,1,2 ... 9 중 택1
    
     //0.0이상 1.0 미만의 임의의 실수
     double ranDouble = random.nextDouble();
     
     //임의의 참/거짓
     boolean randBoolean = random.nextBoolean();
  • ArrayList 클래스

    • ArrayList는 객체를 담기 위한 클래스이다. 해당 클래스는 java.util 패키지에 존재함
      import java.util.ArrayList;
    • 객체 생성과 제네릭
      • ArrayList를 사용하기 위해서는 객체를 만들어야 하는데, 저장할 객체의 타입을 꺽쇠(<>)안에 적어 주어야 한다. 이런 기법을 제네릭(generic)이라고 한다.
        //string 저장을 위한 객체 생성
        ArrayList<String> names = new ArrayList<String>();
      • ArrayList 객체가 만들어지면 객체를 추가하거나, 가져오는 등의 동작을 할 수 있다.
       //객체 추가
       names.add("kang");
       names.add("kim);
       //객체 획득
       System.out.println(names.get(0)); // kang
       System.out.println(names.get(1)); // Kim
      	
       //객체 수 반환
       System.out.println(names.size()); //2
      • ArrayList에 객체를 담기 위해서는, 생성 시 담기 위한 객체의 타입(클래스타입)을 명시해야 한다.
        // Employee 객체를 담기 위한 ArrayList 생성
        ArrayList<Employee> list = new ArrayList<Employee>();
      • 특정 인덱스의 값을 변경할 때에는 set(int index, E element) 메소드를 사용
        Employee emp4 = new Employee();
        list.set(0, emp4); 

    6. 상속

    • 상속이란, 기존 클래스를 확장하여 새 클래스를 만드는 것.

      • extends 키워드를 사용
      • 상속을 사용하면 중복 코드를 제거할 수 있다.
      • 손쉬운 확장 가능
    • 업 캐스팅이란 자식 객체를 부모의 타입으로 해석하는 것으로 예를들어 아래와 같은 상속 관계가 존재할 때 Cat의 인스턴스(객체)는, Animal로 해석될 수 있다. (역은 성립하지 않음)

      class Animal{...}
      class Cat extends Animal {. . .}
      class Dog extends Animal {. . .}
      
      Cat c = new Cat(); // 고양이 객체 생성
      Animal a = c; // 고양이는 동물이다(o). 고양이 객체를 동물로 해석
      • 업캐스팅은 다양한 객체들을 부모의 타입으로 관리할 수 있게 한다.
        Animal c = new Cat();
        Animal d = new Dog();
        //동물배열
        Animal[] animals = {c,d};
    • 메소드 오버라이딩이란, 부모의 메소드를 자식 클래스에서 재정의하는 것

    • protected 제한자는 상속 관계의 클래스까지 접근을 허용한다. 아래 코드의 필드 name은 protected 선언되었으므로, B에서 직접 사용할 수 있다.

      class A{
      	protected String name;
      }
      
      class B extends A{
      	public void printName(){
        	// 부모 클래스 A의 필드 name을 출력 가능
            System.out.println(name);
        }
      }
    • super - 상속과 생성자

      • 자식 객체를 생성과 동시에 초기화 하려면, 먼저 부모 생성자가 호출돼야만 한다. 이때 super 키워드 사용

        //생성자 호출 영역
        Wizard w = new Wizard("프로도", 100, 80);
        
        //생성자 정의 영역
        class Novice{
        	protected String name;
            protected int hp;
            
            public Novie(String name, int hp){
            	this.name = name;
                this.hp = hp;
            }
        }
        class Wizard extends Novice{
        	protected int mp
            
            public Wizard(String name, int hp, int mp){
            	super(name, hp); // 부모 클래스의 생성자 호출
                this.mp = mp;
            }
        }

      7. 인터페이스

    • 인터페이스란 역할을 부여하는 것 !

      • 인터페이스는 추상 메소드(프로토타입 메소드)로 구성된다. 이때 추상 메소드란, 중괄호 내부가 없는 껍데기 메소드이다.
      • 'interface' 키워드를 통해 정의하며, 내부에 추상 메소드를 선언한다.
      • 인터페이스를 클래스에 구현 시 'implements' 키워드를 사용하며, 내부에 추상 메소드를 오버라이딩(재정의)한다.
      • 명확성: 인터페이스를 사용하면 프로그램 설계가 명확해진다.
      • 관계성 부여 가능: 서로 다른 객체들이 같은 인터페이스를 구현한다면, 인터페이스를 타입으로 하여 업캐스팅 할 수 있다.
      • 다형성: 여러 인터페이스를 구현함으로써, 한 객체를 여러 타입으로 해석할 수 있게 된다.
      interface Alarm{
      	//프로토타입 메소드
         public void beep(); //추상메소드
         public playMusic(); // 추상메소드
      }
      // 인터페이스를 글래스에 구현
      class SmartPhone implements Alarm{
      	//프로토타입 메소드 재정의
         public void beep(){
         	System.out.println("삑");
         }
         public void playMusic(){
         	System.out.println("삑");
         }
      }
    • 인터페이스와 다형성

      • 하나의 클래스가 여러 개의 인터페이스를 구현할 수 있다. 마치 스마트폰 클래스에 알람, 전화, 메신저의 역할이 부여되는 것과 같다. 이때 'implements' 키워드로 인터페이스들을 쉼표로 구분지어 적어주면 된다. 이때 인터페이스를 구현하기로 선언했다면, 반드시 프로토타입 메소드를 오버라이딩하여 재정의하여야 한다.

      • 이렇게 하나의 객체가 다양한 타입으로 해석되는 것을 다형성이라 한다.
        ![](https://velog.velcdn.com/images/kyj9609/post/ace106ed-28d1-4649-82bf-0ed38f2068c3/image.png

        -인터페이스와 업캐스팅

      • 업캐스팅이란, 자식 객체를 부모 타입으로 해석하는 것을 의미

      • 마찬가지로, 인터페이스를 구현하는 객체는 인터페이스 타입으로 업캐스팅될 수 있다.

        • 전혀 다른 객체들이더라도, 같은 인터페이스를 구현하였다면, 업캐스팅을 통해 그룹화 가능
       // 다양한 객체 생성
      			Bird bird = new Bird();
      			Helicopter copter = new Helicopter();
      			Rocket rocket = new Rocket();
      			// 인터페이스 타입으로 그룹화
      			Flyable[] flyableThings = { bird, copter, rocket };
      • 또한 다양한 하위 객체들은 상위 인터페이스 타입으로 ArrayList에 저장 가능하다.
    //Flyable 타입을 저장할 Arraylist 생성
    ArrayList<Flyable> list = new ArrayList<FlyAble>();
    //인터페이스를 통한 다양한 하위 객체들 저장
    Flyable b = new Bird();
    Flyable h = new Helicopter();
    Flyable r = new Rocket();
    
    list.add(b);
    list.add(h);
    list.add(r);
    
        
profile
뚝딱뚞딲

0개의 댓글