조컴퓨터

200825 OOP 09 - Java 객체지향 프로그래밍(Ⅰ) 본문

자바 웹개발자 과정/JAVA

200825 OOP 09 - Java 객체지향 프로그래밍(Ⅰ)

챠오위 2020. 8. 27. 09:52

클래스 class

 

클래스 : 인스턴스 = 설계도 : 객체 

 

클래스명의 첫글자는 대문자로 한다.

작성하고자 하는 클래스 내용의 의미를 부여한다.

 

클래스의 구성 : 멤버변수(field) + 멤버함수(method)

 

System.out.println(Math.PI);	//3.141592653589793
System.out.println(Math.abs(3));//3

 

 

 

객체지향프로그램 Object Oriented Program

 

- 함수 기반에서는 구현하기 힘든 상속, 다형성, 캡슐화, 은폐 등을 구현할 수 있다.

- 논리를 요소화해서 재사용성 향상 및 빠른 유지 보수를 가능케 한다.

- 메모리 관리를 가상 머신이 함으로써 매우 안정적으로 운영됨. 플랫폼이 독립되어 있음

- 데이터베이스와 새로운 인터넷 환경 구축을 위한 다양한 API를 지원한다(=라이브러리).

- 정보 은닉*이 가능하다.

 

* 정보 은닉 : 접근 제한을 이용하여 인스턴스 변수를 외부로부터 직접적인 접근을 철저히 차단하고, 자료를 수정 또는 조작할 수 있는 동작들은 내부에 둔다.

 

 

 

객체 생성과 클래스 변수

 

클래스로부터 객체를 생성하는 방법은 다음과 같이 new 연산자를 사용하면 된다.

 

new 클래스();

 

 

클래스를 사용하려면 메모리를 할당하고 사용한다. 

나중에 사용하게 될 생성자함수명으로 미리 선언해 보자.

 

new Sungjuk();

 

 

new 연산자로 생성된 객체는 메모리 힙(heap) 영역에 생성되고 주소값이 발생된다.

메모리 내에서 생성된 객체의 위치를 모르면 객체를 사용할 수 없으므로 new 연산자는 힙 영역에 객체를 생성시킨 후, 객체의 주소를 리턴한다. 이 주소를 참조 타입인 클래스 변수에 저장해 두면, 변수를 통해 객체를 사용할 수 있다.

 

클래스 변수 = new 클래스();

 

 

 

접근제어자, 수정자, 지정자 Access Modifier

 

public, package, protected, private

클래스 내부에서 접근할 경우는 접근제어는 서로 상관없다.

클래스, 함수 앞에 다양하게 붙을 수 있다.

 

  • public : 공개. baxicJava 프로젝트 내에서 모두 접근 가능하다.
  • package : 생략. 같은 패키지(폴더)에 있는 객체들만 접근을 허용한다.
  • protected : 같은 패키지(폴더)에 있는 객체와 상속 관계의 객체들만 접근을 허용한다. 
  • private : 비공개. 클래스 내부에서만 접근 가능하다. 특정 정보를 은폐할 수 있다.

 

멤버 변수의 예시

 

public String name;//클래스 외부에서 접근가능하다
int kor, eng, mat; //package가 생략되어 있다
private int aver;  //클래스 내부에서만 접근가능하다

 

 

멤버함수 method의 예시

 

private void view() {}//view end

 

 

 

예제1) Sungjuk sj = new Sungjuk( );

 

class Sungjuk{

	void calc() {
		//클래스 내부의 멤버들 간에는
		//Access Modifier와 상관없이 접근가능하다
		aver=(kor+eng+mat)/3;
	}//calc() end
	
	public void disp() {
		System.out.println(name);
		System.out.println(kor);
		System.out.println(eng);
		System.out.println(mat);
		System.out.println(aver);
	}//disp() end
    
}//class end

