객체지향-20230609

DONGDONG_JU·2023년 6월 9일
0

자바

목록 보기
12/16

객체지향 정리

너무 정리를 잘해주셔서 나중에 또 봐야지

출처:
https://jeong-pro.tistory.com/95

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

여러 소프트웨어 관련 IT기업 신입사원 기술면접에서 면접자들 긴장을 풀어줄 겸 워밍업으로 자주 나오는 질문이다.

"객체 지향 프로그래밍에 대해 설명 한번 해주세요"

가장 기본인 질문이지만, 이것마저 대답을 못하면 첫인상이 나빠지는 결과를 만들 수 있기에 중요한 질문이다.

앞서 워밍업이라 표현했지만 답변에 따라 꼬리에 꼬리를 무는 모든 질문의 시작점이기도 하다.

객체 지향 프로그래밍(OOP)이 뭐에요?

객체 지향 프로그래밍은 컴퓨터 프로그래밍 패러다임 중 하나로, 프로그래밍에서 필요한 데이터를 추상화시켜 상태와 행위를 가진 객체를 만들고 그 객체들 간의 유기적인 상호작용을 통해 로직을 구성하는 프로그래밍 방법이다.

이러면 이제 아까 말했던 꼬리에 꼬리를 무는 질문이 시작된다.

"객체 지향 프로그래밍을 했을 때 장점이 뭐에요?"

"객체 지향 프로그래밍의 특징을 말씀해주세요"

"객체(또는 클래스)가 뭐에요?"

=> 결국 객체 지향 키워드 5가지와 관련된 내용과 장단점을 알고 있는지에 대한 질문이다. (객체 지향의 5원칙(SOLID)을 말하는 것은 아니다.)

객체 지향 프로그래밍의 장, 단점 간단하게 설명해주세요

  • 장점

▶코드 재사용이 용이

남이 만든 클래스를 가져와서 이용할 수 있고 상속을 통해 확장해서 사용할 수 있다.

▶유지보수가 쉬움

절차 지향 프로그래밍에서는 코드를 수정해야할 때 일일이 찾아 수정해야하는 반면 객체 지향 프로그래밍에서는 수정해야 할 부분이 클래스 내부에 멤버 변수혹은 메서드로 존재하기 때문에 해당 부분만 수정하면 된다.

▶대형 프로젝트에 적합

클래스 단위로 모듈화시켜서 개발할 수 있으므로 대형 프로젝트처럼 여러 명, 여러 회사에서 프로젝트를 개발할 때 업무 분담하기 쉽다.

  • 단점

▶처리 속도가 상대적으로 느림

▶객체가 많으면 용량이 커질 수 있음

▶설계시 많은 시간과 노력이 필요

객체 지향 프로그래밍 키워드 5가지

1) 클래스 + 인스턴스(객체)

2) 추상화

3) 캡슐화

4) 상속

5) 다형성

클래스와 인스턴스(객체)는 무엇인지 설명해주세요.

클래스 : 어떤 문제를 해결하기 위한 데이터를 만들기 위해 추상화를 거쳐 집단에 속하는 속성(attribute)과 행위(behavior)를 변수와 메서드로 정의한 것으로 객체를 만들기 위한 메타정보라고 볼 수 있다.

인스턴스(객체) : 클래스에서 정의한 것을 토대로 실제 메모리에 할당된 것으로 실제 프로그램에서 사용되는 데이터

객체 지향 프로그래밍에서 추상화 (자료의 추상화)

객체 지향 프로그래밍에서는 '추상화' 라는 단어를 여러 군데 붙일 수 있다.

여기서 말하는 추상화는 추상 클래스나 추상 클래스가 갖는 추상 메서드를 의미하기보다는 클래스를 설계하는 것 자체를 의미한다.

즉, "공통의" 속성이나 기능을 묶어 이름을 붙이는 것이다.

캡슐화가 무엇인가요?

캡슐화의 목적 2가지

  1. 코드를 재수정 없이 재활용하는 것.

  2. 접근 제어자를 통한 정보 은닉

