객체 지향 프로그래밍

woom·2022년 11월 7일
0

JAVA

목록 보기
7/18
post-thumbnail

🌼 객체 지향 프로그래밍

  • OOP : Object Oriented Programming

  • 객체(객체가 가지고 있는 기능 요소)를 사용하여 프로그램 작성 / 객체(관계를 맺고 있는)들을 만들려면 클래스 필요

  • 현실 세계에 존재하는 대상을 모델링하여 클래스로 작성하고 클래스로 객체를 생성하여 객체의 요소로 프로그램을 작성하는 방법

  • 관계를 맺고 있는 객체들이 메시지를 주고 받는 것

  • 객체 모델링(Object Modeling) : 현실 세계에 존재하는 대상을 속성(값)과 행위(일)로 구분하여 설계

    • 대상 : 자동차 구매일 경우 (속성: 모델명, 가격, 색상 / 행위: 옵션 추가, 옵션 삭제, 매매)
    • 대상이 같은 자동차라도 프로그램에 따라 다르게 설계
      ex) 주차관련이면 속성: 번호판, 가격은 필요 없음
  • 대상을 모델링(설계)하여 클래스라는 자료 생성 (속성은 필드, 행위는 메소드로 만들어줌)

    • 이 클래스를 이용해 객체 생성 → 이 객체의 요소(ex.메소드)로 프로그램 작성
  • OOP 특징 : 1. 추상화, 2. 캡슐화, 3. 다형성, 4. 상속성


📕 1. 추상화(Abstraction)

  • 객체 모델링한 대상을 클래스(필드와 메소드)로 선언

  • 추상화는 관점에 따라 다르게 표현

  • 해결해야 되는 문제/현실을 SW적으로 단순화 시켜서 만드는 행위

  • 장점 : 클래스라는 자료형 배포 가능 ( ex) 망치가 필요할때 사서 사용)

    • 프로그램의 생산성이 증가 (빠르고 쉽게 만듦)
    • 유지보수의 효율성 증가 (필요한 부분만 수정 가능)

💡 절차 지향 VS 객체 지향

  • 배열 요소값을 오름차순 정렬되도록 저장하고 출력하는 프로그램 작성
  1. 절차 지향 프로그래밍 : 순서(알고리즘) 알아야함, 오래걸리고 하나씩 만들어야해서 많은 사람들이 필요, 개발비용도 증가
public class ArraySortApp {
	public static void main(String[] args) {
		
		int[] array={30,50,10,40,20};
		
		System.out.print("정렬 전 >> ");
		for(int num:array) {
			System.out.print(num+" ");
		}
		System.out.println();
	
		//배열 요소값을 선택 정렬 알고리즘을 사용하여 오름차순 정렬되도록 저장
		for(int i=0;i<array.length-1;i++) {
			for(int j=i+1;j<array.length;j++) {
				if(array[i]>array[j]) {
					int temp=array[i];
					array[i]=array[j];
					array[j]=temp;
				}
			}
		}
		
		System.out.print("정렬 후 >> ");
		for(int num:array) {
			System.out.print(num+" ");
		}
		System.out.println();



  1. 객체 지향 프로그래밍 : 클래스를 가져다 쓰기만 하면 됨
    • Arrays 클래스이용
    • Arrays 클래스 : 배열의 요소값을 처리하는 기능을 제공하는 클래스
    • Arrays.toString(Object[] array) : 매개변수를 통해 배열을 전달받아 배열의 모든 요소값들을 문자열로 변환(to string)하여 반환하는 메소드
    • Arrays.sort(Object[] array) : 배열을 전달받아 배열의 요소값을 오름차순 정렬하여 저장하는 메소드

		int[] array={30,50,10,40,20};

		System.out.println("정렬 전 >> "+Arrays.toString(array));

		Arrays.sort(array);		
		System.out.println("정렬 후 >> "+Arrays.toString(array));
        
        
        

🌼 클래스

  • 객체(Object)를 만들기 위한 자료형(참조형) / 객체 대신 인스턴스(Instance)로 표현 가능

  • 현실 세계의 존재하는 사물을 클래스라는 자료형으로 표현하여 객체로 구현

  • 형식) public(생략가능) class 클래스명(식별자 파스칼표기법) {

    1. 필드(Field) : 대상의 속성을 표현하여 속성값을 저장하기 위해 선언된 변수(멤버변수)
      ...
    2. 생성자(Constructor) : 객체 생성을 목적으로 선언된 메소드 → 생성자 없으면 객체 생성 불가 (기본 생성자 존재)
      ...
    3. 메소드(Method) : 대상의 행위를 명령의 모임으로 표현하기 위해 선언된 함수(멤버함수)
      값을 처리하기 위한 명령들의 모임으로 메소드를 통해 원하는 행동 구현
      ...
      }
  • 클래스 선언 : 필드에는 프로그램 실행에 필요한 값을 저장하고 메소드로 필드값을 사용해 원하는 기능을 제공


📙 클래스 생성

  • 자동차를 객체 모델링하여 작성된 클래스
    • 속성(필드) : 모델명, 엔진상태, 현재속도
    • 행위(메소드) : 시동 온(On), 시동 오프(Off), 속도 증가, 속도 감소, 이동 중지

public class Car { 
	//1. 필드(Field) : 클래스에 선언된 모든 메소드는 필드 사용 가능
    //모든 메소드가 사용할수있도록 클래스에 만들어짐
	private String modelName;		//모델명  (필드 이름은 카멜 표기법 사용)
	private boolean engineStatus;	//엔진상태 - false : Off, true : On
	private int currentSpeed;		//현재속도
	
	//2. 생성자 : 생성자 선언을 생략하면 매개변수가 없는 기본 생성자
    //(Default Constructor)가 존재하는 것으로 처리

	//3. 메소드 : 필드를 이용하여 명령들로 필요한 기능을 제공 
    //메소드 호출: 메시지 주고받는 일 시키는 것
	public void startEngine() {      // startEngine메소드는 시동 온(On) 명령 실행
		engineStatus=true;
	System.out.println(modelName+"의 시동을 켰습니다.");
	}
	
