11. 객체지향 프로그래밍(Object Oriented Programming) [ JAVA ]

duck-ach·2022년 7월 27일
0

JAVA

목록 보기
11/27

클래스(Class)

  • 객체(Object)를 만들어 내기 위한 설계도
  • 객체의 속성(Attribute)행동(Behavior)을 포함하고 있다.
  • 클래스는 객체 내부의 값을 저장하기 위한 필드(Field)와 객체의 기능을 나타내기 위한 메소드(Method)로 구성된다.

현실세계의 무언가를 JAVA로 구현하려면 모든것이 Class에 담겨있어야 한다.

필드(field)

필드(field)객체의 속성(Attribute)를 나타내는 변수를 말한다.

우리가 흔히들 게임에서 불 속성, 물 속성 등등 마법의 속성을 이야기할때의 그때 말하는 속성과 쓰이는 뜻이 유사하다.
객체가 가진 상태성질을 나타낸다.

꼭 알고있어야 할 점은 필드(field)는 일반 변수와 달리 자동으로 초기화 된다는 점이다.

  • boolean 타입 필드 : false 로 초기화
  • 숫자 타입(int, double 등) 필드 : 0으로 초기화
  • 참조타입(String 등) 필드 : null로 초기화

필드 구현 코드

public class User {

	String id;    			// String = null
	String password;		// null
	String email;			// null
	int point;				// 0
	boolean isVip;     		// false  
    
}

필드(field)는 일반 변수와 달리 자동으로 초기화 되기 때문에 0, 0.0, null, false값을 가진다.

이제 메인메소드를 만들어 필드를 출력해 보겠다.
참고할 점 같은 패키지(Package)에 있는 클래스를 불러올 때는 import가 되지 않는다. 그러므로 객체로 만들어서 불러온다.

User user = new User(); // 필드 객체 선언
	
    // 필드 값 변경
	user.id = "admin";
	user.password = "123456";
	user.email = "admin@web.com";
	user.point = 10000;
	user.isVip = (user.point >= 10000);
    
    // 출력
    System.out.println(user.id);
	System.out.println(user.password);
	System.out.println(user.email);
	System.out.println(user.point);
	System.out.println(user.isVip);

선언한 객체의 이름을 입력하고(user) .을 찍으면 자동완성할 메소드를 띄워주는데 그 상태로 enter를 눌러 완성하면 된다.

필드 값을 변경할 때는 변수에 저장된 값을 바꾸듯이 바꿔주면 된다.

학교의 학생들 정보 저장하기

  • 하늘중학교에 다니는 (학생번호 11024)전지현, (학생번호 11025)정우성

필드클래스

public class School {
	
	String name;
	Student[] students = new Student[2];
	
}

public class Student {

	String stuNo;
	String name;
		
}

실행클래스

public class SchoolMain {