절차 지향 프로그래밍에서도 라이브러리를 통해서 변수와 함수를 재활용할 수는 있었지만, 코드의 수정이 일어났을 때 영향 범위를 예상하기 어려운 문제가 있었다.

그러나 객체 지향 프로그래밍에서는 캡슐화를 통해 객체가 외부에 노출하지 않아야할 정보 또는 기능을 접근제어자를 통해 적절히 제어 권한이 있는 객체에서만 접근하도록 할 수 있기에 코드의 수정이 일어났을 때 책임이 있는 객체만 수정하면 되기에 영향 범위를 예측하는데 수월해졌다.

뿐만 아니라 관련된 기능과 특성을 한 곳에 모으고 분류하기 때문에 객체 재활용이 원활해졌다.

객체 지향 프로그래밍에서 기능과 특성의 모음을 "클래스"라는 "캡슐"에 분류해서 넣는것이 캡슐화다.

객체가 맡은 역할을 수행하기 위한 하나의 목적을 한데 묶는다.

상속은 무엇인가요?

절자 지향 프로그래밍에서도 "라이브러리"를 통해서 남이 짜놓은 소스 코드를 가져와 사용할 수 있었다.

하지만 내 의도에 맞게 수정하게되면 다른 라이브러리가 되어 버전에 따라 동작하지 않을 수 있고 불필요한 코드의 수정작업을 해야한다는 것이다.

이런 문제를 해결하기 위해 [상속]이라는 것을 도입하였다.

상속은 부모클래스의 속성과 기능을 그대로 이어받아 사용할 수 있게하고 기능의 일부분을 변경해야 할 경우 상속받은 자식클래스에서 해당 기능만 다시 수정(정의)하여 사용할 수 있게 하는 것이다.

  • 다중상속은 불가하다. (클래스의 상속 관계에서 혼란을 줄 수 있기 때문에 상속은 반드시 하나만 가능하고 필요에 따라 인터페이스를 사용할 수 있게 했다. 자세한 내용은 이전 포스트에 있음.)

다형성은 무엇인가요?

하나의 변수명, 함수명 등이 상황에 따라 다른 의미로 해석될 수 있는 것이다.

즉 오버라이딩(Overriding), 오버로딩(Overloading)이 가능하다는 얘기다.

오버라이딩 : 부모클래스의 메서드와 같은 이름, 매개변수를 재정의 하는것.

오버로딩 : 같은 이름의 함수를 여러개 정의하고, 매개변수의 타입과 개수를 다르게 하여 매개변수에 따라 다르게 호출할 수 있게 하는 것.

getter, setter 를 사용하는 이유는 무엇인가요?

멤버변수에 직접접근하지 못하게 private으로 접근지정자를 설정하고 public으로 getter, setter 메서드를 만드는 것을 많이 해왔다.

그러면서 이럴꺼면 어차피 아무나 접근가능한데 왜 private을 할까? 라고 생각했었다.

결론부터 말하면 getter, setter를 사용하면 메서드를 통해서 접근하기 때문에, 메서드 안에서 매개변수같이 어떤 올바르지 않은 입력에 대해 사전에 처리할 수 있게 제한하거나 조절할 수 있기 때문이다.

예를들면 setter에서 유효범위를 넘은 정수가 들어왔을 때의 처리를 하고나서 set하거나 예외처리를 해버릴 수 있는 것이다.

getter도 마찬가지로 굳이 예를들자면 자료에 무언가 더하거나 빼고 준다든지가 가능하다.


변수의 초기화

-변수를 선언하고 처음으로 값을 저장하는 것
-멤버변수(인스턴스변수,클래스변수)와 배열은 각 타입의 기본값으로 자동초기화되므로 초기화를 생략할 수 있다.
-지역변수는 사용전에 꼭 초기화를 해주어야한다.

-인스턴스 초기화는 생성자 에서 초기화하기

-초기화블럭-

과제1-가위바위보 객체지향적으로

-내가해본거-

