본문 바로가기
Programming/Java

OOP(Object Oriented Programming) 객체지향 프로그래밍

모든 프로그래밍 언어의 기본이자 중요한 내용이다!

객체(object): 물리적 존재 or 추상적 생각하는 것 중에서 식별가능한 자신의 속성을 가진 것

                 ex) 식별가능하고 특징있는 세상의 모든 사물들; 볼펜, 볼펜잉크, 볼펜 심 등

                    속성(field 필드) + 동작(method 메소드)로 구성

                  형태적인 것들(정의)

ex) 걷는 속도  <- 이 개념은 필드.  실제로 걷는 것은 메소드

     자동차의 필드는 색깔 속도 등. 메소드는 달린다와 멈춘다.

 

메소드 호출 : 무언가를 시키는 것

 

매개값 = 매개변수 ( arg;argument) = input값

 

 

[객체관계]

1. 집합 관계: 부품과 완성품의 관계

2. 사용 관계: 객체 간 상호작용

3. 상속 관계: 상위(부모) 객체 기반 하위(자식) 객체 생성

 

Class(클래스): 자바의 설계도

Instance(인스턴스): 클래스로부터 만들어진 객체

 

OOP: 클래스 설계 -> 사용할 객체(인스턴스) 생성 -> 생성된 객체 이용

 

지금까지 정리한 자바 기본 문법은 main() 메소드만 작성해서 실행할 목적으로 클래스 이용함

main()이 없다면 객체 생성 과정을 거쳐 사용해야 함

 

 

 

 

 

클래스 선언: 객체 구상 후 이름 결정. 첫 단어 대문자 중요

보통은 java 소스파일 하나 당 하나의 클래스만 선언하지만 2개 이상도 가능은 하다.

package sec01.exam01;

public class Student {

}

public class Teacher {   //2개 이상 클래스 선언하는 경우

}

이 경우 class 파일이 2개 생김. 이처럼 Student라는 클래스를 실행 클래스 (StudentExample)에서 사용한다면

package sec01.exam01;

public class StudentExample {
	public static void main(String[] args) {
		Student s1 = new Student();
		System.out.println("s1 변수가 Student 객체를 참조합니다.");
		
		Student s2 = new Student();
		System.out.println("s2 변수가 또 다른 Student 객체를 참조합니다.");
	}
}

s1 변수가 Student 객체를 참조합니다.

s2 변수가 또 다른 Student 객체를 참조합니다.

 

이처럼 API(Application program Interface) 라이브러리 목적(Student) 클래스와 실행 클래스(StudentExample)을 분리하여 작성한다.

 

 

 


[클래스를 구성하려면?]

Field: 객체 데이터 저장소

Constructor(생성자): 객체 초기화 담당. new로 호출되는 { } 블록

Method: 객체 동작 실행 { } 블록

 

 

 

Field: 객체 데이터 저장소

아래 두 java 파일은 반드시 같은 패키지안에 있어야 자동으로 가져온다. public이라서 자유롭게 가져오는 것이다.

package sec02.exam01;
public class Car {
	//필드              이 자바파일은 실행시키지 않는다.
	String company = "현대자동차";
	String model = "그랜저";
	String color = "검정";
	int maxSpeed = 350;
	int speed;   // 초기값은 0이다.
}

외부 클래스 (CarExample)에서 Car의 field의 값을 읽는다.

package sec02.exam01;

public class CarExample {
	public static void main(String[] args) {
		//객체 생성
		Car myCar = new Car();  // 생성된 자동차 클래스의 필드값 객체를 가져온다.
		
		//필드 값 읽기
		System.out.println("제작회사: " + myCar.company);
		System.out.println("모델명: " + myCar.model);
		System.out.println("색깔: " + myCar.color);
		System.out.println("최고속도: " + myCar.maxSpeed);
		System.out.println("현재속도: " + myCar.speed);
		
		//필드 값 변경
		myCar.speed = 60;   // 클래스 jave파일은 그대로이고 여기서만 반영된다.
		System.out.println("수정된 속도: " + myCar.speed);
	}
}

제작회사: 현대자동차

모델명: 그랜저

색깔: 검정

최고속도: 350

현재속도: 0