	public void stopEngine() {       // stopEngine메소드는 시동 오프(Off) 명령 실행
		if(currentSpeed!=0) {   	 //자동차가 멈췄있지 않은 경우
			//currentSpeed=0;
			//System.out.println(modelName+"의 자동차가 멈췄습니다.");
			
			//클래스에 선언된 메소드를 서로 호출 가능
			// → 코드의 중복성 최소화 : 프로그램의 생산성 및 유지보수의 효율성 증가 
			speedZero();
		}
		
		engineStatus=false;
		System.out.println(modelName+"의 시동을 껐습니다.");
	}
	
	public void speedUp(int speed) {	
    //speedUp메소드는 매개변수(speed)를 전달받아 속도 증가 명령 실행
		if(!engineStatus) {			//시동이 꺼져 있는 경우
			System.out.println(modelName+"의 시동이 꺼져 있습니다.");
			return;					//메소드 종료
		}
		
		if(currentSpeed+speed>150) {
        //현재속도와 증가된 속도의 합이 최고 속도보다 큰 경우
			speed=150-currentSpeed;	//증가된 속도 변경
		}
		
		currentSpeed+=speed;
		System.out.println(modelName+"의 속도가 "+speed+"Km/h 증가 되었습니다.
        현재 속도는 "+currentSpeed+"Km/h입니다.");
	}
	
	public void speedDown(int speed) {		
    //speedDown메소드는 매개변수(speed)를 전달받아 속도 감소 명령 실행
		if(!engineStatus) {			//시동이 꺼져 있는 경우
			System.out.println(modelName+"의 시동이 꺼져 있습니다.");
			return;//메소드 종료
		}
		
		if(currentSpeed<speed) {	//현재속도보다 감소된 속도가 큰 경우
			speed=currentSpeed;		//감소된 속도 변경
		}
		
		currentSpeed-=speed;
		System.out.println(modelName+"의 속도가 "+speed+"Km/h 감소 되었습니다.
        현재 속도는 "+currentSpeed+"Km/h입니다.");
	}
	
	public void speedZero() {		//speedZero메소드는 속도 0으로 명령 실행
		currentSpeed=0;
		System.out.println(modelName+"의 자동차가 멈췄습니다.");
	}





📌 접근지정자

  • 클래스를 선언할 때 필드 또는 메소드에 접근지정자를 선언하여 접근 가능 유무 설정
    • 클래스 생성 시 지정자(Modifier) 선택하는 창 생성됨
  • 접근지정자(Access Modifier) : 1. private, 2. public, 3. package(default), 4. protected,
    • 클래스, 필드, 생성자, 메소드를 선언할 때 접근 유무를 지정하기 위한 키워드
  1. private : 클래스 내부에서만 접근 가능하며 클래스 외부에서는 접근 불가능하도록 설정하는 키워드 (가장 제한적)
    • 일반적으로 필드 선언시 사용 : 객체로 필드에 직접적으로 접근하는 것을 차단하기 위해 사용
    • 은닉화(Data Hiding) : 숨기는 것 (일반적으로 필드를 은닉화 시키지만 메소드와 생성자도 은닉화 시킬수 있음)
  2. public : 모든 패키지의 클래스에서 접근 가능하도록 설정하는 키워드 (가장 범용적)
    • 일반적으로 메소드 선언시 사용 : 프로그램 작성에 필요한 모든 클래스에서 접근할 수 있도록 사용
  • 접근 지정자 관련 오류메시지 (참조 관련 메시지와 비교)
    • not visible : private로 숨겨져있어서 접근할수없어
    • resolved : 식별자가 선언되지 않았다

📕 2. 캡슐화(Encapsulation)

  • 은닉화 처리된 필드를 위해 필드값을 반환하는 1. Getter 메소드와 필드값을 변경하는 2. Setter 메소드 선언
  • 표현대상을 속성(필드)과 행위(메소드)로 묶어 클래스로 선언
  • 필드를 은닉화 처리하여 보호되어 사용되도록 설정하는 작업 (필드의 잘못된 값을 방지하기 위해 사용)
  1. Getter 메소드 : 클래스 외부에서 필드값을 사용할 수 있도록 반환하는 메소드
    • 은닉화 선언된 필드의 자료형이 boolean인 경우 get 대신 is를 사용하여 메소드 작성
    • 형식) public 반환형 get필드명() { return 필드명; }
    • ex) public String getModelName() {return modelName; }
  2. Setter 메소드 : 매개변수로 값을 전달받아 필드값을 변경하는 메소드 (매개변수에 전달되어 저장된 값에 대한 검증 가능)
    • 형식) public void set필드명(자료형 매개변수) { 필드명=매개변수; }
    • ex) public void setModelName ( String modelName ) { this.modelName = modelName; }
  • 매개변수와 필드명의 이름을 동일시 했을 경우 필드명은 가까운 매개변수로 저장되어 의미없음
    • this(메소드 내부에서 클래스의 객체를 표현하는 키워드)를 사용하여 필드
      (필드명 앞에 내가(객체)this.(가지고있는) modelname(탑클래스에 있는 모델네임)을 의미)
  • 이클립스는 은닉화 선언된 필드에 Getter와 Setter 메소드를 생성하는 기능 제공
    • 기능 넣을 위치로 커서이동 >> 메뉴 >> source >> Generate getter and setter... >> 필드 선택 >> generate
    • 단축키 : [Alt]+[Shift]+[S] >> 팝업메뉴 >> [R] >> 필드 선택 >> Generate


	public boolean isEngineStatus() {
		return engineStatus;
	}

	public void setEngineStatus(boolean engineStatus) {
		this.engineStatus = engineStatus;
	}

	public int getCurrentSpeed() {
		return currentSpeed;
	}

	public void setCurrentSpeed(int currentSpeed) {
		this.currentSpeed = currentSpeed;}}
        




🐣 예제

  • Car 클래스를 사용하여 작성된 프로그램, 메인메소드 실행