-계산클래스-

public class Exam2_1 {
	
	String [] kbb = {"가위","바위","보"};
	String result="";
	
	
	int cal() {
	int com = (int)(Math.random()*3);
			return com;
	}
	
	Object[] rule() {
		int user = 0;
		int com = 0;
		
		switch(user-com) {
		case 0: result= "비겼습니다"; break;
		case 1: case -2: result= "이겼습니다"; break;
		case -1: case 2: result= "졌습니다"; break;
		}
		return kbb;
	}

}

-출력클래스-

public class Exam2 {
	
	String [] kbb = {"가위","바위","보"};
		String result="";
		String intro ="\n\t[가위바위보 게임]\n"
				+ "\n"
				+ "\t1.가위\n"
				+ "\t2.바위\n"
				+ "\t3. 보\n"
				+ "\n\t입력하세요:";

	public static void main(String[] args) {
		
		Scanner sc = new Scanner(System.in);
		Exam2 ex2 = new Exam2();
		Exam2_1 ex2_1 = new Exam2_1();
		
		
		
		System.out.print(ex2.intro);
		int user = sc.nextInt()-1;  //제로베이스위해서 사용자입력을 0부터시작하게함
		
		
		sc.close();
		
		System.out.printf("\n\t사용자: %s , 컴퓨터: %s \n",ex2_1.kbb[user],ex2_1.kbb[ex2_1.cal()]);
		System.out.printf("\t게임의 결과는 %s",ex2_1.rule());
					

	}

}

ㅋㅋ 당연히 결과가 안나옴!

게임의 결과는.....더보기

-모범답안-

-계산하는 클래스-

	public class KawiBawiBo {

		int user;
		int com;
		String [] kbb;
		
		KawiBawiBo(){
			this.kbb = new String[]{"가위","바위","보"};
		}
			
		
		
		KawiBawiBo(int user){
			this();
			this.setUser(user);
			this.setCom();
			
		}
		void setUser(int user) {
			this.user = user -1;
		}
		
		void setCom() {
			this.com = (int)(Math.random() *3);
		}
		
		String getUser() {
			return this.kbb[this.user];
		}
		
		String getCom() {
			return this.kbb[this.com];
		}
		
		String judge() {
			String result="";
			switch(user-com) {
			case 0: result= "비겼습니다"; break;
			case 1: case -2: result= "이겼습니다"; break;
			case -1: case 2: result= "졌습니다"; break;
			}
			
			return result;
		}
}

-출력클래스 1(한번만)-

	Scanner sc = new Scanner(System.in);
		KawiBawiBo kbb;
		
		String intro ="\n\t[가위바위보 게임]\n"
				+ "\n"
				+ "\t1.가위\n"
				+ "\t2.바위\n"
				+ "\t3. 보\n"
				+ "\n\t입력하세요:";
		
		System.out.print(intro);
		kbb = new KawiBawiBo(sc.nextInt());
		
		sc.close();
		
		System.out.printf("\n\t사용자: %s , 컴퓨터: %s \n",kbb.getUser(),kbb.getCom());
		System.out.println("\t게임의 결과는 "+kbb.judge());

-출력클래스 2(사용자가 원할때 까지)-

	public static void main(String[] args) {
		
		Scanner sc = new Scanner(System.in);
		KawiBawiBo kbb = new KawiBawiBo();
		String run = "";
		
		String intro ="\n\t[가위바위보 게임]\n"
				+ "\n"
				+ "\t1.가위\n"
				+ "\t2.바위\n"
				+ "\t3. 보\n"
				+ "\n\t입력하세요:";
		
		while(true) {
			kbb.setCom();
			
			System.out.print(intro);
			kbb.setUser(sc.nextInt());  //제로베이스위해서 사용자입력을 0부터시작하게함
			
			
			System.out.printf("\n\t사용자: %s , 컴퓨터: %s \n",kbb.getUser(),kbb.getCom());
			System.out.println("\t게임의 결과는 "+kbb.judge());
			
			sc.nextLine();
			System.out.print("\n\t계속하시겠습니까? 종료를 원하시면 Q,q: ");
			run = sc.nextLine();
			
			if(run.length()==1 && (run.charAt(0) =='q' || run.charAt(0) =='Q' || run.charAt(0) =='ㅂ')) {
				break;
				
			}
			
			
		}
		
			System.out.println("\t감사합니다");
	}

