본문 바로가기
Learning-log/JAVA

객체지향 프로그래밍 정리(Java, Class, 생성자, 인스턴스, 변수, 메서드, this)

by why제곱 2023. 3. 23.

출처 : 나 자신!

<간단요약>

(아래 다 읽은 후 한번 더 읽어보기! )

  • 타입 : 메모리에 공간을 만드는 도장(각 타입별로 필요한 공간 찍어냄)
  • 변수 : 타입이 찍어낸 공간에 이름 붙인 후, 변수에 대입한 값이 heap에 저장되면 그 주소값 기억
  • 메소드 : 자꾸 반복해야 하는 작업을 일련의 과정으로 정의. 일부가 변화할 필요가 있다면 매개변수 지정.
  • 생성자 : 메소드의 특수한 형태로, 클래스를 호출하여 객체를 만들 때 객체 초기세팅에 이용. 리턴값에 대한 설정이 없고, 설정 안하면 기본 셋팅된다는 특이점 존재.
  • 클래스 : 관련있는 변수와 메소드를 묶어놓은 묶음 도장.
  • 특히 데이터와 밀접한 연관이 있는 메소드는 데이터와 클래스를 묶어서 만들면 사용하기 좋음. 만들어놓고 자료형으로 사용. (String이나 Scanner 떠올려보기)

 

객체지향 프로그래밍

→ 프로그래밍을 할 때 객체 단위로 나누어서 프로그래밍을 하는 것이고 객체 간의 상호작용으로 프로그래밍 하는 방법

→프로그램을 단순히 데이터와 처리방법으로 나누는 것이 아니라, 프로그램을 수많은 ‘객체’라는 기본 단위로 나누고 이들의 상호작용으로 서술하는 방식

  • 객체 모델링 : 현실세계의 객체를 SW객체로 설계하는 것(ex. 학사관리 시스템)
    • 객체는 속성(데이터/변수)과 행위(데이터와 관련된 로직들, 알고리즘 /메서드)로 구성
    • 학사관리 시스템을 구성하는 객체는? 행위가 있을 수도 있음.
      • 학생(전공, GPA, 수강신청을 한다. , 학번..등)
      • 과목(담당교수, 개설학과, 학점, .. 등)
      • 교수님 (사번, 전공, 연차, 급여 등.)
      • 교직원(사번, 직급, 부서, 급여, 업무.. 등)
      ⇒ 이렇게 각 객체가 있고 그 객체의 속성, 행위로 설계하는 것.
  • 절차적 프로그래밍은 어떨까?
    • 어떤 문제가 있을까?유지보수가 어려움.
    • 롤 400만줄의 코드 ⇒ 읽기와 협업의 어려움.
    ⇒ 이를 해결하기 위해 객체 지향 등장 !
  • (main() 안에 모든 함수를 다 넣어서 한꺼번에 실행하는 것)
  • 객체 지향의 장점 : 안정적. 대규모 프로젝트에 적합, 협업 쉬움

 

 

  • 객체지향 프로그래밍 특징 (A PIE)
    • Abstraction (추상화)
      • 객체의 공통적인 속성과 기능을 추출하여 정의함.
      • 서울의 지하철 노선도가 바로 추상화의 대표적인 예.
      • 객체모델링을 할 때, 주어진 클래스들의 모든 데이터가 필요한 것이 아님. 소프트웨어의 목적에 맞게 필요한 속성만 알고 있으면 되므로 필요한 공통의 속성이나 기능을 묶어 이름을 붙이면서 생긴 특성.
    • Polymorphism (다형성)
      • 하나의 객체를 여러 관점에서 볼 수 있음. 
      • 예를 들어, 사람이라는 객체는 사람이자 포유류이자 동물, 또는 하나의 객체. 이렇게 하나의 객체를 다양한 관점으로 볼 수 있음.
      • 어떤 객체의 속성이나 기능이 그 맥락에 따라 다른 역할을 수행할 수 있는 객체지향의 특성으로 대표적인 예로, 메서드 오버라이딩이나 메서드 오버로딩이 다형성을 보여줌. 한 타입의 참조변수를 통해 여러 타입의 객체를 참조할 수 있음. 상위 클래스 타입의 참조변수로, 하위 클래스의 객체를 참조하면 다형성을 활용해 여러 종류의 객체를 배열로 다루는 일이 가능해지면서 간편하고 유연하게 코드 작성 가능
    • Inheritance (상속)
      • 객체를 만들기 위해서는 설계도를 갖고 있음. 다른 객체를 만들 때 기존의 설계도를 활용해서 새로운 설계도를 만드는 것.(차 → 전기차)
      • 상위 개념의 특징을 하위 개념이 물려받는 것으로 매번 새로운 객체를 만들 필요가 없음. 가지고 있는 걸 고쳐쓰기!
    • Encapsulation (캡슐화)
      • 객체 = 데이터+알고리즘 ⇒ 캡슐. 이걸로 소프트웨어 제작. 
      • 서로 연관있는 속성과 기능들을 하나의 캡슐로 만들어 데이터를 외부로부터 보호하는 것.정보은닉의 기능 : 객체 사용 시, 객체의 모든 데이터를 알 필요가 없으므로 일부만 공개됨.승객(탑승,도착 등의 데이터만) 승무원(고도, 지연, 도착, 기내식 시간 등) 기장(더 많은 데이터들) 이처럼 어떤 객체와 다른 객체(승객, 승무원, 기장)들이 상호작용 할 때 가려진 부분, 공개된 부분이 있다.
      • ex. 비행기(수만가지 부품과 각종 기능,동작) :
      • 즉, 외부로부터 클래스에서 정의된 속성과 기능들을 보호하고 필요한 부분만 외부로 노출될 수 있도록 하여 객체 고유의 독립성과 책임영역을 안전하게 지킬 수 있음.
  • 객체지향 프로그래밍의 장점
    • 모듈화된 프로그래밍
    • 높은 재사용성

 