public class CarApp {
	public static void main(String[] args) {
		//Car 클래스로 객체를 생성하여 참조변수에 저장 
        //하나의 클래스로 서로 다른 객체를 여러개 생성 가능 
		//객체를 생성하면 객체의 필드에 기본값 저장 (숫자형:0, 논리형:false, 참조형:null)
		Car carOne=new Car();
		Car carTwo=new Car();
		Car carThree=carTwo;//다른 참조변수에 저장된 객체의 주소를 전달받아 저장 가능
		
		System.out.println("carOne = "+carOne);//oop.Car@5aaa6d82
		System.out.println("carTwo = "+carTwo);//oop패키지.Car클래스의 메모리주소
		System.out.println("carThree = "+carThree);//carTwo와 동일

		//참조변수.필드 : 참조변수에 저장된 객체로 필드에 접근하여 사용
		//문제점 : 필드에 직접 접근하여 필드값을 변경할 경우 비정상적인 값 저장 가능
		//해결법 : 필드를 은닉화 처리하여 클래스 선언 → 은닉화 선언된 필드에 접근할 경우 에러 발생
		//carOne.modelName="티코";		//필드값 변경
		//필드값을 직접 변경 불가 → 필드값을 변경하는 Setter 메소드 호출하여 필드값 변경
		carOne.setModelName("티코");
		carOne.setEngineStatus(true);
		carOne.setCurrentSpeed(100);
		
		//System.out.println("첫번째 자동차의 모델명 = "+carOne.modelName);//필드값 출력
		//필드값을 직접 사용 불가 → 필드값을 반환하는 Getter 메소드 호출하여 필드값 반환받아 출력
		System.out.println("첫번째 자동차의 모델명 = "+carOne.getModelName());//필드값 출력
		System.out.println("첫번째 자동차의 엔진상태 = "+carOne.isEngineStatus());
		System.out.println("첫번째 자동차의 현재속도 = "+carOne.getCurrentSpeed());

		carTwo.setModelName("싼타페");
		
		System.out.println("두번째 자동차의 모델명 = "+carTwo.getModelName());//싼타페
		System.out.println("두번째 자동차의 엔진상태 = "+carTwo.isEngineStatus());//false
		System.out.println("두번째 자동차의 현재속도 = "+carTwo.getCurrentSpeed());//0

		//참조변수.메소드명(값,...) : 참조변수에 저장된 객체를 사용하여 메소드 호출
        
		carTwo.startEngine();	//싼타페의 시동을 켰습니다.
		carTwo.speedUp(50);
        //싼타페의 속도가 50Km/h 증가 되었습니다. 현재 속도는 50Km/h입니다.
		carTwo.speedUp(30);
        //싼타페의 속도가 30Km/h 증가 되었습니다. 현재 속도는 80Km/h입니다.
		carTwo.speedDown(40);
        //싼타페의 속도가 40Km/h 감소 되었습니다. 현재 속도는 40Km/h입니다.
		carTwo.speedZero();//싼타페의 자동차가 멈췄습니다.
		carTwo.stopEngine();}}	//싼타페의 시동을 껐습니다.
        
        
        
        
        

📌 객체 생성 방법

  • 형식) 클래스명 참조변수=new 클래스명();
    • 클래스명() : 기본생성자(생성자명=클래스명)
  • new 연산자로 클래스의 생성자를 호출하여 객체를 생성하고 참조변수에 객체의 주소(해시코드)를 저장
  • 참조변수에 저장된 객체의 필드 또는 메소드를 . 연산자로 (객체의 요소에) 접근하여 프로그램 작성

🌼 메소드

  • 필드를 사용하여 필요한 기능을 제공하기 위한 명령들의 모임
  • 매개변수를 통해 값을 처리하고 처리한 결과를 반환 ( 입출력은 프로그램에서 함 )
  • method class : 참조가 목적인 클래스로 객체 생성을 위한 클래스 (메소드명은 카멜표기법)
  • 메인 메소드가 선언된 클래스 : 실행이 목적인 클래스 (프로그램)

📙 메소드 선언

  • 형식) 자료형 메소드명(자료형 변수명, 자료형 변수명,...) {명령; 명령; ... }
  • (앞 자료형은 아웃풋, 뒤 자료형은 인풋)
  • 반환형(ReturnType) : 메소드를 호출하여 얻을 수 있는 결과값의 자료형
    (명령에 대한 값을 돌려줘야해) 앞 자료형
    • void (무반환형) : 메소드를 호출하여 얻을 수 있는 결과값이 없는 경우 사용하는 자료형 (명령만 실행할 경우)
  • 매개변수(Parameter = Argument) : 메소드의 명령을 실행하기 위한 값으로 메소드 호출시 값을 전달받아 저장하기 위한 변수
    • 매개변수를 통해 필요한 값을 제공 (입력) - 소괄호 안의 변수
  • return : 메소드를 종료하는 키워드 (제어문)
    • 형식1) if (조건식) return;
      조건식의 결과가 참인 경우 메소드 종료 (반환형 : void)
    • 형식2) return 대상;
      메소드 종료시 대상의 값을 반환하여 메소드를 호출한 명령에게 제공
      → 메소드의 반환형과 반환되는 대상의 자료형이 반드시 동일

🐣 예제

public class Method {
	void displayOne() {  //displayOne이라는 메소드를 호출하여 얻을 수 있는 결과값 없음
		System.out.println("# Method 클래스의 displayOne() 메소드 호출 #");}
	
	void displayTwo() {
		System.out.println("# Method 클래스의 displayTwo() 메소드 호출 #");}
	
	void printOne() {
		int tot=0;
		for(int i=1;i<=100;i++) {
			tot+=i;}
		System.out.println("1~100 범위의 정수들의 합계 = "+ tot);}
	
