명품 JAVA Essential
학습 목표 객체 지향의 개념과 특성 이해 자바 클래스 만들기 생성자 만들기 객체 배열 선언 및 활용 객체 치환 이해 객체의 소멸과 가비지 컬렉션 클래스와 멤버에 대한 접근 지정 static 속성을 가진 멤버의 특성 final로 선언된 클래스, 메소드, 필드에 대한 이해
세상 모든 것이 객체다 세상 모든 것이 객체다. 실세계 객체의 특징 컴퓨터 프로그램에서 객체 사례 객체마다 고유한 특성(state)와 행동(behavior)를 가짐 다른 객체들과 정보를 주고 받는 등, 상호작용하면서 살아감 컴퓨터 프로그램에서 객체 사례 테트리스 게임의 각 블록들 한글 프로그램의 메뉴나 버튼들
자바의 객체 지향 특성 : 캡슐화 캡슐화 : 객체를 캡슐로 싸서 내부를 볼 수 없게 하는 것 자바의 캡슐화 객체의 가장 본질적인 특징 외부의 접근으로부터 객체 보호 자바의 캡슐화 클래스(class): 객체 모양을 선언한 틀(캡슐화하는 틀) 객체: 생성된 실체(instance) 클래스 내에 메소드와 필드 구현
자바의 객체 지향 특성 : 상속 상속 실세계의 상속 사례 상위 개체의 속성이 하위 개체에 물려짐 하위 개체가 상위 개체의 속성을 모두 가지는 관계 실세계의 상속 사례 나무는 식물의 속성과 생물의 속성을 모두 가짐 사람은 생물의 속성은 가지지만 식물의 속성은 가지고 있지 않음
서브 클래스 객체는 슈퍼 클래스의 멤버와 서브 클래스의 멤버를 모두 가짐 자바 상속 자바 상속 상위 클래스의 멤버를 하위 클래스가 물려받음 상위 클래스 : 수퍼 클래스 하위 클래스 : 서브 클래스, 수퍼 클래스 코드의 재사용, 새로운 특성 추가 가능 슈퍼 클래스 서브 클래스 서브 클래스 객체는 슈퍼 클래스의 멤버와 서브 클래스의 멤버를 모두 가짐
자바의 객체 지향 특성 : 다형성 다형성 같은 이름의 메소드가 클래스 혹은 객체에 따라 다르게 구현되는 것 다형성 사례 메소드 오버로딩 : 한 클래스 내에서 같은 이름이지만 다르게 작동하는 여러 메소드 메소드 오버라이딩 : 슈퍼 클래스의 메소드를 동일한 이름으로 서브 클래스마다 다 르게 구현
객체 지향 언어의 목적 1. 소프트웨어의 생산성 향상 2. 실세계에 대한 쉬운 모델링 컴퓨터 산업 발전에 따라 소프트웨어의 생명 주기(life cycle) 단축 소프트웨어를 빠른 속도로 생산할 필요성 증대 객체 지향 언어 상속, 다형성, 객체, 캡슐화 등 소프트웨어 재사용을 위한 여러 장치 내장 소프트웨어 재사용과 부분 수정 빠름 소프트웨어를 다시 만드는 부담 대폭 줄임 소프트웨어 생산성 향상 2. 실세계에 대한 쉬운 모델링 초기 프로그래밍 수학 계산/통계 처리를 하는 등 처리 과정, 계산 절차 중요 현대 프로그래밍 컴퓨터가 산업 전반에 활용 실세계에서 발생하는 일을 프로그래밍 실세계에서는 절차나 과정보다 물체(객체)들의 상호 작용으로 묘사하는 것이 용이 실세계의 일을 보다 쉽게 프로그래밍하기 위한 객체 중심적 언어
절차 지향 프로그래밍과 객체 지향 프로그래밍 절차 지향 프로그래밍 객체 지향 프로그래밍 작업 순서를 표현하는 컴퓨터 명령 집합 함수들의 집합으로 프로그램 작성 객체 지향 프로그래밍 컴퓨터가 수행하는 작업을 객체들간의 상호 작용으로 표현 클래스 혹은 객체들의 집합으로 프로그램 작성 커피 자판기 객체지향적 프로그래밍의 객체들의 상호 관련성 절차지향적 프로그래밍의 실행 절차
클래스와 객체 클래스 객체 사례 객체의 속성(state)과 행위(behavior) 선언 객체의 설계도 혹은 틀 클래스의 틀로 찍어낸 실체 프로그램 실행 중에 생성되는 실체 메모리 공간을 갖는 구체적인 실체 인스턴스(instance)라고도 부름 사례 클래스: 소나타자동차, 객체: 출고된 실제 소나타 100대 클래스: 벽시계, 객체: 우리집 벽에 걸린 벽시계들 클래스: 책상, 객체: 우리가 사용중인 실제 책상들
치즈붕어빵, 크림붕어빵, 앙코붕어빵 등이 있습니다. 그래도 이들은 모두 붕어빵입니다. 클래스와 객체와의 관계 붕어빵 틀은 클래스이며, 이 틀의 형태로 구워진 붕어빵은 바로 객체입니다. 붕어빵은 틀의 모양대로 만들어지지만 서로 조금씩 다릅니다. 치즈붕어빵, 크림붕어빵, 앙코붕어빵 등이 있습니다. 그래도 이들은 모두 붕어빵입니다.
사람을 사례로 든 클래스와 객체 사례 객체들은 클래스에 선언된 동일한 속성을 가지지만 속성 값은 서로 다름
자바 클래스 구성 클래스 class 키워드로 선언 멤버 : 클래스 구성 요소 필드(멤버 변수)와 메소드(멤버 함수) 클래스에 대한 public 접근 지정 : 다른 모든 클래스에서 클래스 사용 허락 멤버에 대한 public 접근 지정 : 다른 모든 클래스에게 멤버 접근 허용
예제 4-1 : Circle 클래스의 객체 생성 및 활용 반지름과 이름을 가진 Circle 클래스를 작성하고, Circle 클래스의 객체를 생성하라. public class Circle { int radius; // 원의 반지름을 저장하는 멤버 변수 String name; // 원의 이름을 저장하는 멤버 변수 public double getArea() { // 멤버 메소드 return 3.14*radius*radius; } public static void main(String[] args) { Circle pizza; pizza = new Circle(); // Circle 객체 생성 pizza.radius = 10; // 피자의 반지름을 10으로 설정 pizza.name = "자바피자"; // 피자의 이름 설정 double area = pizza.getArea(); // 피자의 면적 알아내기 System.out.println(pizza.name + "의 면적은 " + area); Circle donut = new Circle(); // Circle 객체 생성 donut.radius = 2; // 도넛의 반지름을 2로 설정 donut.name = "자바도넛"; // 도넛의 이름 설정 area = donut.getArea(); // 도넛의 면적 알아내기 System.out.println(donut.name + "의 면적은 " + area); 자바피자의 면적은 314.0 자바도넛의 면적은 12.56
객체 생성과 활용 1. 레퍼런스 변수 선언 Circle pizza; 2. 객체 생성 - new 연산자 이용 pizza = new Circle(); 3. 객체 멤버 접근 - 점(.) 연산자 이용 pizza.radius = 10; area = pizza.getArea();
예제 4-2 : Rectangle 클래스 만들기 연습 너비(width)와 높이(height) 필드, 그리고 면적 값을 제공하는 getArea() 메소드를 가진 Rectangle 클래스를 작성하라. public class Rectangle { int width; int height; int getArea() { return width*height; } public static void main(String[] args) { Rectangle rect = new Rectangle(); // 객체 생성 rect.width = 4; rect.height = 5; System.out.println("사각형의 면적은 " + rect.getArea()); 사각형의 면적은 20
생성자 개념과 목적 생성자 객체가 생성될 때 초기화 목적으로 실행되는 메소드 객체가 생성되는 순간에 자동 호출
예제 4-3 : 두 개의 생성자를 가진 Circle 클래스 public class Circle { int radius; String name; public Circle() { // 매개 변수 없는 생성자 radius = 1; name = ""; // radius의 초기값은 1 } public Circle(int r, String n) { // 매개 변수를 가진 생성자 radius = r; name = n; public double getArea() { return 3.14*radius*radius; public static void main(String[] args) { Circle pizza = new Circle(10, "자바피자"); // Circle 객체 생성, 반지름 10 double area = pizza.getArea(); System.out.println(pizza.name + "의 면적은 " + area); Circle donut = new Circle(); // Circle 객체 생성, 반지름 1 donut.name = "도넛피자"; area = donut.getArea(); System.out.println(donut.name + "의 면적은 " + area); 생성자 이름은 클래스 이름과 동일 생성자는 리턴 타입 없음 자바피자의 면적은 314.0 도넛피자의 면적은 3.14
생성자의 특징 생성자 이름은 클래스 이름과 동일 생성자는 여러 개 작성 가능(생성자 중복) 생성자는 객체 생성시 한 번만 호출 자바에서 객체 생성은 반드시 new 연산자로 함 생성자의 목적은 객체 생성 시 초기화 생성자는 리턴 타입을 지정할 수 없음 public class Circle { public Circle() {...} // 매개 변수 없는 생성자 public Circle(int r, String n) {...} // 2개의 매개 변수를 가진 생성자 } Circle pizza = new Circle(10, "자바피자"); // 생성자 Circle(int r, String n) 호출 Circle donut = new Circle(); // 생성자 Circle() 호출 public void Circle() {...} // 오류. void도 사용 안 됨
예제 4-4 : 생성자 선언 및 호출 연습 title과 author 필드를 가진 Book 클래스를 선언하고, 필드 값을 매개변수로 받아 초기화하는 2개의 생성자를 작성하라. public class Book { String title; String author; public Book(String t) { // 생성자 title = t; author = "작자미상"; } public Book(String t, String a) { // 생성자 author = a; public static void main(String [] args) { Book javaBook = new Book("Java", "황기태"); // 생성자 Book(String t, String a) 호출 Book bible = new Book("Bible"); // 생성자 Book(String t) 호출
기본 생성자 기본 생성자(default constructor) 매개 변수 없고, 아무 작업 없이 단순 리턴하는 생성자 디폴트 생성자라고도 불림 class Circle { public Circle() { } // 기본 생성자 }
기본 생성자가 자동 생성되는 경우 클래스에 생성자가 하나도 선언되어 있지 않을 때 컴파일러에 의해 기본 생성자 자동 생성
기본 생성자가 자동 생성되지 않는 경우 클래스에 생성자가 선언되어 있는 경우 컴파일러는 기본 생성자를 자동 생성해 주지 않는다.
this 레퍼런스 this 객체 자신에 대한 레퍼런스 컴파일러에 의해 자동 관리, 개발자는 사용하기만 하면 됨 public class Circle { int radius; public Circle() { radius = 1; } public Circle(int r) { radius = r; } double getArea() { return 3.14*radius*radius; } ... public class Circle { int radius; public Circle() { this.radius = 1; } public Circle(int radius) { this.radius = radius; } double getArea() { return 3.14*this.radius*this.radius; ... this를 사용하여 수정한 경우
객체 속에서의 this
this 요약
this()로 다른 생성자 호출 this() 같은 클래스의 다른 생성자 호출 생성자 내에서만 사용 가능 생성자 코드의 제일 처음에 있어야 함 this() 사용 실패 사례 public Book() { System.out.println("생성자 호출됨"); this("", "", 0); // 생성자의 첫 번째 문장이 아니기 때문에 컴파일 오류 }
예제 4-5 this()로 다른 생성자 호출 예제 4-4에서 작성한 Book 클래스의 생성자를 this()를 이용하여 수정하라. public class Book { String title; String author; void show() { System.out.println(title + " " + author); } public Book() { this("", ""); System.out.println("생성자 호출됨"); } public Book(String title) { this(title, "작자미상"); public Book(String title, String author) { this.title = title; this.author = author; public static void main(String [] args) { Book javaBook = new Book("Java", "황기태"); Book bible = new Book("Bible"); Book emptyBook = new Book(); bible.show(); title = "Bible" author = "작자미상" 생성자 호출됨 Bible 작자미상
객체 배열 자바의 객체 배열 자바의 객체 배열 만들기 3 단계 객체에 대한 레퍼런스 배열임 배열 레퍼런스 변수 선언 레퍼런스 배열 생성 배열의 각 원소 객체 생성
객체 배열 선언과 생성 과정 객체 생성 배열에 대한 레퍼런스 변수 선언 레퍼런스 배열 생성
예제 4-6 : Circle 배열 만들기 Circle 객체 5개를 가지는 배열을 생성하고, Circle 객체의 반지름을 0에서 4까지 각각 지정한 후, 면적을 출력하라. class Circle { int radius; public Circle(int radius) { this.radius = radius; } public double getArea() { return 3.14*radius*radius; public class CircleArray { public static void main(String[] args) { Circle [] c; c = new Circle[5]; for(int i=0; i<c.length; i++) c[i] = new Circle(i); System.out.print((int)(c[i].getArea()) + " "); 0 3 12 28 50
예제 4-7 : 객체 배열 만들기 연습 예제 4-4의 Book 클래스를 활용하여 2개짜리 Book 객체 배열을 만들고, 사용자로부터 책의 제목과 저자를 입력 받아 배열을 완성하라. import java.util.Scanner; class Book { String title, author; public Book(String title, String author) { this.title = title; this.author = author; } public class BookArray { public static void main(String[] args) { Scanner scanner = new Scanner(System.in); Book [] book = new Book[2]; // Book 배열 선언 for(int i=0; i<book.length; i++) { System.out.print("제목>>"); String title = scanner.nextLine(); System.out.print("저자>>"); String author = scanner.nextLine(); book[i] = new Book(title, author); // 배열 원소 객체 생성 for(int i=0; i<book.length; i++) System.out.print("(" + book[i].title + ", " + book[i].author + ")"); 제목>>사랑의 기술 저자>>에리히 프롬 제목>>시간의 역사 저자>>스티븐 호킹 (사랑의 기술, 에리히 프롬)(시간의 역사, 스티븐 호킹)
메소드 메소드 메소드 형식 메소드는 C/C++의 함수와 동일 자바의 모든 메소드는 반드시 클래스 안에 있어야 함(캡슐화 원칙) 접근 지정자 다른 클래스에서 메소드를 접근할 수 있는지 여부 선언 public. private, protected, 디폴트(접근 지정자 생략) 리턴 타입 메소드가 리턴하는 값의 데이터 타입
인자 전달 – 기본 타입의 값이 전달되는 경우 매개 변수가 byte, int, double 등 기본 타입으로 선언되었을 때 호출자가 건네는 값이 매개 변수에 복사되어 전달. 실인자 값은 변경되지 않음
인자 전달 – 객체가 전달되는 경우 객체의 레퍼런스만 전달 매개 변수가 실인자 객체 공유
인자 전달 - 배열이 전달되는 경우 객체가 전달되는 경우와 동일 배열 레퍼런스만 매개 변수에 전달 배열 통째로 전달되지 않음 객체가 전달되는 경우와 동일 매개 변수가 실인자의 배열 공유
예제 4-8 : 인자로 배열이 전달되는 예 char[] 배열을 전달받아 배열 속의 공백(' ') 문자를 ','로 대치하는 메소드를 작성하라. public class ArrayParameter { static void replaceSpace(char a[]) { for (int i=0; i<a.length; i++) if (a[i] == ' ') a[i] = ','; } static void printCharArray(char a[]) { System.out.print(a[i]); System.out.println(); public static void main (String args[]) { char c[] = {'T','h','i','s',' ','i','s',' ','a',' ','p','e','n','c','i','l','.'}; printCharArray(c); replaceSpace(c); c main() replaceSpace() a for (int i=0; i<a.length; i++) if (a[i] == ' ') a[i] = ','; , T h i s a p e n c l . This is a pencil. This,is,a,pencil.
메소드 오버로딩 오버로딩(Overloading) 한 클래스 내에서 두 개 이상의 이름이 같은 메소드 작성 메소드 이름이 동일하여야 함 매개 변수의 개수가 서로 다르거나, 타입이 서로 달라야 함 리턴 타입은 오버로딩과 관련 없음
성공한 오버로딩과 메소드 호출
오버로딩 실패 사례 매개 변수의 개수와 타입 이 같기 때문에 오버로딩 실패
객체 치환 시 주의할 점 * 객체 치환은 객체 복사가 아니며, 레퍼런스의 복사이다. 객체 치환 ob1.id=4 ob2.id=4
객체 소멸 객체 소멸 자바에서 사용자 임의로 객체 소멸안됨 new에 의해 할당 받은 객체와 배열 메모리를 자바 가상 기계로 되 돌려 주는 행위 소멸된 객체 공간은 가용 메모리에 포함 자바에서 사용자 임의로 객체 소멸안됨 자바는 객체 소멸 연산자 없음 객체 생성 연산자 : new 객체 소멸은 자바 가상 기계의 고유한 역할 자바 개발자에게는 매우 다행스러운 기능 C/C++에서는 할당 받은 객체를 개발자가 프로그램 내에서 삭제해야 함 C/C++의 프로그램 작성을 어렵게 만드는 요인 자바에서는 사용하지 않는 객체나 배열을 돌려주는 코딩 책임으로부터 개발자 해방
가비지 가비지 켈렉션 가비지 가리키는 레퍼런스가 하나도 없는 객체 더 이상 접근할 수 없어 사용할 수 없게 된 메모리 가비지 켈렉션 자바 가상 기계의 가비지 컬렉터가 자동으로 가비지 수집, 반환
예제 4-9 : 가비지의 발생 다음 소스에서 언제 가비지가 발생하는지 설명하라. public class GarbageEx { public static void main(String[] args) { String a = new String("Good"); String b = new String("Bad"); String c = new String("Normal"); String d, e; a = null; d = c; c = null; }
가비지 컬렉션 가비지 컬렉션 강제 가비지 컬렉션 강제 수행 자바 가상 기계가 가비지 자동 회수 가용 메모리 공간이 일정 이하로 부족해질 때 가비지를 수거하여 가용 메모리 공간으로 확보 가비지 컬렉터(garbage collector)에 의해 자동 수행 강제 가비지 컬렉션 강제 수행 System 또는 Runtime 객체의 gc() 메소드 호출 이 코드는 자바 가상 기계에 강력한 가비지 컬렉션 요청 그러나 자바 가상 기계가 가비지 컬렉션 시점을 전적으로 판단 System.gc(); // 가비지 컬렉션 작동 요청
자바의 패키지 개념 패키지 상호 관련 있는 클래스 파일(컴파일된 .class)을 저장하여 관리하 는 디렉터리 자바 응용프로그램은 하나 이상의 패키지로 구성
접근 지정자 public 자바의 접근 지정자 접근 지정자의 목적 접근 지정자에 따른 클래스나 멤버의 공개 범위 4가지 private, protected, public, 디폴트(접근지정자 생략) 접근 지정자의 목적 클래스나 일부 멤버를 공개하여 다른 클래스에서 접근하도록 허용 객체 지향 언어의 캡슐화 정책은 멤버를 보호하는 것 접근 지정은 캡슐화에 묶인 보호를 일부 해제할 목적 접근 지정자에 따른 클래스나 멤버의 공개 범위 public private 디폴트 protected 동일 패키지와 자식 클래스에 허용 외부로부터 완벽차단 동일 패키지에 허용 모든 클래스에 허용
클래스 접근 지정 클래스 접근지정 다른 클래스에서 사용하도록 허용할 지 지정 public 클래스 다른 모든 클래스에게 접근 허용 디폴트 클래스(접근지정자 생략) package-private라고도 함 같은 패키지의 클래스에만 접근 허용 public class World { // public 클래스 ............ } class Local { // 디폴트 클래스 ............ } public 클래스와 디폴트 클래스의 접근 사례
멤버 접근 지정 public 멤버 private 멤버 protected 멤버 디폴트(default) 멤버 패키지에 관계 없이 모든 클래스에게 접근 허용 private 멤버 동일 클래스 내에만 접근 허용 상속 받은 서브 클래스에서 접근 불가 protected 멤버 같은 패키지 내의 다른 모든 클래스에게 접근 허용 상속 받은 서브 클래스는 다른 패키지에 있어도 접근 가능 디폴트(default) 멤버 같은 패키지 내의 다른 클래스에게 접근 허용
멤버 접근 지정 사례 public 접근 지정 사례 private 접근 지정 사례
디폴트 접근 지정 사례 protected 접근 지정 사례
예제 4-10 : 멤버의 접근 지정자 다음 코드의 두 클래스 SampleClass와 AccessEx 클래스는 AccessEx.java에 들어 있어 컴파일 되면, 동일한 패키지에 저장된다. 컴파일 오류를 찾아내고 이유를 설명하라. class SampleClass { public int field1; protected int field2; int field3; private int field4; } public class AccessEx { public static void main(String[] args) { SampleClass s = new SampleClass(); s.field1 = 0; s.field2 = 1; s.field3 = 2; s.field4 = 3; AccessEx 클래스의 14번 라인에서 컴파일 오류 발생. field4는 SampleClass의 private 멤버이므로 SampleClass 외의 다른 클래스에서 접근할 수 없다. Exception in thread "main" java.lang.Error: Unresolved compilation problem: The field s.field4 is not visible at AccessEx.main(AccessEx.java:14)
객체마다 n, g()의 non-static 멤버들이 생긴다 class StaticSample { int n; // non-static 필드 void g() {...} // non-static 메소드 static int m; // static 필드 static void f() {...} // static 메소드 } 객체마다 n, g()의 non-static 멤버들이 생긴다
StaticSample 의 어떤 객체가 생기기 전에도 static 멤버는 생성되어 있음 객체들에 의해 공유됨 StaticSample 의 어떤 객체가 생기기 전에도 static 멤버는 생성되어 있음
static 멤버와 non-static 멤버 특성 정리
static 멤버 사용 클래스 이름으로 접근 가능 객체의 멤버로 접근 가능 non-static 멤버는 클래스 이름으로 접근 안 됨 StaticSample.m = 3; // 클래스 이름으로 static 필드 접근 StaticSample.f(); // 클래스 이름으로 static 메소드 호출 StaticSample b1 = new StaticSample(); b1.m = 3; // 객체 이름으로 static 필드 접근 b1.f(); // 객체 이름으로 static 메소드 호출 StaticSample.n = 5; // n은 non-static이므로 컴파일 오류 StaticSample.g(); // g()는 non-static이므로 컴파일 오류
static의 활용 1. 전역 변수와 전역 함수를 만들 때 활용 2. 공유 멤버를 만들고자 할 때
예제 4-11 : static 멤버를 가진 Calc 클래스 작성 전역 함수로 작성하고자 하는 abs, max, min의 3개 함수를 static 메소드를 작성하고 호출하는 사례를 보여라. class Calc { public static int abs(int a) { return a>0?a:-a; } public static int max(int a, int b) { return (a>b)?a:b; } public static int min(int a, int b) { return (a>b)?b:a; } } public class CalcEx { public static void main(String[] args) { System.out.println(Calc.abs(-5)); System.out.println(Calc.max(10, 8)); System.out.println(Calc.min(-3, -8)); 5 10 -8
static 메소드의 제약 조건 1 static 메소드는 오직 static 멤버만 접근 가능 객체가 생성되지 않은 상황에서도 static 메소드는 실행될 수 있기 때 문에, non-static 멤버 활용 불가 non-static 메소드는 static 멤버 사용 가능
static 메소드의 제약 조건 2 static 메소드는 this 사용불가
final 클래스와 메소드 final 클래스 - 더 이상 클래스 상속 불가능 final 메소드 - 더 이상 오버라이딩 불가능 final class FinalClass { ..... } class DerivedClass extends FinalClass { // 컴파일 오류 public class SuperClass { protected final int finalMethod() { ... } } class SubClass extends SuperClass { protected int finalMethod() { ... } // 컴파일 오류, 오버라이딩 할 수 없음
final 필드 final 필드, 상수 선언 상수를 선언할 때 사용 상수 필드는 선언 시에 초기 값을 지정하여야 한다 상수 필드는 실행 중에 값을 변경할 수 없다 class SharedClass { public static final double PI = 3.14; } public class FinalFieldClass { final int ROWS = 10; // 상수 정의, 이때 초기 값(10)을 반드시 설정 void f() { int [] intArray = new int [ROWS]; // 상수 활용 ROWS = 30; // 컴파일 오류 발생, final 필드 값을 변경할 수 없다. }