public class Test01_class {
	public static void main(String[] args) {
    
    	//class 사용자 정의 자료형(Datatype)
    	int a;      //int 자료형, a 변수
    	Sungjuk sj; //Sungjuk 자료형, sj 변수 (object 객체)
        
        //기본 자료형, 참조 자료형(reference)
    	//기본 자료형: int,long,double,char
    	//참조 자료형: new 연산자로 메모리 할당이 필요함.
    	//             단, String은 기본 자료형처럼 사용되고 있음
		
		//Sungjuk클래스는 사용자 정의 자료형
        
		//sj 참조변수 (reference)
		Sungjuk sj=new Sungjuk();
        
		//.연산자
		//참조변수를 통해 객체에 접근하는 연산자
		sj.name="손흥민";
		sj.kor=80;
		sj.eng=95;
		sj.mat=100;
		//sj.aver 에러
		//->private속성은 클래스 외부에서 접근 불가능하다
		
		//sj.view(); 에러
		//->클래스 외부에서는 접근 불가능
		
		sj.calc();
		sj.disp();
		
	}//main() end
}//class end

/*
	손흥민
	80
	95
	100
	91
*/

 

 

예제2) Sungjuk sungjuk = new Sungjuk( );

 

class Sungjuk{

	void calc() {
		aver=(kor+eng+mat)/3;
	}//calc() end
	
	public void disp() {
		System.out.println(name);
		System.out.println(kor);
		System.out.println(eng);
		System.out.println(mat);
		System.out.println(aver);
	}//disp() end
    
}//class end

public class Test01_class {
	public static void main(String[] args) {
		
		//객체지향 문법의 특징
		//->정보은닉
		//->캡슐화
		Sungjuk sungjuk=new Sungjuk();
		sungjuk.name="박지성";
		sungjuk.kor=50;
		sungjuk.eng=55;
		sungjuk.mat=70;
        
		sungjuk.calc();
		sungjuk.disp();
				
	}//main() end
}//class end

/*
	박지성
	50
	55
	70
	58
*/

 

 

예제1), 2) 참조변수가 가지고 있는 객체의 주소값

 

System.out.println(sj.hashCode());		//1521118594
System.out.println(sungjuk.hashCode()); //1521118594


//1521118594 동일
//전달값이 제대로 전달되었음
Sungjuk tmp=sj;
System.out.println(tmp.hashCode());	

 

 

 

생성자 Constructor

 

- new라는 명령어에 의하여 객체가 생성될 때 자동으로 호출되는데, 이때 자동으로 호출되는 생성자를 기본생성자(default constructor)라 한다.

- 기본생성자는 자바 컴파일러에 의하여 자동으로 생성된다.

- 클래스 이름과 같아야 한다. (대소문자 구별)

- return Type이 없다.

- 오버로딩이 가능하므로 하나의 클래스에 여러 개의 생성자가 있을 수 있다.

 

- new를 이용하여 객체를 메모리에 할당한 후 할당된 메모리에 특정 값으로 초기화하는 역할을 한다. **

- 대부분 멤버변수의 초기값을 할당할 때 주로 사용한다.

 

 

 

* stack과 heap의 관계에 대하여 잘 정리되어 있는 티스토리 블로그 링크

https://hunit.tistory.com/145

 

자바(Java) Heap영역과 Stack영역 정리

저번 글에서는 자바의 제어문인 조건문과 반복문에 대해서 정리해보았는데요. 이번글에서는 객체와 배열을 하기전 기초지식으로 알아야 되는 Heap영역과 Stack영역에 대해서 살짝 정리하고 넘어�

hunit.tistory.com

 

 

 

 

기본생성자를 반드시 선언해야 하는 이유 (★★)

- 생성자함수는 오버로딩이 되면 기본생성자 함수를 자동으로 생성하지 않는다.

- 기본생성자는 기본적으로 자동 생성이 되지만 생성자 오버로딩이 필요한 경우에는 반드시 기본생성자를 수동적으로 만들어 주어야 한다.

- 생성자에 초기화하는 변수가 없어도 반드시 생성자를 선언할 것을 권장한다.