	//메소드 호출시 매개변수에 값이 정상적으로 전달되어 저장되야만 메소드의 명령 실행
	// → 매개변수에 값이 저장되지 않을 경우 메소드 호출 불가능 (에러 발생)
	void printTwo(int num) {
		//매개변수에 저장된 값에 대한 검증
		if(num<0) {//비정상적인 값이 매개변수에 저장된 경우
			System.out.println("[에러]매개변수에 0보다 큰 정수값이 저장되어야 됩니다.");
			return;//메소드 종료
		}		
		int tot=0;
		for(int i=1;i<=num;i++) {
			tot+=i;
		}
		System.out.println("1~"+num+" 범위의 정수들의 합계 = "+ tot);}

	void printThree(int num1, int num2) {
		/*
		if(num1>num2) {//비정상적인 값이 매개변수에 저장된 경우
			System.out.println("[에러]첫번째 전달값이 두번째 전달값보다 작아야 됩니다.");
			return;//메소드 종료
		}
		*/
		
		if(num1>num2) {
			int temp=num1;
			num1=num2;
			num2=temp;}
		
		int tot=0;
		for(int i=num1;i<=num2;i++) {
			tot+=i;}
		System.out.println(num1+"~"+num2+" 범위의 정수들의 합계 = "+ tot);}
	
	int returnTot(int num1, int num2) {
		if(num1>num2) {
			int temp=num1;
			num1=num2;
			num2=temp;}
		
		int tot=0;
		for(int i=num1;i<=num2;i++) {
			tot+=i;}
		
		//변수에 저장된 값을 메소드 종료하며 반환
		//→ 반환되는 값의 자료형과 메소드 반환형이 반드시 동일
		return tot;}
	
	//매개변수로 정수값을 전달받아 홀수와 짝수를 구분하여 반환하는 메소드
	// → false 반환 : 홀수, true 반환 : 짝수라고 약속
	boolean isOddEven(int num) {//is로 시작하는 메소드는 boolean자료형 사용
		if(num%2!=0) {
			return false;
		} else {
			return true;
		}
	}
	
	//배열(여러개의값)의 메모리 주소를 반환하는 메소드
	int[] returnArray() {
		/*
		int[] array={10,20,30,40,50};
		return array;//참조변수에 저장된 배열의 메모리 주소 반환 - 배열 반환
		*/
		
		//return {10,20,30,40,50};//에러 발생
		return new int[]{10,20,30,40,50};
	}
	
	//3개의 매개변수에 정수값을 전달받아 합계를 계산하여 반환하는 메소드
	int sumOne(int num1, int num2, int num3) {
		return num1+num2+num3;
	}
	
	//배열을 전달받아 배열의 모든 요소값들의 합계를 계산하여 반환하는 메소드
	int sumTwo(int[] array) {
		int tot=0;
		for(int num:array) {
			tot+=num;
		}
		return tot;
	}
	
	//매개변수 생략 기호(...)를 사용하여 매개변수를 선언한 경우 값을 0개 이상 전달받아 저장 가능
	//→ 매개변수로 값들을 전달받아 내부적으로 배열을 생성하여 요소값으로 저장  
	int sumThree(int...array) {
		int tot=0;
		for(int num:array) {
			tot+=num;
		}
		return tot;
	}
}





📙 메소드 호출

  • (Method Invoke) : 메소드를 호출해야 메소드의 명령이 실행되어 기능을 제공받을 수 있음
  • 형식) 객체.메소드명(값,값,...);
  • 객체가 저장된 참조변수(에 저장된 주소값)를 이용하여 메소드에 접근해 메소드 호출
  • 메소드 호출시 나열된 값이 매개변수에 차례대로 전달되어 저장
  • 매개변수에 값이 정상적으로 전달되지 않은 경우 메소드 호출 불가능
  • 명령을 읽어들이는 쓰레드가 메소드를 호출하면 메소드로 이동해서 실행하고 되돌아옴

  • 실행이 목적인 MethodApp 클래스 생성 (메소드 호출) : 메인 메소드가 선언된 클래스-프로그램

🐣 예제

//클래스 선언 예제인 Method 클래스 참고
public class MethodApp {
	public static void main(String[] args) {
		//클래스로 객체를 생성하여 객체의 메모리 주소를 참조변수에 저장
		// → 같은 패키지의 클래스는 패키지 표현없이 클래스만 사용하여 접근 가능
		// → 참조변수를 사용하여 객체의 필드 또는 메소드 접근
		Method method=new Method();
        
		//참조변수에 저장된 값을 출력할 경우 "자료형@메모리주소" 형식으로 제공된 결과값 출력
		System.out.println("method = "+method);//oop.Method@5aaa6d82
		

		//메소드 호출 : 메소드를 호출하면 프로그램 흐름(스레드)이 객체의 메소드로 이동하여
		//메소드의 명령을 실행하고 메소드가 종료되면 다시 되돌아와 다음 명령 실행
		method.displayOne();//# Method 클래스의 displayOne() 메소드 호출 #"
		method.displayTwo();//# Method 클래스의 displayTwo() 메소드 호출 #"

		method.printOne();//5050

		method.printTwo(80);//1~80 범위의 정수들의 합계 = 3240
		method.printTwo(-30);//[에러]매개변수에 0보다 큰 정수값이 저장되어야 됩니다.
		
		//메소드 호출시 나열될 값이 매개변수에 차례대로 전달되어 저장
		method.printThree(25, 75);//25~75 범위의 정수들의 합계 = 2550
		method.printThree(77, 45);//45~77 범위의 정수들의 합계 = 2013

		//메소드를 호출하여 반환되는 결과값을 변수에 저장
		// → 메소드 명령에 대한 결과값을 지속적으로 사용할 경우 변수에 저장
		int tot=method.returnTot(34, 86);
		//입력과 출력 명령은 프로그램에서 작성 (프로그램에 대한 독립성 확보)
		// → 메소드에서는 값에 대한 계산만 하고 입력과 출력은 미작성 
		System.out.println("합계(메소드 호출의 반환 결과값) = "+tot);
		//반환값을 일시적으로 사용할 경우 변수에 미저장
		System.out.println("합계 = "+method.returnTot(40,80));//합계 = 2460
		
        
		boolean result=method.isOddEven(10);  
		if(result) {
			System.out.println("매개변수에 전달된 값은 [짝수]입니다.");
		} else {
			System.out.println("매개변수에 전달된 값은 [홀수]입니다.");
		}
		
		//if 구문의 조건식 대신 논리값을 반환하는 메소드를 호출하여 명령 선택 실행 
		if(method.isOddEven(11)) {
			System.out.println("매개변수에 전달된 값은 [짝수]입니다.");
		} else {
			System.out.println("매개변수에 전달된 값은 [홀수]입니다.");
		}


		//메소드 호출시 반환되는 배열의 메모리 주소를 참조변수에 저장 (배열의 요소 참조 가능)
		int[] array=method.returnArray();
		for(int num:array) {
			System.out.print(num+" ");
		}
		System.out.println();//10 20 30 40 50 
		
        
		System.out.println("합계 = "+method.sumOne(10, 20, 30));//합계 = 60
		//매개변수에 값이 정상적으로 전달되지 않을 경우 메소드 호출에 대한 에러 발생 
		//System.out.println("합계 = "+method.sumOne());
		//System.out.println("합계 = "+method.sumOne(10, 20));
		//System.out.println("합계 = "+method.sumOne(10, 20, 30, 40));
		
		
		//배열을 만들어서 사용하면 원하는 값을 통채로 전달하므로 오류 발생 X
		//System.out.println("합계 = "+method.sumTwo({10,20,30}));
        //매개변수가 객체가 아니므로 에러 발생
		System.out.println("합계 = "+method.sumTwo(new int[]{10, 20, 30}));//60
		System.out.println("합계 = "+method.sumTwo(new int[]{}));//합계 = 0
		System.out.println("합계 = "+method.sumTwo(new int[]{10, 20}));//합계 = 30
		System.out.println("합계 = "+method.sumTwo(new int[]{10, 20, 30, 40}));
		
		//int sumThree(int...array) : 매개변수로 값들을 전달받아 내부적으로 배열 생성
		System.out.println("합계 = "+method.sumThree(10, 20, 30));
		System.out.println("합계 = "+method.sumThree());
		System.out.println("합계 = "+method.sumThree(10, 20));
		System.out.println("합계 = "+method.sumThree(10, 20, 30, 40)); }}
        