⇒ 객체를 어떻게 만들까? ⇒ 설계도, 형틀이 필요하다. 그게 바로 Java의 클래스.

클래스

  • 객체를 만드는 설계도(Blueprint)이자 형틀(Template) (모든객체들의 생산처)
  • 이를 이용해 객체를 하나씩 찍어냄.
  • 관련 있는 변수와 함수를 묶어서 만든 사용자 정의 자료형
  • ⇒ 클래스 자체가 String처럼 자료형처럼 쓰이게 됨. ex. Scanner sc = …~
  • 프로그래밍이 쓰이는 목적을 생각하여 어떤 객체를 만들어야 하는지 결정
  • 각 객체들이 어떤 특징(속성(데이터)과 동작(메서드))을 가지고 있을지 결정
  • 객체들 사이에서 메시지를 주고받도록 만들어짐
  • 객체를 찍어낼 수 있는 묶음 도장! 클래스 안에 메소드, 변수 들을 쫘르르 짜놓으면 new와 생성자를 통해 객체가 생성될 때 도장이 꾸욱! 찍어지고 클래스 내에 있던 메소드, 변수들을 몽땅 다 ! 사용할 수 있다 ! 모여있던 도장들을 몽땅 객체에 찍어낸 것.
  • 묶음 도장인데 아무 관련 없는 걸 한 곳에 모아두면 필요한 도장을 찾기도, 이를 사용하기도 어렵고 번거로우므로, 관련 있는, 사용 목적이 유사한 도장들만 같은 클래스에 모아두자.
  • 구성
    • 속성(Attribute) - 필드 : 변수들, 데이터를 가짐
    • 동작(Behavior) - 메소드
    • 생성자(Constructor) : 객체를 생성할 때 호출하는 것. 객체를 만든다하고 호출하는 행위를 할 때 사용하게 됨.
    • 중첩클래스(클래스 내부의 클래스)
  • 선언
    • 클래스명 : PascalCase (대문자로 시작, 단어가 합성된 경우는 대문자로 구분)
    • 클래스명 (자료형) 변수명 = new 클래스명(); → new 다음이 생성자
    • ⇒ new를 하면 객체가 생성되고 주소값이 변수에 저장되게 됨