	public static void main(String[] args) {
		
		School school = new School();
		Student student1 = new Student();
		Student student2 = new Student();
		
		
		student1.name = "전지현";
		student1.stuNo = "11024";
		
		student2.name = "정우성";
		student2.stuNo = "11025";
		
		school.name = "하늘중학교";
		
		school.students[0] = student1;
		school.students[1] = student2;
		
		for(int i = 0; i<school.students.length; i++) {
			System.out.println(school.students[i].stuNo);
			System.out.println(school.students[i].name);
		}
        // 11024
        // 전지현
        // 11025
        // 정우성

필드를 데이터에 저장

school.students[0] = student1;
school.students[1] = student2;

위의 코드가 선언되었을때, 데이터 내부의 배열값들이 어떻게 저장되어 있는지 알아보자.
우선 student1student2new를 이용해 새로운 객체를 만들어 주었으므로 서로 다른 주소값에 데이터가 저장이 된다.

Student 클래스에서 우리는 학생번호와 학생이름 데이터를 할당받았고, 그 학생정보 뭉텅이를 다시 School클래스에 저장을 했다.

배열은 같은 공간에 저장이 되므로 저런형태로 저장이 된다.


메소드(Method)

  • 메소드는 객체(Object)의 행동(Behavior)을 행하는 함수를 의미한다.
  • 함수(Function)
    • 독립적인 기능을 수행하는 프로그램의 단위
    • 기능별로 구분한 프로그램 단위로 재사용이 가능하다.
  • 형식
접근권한 반환타입 메소드명(매개변수) {
 실행코드
 return 반환값
}

메소드 코드 구현

이해를 돕기 위해 간단한 계산기를 만들어 보겠다.

더하기, 빼기, 곱하기, 나누기를 하는 계산기 만들기.

메소드클래스

public class Calculator {

	int add(int a, int b) {
		int result = a + b;
		return result; // 반환값
	}
	
	int sub(int a, int b) {
		int result = a - b;
		return result;
	}
	
	int mul(int a, int b) {
		int result = a * b;
		return result;
	}
	
	double div (int a, int b) {
		double result = (double)a / b;
		return result;
		 
	}
    
}
  • int는 반환 타입이다.
  • int aint b는 매개변수인데, 이 클래스를 호출 해서 사용할 때 Integer타입의 a와 b를 필요로 하다는 뜻이다.
  • add , sub, mul, div는 메소드의 이름을 말한다.
    메소드의 이름은 우리가 변수이름을 정하듯이 마음대로 정하면 된다.

이제 실행코드를 작성해보겠다.

실행클래스

public class CalculatorMain {

	public static void main(String[] args) {
		
		// 객체 생성
		Calculator calculator = new Calculator();
		
        // 변수를 생성하여 Calculator 클래스에 전달할 매개변수 입력
		int answer = calculator.add(2, 3);
		int answer2 = calculator.sub(5, 2);
		int answer3 = calculator.mul(5, 2);
		double answer4 = calculator.div(5, 2);
		
		System.out.println(answer); // 5
		System.out.println(answer2); // 3
		System.out.println(answer3); // 10
		System.out.println(answer4); // 2.5

	}

}

커피 자판기

  • 한잔에 1000원이며, 돈을 넣고 1을 누르면 아메리카노, 2를 누르면 카페라떼가 나온다.
  • 돈을 넣은만큼 잔수가 추가된다. (ex) 2000원을 넣으면 2잔이 나온다.

메소드클래스

public class VendingMachine {

	String getCoffee(int a, int b) {
		
		String[] menu = {"아메리카노", "카페라떼"};
		return menu[b - 1] + " " + (a / 1000) + "잔";	
	}
	
}

실행클래스

public class VendingMachineMain {

	public static void main(String[] args) {
		
		VendingMachine machine = new VendingMachine();
				
		String coffee1 = machine.getCoffee(1000, 1); // 아메리카노 1잔
		String coffee2 = machine.getCoffee(2000, 2); // 카페라떼 2잔
		
		System.out.println(coffee1);
		System.out.println(coffee2);
	}

}

메소드 오버로딩 ( Method Overroading)

  • 같은 이름의 메소드가 2개 이상 존재하는 것이다.
  • 같은 이름다른 매개변수 를 가져야 오버로딩(Overroading) 할 수 있다.
  • 반환타입은 오버로딩과 상관이 없다.

성공

public int add(int a, int b) {
	return a + b;
}
public int add(int a, int b, int c) {
	return a + b + c;
}

메소드 이름이 같고, 매개변수가 다르다.

실패

public int add(int a, int b) {
	return a + b;
}
public double add(int a, int b) {
	return (double)(a + b);
}

반환타입이 다르지만, 메소드 이름과 매개변수가 모두 같다.

오버로딩을 이용한 간단한 계산기 만들기

메소드클래스

public class Calculator {
	
	int add(int a, int b) {
		return a + b;
	}
	
	int add(int a, int b, int c) {
		return a + b + c;
	}
	
	int add(int a, int b, int c, int d) {
		return a + b + c + d;
	}
    
    int add(int[] arr) {
		int total = 0;
		for(int n : arr) {
			total += n;
		}
		return total;

실행클래스

public class CalculatorMain {

	public static void main(String[] args) {
		
		Calculator calculator = new Calculator();
		System.out.println(calculator.add(1, 1)); //2
		System.out.println(calculator.add(1, 1, 1)); //3
		System.out.println(calculator.add(1, 1, 1, 1)); //4
		
		int[] arr = {1, 2, 3, 4, 5};
		System.out.println(calculator.add(arr)); // 15

	}

}

생성자(Constructor)와 디폴트 생성자(Default Constructor)

생성자(Constructor)

  • 객체를 생성하는 역할을 지닌 클래스의 내부 요소이다.
  • 메소드 이름이 클래스 이름과 같으며 반환타입이 존재하지 않는다.
  • 생성자는 필드 초기화 용도로 사용한다.

만약 요리를 한다면, 재료 준비와 사용할 냄비 준비 등 세팅을 먼저 할것이다. 도마도 두고, 야채를 썰 칼도 준비하고, 야채를 씻어놓기도 할것이다. 즉 어떤 일을 시작하기전에 준비를 하게 되는데 이것을 다른 말로 초기화 라고한다.
객체 지향 프로그래밍 에서도 초기화에 해당하는 기능이 제공되는데 이것을 생성자(constructor)라고한다.

카레에 감자를 넣어 보자.

public class CookMain {

	public static void main(String[] args) {
    	Cook myCook = new Cook();
        myCook.cook("감자");
  
        myCook.Result();
        
	}
}
public class Cook {

// 필드 (field)
	private String pot;
    
// 생성자(constructor)
	String cook(String stuff) {
		pot = stuff;
    }
// 메소드(method)
	public void cookingResult() {
    	System.out.println("냄비에 들어간 것 : " + pot);
}

위의 예제는 객체를 이용하기 위한 로직이다.
메소드의 cookingResult()의 값으로 "감자"를 지정했다. 이 값은 객체 내부에서 인스턴스 변수 stuff의 값으로 설정되어 유지된다.

디폴트 생성자(Default Constructor)

  • 클래스에 생성자가 단 하나도 정의되지 않았을 때 자바가 컴파일러에 의해 자동으로 생성하는 생성자
  • 아무 일도 안하는 형태
public class Computer {
Computer() {
		
	}
 public class ComputerMain {
 
	public static void main(String[] args) {
    
    Computer myCom = new Computer();
    
    }
}

This

  • 현재 객체의 참조값
  • 현재 객체의 멤버(필드, 메소드)를 호출할 때 사용한다.
    (메소드는 거의 사용되지 않고 필드용으로 사용된다.)
  • 생성자 내부에서 다른 생성자를 호출할 때 this() 형태로 사용한다.

우리는 클래스 내부에서 참조변수명.멤버명의 형태의 객체안의 멤버를 사용할 수 있다.

public class Output {

	int m;
    int n;
    
    void init(int a, int b) {
    	int c;
        c = 3;
        this.m = a; // this.를 생략했을 때 자동으로 추가
        this.n = b; // this.를 생략했을 때 자동으로 추가
    }
    void work() {
    	this.init(2, 3); // this.를 생략했을 때 자동으로 추가
    }
}
public class ThisKeyword_1 {
	public static void main(String[] args) {
    // 클래스 객체 생성
    Output output = new Output();
    
    // 메소드 호출 / 필드 값 활용
    output.work();
    
    System.out.println(a.m); // 2
    System.out.println(a.n); // 3
    
    }
}

학교에 다니는 학생들의 명단을 작성해보자.

public class Student {

	// 필드
	private String stuNo; 
	private String name;

	// 생성자
	public Student() {
		
	}
	// 학번하고 이름을 받아오는 생성자
	public Student(String stuNo, String name) {
		this.stuNo = stuNo;
		this.name = name;
	}
    
	// Getter Setter 메소드
    	public String getStuNo() {
		return stuNo;
	}
	public void setStuNo(String stuNo) {
		this.stuNo = stuNo;
	}
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}
    

this를 쓰면 메소드에 매개변수를 넣어 필드에 값을 넣을 때 이름이 동일해도 구분이 간다.

Getter, Setter

get메소드와 set메소드를 손으로 작성하면 오타와 같은 Human Error가 날 수 있기 때문에 Getter Setter 도구를 이용하여 자동 설정 할 수 있다.

주의 : Getter, Setter를 사용하여 메소드 이름을 바꾸면 안된다. Getter Setter를 사용하면 DB까지 한번에 다 연결이 되는데, 이름이 바뀌면 동작하지 않는다.

예시는 위의 this예시를 보면 나와있다.
1 Generate Getters and Setters... 를 클릭한다.

2 getter와 setter를 만들 메소드를 선택한다.
옆의 > 표시를 누르면 getter와 setter를 선택할 수도 있다.
그냥 체크표시를 하면 자동으로 둘다 생성된다.

예제를 풀어보자.

직사각형과 정사각형의 둘레와 넓이를 구하기

public class Rectangle {

	// 필드
	private int width;
	private int height;
	
	// 생성자
	public Rectangle(int width, int height) {	 // <- 밑의 this(n, n)이 가리키는 것.
		this.width = width;
		this.height = height;
	}
	
	public Rectangle(int n) {
//		this.width = n;
//		this.height = n;
		
		this(n, n);  //인수 2개인 다른 생성자를 호출한다.
		// 여기서 this란, (나말고 다른) 생성자를 이야기 하는것이다.
	}
		
	// 메소드
	public int getArea() {
		return width * height;
	}
	public int getCircumference() {
		return 2 * (width + height);
	}
	
	
}

public class RectangleMain {

	public static void main(String[] args) {
		
		// 직사각형
		Rectangle rect1 = new Rectangle(3, 4);
		
		
		// 정사각형
		Rectangle rect2 = new Rectangle(5);

		System.out.println("넓이 : " + rect1.getArea());
		System.out.println("둘레 : " + rect1.getCircumference());

		System.out.println("넓이 : " + rect2.getArea());
		System.out.println("둘레 : " + rect2.getCircumference());
		
	}

}

Static

static은 정적요소라는 뜻이다.

  • 객체 생성 이전에 메모리에 미리 만들어지는 공동 요소이다.
  • 클래스에서 1개만 만들어진다.
  • 클래스를 이용해서 호출하기 때문에 클래스 변수, 클래스 메소드라고 부른다.

예를들면 우리가 흔히 Java를 사용하면서 Math 클래스에 속해있는 메소드들을 많이 사용하는데, 그 Math클래스는 따로 생성자로 생성해주지 않아도 어디서든 클래스만 호출하면 사용할 수 있다.

myMath 만들기

public class MyMath {

	// 필드
	public static final double PI = 3.141592;
	
	// 메소드
	// 절대값 반환하는 메소드
	public static int abs(int n) {
		return (n >= 0)  ? n : -n ;
	}
	
	public static int pow(int a, int b) {
		// a의 b제곱 반환
		// for문 구현
		int result = 1;
		for(int cnt = 0; cnt < b; cnt++) {
			result *= a;
		}
		
		return result;
	
		
	}
	
	
}
public class MyMathMain {

	public static void main(String[] args) {
		
//		MyMath math1 = new MyMath();
//		System.out.println(math1.abs(-5));	
//		MyMath math2 = new MyMath();
//		System.out.println(math2.abs(-8));	
//		MyMath math3 = new MyMath();
//		System.out.println(math3.abs(12));

// 위의 코드처럼 구현하게 되면 객체를 계속 생성해야 하므로 메모리 낭비가 많이 생긴다.
		
		System.out.println(MyMath.PI);
		System.out.println(MyMath.abs(12));
		
		System.out.println(Math.abs(12));
		
		System.out.println(MyMath.pow(2, 3));
	
		
	}

}

Math의 경우 이 객체를 불러와서 계산을 해도 공식이 같고, 저 객체를 시켜도 공식이 같다.
Math스스로 모든 객체가 내보내는 값이 같으므로 추가로 객체를 만들지 못하게 한다. (아마 만들려고 하면 컴파일오류가 날것이다.)
그래서 객체를 저렇게 따로 생성하지 않고 static 정적요소를 활용하여 항상 움직이지 않는 값을 나타낼 수 있도록 한다.

profile
자몽 허니 블랙티와 아메리카노 사이 그 어딘가

0개의 댓글