📕 3. 다형성(Polymorphism)

  • 같은 이름의 메소드를 호출할 경우 상태에 따라 메소드가 선택 호출되는 기능

  • 호출되는 기능 : 1. 메소드 오버로드, 2. 메소드 오버라이드

  1. 메소드 오버로드 ( Method Overload )

    • 같은 기능은 같은 메소드를 사용(여러개 선언)
    • 클래스에 동일한 기능을 제공하는 메소드가 매개변수에 의해 여러개 선언하는 경우 메소드의 이름을 같도록 선언하는 기능
    • 메소드는 같지만 매개변수의 자료형 또는 갯수가 같지 않도록 선언
    • 접근지정자와 반환형은 오버로드 선언과 무관
    • 전달된 값에 대한 자료형의 매개변수가 없는 경우 에러 발생
    • 오버로드 선언된 메소드는 매개변수에 전달되는 값에 의해 메소드를 선택 호출

🐣 예제

//같은 기능을 가진 메소드를 오버로드 (메소드 이름 동일하게 선언)
public class Overload {
	public void displayInt(int param) {	
    //displayint메소드를 이용해 정수값 param값 반환
		System.out.println("정수값 = "+param);
	}
	
	public void displayBoolean(boolean param) {
		System.out.println("논리값 = "+param);
	}
	
	public void displatString(String param) {
		System.out.println("문자열 = "+param);
	}
	
	// 같은 메소드 사용하여 매개변수에 전달되는 값에 의해 메소드를 선택 호출
	public void display(int param) {
		System.out.println("정수값 = "+param);
	}
	
	public void display(boolean param) {
		System.out.println("논리값 = "+param);
	}
	
	public void display(String param) {
		System.out.println("문자열 = "+param);}}
	

//오버로드로 선언한 메소드 프로그램 실행
public class OverloadApp {
	public static void main(String[] args) {
		Overload overload=new Overload();// Overload 객체 생성

		overload.displayInt(100);//overload참조변수를 통해 displayInt메소드 호출
		
		//overload.displayInt(false);
        //메소드 호출시 매개변수에 값을 잘못 전달한 경우 에러 발생
		overload.displayBoolean(false);
		overload.displatString("홍길동");

		//오버로드 선언된 메소드는 매개변수에 전달되는 값에 의해 메소드를 선택 호출
        //→메소드 오버로드에 의한 다형성
		overload.display(200);
		overload.display(true);
		overload.display("임꺽정");
		//overload.display(12.34);}}
        //전달된 값에 대한 자료형의 매개변수가 없는 경우 에러 발생





📌 this (키워드)

  • 메소드에 숨겨져있는 매개변수로 this 매개변수의 자료형은 메소드가 선언된 클래스
  • 메소드를 호출한 객체의 메모리주소(해시코드)를 자동으로 전달받아 저장하는 참조변수
    • ex) this는 member1라는 객체의 참조변수에 저장된 메모리주소가 전달됨
  • 메소드에서 객체의 필드 또는 메소드를 사용하기 위해 this 키워드 사용
  • this 키워드를 사용하지 않아도 자동으로 객체의 필드 또는 메소드에 접근하여 사용 가능
  • 메소드에 this 매개변수가 존재하는 이유:

    • 필드는 객체마다 메모리(힙영역)에 따라 생성되지만 메소드는 객체에 상관없이 메모리(static)에 하나만 저장된다. (prototype Class)
    • 메소드에서 필드를 사용할 때 this 키워드를 사용하여 객체를 구분하여 필드에 접근
  • this 키워드를 표현하여 사용하는 경우

    1. 메소드에서 매개변수의 이름을 필드의 이름과 동일하게 작성한 경우 필드를 표현하기 위해
      ex) this 키워드 사용 (생성자와 Setter 메소드)
    2. 생성자에서 다른 생성자를 호출하여 초기화 작업을 하기 위한 this 키워드 사용
    3. 이벤트 처리 프로그램 또는 다중 스레드 프로그램의 메소드에서 객체 자체를 표현하기 위한 this 키워드 사용