" [접근제한자][활용제한자] class 클래스명(PascalCase) {"
			public class Person {    //클래스명 선언
				String name; //속성(인스턴스 변수)
				int age;     //속성

			public void eat() { // 메서드
			}
			public Person () { //생성자 Person : 클래스 이름과 똑같이 생김) 
			} 
		}
  • . (dot 연산자) : 멤버 연산자
    • 변수명.필드명;( 객체에 . 을 붙이면 변수와 메서드에 접근 가능)
    • 변수명.메소드명();
    • 앞에 적힌 클래스, 메서드 등의 꾸러미를 까는 역할.
    • A.b 일 때, A가 기억하고 있는 주소들의 꾸러미를 열어서 내가 찾는 b를 확인하거나 접근 가능.

 

인스턴스

  • 클래스를 통해 생성된 객체 ( 클래스가 찍어낸 객체)
    • 객체와 동일시 해도 되지만 객체가 조금 더 포괄적인 의미
  • 인스턴스를 객체라고 부를 수 있으나 클래스를 통해 생성되는 의미로 사용해 다소 협소한 의미이다.
  • 데이터와 알고리즘을 따로따로 소유하고 있게 됨.

 

변수

  • 타입(자료형)이 일정한 모양의 공간을 메모리 상에 찍어내주면 그 공간의 이름을 내가 붙이는 것.
  • 내가 지정한 변수(공간의 이름)에 값을 넣는다는 건, 내가 입력한 값이 Heap에 저장되고 그 주솟값을 변수가 기억한다는 의미.
  • 클래스 변수(class variable) : 설계도에 들어가 있는 변수.
    • 여기에 지정해놓으면 이 설계도로 만든 모든(해당 클래스로 생성된) 인스턴스에 공유됨.
    • 클래스 영역 선언(static 키워드)
    • 생성시기 : 클래스가 메모리에 올라갔을 때
    • 활용 예
      • 각 객체가 한 사람을 의미하는 클래스의 경우, 객체의 개수를 count함으로써 사람 수 count 가능. 이럴 때 인스턴스변수로 count가 존재하면 각 객체마다 count 변수 값으로 1을 가지게 되므로 의미 없음. ⇒ 클래스변수로 객체 전체를 아우르는 변수 생성 가능.
  • 인스턴스 변수
    • 클래스 영역 선언
    • 생성시기 : 인스턴스가 생성되었을 때(new)
    • 인스턴스 별로 생성(각 인스턴스가 고유하게 갖고 있으며 공유x)
  • 지역변수(local variable)
    • 클래스 영역 이외(메서드, 생성자 등)
    • 생성시기 : 선언되었을 때
public class Person {
	
//static 있으므로 '클래스 변수'
	static String species = "호모 사피엔스 사피엔스"; 

// static 키워드 없으므로 '인스턴스 변수'
	String name;
	int age;
	
	//메서드
	public void eat() {
		//eat이라는 메서드 내에 있으므로 지역 변수
			//해당 메서드가 끝나면 변수도 끝!
		String dish = "탕수육";
	}
}

 

메소드(Method)

  • 객체가 할 수 있는 행동 정의
  • 어떤 작업을 수행하는 명령문의 집합에 이름을 붙여놓은 것
  • 목적 : 반복작업을 줄이기 위해서 ! 한글자라도 바뀌었을 때 또 새로운 메소드를 만들긴 어려우니까 매개변수(입력값)를 받아 유연하게 활용하기 위함
  • 메소드의 이름은 소문자로 시작하는 것이 관례 (camelCase : 소문자 시작, 띄어쓰기 시 대문자로 구분)
  • 반환값 : 반환값이 없다면 void라 쓰고 반환X
  • 매개변수들 : 데이터 ⇒ 지역변수처럼 사용하게 됨(해당 메소드가 종료되면 그 매개변수는 끝이라는 의미)
  • 메소드의 종료
    • 블록의 끝을 만날 때
    • return문을 만날 때 (void에서도 return문을 쓸 수 있음)
