Java - class, method, 생성자, 접근제어자, 추상클래스, 인터페이스

호호빵·2022년 5월 17일
0

Java

목록 보기
2/19

객체지향언어

java는 객체지향언어로써 코드간에 관계를 맺어 줌으로써 보다 유기적인 프로그램을 구성할 수 있음

Class

객체의 속성을 정해놓은 것
멤버변수 : 클래스 내부의 정보
인스턴스 : 클래스로부터 만들어진 객체를 그 클래스의 인스턴스라 함

# Phone이라는 클래스에 galaxy, iPhone이라는 인스턴스
class Phone {
    String model;
    String color;
    int price;
}

public class Main {
    public static void main(String[] args) {
        Phone galaxy = new Phone();  // [생성된 인스턴스].[멤버변수] 로 멤버변수에 접근
        galaxy.model = "Galaxy10";
        galaxy.color = "Black";
        galaxy.price = 100;
        
        Phone iphone = new Phone();
        iphone.model = "iPhoneX";
        iphone.color = "Black";
        iphone.price = 200;
        

        System.out.println("철수는 이번에 " + galaxy.model + galaxy.color + " + 색상을 " + galaxy.price + "만원에 샀다.");
        System.out.println("영희는 이번에 " + iphone.model + iphone.color + " + 색상을 " + iphone.price + "만원에 샀다.");
    }
}

method

어떠한 작업을 수행하는 코드를 하나로 묶어 놓은 것

  • (재사용성)
    메소드를 만들어 놓으면 이후 반복적으로 재사용이 가능. 다른 프로그램에서도
  • (중복된 코드 제거)
    프로그램을 작성하다보면 같은 코드가 여러번 반복되어 작성되는데 이럴 때, 메소드를 활용하면 중복된 부분을 없애므로 보다 효율적인 코드가 됨
  • (프로그램 구조화)
int[] heights = new int[5]; // 키가 들어가 있는 배열

initHeight(heights); // 1. 키에 대한 초기화
sortHeight(heights); // 2. 키를 오름차순으로 정렬
printHeight(heights); // 3. 정렬된 키를 출력
class Calculation {
// 반환타입 메소드(타입 변수명)		
    int add(int x,int y) {    // add 메소드, return의 반환타입 int
        return x + y;
    }
    int subtract(int x, int y) {   // subtarct 메소드
        return x - y;
    }
}

public class Main {	   // void : 반환타입 없음(메소드 내에서 출력할 때)
    public static void main(String[] args) {
        Calculation calculation = new Calculation();
        int addResult = calculation.add(1, 2);
        int substractResult = calculation.subtract(5, 3);

        System.out.println(addResult);
        System.out.println(substractResult);
    }
}
// 3, 2

생성자

인스턴스가 생성될 때 사용되는 인스턴스 초기화 메소드

  • new와 같은 키워드로 인스턴스가 새로 생성될 때, 자동으로 호출되는 메소드
  • 인스턴스가 생성될 때 수행할 동작 코드를 짤 수 있음
    (대표적으로 인스턴스 변수를 초기화하는 용도로 사용)
  • 생성자의 이름은 클래스명과 같아야 함 , 생성자는 리턴 값이 없음
  • 모든 클래스에는 반드시 하나 이상의 생성자가 있어야하고, 없을 경우 java 컴파일러가 기본 생성자를 추가 해줌(매개변수와 내용이 없는 생성자)
class Phone {
    String model;
    String color;
    int price;

	Phone() {}  // 기본 생성자 

    Phone(String model, String color, int price) {
        this.model = model;  // this : 생성된 객체 자신을 가리킴
        this.color = color;
        this.price = price;
    }
}

public class Main {
    public static void main(String[] args) {
        Phone galaxy = new Phone("Galaxy10", "Black", 100);
        Phone iphone =new Phone("iPhoneX", "Black", 200);

        System.out.println("철수는 이번에 " + galaxy.model + galaxy.color + " + 색상을 " + galaxy.price + "만원에 샀다.");
        System.out.println("영희는 이번에 " + iphone.model + iphone.color + " + 색상을 " + iphone.price + "만원에 샀다.");
    }
}

상속

  • 기존 클래스를 재사용 하는 방식
  • 부모 클래스에서 정의된 필드와 메소드를 물려 받음(하나의 클래스만 물려받을 수 있음)
  • 새로운 필드와 메소드를 추가할 수 있음
  • 부모 클래스에서 물려받은 메소드를 수정 가능
  • super 더 알아보기
# extends를 이용하여 상속
claa Animal{}						Animal     부모클래스
class Dog extends Animal{}			  ㄴ Dog	   자식클래스
class Cat extends Animal{}			  ㄴ Cat	   자식클래스
class Animal {
    String name;