어렵다.. 생각지도 못한 코드!


상속

-기존의 클래스를 재사용해서 새로운 클래스를 작성하는 것.
-두 클래스를 조상과 자손으로 관계를 맺어 주는 것.
-자손은 조상의 모든 멤버를 상속받는다.(생성자,초기화블럭 제외)
-자손의 멤버개수는 조상보다 적을 수 없다.(같거나 많다)

-자바에서는 다중상속이 없다. 자바는 단일상속만.
-다중상속하게되면 너무 복잡함.

→class 자손클래스 extends 조상클래스{}

클래스간의 관계-상속관계(inheritance) is a

-공통부분은 조상에서 관리하고 개별부분은 자손에서 관리한다.
-조상의 변경은 자손에 영향을 미치지만, 자손의 변경은 조상에 아무런 영향을 미치지 않는다.
-원은 도형 이다 Circle is a Shape

classA

public class classA {

	int num1;
	
	classA(){
		this.num1 = 10;
	}
	
	String method1() {
		return ("classA 클래스의 method1() 입니다.");
		
	}
	
	
}

classB

public class classB {

	int num2;
	classA classA;
	
	classB(){
		this.num2 = 20;
		classA = new classA();
	}
	
	String method2() {
		return("classB 클래스의 method2() 입니다.");
	}
	
	
}

-ex1-

public static void main(String[] args) {
		
		classB classB = new classB();
		
		//num1,num2 method1(),method2(), 모두의 값과 결과를 확인하세요.
		
		System.out.println("num1: "+ classB.classA.num1);
		System.out.println("num2: "+ classB.num2);
		System.out.println("method1: "+classB.classA.method1());
		System.out.println("method2(): "+classB.method2());

	}

classC

	public class classC extends classA{

	int num3;
	
	classC(){
		this.num3 = 20;
	
	}
	
	String method3() {
		return("classC 클래스의 method3() 입니다.");
	}
	
	
}

-ex2-

public class Ex2 {

	public static void main(String[] args) {
		
		classC classC = new classC();
		
		//num1,num2 method1(),method2(), 모두의 값과 결과를 확인하세요.
		
		System.out.println("num1: "+ classC.num1);
		System.out.println("num3: "+ classC.num3);
		System.out.println("method1: "+classC.method1());
		System.out.println("method3(): "+classC.method3());

	}

}


클래스간의 관계-포함관계(composite) has a

-한 클래스의 멤버변수로 다른 클래스를 선언하는것
-작은 단위의 클래스를 먼저 만들고, 이 들을 조합해서 하나의 커다란 클래스를 만든다.
-원은 점을 가지고 있다. Circle has a Point

상속 vs 포함


단일 상속(single inheritance)

-java는 단일상속만을 허용한다
-비중이 높은 클래스 하나만 상속관계로, 나머지 포함관계로 한다.

object클래스 - 모든 클래스의 최고조상

-조상이 없는 클래스는 자동적으로 object클래스를 상속받게 된다.
-상속계층도의 최상위에는 object클래스가 위치한다.
-모든 클래스는 object클래스에 정의된 11개의 메서드를 상속받는다.
=toString(),equals(object obj),hashCode(),.....

오버라이딩

-부모로부터 상속받은 메소드 재정의 = 오버라이딩
-조상클래스로부터 상속받은 메서드의 내용을 상속받는 클래스에 맞게 변경하는 것을 오버라이딩이라고 한다.

▶오버라이딩 조건
-1.선언부가 같아야 한다.(이름,매개변수,리턴타입)
-2.접근제어자를 좁은 범위로 변경할 수 없다.
-3.조상클래스의 메서드보다 많은 수의 예외를 선언할 수 없다.