수정된 속도: 60

 

 

 

각종 타입의 초기값을 알아보자. (외부클래스에서 읽기)

package sec02.exam02;

public class FieldInitValue {
	//필드
	byte byteField;
	short shortField;
	int intField;
	long longField;
	
	boolean booleanField;
	char charField;	
	
	float floatField;
	double doubleField;
	
	int[]  arrField;
	String referenceField;	
}
package sec02.exam02;

public class FieldInitValueExample {
	public static void main(String[] args) {	
		FieldInitValue fiv = new FieldInitValue();
		
		System.out.println("byteField: " + fiv.byteField);
		System.out.println("shortField: " + fiv.shortField);
		System.out.println("intField: " + fiv.intField);
		System.out.println("longField: " + fiv.longField);		
		System.out.println("booleanField: " + fiv.booleanField);
		System.out.println("charField: " + fiv.charField);		
		System.out.println("floatField: " + fiv.floatField);
		System.out.println("doubleField: " + fiv.doubleField);		
		System.out.println("arrField: " + fiv.arrField);
		System.out.println("referenceField: " + fiv.referenceField);
	}
}
 

byteField: 0

shortField: 0

intField: 0

longField: 0

booleanField: false

charField:

floatField: 0.0

doubleField: 0.0

arrField: null

referenceField: null

 

 

 

 

 

Constructor(생성자): 객체 초기화 담당. new로 호출되는 { } 블록

package sec03.exam01;

public class Car {
	//생성자  color와 cc값이 있음 (형식)
	Car(String color, int cc) {
	}
}
package sec03.exam01;

public class CarExample {
	public static void main(String[] args) {
		Car myCar = new Car("검정", 3000); // color와 cc값 형식을 맞추었다.
		//Car myCar = new Car();  (이러한 기본 생성자는 존재하지 않으므로 오류)
	}      // 이걸 사용하려면 기본 생성자 전용도 따로 만들어줘야 함.
}

 

 

 

필드와 생성자(매개변수)는 이름을 동일한 경우가 많다. 이 경우 this를 통해(파이썬 self개념) 필드임을 구분한다

package sec03.exam02;

public class Korean {
	//필드
	String nation = "대한민국";
	String name;
	String ssn;

	//생성자 이렇게 잘 안씀
	/* public Korean(String n, String s) {
	  name = n;
	  ssn = s;
	}*/
// 생성자 보통 이렇게 씀	
	public Korean(String name, String ssn) { 
	  this.name = name;
	  this.ssn = ssn;
	}
}
package sec03.exam02;

public class KoreanExample {
	public static void main(String[] args) {
		Korean k1 = new Korean("박자바", "011225-1234567");
		System.out.println("k1.name : " + k1.name);
		System.out.println("k1.ssn : " + k1.ssn);
		
		Korean k2 = new Korean("김자바", "930525-0654321");
		System.out.println("k2.name : " + k2.name);
		System.out.println("k2.ssn : " + k2.ssn);
	}
}

k1.name : 박자바

k1.ssn : 011225-1234567

k2.name : 김자바

k2.ssn : 930525-0654321

 

 

 

 

생성자 여러개 준비하기 (생성자 overloading)

단 순서만 바꾼다거나 이름만 바꾸는 것는 해당안됨을 유의한다.

package sec03.exam03;

public class Car {
	//필드
	String company = "현대자동차";
	String model;
	String color;
	int maxSpeed;
	
	//생성자
	Car() {
	} // 아무것도 없는 경우(default)이며 new가 입력 가능하다.
	
	Car(String model) {
		this.model = model;
	}
	
	Car(String model, String color) {
		this.model = model;
		this.color = color;
	}
	
	Car(String model, String color, int maxSpeed) {
		this.model = model;
		this.color = color;
		this.maxSpeed = maxSpeed;
	}
}
package sec03.exam03;