- 상속 관계에 들어갈 때 기본생성자가 선언되지 않으면 상황에 따라 에러가 발생한다.

- 기본생성자는 하는 일이 없어도 상속시 에러가 발생하는 경우가 있으니 수동적으로 무조건 선언을 적극 권장한다.

 

 

* 소멸자함수 Destructor 자바에는 존재하지 않는다.

** 가비지 콜렉팅 Garbage Collecting : JVM이 자동으로 메모리 회수를 진행한다. (★★)

 

 

 

package oop0825;

import java.util.GregorianCalendar;

class School{
	//멤버변수 field
	private String name;
	private int kor, eng, mat;
	private int aver;
	
	//생성자함수 Constructor
	//->클래스명과 동일한 함수
	//->리턴형이 없다
	//public void School() {} 주의!!
	public School() {//기본생성자함수
			//default constructor
			//자동생성된다
		System.out.println("School()...");		
	}//end
	
	//생성자함수도 오버로딩(중복정의)이 가능하다
	public School(String n) {
		name=n;
	}//end
    
	public School(int k, int e, int m) {
		kor=k;
		eng=e;
		mat=m;
	}//end
    
	public School(String n, int k, int e, int m) {
		name=n;
		kor=k;
		eng=e;
		mat=m;
	}//end
	
    
	//멤버함수 method
	public void calc() {
		aver=(kor+eng+mat)/3;
	}//calc() end
	
	public void disp() {
		System.out.println(name);
		System.out.println(kor);
		System.out.println(eng);
		System.out.println(mat);
		System.out.println(aver);
	}//disp() end
	
}//class end


public class Test02_constructor {
	public static void main(String[] args) {
		//생성자함수 Constructor
		//->클래스명과 동일한 함수
		//->new 연산자와 함께 메모리 할당할 때 사용한다
		//->오버로딩이 가능하다
		
		//소멸자함수 Destructor->자바에는 없음!!
		//가비지 콜렉팅(Garbage Collecting)
		//->JVM이 자동으로 메모리 회수를 함
		
//---------------------------------------------------------------		
		//one->참조변수(reference)
		School one=new School(); //#50번지
		one.calc();
		one.disp();
		
		/*
		//null : 비어있는 값
		String a="";  //빈 문자열
		String b=null;//메모리할당은 하지 않고
					  //b라는 참조변수 선언만 해 놓음
		System.out.println(a.length()); //글자갯수 0
		
		//NullPointerException 발생
		System.out.println(b.length());
		*/
		
		/*
			School()...
			null	//이름
			0		
			0
			0
			0
		*/
		/*	
		 	null 상세설명
			true
			false
			null : 비어있는 값
			
			0 vs null
			예시) 휴지를 다 써서 없는 것 vs 원래 없는 것 
		*/
		
//---------------------------------------------------------------	
		School two=new School("개나리"); //#60번지	**번지는 예시이다
		two.calc();
		two.disp();
		/*
			개나리
			0
			0
			0
			0
		*/
		
		School three=new School(10, 15, 25); //#70번지
		three.calc();
		three.disp();
		/*
			null
			10
			15
			25
			16
		*/
		
		School four=new School("채치수", 40, 45, 55); //#80번지
		four.calc();
		four.disp();
		/*
			채치수
			40
			45
			55
			46
		*/
		
//---------------------------------------------------------------
		String str1="HAPPY";
		String str2=new String("APPLE");
		System.out.println(str1); //HAPPY
		System.out.println(str2); //APPLE
		
		//교재 11챕터 조금씩 볼 수 있을 거임 해봐요~		

	}//main() end
}//class end

 

 

 

*참조

GregorianCalendar 클래스

GregorianCalendar 클래스를 이용해 각 년도의 윤년과 평년을 알아볼 수 있다.

 

GregorianCalendar today=new GregorianCalendar();
if(today.isLeapYear(2020)) {
	System.out.println("윤년");
}else {
	System.out.println("평년");
}//if end