계좌 돈 넣고 빼보기

-account 클래스-

public class Account {

	String accountNo;  //계좌번호
	String name;  //예금주
	int balance; //통장잔액
	
	
	void deposit(int amount) {   //입금
		balance += amount;
	}
	
	int withdraw(int amount){//출금
		if(amount > balance) {
			amount = -1;
		}else {
			balance -=amount;
		}
		
		return amount;
	}
	
}

-계산클래스-

public class CreditLineAccount extends Account {
	
	int creditLine;
	
	CreditLineAccount(int creditLine){
		this.creditLine = creditLine;
	}
	
	int withdraw(int amount){//출금
		if(amount > (balance+creditLine)) {
			amount = -1;
		}else {
			balance -=amount;
		}
		
		return amount;
	}

}

-출력클래스-

public static void main(String[] args) {
		
		CreditLineAccount cAccount = new CreditLineAccount(50000000);
		cAccount.accountNo = "A1234";
		cAccount.name= "어피치";
		cAccount.balance= 1000000;
		
		cAccount.deposit(500000);
		System.out.println("현재 잔액: "+cAccount.balance);
		
		if(cAccount.withdraw(2000000) == -1) {
			System.out.println("잔액이 부족합니다.");
			System.out.println("현재 잔액: "+cAccount.balance);
		}else {
			System.out.println("현재 잔액: "+cAccount.balance);
		}
		
		if(cAccount.withdraw(100000000) == -1) {
			System.out.println("잔액이 부족합니다.");
			System.out.println("현재 잔액: "+cAccount.balance);
		}else {
			System.out.println("현재 잔액: "+cAccount.balance);
		}

	}

}


super()

-this: 인스턴스 자신을 가리키는 참조변수, 인스턴스의 주소가 저장되어있음,
모든 인스턴스 메서드에 지역변수로 숨겨진 채로 존재
-super: this와 같음. 조상의 멤버와 자신의 멤버를 구별하는 데 사용.

-자손클래스의 인스턴스를 생성하면, 자손의 멤버와 조상의 멤버가 합쳐진 하나의 인스턴스가 생성된다.
-조상의 멤버들도 초기화되어야 하기 때문에 자손의 생성자의 첫 문장에서 조상의 생성자를 호출해야 한다.

-child클래스-

	public class Child extends Parent {
	
	Child(){
		System.out.println("Child 인스턴스 생성");
	}
	
	void methodA() {
		super.methodA();  //숨겨진 부모클래스의 methodA 출력
		System.out.println("Child 클래스 methodA()");
	}

}

-Parent클래스-

	public class Parent {
	
	Parent(){
		System.out.println("Parent 인스턴스 생성");
	}
	
	void methodA() {
		System.out.println("Parent 클래스 methodA()");
	}
	

}

-출력클래스-

	public class Ex4 {

	public static void main(String[] args) {
		Child child = new Child();
		child.methodA();

	}

}

-parent클래스-

public class Parent {
	
	String name;
	
	Parent(String name){
		this.name = name;  //자식클래스 오류남. 매개변수가 있는, 인스턴스 생성불가
		System.out.println("Parent 인스턴스 생성");
	}
	
	void methodA() {
		System.out.println("Parent 클래스 methodA()");
	}
	

}

-child클래스-

public class Child extends Parent {
	
	String gender;
	
	Child(String name, String gender){
		super(name);
		this.gender = gender;
		System.out.println("Child 인스턴스 생성");
	}
	
	void methodA() {
		super.methodA();  //숨겨진 부모클래스의 methodA 출력
		System.out.println("Child 클래스 methodA()");
	}

}

-출력클래스-

public static void main(String[] args) {
		Child child = new Child("손흥민","남자");
		child.methodA();
		System.out.println(child.name+" : "+child.gender);

	}


참고문헌- 자바의정석 (남궁성)

profile
웹개발자로 취업하고싶어 공부중인 HDJ 입니다

0개의 댓글