    public void cry() {
        System.out.println(name + " is crying.");
    }
}

class Dog extends Animal {
    Dog(String name) {
        this.name = name;
    }

    public void swim() {
        System.out.println(name + " is swimming!");
    }
}

public class Main {
    public static void main(String[] args) {
        Dog dog = new Dog("코코");  // 자식개체에 할당
        dog.cry();
        dog.swim();
        
        Animal dog2 = new Dog("미미");	// 부모개체에도 할당 가능
        dog2.cry();						// 하지만 Dog로 생성한 개체
//      dog2.swim(); // compile error  Animal(부모)에 있는 cry만 됨
    }
}

코코 is crying
코코 is swimmin
미미 is crying

Overloading vs Overriding

  1. 오버로딩(기존에 없는 새로운 메소드 정의)
  • 한 클래스 내에 동일한 이름의 메소드를 여러개 정의하는 것
    (매개변수의 개수 혹은 타입이 달라야 함)
  1. 오버라이딩(상속받은 메소드 내용 변경)
  • 부모 클래스로부터 상속받은 메소드의 내용을 변경하는 것(변경이 필요한 경우 사용)
  • 부모클래스의 메소드와 이름이 같고, 매개변수도 같고, 변환타입도 같아야 함.
# 오버로딩
public class Main {
    public static void main(String[] args) {
    	// 변환타입은 int, long으로 다르지만 매개변수 타입과 개수는 같아서 오버로딩 아님
		int add(int x, int y, int z) {
          int result = x + y + z;
          return result;
        }

        long add(int a, int b, int c) {
            long result = a + b + c;
            return result;
        }
        
        // 오버로딩 맞음
		int add(int x, int y, int z) {
            int result = x + y + z;
            return result;
        }

        long add(int a, int b, long c) {  // 매개변수 타입 다름
            long result = a + b + c;
            return result;
        }

        int add(int a, int b) {      // 매개변수 개수 다름
            int result = a + b;
            return result;
        }		
    }
}

# 오버라이딩
class Animal {
    String name;
    String color;

    public void cry() {
        System.out.println(name + " is crying.");
    }
}

class Dog extends Animal {
    Dog(String name) {
        this.name = name;
    }

    public void cry() {
        System.out.println(name + " is barking!");
    }
}

public class Main {
    public static void main(String[] args) {
        Animal dog = new Dog("코코");
        dog.cry();
    }
}

접근 제어자(Access Modifier)

외부에서의 접근을 제한하는 역할(멤버변수, 함수에 사용)
객체지향 프로그래밍이란 객체들 간읜 상호작용을 코드로 표현하는 것
접근제어자는 캡슐화가 가능할 수 있도록 돕는 도구

  • private : 같은 클래스 내에서만 접근 가능
  • defalt(nothing) : 같은 패키지 내에서만 접근 가능
  • protected : 같은 패키지 내에서, 다른 패키지의 자손클래스까지 접근 가능
  • public : 접근제한 없음
  • main > java에 패키지파일 만들기(pkg), pkg > ModifierTest.java 만들기
# pkg > ModifierTest.java
package pkg;

public class ModifierTest {
    private void messageInside() {
        System.out.println("This is private modifier");
    }

    public void messageOutside() {
        System.out.println("This is public modifier");
        messageInside();
    }

    protected void messageProtected() {
        System.out.println("This is protected modifier");
    }
}

# Main.java
import pkg.ModifierTest;

class Child extends ModifierTest{
    void callParentProtected() {
        System.out.println("call my parent's protected method");
        super.messageProtected();  // super : 내가 상속받은 부모클래스를 가리키는 키워드
    }
}

public class Main {
    public static void main(String[] args) {
        ModifierTest modifierTest = new ModifierTest();
        modifierTest.messageOutside();
        // modifierTest.messageInside();  private, protected 라 안됨
        // modifierTest.messageProtected();
        // 추가
    }
}
-> This is public modifier
   This is private modifier
  
# 추가
		Child child = new Child();
        child.callParentProtected();
        
  -> call my parent's protected method
  	 this is protected modifier

추상 클래스

추상 메소드를 선언할 수 있는 클래스

  • 상속받는 클래스 없이 그 자체로 인스턴스를 생성할 수 없음
  • 설계만 되어있으며 수행되는 코드에 대해서는 작성이 안된 메소드
    (상속받는 클래스마다 동작이 달라지는 경우에 사용하기 위해 클래스 작성자가 작성하도록)
abstract class Bird {
    private int x, y, z;