⭐ VO 클래스

  • VO(Value Object) 클래스 : 값 저장이 목적인 객체를 생성하기 위한 클래스 (값 만을 저장하려고 만든 클래스)
    • 회원정보(아이디,이름,이메일)를 저장하기 위한 클래스
    • 필드 선언후 세터 게터 메소드 생성
    • 객체 생성시 객체의 필드에는 기본값(숫자형:0,논리형:false,참조형:null)이 자동 저장
    • 객체 생성시 필드에 저장될 기본값 변경 가능
    • 일반적으로 필드 생성자 메소드 순으로 만들어주나 순서 바뀌어도 상관없음
    • 소스파일에는 클래스 하나만 생성 → 참조클래스와 메인메소드가 들어간 실행클래스 두 개 만들어서 사용
public class Member {
	private String id="NoId";//필드(Field) 선언
	private String name="NoName";
	private String email="NoEmail";
    
    
    

🌼 생성자

  • 생성자(Constructor) 선언 : 객체를 생성하기 위한 특별한 메소드
  • 생성자를 선언하지 않으면 매개변수가 없는 기본 생성자가 제공되어 처리
  • 생성자를 선언하는 이유는 객체의 필드를 원하는 값으로 초기화 처리하기 위해 선언
  • 생성자를 선언하면 기본 생성자는 미제공
  • 필드에 초기화 작업을 하기 위해서 생성자 생성
    • 형식) 접근지정자 클래스명(자료형 매개변수,...) { 초기화명령; ... }
  • 반환형을 작성하지 않으며 생성자의 이름은 반드시 클래스의 이름과 동일하게 작성 (작성규칙)
  • 메소드 오버로드 선언 가능 (매개변수의 자료형 또는 갯수가 다른 여러개의 생성자 선언 가능)
  1. 매개변수가 없는 생성자 - 기본 생성자(Default Constructor)
    • 초기화 작업 미구현 (객체 생성시 필드에는 기본값이 초기값으로 저장)
    • 매개변수가 없는 생성자를 선언하지 않으면 상속(물려받아서 사용)시 문제가 발생되므로 선언하는 것을 권장
    • 이클립스를 사용하여 기본 생성자 자동 완성
      [Ctrl]+[Space] → 나열된 목록 중 Constructor 선택 [enter]
      (todo ... : 아래에 명령을 입력하세요라는 의미)
     public Member() { 
     this("NoId","NoName","NoEmail");
     }
    • this (값, 값, ...) : this 키워드로 다른 생성자를 호출하는 명령 (this를 이용해 생성자 호출)
      • 생성자에서만 사용 가능한 명령
      • 다른 명령보다 먼저 실행되도록 작성 (다른 명령이 먼저 작성된 경우 에러 발생)
    • 생성자를 호출하는 것은 첫번째 명령
  1. 매개변수가 존재하는 생성자 (초기값 생성)
    • 매개변수에 전달되어 저장된 값으로 필드의 초기값으로 저장
    • 객체 생성시 필드에 원하는 값이 저장되도록 생성자 작성
    • 이클립스를 사용하여 매개변수가 있는 생성자 자동 완성
      [Alt]+[Shift]+[S] → 팝업메뉴 → [o]필드선택 → generate
      : (source메뉴 - generate constructor using field)

🐣 예제


	public Member(String id) {
		this.id=id;//this.id : id 필드의 초기화
	}
	public Member(String id, String name) {
		super();
		this.id = id;
		this.name = name;
	}
	public Member(String id, String name, String email) {
		super();
		this.id = id;
		this.name = name;//this.name : 필드 & name : 매개변수
		this.email = email;
	}
	//getter, setter 메소드(Method) 선언
	public String getId() {
		return id;
	}
	public void setId(String id) {
		this.id = id;
	}
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}
	public String getEmail() {
		return email;
	}
	public void setEmail(String email) {
		this.email = email;
	}
	//필드값을 출력하는 메소드
	public void display() {
		System.out.println("아이디 = "+id);
		System.out.println("이름 = "+name);
		System.out.println("이메일 = "+email);}}
        
        
  

🐣 실행예제

public class MemberApp {
	public static void main(String[] args) {
		//new 연산자로 클래스의 매개변수가 없는 기본 생성자를 사용하여 객체 생성
		//→ 생성된 객체의 필드는 기본값으로 자동 초기화
		//→ new 연산자로 호출한 생성자가 없는 경우 에러 발생 (객체 생성 불가능)
		Member member1=new Member();
	
		//Getter 메소드를 호출하여 필드값을 반환받아 출력
		System.out.println("아이디 = "+member1.getId());
		System.out.println("이름 = "+member1.getName());
		System.out.println("이메일 = "+member1.getEmail());
		
		//Setter 메소드를 호출하여 매개변수의 전달값으로 객체의 필드값 변경
		member1.setId("aaa");
		member1.setName("홍길동");
		member1.setEmail("hgd@google.com");
		
		member1.display();
		

		Member member2=new Member("bbb"); //원하는 필드에 초기값 저장
		member2.display();                //display 메소드 호출
		

		Member member3=new Member("ccc", "임꺽정");
		member3.display();
		

		Member member4=new Member("ddd", "전우치", "chon@itwill.xyz");
		member4.display();}}





⭐ prototype 클래스

  • 메모리에는 클래스1, 메소드1, 객체 여러개가 저장됨으로서 메모리 절약할수있다.
  • 메모리에 값이 저장되는 순서 (Member,MemberApp참조)
  1. jvm이 Member 클래스에 있는 memberapp 메소드 호출
  2. Member클래스에는 Member라는 이름의 생성자 ,string 생성자, 메소드 가 static 영역에 저장됨
  3. 생성자를 호출하여 heap영역에 객체 여러개 생성(클래스이름member, id, name, email)
  4. stack 영역에 있는 참조변수 member1이 해시코드를 참조하여 객체에 접근하여 2000이라는 메모리 주소가 생성자에 저장
    • 클래스에 있는 메소드에 접근해 메소드 호출 (display메소드를 통해 member1이 가지고 있는 필드값이 저장됨)
  • 인스턴스 필드(Instance Field) : 객체 생성시 메모리(Heap 영역)에 만들어지는 필드
    • static 을 통해 필드를 만들면 이탤릭체가 됨