public class CarExample {
	public static void main(String[] args) {
		Car car1 = new Car();
		System.out.println("car1.company : " + car1.company);
		System.out.println();
		
		Car car2 = new Car("자가용");
		System.out.println("car2.company : " + car2.company);
		System.out.println("car2.model : " + car2.model);
		System.out.println();
		
		Car car3 = new Car("자가용", "빨강");
		System.out.println("car3.company : " + car3.company);
		System.out.println("car3.model : " + car3.model);
		System.out.println("car3.color : " + car3.color);
		System.out.println();
		
		Car car4 = new Car("택시", "검정", 200);
		System.out.println("car4.company : " + car4.company);
		System.out.println("car4.model : " + car4.model);
		System.out.println("car4.color : " + car4.color);
		System.out.println("car4.maxSpeed : " + car4.maxSpeed);
	}
}

car1.company : 현대자동차

 

car2.company : 현대자동차

car2.model : 자가용

 

car3.company : 현대자동차

car3.model : 자가용

car3.color : 빨강

 

car4.company : 현대자동차

car4.model : 택시

car4.color : 검정

car4.maxSpeed : 200

-> 생정자가 여러개라서 이에 맞는 다양한 형식의 출력이 가능해졌다.

 

 

 

 

 

this()를 통해서 클래스의 반복되는 생성자 구문을 간략하게 할 수 있다.

package sec03.exam04;

public class Car {
	//필드
	String company = "현대자동차";
	String model;
	String color;
	int maxSpeed;
	
	//생성자
	Car() {
	}
	
	Car(String model) {
		this(model, null, 0);
	}
	
	Car(String model, String color) {
		this(model, color, 0);
	}
	
	Car(String model, String color, int maxSpeed) {
		this.model = model;
		this.color = color;
		this.maxSpeed = maxSpeed;
	}
}

제일 밑에 모든 필드가 있는 경우를 놓고 위에 this로 호출이 가능하다.

 

 

 

 

 

 

 

 

 

 

Method: 객체 동작 실행 { } 블록. 관례적으로 소문자로 이름 지음. (클래스는 첫 글자 대문자)

리턴값: 메소드 결과값. 메소드는 리턴값 유무가 제각각

 

필드는 괄호가 없지만 메소드는 () 괄호가 있다.

 

리턴값 없는 메소드 = void (실행 강제)

package sec04.exam01;

public class Calculator {
	//메소드
	void powerOn() {
		System.out.println("전원을 켭니다.");
	}
	
	int plus(int x, int y) {
		int result = x + y;
		return result;
	}
	
	double divide(int x, int y) {
		double result = (double)x / (double)y;
		return result;
	}
	
	void powerOff() {
		System.out.println("전원을 끕니다");
	}
}
package sec04.exam01;

public class CalculatorExample {
	public static void main(String[] args) {
		Calculator myCalc = new Calculator(); // 클래스 객체화
		myCalc.powerOn(); // 클래스의 print문 출력
		
		int result1 = myCalc.plus(5, 6);
		System.out.println("result1: " + result1);
		
		byte x = 10;
		byte y = 4;
		double result2 = myCalc.divide(x, y);
		System.out.println("result2: " + result2);
		
		myCalc.powerOff();
	}
}

전원을 켭니다.

result1: 11

result2: 2.5

전원을 끕니다

 

 

 

매개변수 ... (도트연산자) 는 배열이아닌 값만 가져올 때 사용한다. 

매개변수의 개수를 모를 때에는 배열 타입으로 선언한다.

package sec04.exam02;

public class Computer {
	int sum1(int[] values) {  // 여기서 values는 이름일 뿐이다.
		int sum = 0;
		for(int i=0; i<values.length; i++) {
			sum += values[i];
		}
		return sum;
	}
	
	int sum2(int ... values) {  //배열이 아니더라도 알아서 맞춰 넣어준다.
		int sum = 0;
		for(int i=0; i<values.length; i++) {
			sum += values[i];
		}
		return sum;
	}
}
package sec04.exam02;

public class ComputerExample {
	public static void main(String[] args) {
		Computer myCom = new Computer();
		
		int[] values1 = {1, 2, 3};
		int result1 = myCom.sum1(values1);
		System.out.println("result1: " + result1);
		
		int result2 = myCom.sum1(new int[] {1, 2, 3, 4, 5});
		System.out.println("result2: " + result2);		
		
		int result3 = myCom.sum2(1, 2, 3);
		System.out.println("result3: " + result3);
		
		int result4 = myCom.sum2(1, 2, 3, 4, 5);
		System.out.println("result4: " + result4);
	}
}