//is로 시작하는 함수는 물어보는 함수 true, false형태로 답이 나온다 (리턴형이 boolean)
//today.isLeapYear(2020);

/*
	윤년
*/

 

 

 

변수의 유효범위(scope)와 this

 

변수의 유효범위(scope)

- 해당 변수를 사용할 수 있는 범위 또는 그 공간, 지역

- 멤버 변수(field)의 유효범위(해당 클래스) 내에서 사용 가능

- 일반 지역 변수(local variable)의 유효 범위

  · 해당 메소드 내에서만 사용 가능

  · 메소드 안으로 들어올 때 메모리에 할당되고 메소드 밖으로 나가면서 메모리에서 삭제된다.

  · 멤버 변수보다 지역 변수의 우선 순위가 더 높다.

 

 

this

- 해당 객체를 지칭하는 키워드

- 해당 멤버 변수에 접근할 때 일반 지역 변수와 구분하기 위해 사용한다.

- 특정 객체 내에서 현재 객체 자신을 의미하는 참조 변수

- 자신이 객체가 되어 메모리 내에 존재하므로 자신의 위치값(reference)을 기억하고 있음

- 메소드 내에서만 사용된다.

- static 메소드에서는 사용할 수 없다.

- 멤버 변수와 지역 변수를 구별해야 할 때 멤버 변수 앞에서 this를 붙여 사용

 

 

package oop0825;

class Score{
	private String name="손흥민";	//멤버변수
	private int kor, eng, mat;
	private int aver;
	
	//생성자함수를 오버로딩하면 기본생성자 함수는 자동으로 생성되지 않는다.
	//-> 기본생성자함수는 수동으로 생성할 것을 추천함!
	public Score() {}
		
	public Score(String name, int kor, int eng, int mat) {
		this.name=name;//this.멤버 변수=지역 변수 -> 지역 변수를 this.멤버 변수에 넣기 위해
		this.kor=kor;
		this.eng=eng;
		this.mat=mat;
		this.aver=(kor+eng+mat)/3;
	}//end
	
	public void disp() {
		//지역 변수의 우선순위가 가장 높다
		//String name="박지성";		//지역 변수
		//System.out.println(name);		//박지성
		//this.멤버 변수
		System.out.println(this.name);	//손흥민
		System.out.println(this.kor);
		System.out.println(this.eng);
		System.out.println(this.mat);
		System.out.println(this.aver);
	}//disp() end
	
}//class end


public class Test03_this {
	public static void main(String[] args) {
		//this 
		//->클래스 자신을 가리키는 대명사
		//->일반 지역변수와 멤버변수를 구분하기 위함
		//this()
		//->생성자함수간의 호출
		
		//Score one=new Score();//Score(); 에러
		//one.disp();
		
		//Score two=new Score("채치수", 70, 80, 95);
		//two.disp();
		/*
			채치수
			70
			80
			95
			81
		*/

//---------------------------------------------------------------
		/*
		Score kim =new Score("봉선화", 70, 85, 100);
		Score lee =new Score("라일락", 60, 65, 30);
		Score park=new Score("진달래", 40, 20, 90);
		*/
		//객체 배열
		Score[] score= {
				new Score("봉선화", 70, 85, 100)
				, new Score("라일락", 60, 65, 30)
				, new Score("진달래", 40, 20, 90)
		};
		
		int size=score.length;//3
		
		//score[0].disp();
		//score[1].disp();
		//score[2].disp();
		
		//반복문으로 완성
		
		for(int i=0; i<size; i++) {
			score[i].disp();
		}//for end
		
//---------------------------------------------------------------		
		Score sco=new Score();
		System.out.println(sco); //null값만 안나오면 된다. 값이 나오면 메모리 할당을 잘했다는 의미
		
		sco=null;
		System.out.println(sco); //null
		
		
	}//main() end
}//class end

 

 

 

* eclipse에서 생성자 함수 자동 생성시키는 방법

 

- 기본생성자 자동 추가하는 방법

  Source → Generate Constructors from Superclass

 

 