📌 제한자 (Modifier)

  • 기능을 제한하기 위한 키워드 Acess Modifier(public, private, package, protected) static, final, abstract
  • static : 객체가 아닌 클래스로 접근하기 위한 기능을 제공하기 위한 제한자

📒 정적 필드(Static Field)

  • 클래스 생성시 메모리(Static 영역)에 만들어지는 필드로 객체가 생성되기 전에 메모리에 하나만 생성되는 필드
  • 생성자에서 초기화 처리하지 않고 직접 초기화 설정
  • 모든 객체에서 정적 필드 사용 가능 (정적필드는 공유값으로 메모리 절약 및 필드값 변경 용이)
    • 합계변수는 객체마다 필요하지X, 하나만 있으면 되므로 공유값으로 필드
  • 클래스 외부에서는 클래스 이름을 사용하여 접근
    (객체를 이용해 접근X, class를 이용해 접근 : class.메소드명(값, 값...) )

🐣 예제

//학생정보(학번,이름,국어,영어,총점)를 저장하기 위한 VO클래스
public class Student {
	private int num;//일반적으로 String or int의 결정은 연산 여부로 판단
	private String name;//필드 생성
	private int kor, eng, tot;

	private static int total=0;	//기본값 사용시 초기값 설정 생략, 필드 작성시 작성
	//private int total; 하면 객체 여러개 생성됨 (비효율)
    //total변수는 메모리에 하나만 있으면 됨 → static 사용 필요

	//생성자 : 객체 생성시 인스턴스 필드에 원하는 초기값을 저장하기 위해 작성
	public Student() {	}// Student 기본생성자 [ctrl]+[space]

	public Student(int num, String name, int kor, int eng) { 
		super();			
		this.num = num;	// 필드 생성자 초기화
		this.name = name;
		this.kor = kor;
		this.eng = eng; 
		
	//총점을 계산하여 필드에 저장하는 명령 작성 (메소드 호출)
	// → 코드의 중복성을 최소화하여 프로그램의 생산성 및 유집보수의 효율성 증가
		//tot=kor+eng;
		calcTot();  }// 계산 메소드 호출하면 총점을 계산하는 메소드 호출할 필요 없음
		// 메소드가 생성자를 호출할수없지만 생성자가 메소드를 호출하는것은 가능
        
	//1. 인스턴스 메소드 : this 매개변수가 존재하는 메소드로 인스턴스 필드 및 정적 필드 접근 가능
	public int getNum() {
		return num;
	}
	public void setNum(int num) {//getter,setter 메소드 선언 [alt]+[shift]+[s]→[r]
		this.num = num;
	}
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}
	public int getKor() {
		return kor;
	}
	public void setKor(int kor) {
		this.kor = kor;
		calcTot();
	}
	public int getEng() {
		return eng;
	}
	public void setEng(int eng) {
		this.eng = eng;
		calcTot();
	}
	public int getTot() {
		return tot;
	}
	public void setTot(int tot) {
		this.tot = tot;
	}
	/*
	public void calcTot() {//총점을 계산하는 메소드
		tot=kor+eng;
	}
	*/
	
	//은닉화 선언된 메소드 (클래스 내부에서만 사용하는 메소드) : 시스템 메소드
	// → 코드의 중복성을 최소화하기 위한 기능을 제공
	private void calcTot() {
		tot=kor+eng;
	}
	public void display() {		//필드값을 출력하는 메소드
		System.out.print(name+"["+num+"]님의 성적 >> ");
		System.out.println("국어 = "+kor+", 영어 = "+eng+", 총점 = "+tot);
	}

	
	//2. 정적 메소드(Static Method) : this 매개변수가 없는 메소드 
    //this 매개변수가 없으므로 인스턴스 필드에 접근 불가(정적 필드만 접근하여 사용 가능)
	//객체 생성 전에 클래스 이름을 사용하여 호출 가능 (메소드 호출의 용이성) 
	// ex) math class : 수학 관련된 기능만 제공, 생성자 은닉화하여 객체생성불가.
	public static int getTotal() {
		return total;
	}
	public static void setTotal(int total) {
		Student.total = total; }}





🐣 실행예제

public class StudentApp {
	public static void main(String[] args) {
    	//방법1
		Student student1=new Student(1000, "홍길동", 90, 90);
		Student student2=new Student(2000, "임꺽정", 94, 98);
		Student student3=new Student(3000, "전우치", 92, 80);
		Student student4=new Student(4000, "일지매", 76, 82);
		Student student5=new Student(5000, "장길산", 84, 86);
		
		//student1.calcTot(); 은닉화 처리된 메소드 사용 불가
		
		student1.display();
		student2.display();
		student3.display();
		student4.display();
		student5.display();

		student1.setKor(100);//국어점수 변경
		student1.display();//변경값 확인
		
        
        //방법2
		//객체를 저장할 수 있는 참조요소가 5개인 배열 생성 (배열의 참조요소 초기값: null)
		//참고로 자리가 30개→학생이 30명 X (참조요소가 5개있다고 객체가 만들어진것 X)
		Student[] students=new Student[5];
		
		//배열의 참조요소에 객체를 생성하여 저장 (객체 배열)
		students[0]=new Student(1000, "홍길동", 90, 90);
		students[1]=new Student(2000, "임꺽정", 94, 98);
		students[2]=new Student(3000, "전우치", 92, 80);
		students[3]=new Student(4000, "일지매", 76, 82);
		students[4]=new Student(5000, "장길산", 84, 86);
		
		//참조변수에 null이 저장된 상태에서 메소드를 호출한 경우 NullPointerException 발생
		for(int i=0;i<students.length;i++) {
			//참조변수(요소)에 저장된 값이 null이 아닌 경우에만 메소드 호출 
            //→ NullPointerException 발생 방지
			if(students[i]!=null) {
				students[i].display(); }}
		
        
		//방법3
		Student[] students={new Student(1000, "홍길동", 90, 90)
			, new Student(2000, "임꺽정", 94, 98), new Student(3000, "전우치", 92, 80)
			, new Student(4000, "일지매", 76, 82), new Student(5000, "장길산", 84, 86)};

		for(Student student:students) {//참조변수를 통해 배열을 호출하여 명령 실행
			student.display();
						
			//정적 필드는 클래스를 이용하여 접근 - 형식)클래스명.필드명 
			// 정적 필드의 접근 지정자가 private인 경우 접근 불가능
			//Student.total+=student.getTot();
			
			//정적 메소드는 클래스를 이용하여 호출 - 형식)클래스명.메소드명(값,값,...);
			Student.setTotal(Student.getTotal()+student.getTot());
		}	// Total이라는 정적 필드를 변경하여 총합계 계산

		System.out.println("총합계 = "+Student.getTotal()); }}
        //모든 학생들의 점수 총합계를 출력
        
        
        