[접근제한자][활용제한자] 반환값 메소드 이름([매개변수들]) {
	
		행위기술 ...
}
public class Person { //클래스 생성
	static String species = "호모 사피엔스 사피엔스"; //클래스 변수
	
	String name;
	int age;              //인스턴스 변수
	

	
	//메소드(두개의 매개변수가 오고 반환값이 int인 메서드) 
		//public 바로 다음이 반환값으로 만약 'void'라면 반환값이 없다는 뜻.
	public int add(int a, int b) { 
		return(a+b);
	} 
// => '}'를 만나서 메소드 종료
	
	
	public void study(String subject) {
		double probability = Math.random();
		System.out.println(subject +"를 공부합니다.");
		System.out.println("알고리즘 문제를 풉니다.");
		if(probability <0.9999)
			return; 
		// 99.99%의 확률로 return이 돼서 return 종료 되고 밑에 실행 x
//위 if문에서 return 실행이 안됐다면 아래가 실행될 것.
		System.out.println("게임을 합니다.");
		System.out.println("롤 영상을 시청합니다.");
	}
  • 메소드 오버로딩(Overloading) : 이름이 같은 여러 메소드
    • 이름 같고 매개변수 다른 메소드 여러개 정의
    • 중복 코드에 대한 효율적인 관리 가능
    • 파라미터의 개수, 순서, 타입이 달라야 할 것
    • 리턴 타입이 다른 것은 의미 X (신경 안쓴다는 뜻)
    public int add(int a, int b) { 
    		return(a+b);
    	}
    	