내 경우 Object( ) 선택 후 생성

 

- 매개 변수가 있는 생성자 자동 추가하는 방법

  Source → Generate Constructor using Fields

 

 

 

 

 

예제) 성적프로그램 OX 표시하기

 

package oop0825;

public class Jumsu {
	//멤버변수 field
	private int no;			//번호
	private String name;		//이름
	private char[] ox=new char[5];  //OX표시
	private int[] answer=new int[5];//답안제출
	public int score=0;		//점수
	public int rank;		//등수
	
	
	//생성자함수 constructor
	public Jumsu() {}//오버로딩
	
    
	//답안제출 int[]로 받는게 낫다
	public Jumsu(int no, String name, int a0, int a1, int a2, int a3, int a4) { 
		this.no=no;
		this.name=name;
		this.answer[0]=a0;
		this.answer[1]=a1;
		this.answer[2]=a2;
		this.answer[3]=a3;
		this.answer[4]=a4;	
		this.rank=1;
	}//end
	
    
	//멤버함수 method
	public void compute() {
		//정답
		int[] dap= {3, 3, 3, 3, 3};
        
		//정답과 제출한 answer답안을 비교해서 OX 구하고, 맞은 갯수에 따라 점수 구하기
		for(int i=0; i<dap.length; i++) {
			if(dap[i]==answer[i]) {
				ox[i]='O';
				score=score+20; //한문제당 20점씩
			}else {
				ox[i]='X';
			}//if end
		}//for end
	}//compute() end
	
	
    
    	//public void rank
	public void disp() {//출력하기
		System.out.print(no+" ");
		System.out.print(name+" ");
		for(int i=0; i<5; i++) {
			System.out.print(ox[i]+" ");
		}//for end
		System.out.print(score+" ");
		System.out.print(rank+" ");
		System.out.println();
	}//disp() end
	
	
}//class end

 

package oop0825;

public class Test04_ox {
	public static void main(String[] args) {
		//[예제] 성적프로그램 OX 표시하기
		//클래스명: Jumsu
		
		//한 사람 대상으로 성적 구하기
		/*
		Jumsu student=new Jumsu(1, "홍길동", 3, 2, 3, 3, 3);
		student.compute();
		student.disp();
		*/

//---------------------------------------------------------------
		//다음 5명의 성적을 출력하시오.
		Jumsu[] student= {
				new Jumsu(1, "홍길동", 3, 2, 3, 3, 3)
				, new Jumsu(2, "무궁화", 3, 3, 3, 3, 3)
				, new Jumsu(3, "라일락", 2, 2, 2, 2, 3)
				, new Jumsu(4, "진달래", 2, 2, 2, 3, 3)
				, new Jumsu(5, "봉선화", 3, 3, 2, 2, 2)				
		};
		
		//1) OX와 점수 계산하기
		int size=student.length;
		for(int i=0; i<size; i++) {
			student[i].compute();
		}//for end
		
		/*
			1 홍길동 O X O O O 80 1 
			2 무궁화 O O O O O 100 1 
			3 라일락 X X X X O 20 1 
			4 진달래 X X X O O 40 1 
			5 봉선화 O O X X X 40 1
        */
        
        
		//2) 등수 구하기(score를 기준으로)
        //일전의 rank 활용
		/*
		for(int i=0; i<size; i++) {
			for(int j=0; j<size; j++) {
				if(aver[i]<aver[j]) {
					rank[i]=rank[i]+1;
				}//if end
			}//for end	
		}//for end
		*/
		
		for(int i=0; i<size; i++) {
			for(int j=0; j<size; j++) {
				if(student[i].score<student[j].score) {
					student[i].rank=student[i].rank+1;
				}//if end
			}//for end	
		}//for end
	
		
		//3)출력하기
		for(int i=0; i<size; i++) {
			student[i].disp();
		}//for end
		
		
	}//main() end
}//class end

 

제시한 5명의 학생들의 성적 데이터를 조회하는 내용이다.

 