📌 runtime 클래스

  • Java 프로그램을 실행하는 JVM 관련 정보를 저장하기 위한 클래스

    • jvm관련 정보는 객체가 가지고 있는 값이 모두 동일
    • 객체를 여러개 만들 필요 없이 하나면 만들면 됨
  • Runtime.getRuntime() : Runtime 객체를 반환하는 정적 메소드 (클래스명으로 호출)

    • getRuntime() 메소드를 여러번 호출해도 같은 객체를 반환
  • Runtime.totalMemory() : JVM이 사용 가능한 전체 메모리의 크기(Byte)를 반환하는 메소드

  • Runtime.freeMemory() : JVM이 사용 가능한 여유 메모리의 크기(Byte)를 반환하는 메소드

  • Runtime.gc() : 메모리를 청소하는 가비지 콜렉터(Garbage Collector)를 실행하는 메소드

    • System.gc() 메소드로 동일한 기능 제공 가능 (정적 메소드)

🐣 예제

public class RuntimeApp {
	public static void main(String[] args) {
 
  		//생성자가 은닉화 선언되어 있어 new 연산자로 객체 생성 불가능	
        //getRuntime() 메소드를 여러번 호출해도 같은 객체를 반환 (같은 메모리 주소 출력)
		Runtime runtime1=Runtime.getRuntime();
		Runtime runtime2=Runtime.getRuntime();
        
		System.out.println("청소 전 JVM 사용 메모리 크기 = "
		+(runtime1.totalMemory()-runtime1.freeMemory())+"Byte");
        
		//싱글톤 클래스는 객체를 반환받아 참조변수에 저장하여 메소드를 호출하지 않고 객체를 
		//반환받아 직접 메소드를 호출하여 사용하는 것을 권장
		System.out.println("청소 전 JVM 사용 메모리 크기 = "+
        (Runtime.getRuntime().totalMemory()-Runtime.getRuntime().freeMemory())+"Byte");
		
		Runtime.getRuntime().gc();





📒 싱글톤

  • 싱글톤 디자인 패턴을 적용하여 작성된 클래스 : 싱글톤 클래스(Singleton Class) - 상속이 안됨
  • 프로그램에 객체를 하나만 제공하기 위한 목적의 클래스를 작성하기 위해 사용
    • 프로그램에 불필요한 객체가 여러개 생성되는 것을 방지할 목적으로 사용
  • 클래스의 객체를 저장하기 위한 시스템 필드 선언
    • static 지정자를 사용하여 정적 필드로 선언
    • 시스템 필드 : 클래스 내부에서만 사용될 값을 저장하기 위한 필드
    • Getter 메소드와 Setter 메소드를 선언하지 않는 필드
    • 일반적인 필드와 구분하기 위해 필드명을 _로 시작되도록 작성하는 것을 권장
  • 정적 영역(Static Block) : 클래스가 메모리에 생성된 후 자동으로 실행될 명령을 작성하는 영역
    • 프로그램에서 한번만 실행되는 명령으로 정적 필드 또는 정적 메소드만 사용 가능

🐣 예제

public class Singleton {
	private static Singleton _instance;
	
	//생성자를 은닉화 선언 : 클래스 외부에서 생성자에 접근하지 못하도록 설정(객체 생성 불가능)
	private Singleton() {	}
    
	static {
		//클래스로 객체를 생성하여 시스템 필드에 저장 (프로그램에서 하나의 객체만 생성하여 사용)
		_instance=new Singleton();
	}
	//미리 생성되어 시스템 필드에 저장된 객체를 반환하는 정적 메소드 선언
	public static Singleton getInstance() {
		return _instance;
	}
	//인스턴스 메소드
	public void display() {
		System.out.println("Singleton 클래스의 display() 메소드 호출"); }}

🐣 실행예제

public class SingletonApp {
	public static void main(String[] args) {
		//싱글톤 클래스는 생성자가 은닉화 선언되어 new 연산자로 객체 생성 불가능
		//클래스 생성시 미리 생성되어 시스템 필드에 저장된 객체를 반환하는 정적 메소드 호출
		// → 프로그램에서 객체를 하나만 제공받아 사용 
		Singleton singleton1=Singleton.getInstance();
		Singleton singleton2=Singleton.getInstance();
		
		System.out.println("singleton1 = "+singleton1);
		System.out.println("singleton2 = "+singleton2);
        //동일한 메모리 주소 출력
		
		singleton1.display();
		singleton2.display();

		//싱글톤 클래스는 참조변수에 객체를 저장하여 참조변수로 메소드를 호출하지 않고 
        //객체를 반환받아 메소드를 직접 호출하여 사용하는 것을 권장
		Singleton.getInstace().display(); }}





profile
Study Log 📂

0개의 댓글

관련 채용 정보