result1: 6

result2: 15

result3: 6

result4: 15

 

 

 

 

return은 메소드 실행을 강제 종료한다. (break보다 효율적으로 전체종료 可)

package sec04.exam03;

public class Car {
	//필드  (보안문제로 이렇게 작성하기보단 아래 메소드형식으로 쓴다)
	int gas;
	
	//생성자   없어도 기본 생성자는 자동으로 생성된다!
	
	//메소드
	void setGas(int gas) {  // set는 값 주입하는 것.
		this.gas = gas;
	}
	
	boolean isLeftGas() {
		if(gas==0) {
			System.out.println("gas가 없습니다."); 
			return false;
		}
		System.out.println("gas가 있습니다."); 
		return true;
	}
package sec04.exam03;

public class CarExample {
	public static void main(String[] args) {
		Car myCar = new Car();
		
		myCar.setGas(5);  //Car의 setGas() 메소드 호출
		
		boolean gasState = myCar.isLeftGas();  //Car의 isLeftGas() 메소드 호출
		if(gasState) {
			System.out.println("출발합니다.");
			myCar.run();  //Car의 run() 메소드 호출
		}
		
		if(myCar.isLeftGas()) {  //Car의 isLeftGas() 메소드 호출
			System.out.println("gas를 주입할 필요가 없습니다.");
		} else {
			System.out.println("gas를 주입하세요.");
		}
	}
}

gas가 있습니다.

출발합니다.

달립니다.(gas잔량:5)

달립니다.(gas잔량:4)

달립니다.(gas잔량:3)

달립니다.(gas잔량:2)

달립니다.(gas잔량:1)

멈춥니다.(gas잔량:0)

gas가 없습니다.

gas를 주입하세요.

 

 

 

 

 

 

클래스 내부에서 메소드를 계속 호출하는 예제이다.

package sec04.exam04;

public class Calculator {
	//필드
	//생성자
	//메소드
	int plus(int x, int y) {
		int result = x + y;
		return result;
	}
	
	double avg(int x, int y) {
		double sum = plus(x, y);
		double result = sum / 2;
		return result;
	}
	
	void execute() {
		double result = avg(7, 10);
		println("실행결과: " + result);  //이것도 메소드이다.
	}
	
	void println(String message) {
		System.out.println(message);
	}	
}
package sec04.exam04;

public class CalculatorExample {
	public static void main(String[] args) {
		Calculator myCalc = new Calculator();
		myCalc.execute();    // 실행한 것은 이것 뿐
	}
}

실행결과: 8.5

 

 

 

 

 

 

 

 

 

 

 

 

 

 

메소드 오버로딩(overloading): 같은 이름의 메소드인데 기능이 여러개임을 구현하는 경우

package sec04.exam06;

public class Calculator {
	//정사각형의 넓이
	double areaRectangle(double width) {
		return width * width;
	}
	
	//직사각형의 넓이
	double areaRectangle(double width, double height) {
		return width * height;
	}	
}
package sec04.exam06;

public class CalculatorExample {
	public static void main(String[] args) {
		Calculator myCalcu = new Calculator();
		
		//정사각형의 넓이 구하기
		double result1 = myCalcu.areaRectangle(10);

		//직사각형의 넓이 구하기
		double result2 = myCalcu.areaRectangle(10, 20);
		
		//결과 출력
		System.out.println("정사각형 넓이=" + result1);
		System.out.println("직사각형 넓이=" + result2);
	}
}

정사각형 넓이=100.0

직사각형 넓이=200.0

 

직사각형 넓이의 경우 int로 들어갔으므로 밑에 같은 이름에 int로 지정된 곳을 가지만 없으면 자동타입변환 규칙에 의해

double이 있는 경우가 실행되었다.

 

 

 

 

 

 

 

 

 

728x90
반응형

'Programming > Java' 카테고리의 다른 글

Interface (인터페이스)  (0) 2023.10.17
Inheritance(상속)  (1) 2023.10.16
instance, static, package, access modifier  (0) 2023.10.16
참조타입, 배열, 열거타입  (0) 2023.10.12
java basic (기본 문법)  (0) 2023.10.11