가장 먼저 생각해야 할 것은 '어떤 데이터를 뽑을 것인가?' 이다.

성적표에는 학생의 학번과 이름, 해당 학생이 어떤 문제를 틀리고 맞았는지 여부와 이를 토대로 한 총 점수, 그리고 등수('수, 우, 미, 양, 가'에 대한 내용도 들어가면 좋겠지만 나중에 하자) 등의 내용이 들어가야 한다.

 

이 시간에는 학생의 학번(편의상 1, 2, 3, 4, 5)와 그 학생의 이름, 정답 여부(OX로 표기), 총 점수, 등수를 나타내 보았다.

총 5가지의 항목이 필요한데, 여기서 학생들이 각각 5문제씩 풀었기 때문에 이 부분에만 5가지의 결과치가 필요하므로 

결과적으로 9개의 변수가 필요한 셈이 된다.

 

이렇게 정리한 이후에 식을 생각하는 습관이 필요하다.

 

새로운 종이에 Jumsu 클래스를 만들어서 변수를 지정해 주고, 생성자 함수를 호출하였다. (반드시 호출할 것!)

지정한 변수를 다시금 this로 호출하면 준비가 다 된 것이다.

이 과정이 귀찮으면 자동으로 설정할 수도 있다. (위에 있는 * eclipse에서 생성자 함수 자동 생성시키는 방법 참고)

 

정답과 학생들의 답을 비교해야 총 점수가 나오므로 계산을 진행 할 compute( ) 메소드를 만든다.

이 안에는 무엇이 필요한가? 정답을 넣어야 비교를 할 수 있을테니 우선 정답을 집어 넣고...

이 정답과 학생들의 답지를 비교해야 할테니 for문을 이용하여 나열된 학생들의 점수를 비교한다.

맞으면 O, 틀리면 X를 표기. 이와 동시에 O가 나왔을 때 20점씩 부여하여 총 점수 데이터까지 준비한다.

 

채점이 끝났으니 이제는 출력을 할 차례이다.

학생이 입력해 준 학번을 뽑고, 이름을 뽑고, Jumsu 클래스의 결과값인 OX 데이터를 뽑고, 총 점수 데이터를 뽑고, 해당 학생의 등수까지 뽑는다. 

 

그런데 이때 데이터를 출력하면 아무것도 안 나온다. 아직 결과값을 뽑을 식을 만들지 않았으니... 

5명의 학생의 성적 데이터를 얹어 놓은 Test04_ox 페이지에 가서 Jumsu( ) 메소드에서 선언한 compute( )를 for문을 통해 출력한다. 이 과정을 진행하면 결과값은 다음과 같다.

 

1 홍길동 O X O O O 80 1 
2 무궁화 O O O O O 100 1 
3 라일락 X X X X O 20 1 
4 진달래 X X X O O 40 1 
5 봉선화 O O X X X 40 1

 

여기서 등수를 계산해야 함을 알 수 있다. 

 

이렇게 중간중간 출력을 해 보면 내가 잘 해 나가고 있는지를 알 수 있다.

 

for문을 이용하여 1번 홍길동과 2번 무궁화의 점수를 비교해 점수가 낮은 홍길동을 2등으로 보내고

1번 홍길동과 3번 라일락의 점수를 비교해 홍길동의 점수가 높으므로 2등 자리 유지

1번 홍길동과 4번 진달래의 점수를 비교해 홍길동의 점수가 높으므로 다시 2등 자리 유지

1번 홍길동과 5번 봉선화의 점수를 비교해 홍길동의 점수가 높으므로 2등 확정

 

이 과정을 전부 거치면 다음과 같은 결과값이 출력된다.

 

1 홍길동 O X O O O 80 2 
2 무궁화 O O O O O 100 1 
3 라일락 X X X X O 20 5 
4 진달래 X X X O O 40 3 
5 봉선화 O O X X X 40 3 

 

4번 진달래와 5번 봉선화는 각각 40점으로 점수가 같아 공동 3등이 출력된다.