    void fly(int x, int y, int z) {
        printLocation();
        System.out.println("이동합니다.");
        this.x = x;
        this.y = y;
        if (flyable(z)) {
            this.z = z;
        } else {
            System.out.println("그 높이로는 날 수 없습니다");
        }
        printLocation();
    }

    abstract boolean flyable(int z);

    public void printLocation() {
        System.out.println("현재 위치 (" + x + ", " + y + ", " + z + ")");
    }
}

class Pigeon extends Bird {
    @Override
    boolean flyable(int z) {
        return z < 10000;
    }
}

class Peacock extends Bird {
    @Override
    boolean flyable(int z) {
        return false;
    }
}

public class Main {
    public static void main(String[] args) {
        Bird pigeon = new Pigeon();
        Bird peacock = new Peacock();
        System.out.println("-- 비둘기 --");
        pigeon.fly(1, 1, 3);
        System.out.println("-- 공작새 --");
        peacock.fly(1, 1, 3);
        System.out.println("-- 비둘기 --");
        pigeon.fly(3, 3, 30000);
    }
}
- fly(x,y,z) 함수는 Bird를 상속받는 모든 클래스에서 동일한 동작을 하지만
  그 안에서 호출된 flyable(z)의 동작만 자식 클래스에서 구현한대로 동작.
- 비둘기는 어느정도 높이까지 날 수 있고, 공작새는 전혀 날지 못하기 때문에
  새의 종류마다 중복코드 없이 구현하기 위해 추상클래스, 추상메소드 사용  


인터페이스

객체의 특정 행동의 특징을 정의하는 문법

  • 접근제어자, 리턴타입, 메소드 이름만을 정의(함수 내용 없음)
  • 인터페이스를 구현하는 클래스는 인터페이스에 존재하는 함수의 내용을 반드시 구현해야 함
interface 인터페이스명 {
	public abstract void 추상메서드명();
}
interface Bird {
    void fly(int x, int y, int z);
}

class Pigeon implements Bird{
    private int x,y,z;

    @Override
    public void fly(int x, int y, int z) {
        printLocation();
        System.out.println("날아갑니다.");
        this.x = x;
        this.y = y;
        this.z = z;
        printLocation();
    }
    public void printLocation() {
        System.out.println("현재 위치 (" + x + ", " + y + ", " + z + ")");
    }
}

public class Main {

    public static void main(String[] args) {
        Bird bird = new Pigeon();
        bird.fly(1, 2, 3);
//      bird.printLocation(); // compile error
    }
}
# interfaceBird 타입으로 선언한 bird 변수는 실제로 Pigeon 객체이지만, 
  interfaceBird 에 선언되지 않은 printLocation() 이라는 함수는 호출할 수 없음
# interface type으로 선언되어 있는 부분에서는 실제 객체가 무엇이든지, interface에 정의된 행동만 할 수 있습니다.


추상클래스, 인터페이스 비교

추상클래스인터페이스
클래스를 상속받아 이용 및 확장을 위함구현하려는 객체의 동작명세
단일 상속다중 상속 가능
extends 이용implements 이용
추상메소드에 대한 구현 기능메소드 시그니처만 선언 가능


객체지향 퀴즈

1. 사람은 자식, 부모님, 조부모님이 있다.
2. 모든 사람은 이름, 나이, 현재 장소정보(x,y좌표)가 있다.
3. 모든 사람은 걸을 수 있다. 장소(x, y좌표)로 이동한다.
4. 자식과 부모님은 뛸 수 있다. 장소(x, y좌표)로 이동한다.
5. 조부모님의 기본속도는 1이다. 부모의 기본속도는 3, 자식의 기본속도는 5이다.
6. 뛸때는 속도가 기본속도대비 +2 빠르다.
7. 수영할때는 속도가 기본속도대비 +1 빠르다.
8. 자식만 수영을 할 수 있다. 장소(x, y좌표)로 이동한다.

위 요구사항을 만족하는 클래스들을 바탕으로, Main 함수를 다음 동작을 출력(`System.out.println`)하며 실행하도록 작성하시오. 이동하는 동작은 각자 순서가 맞아야 합니다.

1. 모든 종류의 사람의 인스턴스는 1개씩 생성한다.
2. 모든 사람의 처음 위치는 x,y 좌표가 (0,0)이다.
3. 모든 사람의 이름, 나이, 속도, 현재위치를 확인한다.
4. 걸을 수 있는 모든 사람이 (1, 1) 위치로 걷는다.
5. 뛸 수 있는 모든 사람은 (2,2) 위치로 뛰어간다.
6. 수영할 수 있는 모든 사람은 (3, -1)위치로 수영해서 간다.

최종정리

profile
하루에 한 개념씩

0개의 댓글

관련 채용 정보