    public double add(double a, double b) {
    	  return(a+b);
    
    // 두 메소드의 이름이 같지만 매개변수의 type이 int와 double로 다르므로 가능.
    
    public void eat() {
    		//지역 변수(메서드 또는 생성자 내에 있으면)
    		System.out.println("식사를 합니다.");
    	}
    
    	public void eat( String dish) {
    		System.out.println(dish + "를 먹습니다.");
    	}
    	
    	public void eat(String dish, int times) {
    		System.out.println(dish + "를"+times +"번 먹습니다.");
    	}
    		public void eat(int times,String dish) {  
    					//이렇게 위와 순서가 달라져도 오버로딩 가능
    		System.out.println(dish + "를"+times +"번 먹습니다.");
    	}
    
  • 메소드 오버로딩의 장점 : 다양한 자료형에 대해 만들 때도 이름 똑같이 가능해서 굳이 이름 다르게 addInt(), addDouble()과 같은 메소드를 따로 만들 필요 없음.

 

생성자

  • 생성자 메소드 : 메소드 중 특!별!한! 녀석!
  • 주요 기능
    • new 키워드와 함께 사용하여 객체 생성를 생성하고 주솟값을 저장하게 하는 것.(new 다음에 쓰이는게 생성자, 객체 생성시 반드시!)
    • 객체가 생길 때 해당 객체 멤버필드 초기화나 기능을 세팅 가능.
  • 생성자 특징
    • 클래스 명과 이름이 동일(대,소문자)
    • 결과형 리턴값 갖지 않음(void조차 쓰지 않음)
    • 하나의 클래스 내부에 생성자 하나도 없으면 자동적으로 default 생성자 있는 것으로 인지(JVM이 자동으로 생성자 제공)
    • 하나라도 생성자 만들면 default 생성자는 사용 불가
    • 매개변수의 개수가 다르거나 자료형이 다른 여러개의 생성자가 있을 수 있음(생성자 오버로딩) (메서드니까 오버로딩 가능)
    • 생성자의 첫번째 라인으로 this()생성자를 사용하여 또 다른 생성자 하나 호출 가능
      • why?
      생성자에서 this를 쓸 때 초기화할 값들을 잔뜩 적어놓고 this를 써버리면 그 앞에 쓴 게 무의미해지므로 생성자에서 this를 쓸거면 처음부터 this를 쓰고 시작해야 함. 그래서 this를 첫번째 라인으로 쓰도록 된 것.
  • 파라미터가 있는 생성자
    • 생성자의 목적이 필드 초기화
    • 생성자 호출 시 값을 넘겨주어야 함
    • 해당 생성자를 작성하면 JVM에서 기본생성자 추가X
Class Dog {
	String name;
	int age;

//생성자
//생성자가 있으므로 기본생성자는 사용 불가
	Dog(String n, int a){ 
		name = n;
		age = a;
  • 생성자 오버로딩 지원
    • 클래스 내에 메소드 이름이 같고 매개변수의 타입 또는 개수가 다른 것
class Dog{
	Dog() {}
	Dog(String name) {}
	Dog(int age) {}
	Dog(String name, int age{}

 

this()

  • 참조 변수로써 객체 자신을 가리킴 ⇒ 자신이 속한 객체에서 찾는다는 뜻
  • this를 이용하여 자신의 멤버 접근 가능(변수, 메서드)
  • 지역변수(매개변수)와 필드의 이름이 동일할 경우 필드임을 식별할 수 있게 함
  • 객체에 대한 참조이므로 static(설계도)영역에서 사용 불가
  • this의 활용
    • this.멤버변수
    public class Person {
    	String name; //인스턴스 변수
    	int age;
    
    		public Person(String name, int age) {
    				//this 키워드 : 인스턴스의 멤버에 접근
    			this.name = name;
    				//this.이 붙은건(좌변) 멤버변수인 name
    				//우변 파라미터로 들어온 name
    	}
    
    • this([인자값 ..]) : 생성자 호출
      • this 생성자 호출시 제한 사항
        • 생성자 내에서만 호출 가능 :
          • 생성자를 호출할 때 생성자명이 아닌 this로 호출하는 이유 : 자바 문법 만들어질 때 이미 클래스 변수와 클래스 메소드를 호출할 때 (클래스명.변수) 나 (클래스명.함수)로 호출하기 때문에, 이미 문법을 선점 당해 this를 사용하게 됨.
          • 생성자 내에서 첫번째 구문에 위치해야 함
        생성자 안에서 이미 초기화 해놓고 마지막에 다른 생성자 호출하는 건 불가능 하다는 뜻. 다른 일 다~~해놨는데 마지막에 띵 호출하지 말고 미리미리 합시다!
    궁금한점 ! 생성자가 여러개일 땐 여러 생성자 중 this가 가리키는 생성자가 뭔지 어떻게 알지?
    public Person() {
    		this("정민우", 31);  //아래 생성자를 호출해오는 것.
    	}
    	
    	public Person(String name, int age) {
    		this.name = name;
    	}
    
  • ⇒ 생성자가 여러개라는건 오버로딩이 됐다는 뜻이므로 매개변수의 타입, 순서가 다르므로 그것으로 구분 가능

**** 헷갈리는 부분 정리 ****

메소드와 생성자의 구분은 ? 반환 타입을 반드시 써야하는가의 여부가 달라진다. 생성자는 반환타입이 없다!

메소드는 함수같은 역할로, 객체를 만들었으면 그 객체로 쓸 수 있는 여러 기능이다!

객체.메소드(매개변수~) 이렇게 사용.

생성자는 객체를 만들기 위한 도구이다. 메소드 중 특별한 녀석. new 다음에 생성자를 쓴다.

타입 객체 = new 생성자 이렇게 사용해서 객체 생성.