* java.lang 패키지의 클래스들은 import 하지 않고 사용 가능하다.

 

(1) Java.lang.object에서 가장 많이 사용되는 3가지 (사용할 때 반드시 override해서 사용!!)

 

- toString() : 객체가 가진 값을 문자열로 반환

- hashCode() : 객체의 주소값 호출 --> 자료구조에서 자주 사용

- equals(Object) : 객체의 값이 같은지 비교

 

cf) finalize() : 객체에 대한 참조가 없음을 확인할 때 객체의 가비지 수집기에 의해 호출되어

해당 객체를 메모리에서 꺼냅니다.(C에서의 소멸자와 비슷)

 

 

(2) 비교연산자 : ==

 

기DT == 기DT : 값 비교

참DT == 참DT : 주소값 비교

Object : equals() >> 주소값 비교 (각 클래스에 맞게끔 override해서 사용)

 

public class Car {
	String carName;

	public Car(String carName){
		this.carName = carName;
	}	

	@Override
	public boolean equals(Object obj){
		Car car = (Car) obj; //형변환
		if(carName == car.carName)
			return true;
		else
			return false;			
	}

	@Override
	public String toString() {
		return "차이름 : " + carName;	
	}
}
 package com.mycompany;
 
 public class Car { 
	private String carName;
	private int speed;

	public Car(String carName){
		this.carName = carName;
	}

	public void speedUp(){
		this.speed += 10;
	}

	public String getCarName(){
		return carName;
	}

	public int getSpeed(){
		return speed;
	}
}
import com.mycompany.Car;

public class CarUser {
	public static void main(String[] args) {
		Car car = new Car("K5"); //Car클래스 사용하고자..
		System.out.println("자동차의 이름 : " + car.getCarName());
		car.speedUp();
		System.out.println("자동차의 속도 : " + car.getSpeed());
	}
}
public class ObjectTest {
	public static void main(String[] args) {
		Object ob1 = new Object();
		Object ob2 = new Object();
		System.out.println("ob1 : " + ob1.toString());
		System.out.println("ob2 : " + ob2.toString());
		System.out.println("ob1 hashcode : " + ob1.hashCode());
		System.out.println("ob2 hashcode : " + ob2.hashCode());

		if (ob1==ob2)
		System.out.println("ob1과 ob2는 주소값이 같다.");
		else
			System.out.println("ob1과 ob2는 주소값이 다르다.");

		if (ob1.equals(ob2))
		System.out.println("ob1과 ob2는 같다.");
		else
			System.out.println("ob1과 ob2는 다르다.");

		Car car1 = new Car("쏘나타");
		Car car2 = new Car("쏘나타");

		if (car1.equals(car2))
		System.out.println("car1과 car2는 차이름이 같다.");
		else
			System.out.println("car1과 car2는 차이름이 다르다.");

		System.out.println("car1 " + car1);
		System.out.println("car2 " + car2);
	}
}
---------- run ----------
ob1 : java.lang.Object@15db9742
ob2 : java.lang.Object@6d06d69c
ob1 hashcode : 366712642
ob2 hashcode : 1829164700
ob1과 ob2는 주소값이 다르다.
ob1과 ob2는 다르다.
car1과 car2는 차이름이 같다.
car1 차이름 : 쏘나타
car2 차이름 : 쏘나타

(3) Wrapper Class : 8개의 기본DT를 객체로 변환시킬 때 사용하는 클래스

더보기

Wrapper Class : 기본DT을 object(참조형)화 시킨 class

기본DT 참조DT

boolean Boolean

char Character

byte Byte

short Short

int Integer

long Long

float Float

double Double

 

기DT >> String으로 변환

int x = 10;

1. String s = x + ""; (int를 문자열로 변환)

2. String s = Integer.toString(x);

3. String s = String.valueOf(x);

 

String >> 기본DT으로 변환 --- 기DT = Wrapper.parseXXX(String); -- 생성자 생성 안하고 클래스

이름으로 바로 사용 가능한 메소드

String s = "10";

int x = Integer.parseInt(s);

 

 

* java 5부터 생김... 점점 자바 버전이 높아질수록 사용자가 편리해진다.

autoboxing : Wrapper 클래스에서만 각 클래스에 대응되는 기본형DT으로 자동 형변환이 가능

unboxing : Wrapper 참조형 DT을 대응되는 기본형DT에 넣을 때 사용

boxing : 기본형 DT를 대응되는 Wrapper 참조형 DT에 넣을 때 사용

 

public class WrapperTest {
	public static void main(String[] args) {
		String s = "true";
		Boolean b = new Boolean(s); 
		System.out.println(b); //true

		//boolean bl = (boolean) s; //error
		boolean bl1 = b.booleanValue(); //String "true"가 boolean으로 바꿈
		if (bl1)
			System.out.println("bl1 boolean으로 바꼈다.");

		boolean bl2 = Boolean.parseBoolean(s); //기본DT을 참조DT으로 바꾸기
		if (bl2)
			System.out.println("bl2 boolean으로 바꼈다.");

		String s2 = "123";
		Integer i = new Integer(s2);
		int x1 = i.intValue();
		System.out.println(x1+100);//223

		int x2 = Integer.parseInt(s2); //String 참조타입인 123을 int 기본 타입으로 변환
		System.out.println(x2+200);//323

		//autoboxing(int와 Integer끼리만 boolean Boolean끼리만 가능)
		int z = 100;
		Integer it = new Integer(100); //Wrapper class
        Integer it1 = 100; //위에 new Integer(100)이랑 같은 코드, 자동으로 new를 생성해준다고 기억

		//unboxing(참조를 기본에다 집어넣을 때는)
		int y = it;
		System.out.println("y == " + y);
		
        //boxing (기본을 참조에다 집어넣을 때는)
		Integer it2 = y;
		System.out.println("it2 == " + it2);


	}
}
---------- run ----------
true
bl1 boolean으로 바꼈다.
bl2 boolean으로 바꼈다.
223
323
y == 100
it2 == 100

 

cf) Edit Plus에서 사용자 도구 > 기본설정 > 사용자도구> run의 동작을 없음 or 캡처로 바꾸기

 

(1) 참조DT을 저장하는 배열의 사용.

a. 선언

형식) 접근제어자 참DT[ ] 배열명; or 접근제어자 참DT 배열명[ ];

ex)

public String name[ ];

public Car car[ ];

private TV tv[ ];

 

b. 생성

형식) 배열명 = new 참DT[크기];

ex)

name = new String[3];

car = new Car[5];

tv = new TV[3];

 

>>>>>> a, b를 동시에..

접근제어자 참DT 배열명[] = new 참DT[크기];

ex)

public String name[ ] = new String[3];

public Car car[ ] = new Car[5];

private TV tv[ ] = new TV[3];

 

**c. 사용 : 주소값이 할당 (객체가 저장되는 것이 X) //

기본데이터 타입 배열은 생성자를 만들 필요가 없었다(바로 사용),

but, 참조형 데이터 타입 배열은 객체를 생성해줘야 함!!!

형식)

배열명[index] = new ClassName();

 

ex)

name[0] = new String();

or

name[0] = "홍길동"; -----> String만 이렇게 가능!!

car[0] = new Car("쏘나타");

tv[0] = new TV();

 

 

>>>>>> a, b, c를 동시에.. (값이 정해져 있을 때 - 주로 String 클래스에서 사용)

ex)

public String name[] = {"a","b","c"};

 

public class Car {
	String carName;
	private int speed;

	public Car(String carName) {
		this.carName = carName;
	}

	public int changeSpeed(int speed){
		this.speed = speed;
		return this.speed; //이게 리턴하는 값만 가지고 사용할 수 있도록 private으로 잡기
	}
}
public class CarArray {
	public static void main(String[] args) {
		Car c1 = new Car("쏘나타"); //자동차를 만든 것
		System.out.println("c1의 이름 : " + c1.carName);

		Car car[] = new Car[3];//배열 생성 - 자동차를 만든 것이 아니라 3칸짜리 공간만 만든 것
		//car[0] = c1; //c1이 주소값이니까 쏘나타 출력
		car[0] = new Car("쏘나타");
		car[1] = new Car("코란도");
		car[2] = new Car("제네시스");
		System.out.println("car[0]의 이름 : " + car[0].carName); //NullPointerException error > 무조건 . 앞에가 null일 때 발생
		System.out.println("car[1]의 이름 : " + car[1].carName);
		System.out.println("car[2]의 이름 : " + car[2].carName);

		System.out.println("---------------------------------");
		//쏘나타, K5, 제네시스, 테슬라, 마이바흐, 롤스로이스...
		String name[] = {"쏘나타", "K5", "제네시스", "테슬라",  "롤스로이스"}; //추가되거나 삭제되더라도 가능한 프로그램 만들기
		
		Car mycar[] = new Car[name.length]; //새로운 빈 공간을 만든다.
		for (int i=0;i<mycar.length ;i++ ){
			mycar[i] = new Car(name[i]); // 차를 하나씩 집어넣기
            System.out.println(mycar[i].carName);
		}
	}
}
---------- run ----------
c1의 이름 : 쏘나타
car[0]의 이름 : 쏘나타
car[1]의 이름 : 코란도
car[2]의 이름 : 제네시스
---------------------------------
쏘나타
K5
제네시스
테슬라
롤스로이스
public class ArrayTest5 {
	public static void main(String[] args) {
		int[] x = new int[5];
		x[0] = 1;
		x[1] = 2;
		x[2] = 4;
		x[3] = 5;
		for (int i=0;i<5 ;i++ ){
			System.out.println(x[i]);
		}
		//실수로 빼먹은 3을 x[2]에 삽입.
		int idx = 2;
		for (int i=x.length-1;i>idx ;i-- ){ //for문 역순, 먼저, x[2], x[3]에 있는 것을 뒤로 미룬 후 대입
			x[i] = x[i-1];

		}
		x[idx] = 3;
		System.out.println("삽입후-------------");
		for (int i=0;i<5 ;i++ ){
			System.out.println(x[i]);
		}
	}
}
---------- run ----------
1
2
4
5
0
삽입후-------------
1
2
3
4
5
import java.io.*;

public class ArrayTest6 {

	private  BufferedReader in;

	public ArrayTest6() { //프로그램이 시작하자마자 실행
		in = new BufferedReader(new InputStreamReader(System.in));
	}

	private  String read() {
		String msg = "";
		try{
			msg = in.readLine();
		}catch (Exception e){
			e.printStackTrace();
		}
		return msg;
	}

	public static void main(String[] args) {
		ArrayTest6 a = new ArrayTest6();
		int c = 2; //입력횟수
		int n = 20;
		int cnt = 0;
		
		int[] x = new int[c];
	
		for (int i=0;i<c;i++ ){
			x[i] = Integer.parseInt(a.read()); //read로 적은 것은 int로 변환 (4,6입력하기)

		}		
			boolean b[] = new boolean[n+1]; //
			for (int i=0;i<c;i++){
				for (int k=x[i];k<n+1 ;k+=x[i] ){//4의배수, 6의배수 자체를 true로 만듦
					b[k] = true;
				}  		
			}
			
			for (int i=0;i<n+1 ;i++ ){
				if (b[i]){
					cnt++;
				}
				
			}
				System.out.println(cnt);//7 (겹치는 12는 한 번만 카운팅)
		}
}
//백준 알고리즘 (배열 - 오르막길)

import java.io.*;
import java.util.*;

public class Main {
	public static void main(String[] args) throws IOException {
		BufferedReader in = new BufferedReader(new InputStreamReader(System.in));
		int N = Integer.parseInt(in.readLine());
		String str = in.readLine();
		int x[] = new int[N];
		StringTokenizer st = new StringTokenizer(str);
		for(int i=0;i<N;i++) {
			x[i] = Integer.parseInt(st.nextToken());
		}

		int max = 0;
		int start = x[0];
		int tmp = start;
		int s = 0;
		for(int i=1;i<N;i++) {
			int end = x[i];
			if(tmp < end) {
				tmp = end;
				if(i == N - 1) {
					s = tmp - start;
					if(max < s)
						max = s;
				}
			} else {
				s = tmp - start;
				if(max < s)
					max = s;

				start = tmp = x[i];
			}
		}
		System.out.println(max);
	}
}

// 숫자 야구 게임 (미완성.. 버그 발생)

/*
1. 123은 x스트라이크 x볼입니다.
2. 456은 x스트라이크 x볼입니다.
.
.
.
.
10. 749는 정답입니다.
-- a. 컴이 3자리 난수 발생 -- 로또
-- b. 내가 3자리 숫자 입력 -- 자판기
-- c. a와 b의 숫자를 비교
	c-1. 숫자가 같다면 ? 
		c-1-1. 자리수가 같다면? 스트라이크 // 자리수 비교는 '배열'
		c-1-2. 자리수가 다르다면 ? 볼
	c-2. 숫자가 다르다면 ? 아무런 일도 발생하지 x
-- d. 스트라이크가 3이면 '749는 정답입니다.' >> 게임 종료
				아니라면 456은 x스트라이크 x볼입니다. >> 다음으로 진행
*/

import java.io.*;

public class NumberBaseBall {

	private static BufferedReader in;

	int[] my = new int[3];
	int[] com = new int[3];
    int strikeCount = 0;
	int ballCount = 0;
	int count = 0;

	public NumberBaseBall(){
		in = new BufferedReader(new InputStreamReader(System.in));
	}
	
	private static String read(){
		String msg = "";
		try{
			msg = in.readLine();
		} catch (Exception e) {
			e.printStackTrace();
		}
		return msg;
	}
	
	void comNansu(){
		//난수발생, 배열에 집어넣기
		
		do{	
			com[0] = (int)(Math.random()*9+1);
		}
		while (com[0] == 0); //처음에 0이 나올 수 없으므로, 0이 나오면 반복문으로 올라감
		
		do{
			com[1] = (int) (Math.random()*9+1);
		}
		while (com[0] == com[1]);

		do{
			com[2] = (int) (Math.random()*9+1);
		}
		while (com[0] == com[2] || com[1] == com[2]);
	}
	
	void game(){
		while (true){ //무한루프
		strikeCount = 0; //누적이 아니기 때문에 초기화 필요
		ballCount = 0;
		count ++;
		System.out.print("숫자입력 : ");
		String msg = read(); //숫자를 얻어옴
		System.out.println("받은 값 : " + msg);
		my[0] = Integer.parseInt(msg)/100; // int이기 때문에 백의자리, 십의자리, 일의자리로 구해주지 않으면 123123123으로 출력됨...
		my[1] = Integer.parseInt(msg)%100/10;
		my[2] = Integer.parseInt(msg)%10;
		System.out.println(my[0] +""+ my[1]+""+my[2]);

		/*for (int i=0;i<my.length ;i++ ){
			for (int j=0;j<com.length ;j++ ){

				if (my[i] == com[i] ){ //숫자가 같다면..
					strikeCount++;
					System.out.println("스트라이크");
					continue;
					
				} else if (my[i] == com[j]){
					ballCount++;
					System.out.println("볼");
					break;
				}	
			}	
		}*/
		
		for (int i=0;i<my.length ;i++ ){
			if (my[i] == com[i] ){
					strikeCount++;
					System.out.println("스트라이크");
					continue;
			} else {
				for (int j=0;j<com.length ;j++ ){
					if(my[i] == com[j]){
					ballCount++;
					System.out.println("볼");
					break;
					}
				}
			}
		}
		
		if (strikeCount == 3){
			System.out.println(count+"." +com[0] +""+ com[1]+""+com[2] +"" +"는 정답입니다.");
			break;
		} else {
			System.out.println(count+"." + my[0]+""+my[1]+""+my[2]+"는 " + strikeCount + "스트라이크 " + ballCount +"볼 입니다.");
		} 
		} 
	}

	public static void main(String args[]){
		NumberBaseBall nbb = new NumberBaseBall();
		
		nbb.comNansu();
		System.out.println(nbb.com[0] +""+ nbb.com[1]+""+nbb.com[2]); //int변수이기 때문에 중간에 ""을 주지 않으면, 더하기를 해버림...
		nbb.game();

		/*
		System.out.print("숫자입력 : ");
		String msg = read();
		System.out.println("받은 값 : " + msg);
		nbb.my[0] = Integer.parseInt(msg)/100;
		nbb.my[1] = Integer.parseInt(msg)%100/10;
		nbb.my[2] = Integer.parseInt(msg)%10;
		System.out.println(nbb.my[0] +""+ nbb.my[1]+""+nbb.my[2]);
		*/
		
		//int num = Integer.parseInt(msg); //String문자열을 int 숫자형으로 바꿔주는 메소드
	}
}

// 숫자 야구 게임 (정상 실행)

import java.io.*;

public class NumberBaseBall1 { 

	private static BufferedReader in;

	int my[] = new int[3];
	int com[] = new int[3];

	public NumberBaseBall1() { //프로그램이 시작하자마자 실행
		in = new BufferedReader(new InputStreamReader(System.in));

		comNansu();
	}

	private static String read() {
		String msg = "";
		try{
			msg = in.readLine();
		}catch (Exception e){
			e.printStackTrace();
		}
		return msg;
	}

	private void comNansu() {
		com[0] = (int) (Math.random() * 9) + 1;//1 - 9
		do{
			com[1] = (int) (Math.random() * 10);//0 - 9
		}while(com[0] == com[1]);
		do{
			com[2] = (int) (Math.random() * 10);//0 - 9
		}while(com[0] == com[2] || com[1] == com[2]);
		System.out.println(com[0] + " " + com[1] + " " + com[2]);
	}

	private void game() {
		int count = 0;
		while(true) {
			System.out.print("숫자입력 : ");
			int myNum = Integer.parseInt(read());//573
			my[0] = myNum / 100;//5
			my[1] = myNum % 100 / 10;//7
			my[2] = myNum % 10;//3
			System.out.println(my[0] + " " + my[1] + " " + my[2]);

			int strike = 0;
			int ball = 0;
			for(int m=0;m<3;m++) {
				for(int c=0;c<3;c++) {
					if(my[m] == com[c]) {//숫자가 같다면..
						if(m == c)//자리수 같다면...
							strike++;
						else
							ball++;
					}
				}
			}// 숫자비교 for end

			if(strike != 3) {
				System.out.println(++count + ". " + myNum + "은 " + strike + "스트라이크 " + ball + "볼입니다.");
			} else {
				System.out.println(++count + ". " + myNum + "은 정답입니다.\n" + count + "번만에 정답!!!!");
				System.out.print("0 : 종료, 1 : 새게임 >> ");
				int num = Integer.parseInt(read());
				if(num == 0) {
					break;
				} else {
					System.out.println("새로운 게임을 시작합니다.");
					count = 0; //누적되는 것이 아니라 새롭게 시작해야 하니까 초기화해주기
					comNansu(); //다시 난수 발생
				}
			}
		}
	}


	public static void main(String[] args) {
		NumberBaseBall1 nbb = new NumberBaseBall1();
		nbb.game();
		/*
		System.out.print("숫자입력 : ");
		String msg = read();
		System.out.println("받은 값 : " + (msg + 100));
		int num = Integer.parseInt(msg);
		System.out.println("받은 값 : " + (num + 100));
		*/
	}
}

 

(1) 패키지 (package) : 폴더(디렉토리)와 비슷

> 클래스를 기능별로 묶은 것

> os(operating system 운영체제)의 folder (구분 - win : \ , linux mac : /)

> java의 package 구분 : .

> 클래스 이름의 일부

전체 클래스 이름 = 상위패키지.하위패키지.클래스

* 클래스명이 같아도 패키지명이 다르면 다른 클래스!!

> 클래스를 선언할 때 패키지가 결정된다.

클래스 파일은(~.class) 선언된 패키지와 동일한 폴더 안에서만 동작 (다른 폴더에서는 동작 x)

 

선언)

클래스 선언 첫 줄에 해야 한다.

package 상위패키지.하위패키지;

public class ClassName{ }

 

package pn.pn.pn;

접근제어자 [modifier] class ClassName [extends ClassName implements x1,x2,x3....] {

        variable
        - instance var
        - class var (static)

            constructor
            - ClassName()

            method
            - method(){}
            [ - abstract method();]

}

 

* 패키지 이름 규칙, 관례

1. 전부 알파벳 소문자로 작성

2. 숫자로 시작 x

3. _,$ 를 제외한 특수 문자 사용 x

4. 회사 도메인의 역순으로 보통 패키지 이름을 작성 (ex) com.samsung.projectname)

 

- 자바에서 제공하는 system package ****** (숙달 필요!!!!)

 

-java.lang : 가장 기본 package (별도의 import 없이 사용 가능)

-java.util : 없어도 되지만, 있으면 편한 것

-- util class

-- JCF(Java Collection Framework)

-java.io : input/output(입출력)

-java.text : 형식

-java.awt : 추상윈도우 만드는 것 (abstract window toolkit)

-java.awt.event : event처리

-java.net : network

-java.sql : JDBC (Java DataBase Connectivity)

.

.

.

 

(2) import문

> 같은 패키지 내에 포함된 클래스간에는 자유롭게 사용이 가능하다.

> 다른 패키지에 있는 클래스를 사용할 수 있는 방법 2가지

(패키지가 달라지면 import 필요, 패키지의 모든 class는 import로 사용 가능)

 

① 패키지명이 포함된 전체 클래스 이름을 사용 (전체를 다 입력해줘야 하기 때문에 귀찮다....)

 

package com.mycompany;

public class Car{
     com.hankook.Tire tire = new com.hankook.Tire();
}

② import문으로 패키지를 지정하고 사용 (주로 사용되는 방법)

package com.mycompany;

import com.hankook.Tire;

public class Car{
  Tire tire = new Tire();
}

 

* 컴파일 에러(~ cannot be resolved to a type) 가 난 상태에서 이클립스 단축키 (Ctrl + Shift + O) 누르면?

자동으로 import문 생성

 

Q. import com.hankook. * 같은 패키지 내에 있는 여러 개의 클래스를 모두 사용하고자 한다면?

이클립스에서 설정방법) 1. window>preference>java>code style>organize imports 선택

2. number of imports needed for.*의 99를 1로 변경한 후 [OK] 버튼 클릭

3. 다시 Ctrl + Shift + O 클릭

 

(3) cmd 이용하기

 

** cmd에서 class가 저장되어 있는 폴더로 이동

 

Q. cmd창에서 클래스 파일을 자동으로 javac로 compile 하는 법

javac -d .*.java (현재폴더)

javac -d d:\ .*.java (d드라이브 특정위치)

 

Q. jar 압축 파일 생성하는 법

jar 입력해서 사용법 보기

jar -cvf tire.jar com (저장하고자 하는 파일 이름)

c: create

v: 추가하는 중 : ~% 저장함

f : 폴더

 

Q. 외부에서 클래스파일을 가져오게 된다면? jar 압축 파일 활용하는 2가지 방법 (폴더까지 달라지면)

1.C:\Program Files\Java\jdk1.8.0_231\jre\lib\ext (java가 기본으로 참조한다.)

여기에 잘라내기 해서 붙여넣기

 

2.내PC>속성>환경변수 : CLASSPATH 원래 .만 있던 곳에 .;D:\javadata (java.jar 파일이 있는 곳) 설정하기

 

 

 

(1) 열거 타입 : 한정된 값만을 갖는 데이터 타입 (요일, 계절, 로그인 성공? 실패?.....)

: 한정된 값은 열거 상수(요일 中 월, 화, 수, 목, 금, 토, 일)

** JDK5에서 추가 (이전에는 상수를 열거형 대신 사용)

Q. 열거 대신 상수를 사용했을 때의 문제점??

> String 으로 선언된 변수에 한정된 값만을 대입하고 싶은데, String 타입이기 때문에 아무 문자열이나 올 수 있게 된다.... 해결 방법으로 열거형이 나옴!!

 

선언) 파일 이름과 동일한 이름으로 할 것!!!

public enum 열거타입이름 {열거상수1,열거상수2....} // 열거 상수는 모두 대문자,' _ ' 사용!!

 

열거 타입 변수 선언)

Week today;

Week reservationDay;

 

열거 상수값 저장)

열거타입 변수 = 열거타입.열거상수;

Week today = Week.MONDAY;

* 열거 타입 변수는 참조 타입이므로 null값으로 초기화 가능~

 

- 열거 객체는 열거 상수의 문자열을 내부 데이터로 가지고 있다.

그렇기 때문에, 열거 상수값을 저장할 때 열거타입.열거상수로만 해야 됨!!

 

- 열거 타입은 컴파일시 java.lang.Enum 클래스를 자동 상속한다.

 

- values() 메소드 / 향상된 for문 이용

Week[] days = Week.values();

for(Week day : days) {

System.out.println(day);

}

> days[0] ~days[6] : MONDAY~SUNDAY 까지 출력됨.

 

(2) 싱글톤(Singleton) : 어떠한 클래스는 단 하나의 객체만 생성되야 하는 클래스가 존재한다.

만드는 방법)

1. 클래스 자신의 타입으로 정적 필드를 선언하고, 자신의 객체를 생성해 초기화한다.

 

2. private 접근 제한자를 생성자 앞에 붙인다. (외부에서 여러 개의 생성자 생성하는 것을 막는다.)

 

3. 외부에서 호출할 수 있는 정적 메소드인 getInstance()를 선언한다.

(정적 필드에서 참조하고 있는 자신의 단 하나의 객체만 리턴하도록!!!)

public class 클래스이름 {
//정적 필드
private static 클래스이름 singleton = new 클래스이름();

//생성자
private 클래스() {}

//정적 메소드
public static 클래스이름 getInstance() {
	return singleton;

	}
}

 

public class Singleton {
	
		private static Singleton singleton = new Singleton(); //객체 생성

		private Singleton(){ //생성자 생성
			
		}

		static Singleton getInstance(){
			return singleton;
		}
}
public class SingletonExample {
	public static void main(String[] args) {
		//Singleton obj = new Singleton(); private으로 생성자 생성을 막아놓았기 때문에 error

		//유일한 singleton 메소드 호출 방법
		Singleton obj1 = Singleton.getInstance();
		Singleton obj2 = Singleton.getInstance();

		if (obj1 == obj2){
			System.out.println("같은 Singleton 객체입니다.");
		} else {
			System.out.println("다른 Singleton 객체입니다.");
		}
	}
}

 

---------- run ----------
같은 Singleton 객체입니다.

 


 

package test06;

public class SingletonClass {

	//static이니까 SINGLETON_CLASS_INSTANCE 데이터영역에 존재, SingletonClass()는 heap영역에 존재
	private static SingletonClass SINGLETON_CLASS_INSTANCE = new SingletonClass();
	public int i = 10;
	
	//외부에서 생성자 생성 막기 위해서 private
	private SingletonClass() {}
	
	//객체를 못 만드니까 static으로 객체가 만들어지기 전부터 데이터 영역(클래스 영역)에서 사용 가능
	//자신의 클래스에서 객체생성을 하고 있다.
	public static SingletonClass getSingletonClass() {
		if(SINGLETON_CLASS_INSTANCE==null) { //FirstClass
			SINGLETON_CLASS_INSTANCE = new SingletonClass();
		}
		return SINGLETON_CLASS_INSTANCE; //SecondClass
	}
	
	public int getI() {
		return i;
	}
	
	public void setI(int i) {
		this.i = i;
	}
}
package test06;

public class FirstClass {

	public FirstClass() {

		SingletonClass singletonClass = SingletonClass.getSingletonClass();
		System.out.println("FirstClass 입니다.");
		System.out.println("i=" + singletonClass.getI());
		singletonClass.setI(200);
		System.out.println("i=" + singletonClass.getI());
	}
}
package test06;

public class SecondClass {

	public SecondClass() {

		SingletonClass singletonClass = SingletonClass.getSingletonClass();
		System.out.println("SecondClass 입니다.");
		System.out.println("i=" + singletonClass.getI());
	}
}
package test06;

public class MainClass {

	public static void main(String[] args) {

		FirstClass firstClass = new FirstClass();
		SecondClass secondClass = new SecondClass();
	}
}
FirstClass 입니다.
i=10
i=200
SecondClass 입니다.
i=200

 

(1) 수정자 (modifier)

 

1.abstract : 추상 (class, method)

 

2.final : 변수, 메소드, 클래스에 모두 사용

variable : 변수에 final을 붙이게 되면 상수화(변수 변경 불가)가 된다.

public class FinalVarTest {
	private final int x; //error : final을 붙였기 때문에 상수화

	public void changeX() {
		x=10;
	}
}
---------- compile ----------
FinalVarTest.java:5: error: cannot assign a value to final variable x
		x=10;

 method : 메소드에 final을 붙이게 되면 상속후에도 override가 불가능하다.

public class FinalMethodTest {
	
	public final void x() {} //final method 
}
public class FinalMethodExt extends FinalMethodTest {
	
	public final void x(){} //final method는 override 불가
}
---------- compile ----------
FinalMethodExt.java:3: error: x() in FinalMethodExt cannot override x() in FinalMethodTest
	public final void x(){} //final method는 override 불가

 

class : 클래스에 final을 붙이게 되면 상속이 불가능하다.

public final class FinalClassTest {
	
}
//final class는 상속 불가능!!

public class FinalClassExt extends FinalClassTest {
	public static void main(String[] args) {
		System.out.println();
	}
}
---------- compile ----------
FinalClassExt.java:3: error: cannot inherit from final FinalClassTest
public class FinalClassExt extends FinalClassTest {

 

3.static : 공유 (객체 생성하지 않아도 클래스의 이름으로 접근 가능), class 변수라고 한다.

> 클래스 변수 : static한 변수, 값을 저장할 수 있는 공간이 하나밖에 없어서 값을 공유한다.

> 인스턴스가 여러개 생성되어도 static 변수는 딱 하나이다.

 

공용적인 데이터, 동일한 값, 고정 값 등

사용 ) 클래스의 이름.변수이름

VS

instance 변수 : 각자의 객체를 참조해야 접근 할 수 있는 변수, 객체 생성 필요

객체마다 가지고 있어야 할 데이터, 변화 가능한 객체들의 특징

사용) 객체의 이름. 변수이름

 

variable : static을 붙일 수 있다.

method : static을 붙일 수 있다.

class : static을 붙일 수 없다. (단, inner class에서는 가능)

class A {

	class B {

	}

}

 

Q. static 블록과 메소드에서 instance 필드나 메소드를 사용하고 싶다면??

> 객체를 생성해서 사용 가능하다!! or 필드나 메소드에 static 붙이기

 

* static이 선언되지 않은 변수와 메소드는 static 블록내(main method)에서 사용 불가능

(but, static 블록이 아닌 다른 블록 내에서는 static 변수와 메소드가 사용 가능!!!)

Static(공유)

y

class 변수

A

Heap

(동적할당)

 

x=10

y

----------

x

y=20

 

instance 변수

Stack

a1 a2

 

 

a1.x = 10;

S.o.p(a2.x); //0

a2.y = 20; -----------A.y = 20;

S.o.p(a1.y); //0 ------S.o.p(A.y); //20

 

* static과 객체와의 관계

> static은 클래스 변수다.

> 객체는 클래스에서 생성(복사) 되어진다.

> 클래스 하나에서 무한대로 객체를 생성할 수 있지만, 독립적인 전혀 다른 덩어리들이다.

> static이 붙은 변수는 클래스 변수로써 객체가 생성되기 전에 이미 존재한다.

 

클래스들이 모여 있는 데이터 영역 (new로 객체 생성하기 전)

객체들이 모여 있는 Heap 영역(new로 객체 생성) ----> 가비지 콜렉터는 Heap 영역만 메모리를 관리한다.

 

*설명

 

variable

method

class

abstract

x

o

o

final

o

o

o

static

o

O

X

(but,

inner class o)

 

4. 상수 : 상수이기 때문에 초기화 필요 (한 번 값을 초기화하면 변경 불가), 대문자로 작성하는 것이 관례

초기화 방법 )

1. 처음 선언에서 초기화 하기

static final DataType CONSTANCE_NAME = 값;

2. static 블록에서 초기화 하기 (복잡한 초기화 식이 있을 때)

static final DataType CONSTANCE_NAME;

static{

상수 = 초기값;

final 필드

static final (상수)

instance 필드

정적 필드

생성자에서 초기화 될 수 있다.

생성자에서 초기화 될 수 x

* 생성자를 생성하는 것 자체가 객체를 생성하는 것이기 때문에 상수는 객체를 생성하기 전에

이미 완성이 되어 있어야 한다!!

(선언할 때 or 정적 블록에서 초기화 되야 함)

 

대문자로 작성, 합성어인 경우 _로 구분

 

객체 생성없이 클래스를 통해 사용

초기값이 저장되면 값을 변경할 수 없다.


- 포인트 적립 ex) 객체 따로따로 counting...

public class PointCard {
	String name;
	int count; 

	public PointCard(String name){
		this.name = name;
	}

	public void buy(){
		count++;
	}
}
public class PointStore {
	public static void main(String[] args) {
		PointCard pc1 = new PointCard("홍길동");
		PointCard pc2 = new PointCard("임꺽정");
		System.out.println(pc1.name + "님 구매!!!");
		pc1.buy();
		System.out.println("스탬프 : " + pc1.count + "개");

		System.out.println(pc2.name + "님 구매!!!");
		pc2.buy();
		System.out.println("스탬프 : " + pc2.count + "개");

		System.out.println(pc1.name + "님 구매!!!");
		pc1.buy();
		System.out.println("스탬프 : " + pc1.count + "개");

		System.out.println(pc2.name + " 스탬프 확인 : " + pc2.count + "개");
	}
}
---------- run ----------
홍길동님 구매!!!
스탬프 : 1개
임꺽정님 구매!!!
스탬프 : 1개
홍길동님 구매!!!
스탬프 : 2개
임꺽정 스탬프 확인 : 1개

 

- 위의 코딩에 static만 추가해 본다면?? '누적' 방문객 수를 출력할 수 있다!! (공유), 객체 생성하지 않고!!

> 하나의 변수이기 때문에 값이 계속 누적!!

public class Guest {
	String name;
	static int count; //방문횟수

	public Guest(String name){
		this.name = name;
	}

	public static void visit(){
		count++;
	}
}
public class Store {
	public static void main(String[] args) {
		
		System.out.println("손님 방문!!!"); 
		Guest.visit();
		System.out.println("방문자수 : " + Guest.count + "명");

		System.out.println("손님 방문!!!");
		Guest.visit();
		System.out.println("방문자수 : " + Guest.count + "명");

		System.out.println("손님 방문!!!");
		Guest.visit();
		System.out.println("방문자수 : " + Guest.count + "명");
	}
}
---------- run ----------
손님 방문!!!
방문자수 : 1명
손님 방문!!!
방문자수 : 2명
손님 방문!!!
방문자수 : 3명

 

ex) 객체 생성하지 않고 호출하기

public class Printer{
	
	static void printin(int a){
		System.out.println(a);
	}

	static void println(boolean a){
		System.out.println(a);
	}

	static void println(double a){
		System.out.println(a);
	}

	static void println(String a){
		System.out.println(a);
	}	
}
public class PrinterExample {
	public static void main(String[] args) {
		
		Printer.println(10);
		Printer.println(true);
		Printer.println(5.7);
		Printer.println("홍길동");
	}
}

 

(2) 배열 (Array) -- 반복문과 단짝!!!!

 

장점 : 서로 연관된 데이터를 정리정돈 !!

(* 변수가 많을수록 오류 or 혼동 가능성이 있기 때문에 서로 연관된 데이터는 하나의 배열 변수로 만들어 주는 것이 좋다!!!!)

 

1.같은 DataType 여러 개 을 연속적으로 저장.

 

2.배열은 생성시 크기를 반드시 지정 >> 한 번 정해진 배열의 크기는 변할 수 없다..

>> 배열의 크기 : int size = 배열명.length;

 

3.기본DataType을 저장하는 reference 배열의 사용

a. 선언

형식) 접근제어자 기본DT[ ] 배열명;

                       or

        접근제어자 기본DT 배열명[ ]; (둘 다 똑같지만, 이 형식을 더 많이 사용)

 

ex)

public int x[ ];

private boolean b[ ];

 

b.생성

형식) 배열명 = new 기DT[크기];

ex)

x = new int[3]

b = new boolean[2];

 

>> a, b를 동시에 가능!!

접근제어자 기DT 배열명[ ] = NEW 기DT[크기];

public int x[ ] = new int[3];

private boolean b [ ]= new boolean[2];

 

c. 사용 : 값 할당

형식)

get : 배열명[index];

set : 배열명[index] = 값;

ex)

int x1 = 10;

int x2 = 30;

int x3 = 30;

>>> 배열

x[0] = 10;

x[1] = 20;

x[2] = 30;

S.o.p(x[0]);//10

S.o.p(x[1]);//20

S.o.p(x[2]);//30

       or

int len = x.length;

for(int i=0;i<len;i++) {

x[i] = (i+1) * 10;

S.o.p(x[i]);

}

 

>> a,b,c를 동시에..

ex)

public int x[] = {10,20,30};

public class ArrayTest1 {
	public static void main(String[] args) {
		int x1 = 10;
		int x2 = 20;
		int x3 = 30;
		System.out.println("x1 : " + x1 + "  x2 : " + x2 + "  x3 : " + x3);

		int x[] = new int[3];
		x[0] = 10;
		x[1] = 20;
		x[2] = 30;
		System.out.println("x[0] : " + x[0] + "  x[1] : " + x[1] + "  x[2] : " + x[2] );

		int y[] = new int[3];
		int len = y.length;
		for (int i=0;i<len ;i++ ){ //규칙이 있다면 for문 사용
			y[i] = (i+1)*10;
			System.out.print("  y[" + i + "] : " + y[i]);
		}
		System.out.println();

		int z[] = {10,20,30,40};
		len = z.length;
		for (int i=0;i<len ;i++ ){
			System.out.print("  z[" + i + "] : " + z[i]);
		}
	}
}
---------- run ----------
x1 : 10  x2 : 20  x3 : 30
x[0] : 10  x[1] : 20  x[2] : 30
  y[0] : 10  y[1] : 20  y[2] : 30
  z[0] : 10  z[1] : 20  z[2] : 30  z[3] : 40
/*
정수형의 5개의 배열을 만드시오.
1-10까지의 수 중 짝수만 저장.
출력.
*/

public class ArrayTest2 {
	public static void main(String[] args) {
		int x[] = new int[5];
		int idx = 0;
			for (int i=1;i<=10 ;i++ ){
				if (i%2==0){
					x[idx++] = i; //x[]에 i를 대입해라
				}
			}
		int len = x.length;
		for (int i=0;i<len ;i++ ){
			System.out.println(x[i]);
		}
	}
}
/*백준 알고리즘 배열 문제 (음계)
int x[] = {1,2,3,4,5,6,7,8}; -- ascending
int x[] = {8,7,6,5,4,3,2,1}; -- descending
int x[] = {8,1,7,2,6,3,5,4}; -- mixed
*/

public class ArrayTest3 {
	public static void main(String[] args) {
		int x[] = {1,2,3,4,5,6,7,8};
		//int x[] = {8,7,6,5,4,3,2,1};
		//int x[] = {8,1,7,2,6,3,5,4};
		
			/*int len = x.length;
			int idx = 0;
			for (int i=1;i<len ;i++ ){
				if (x[0]<x[1]){
					x[idx++] = i;
					System.out.println("ascending");
			}

				if (x[0]>x[1]){
					x[idx++] = i;
					System.out.println("descending");
				} else {
					System.out.println("mixed");
				}
			}*/

		int len = x.length;
		int a = 0;
		int d = 0;
		String str = "mixed";  
		for(int i=1;i<len;i++) { //배열의 길이는 8, 서로 비교해야 하니까 0이 아닌 1부터 시작!!
			if(x[i-1] < x[i])    
				a++;
			if(x[i-1] > x[i])
				d++;
		}
		
		if(a == 7)
			str = "ascending";
		else if(d == 7)
			str = "descending";
		System.out.println(str);

	}
}

 

4. for each문 : 값을 꺼내서 알아서 대입해 준다. for문 보다 훨씬 간결해진다.

for(타입 값을 받아줄 변수명 : 출력하고 싶은 자료구조)

//for each문을 이용해서 iarr의 값을 한 줄씩 출력하라.

public class Array1 {
	public static void main(String[] args) {
		int[] iarr = {10,20,30,40,50};

		
		for (int i=0;i<iarr.length ;i++ ){
			int value = iarr[i];
			System.out.println(value);
			
		}
		//System.out.println(value); //반복된 후 마지막 값인 50만 출력됨.

		for (int value : iarr){
			System.out.println(value);
		}
	}
}

 

 

 

cf) 오라클에서 날짜 구하는 방법

select to_char(sysdate, 'd') : 'ddd'는 365일, 'dd'는 '한달', 'd'는 한주

 

cf) cmd창에서 경로 이동할 때,

cd \ : 최상위

cd .. : 하나위

cd . : 현재폴더

 

(1) API 문서에서 check할 것

1. 제일 먼저 추상클래스(abstract) 인지 아닌지 확인하기!!

2. 생성자 확인 ()

3. 추상클래스라면 하위클래스가 있는지 확인 Direct Known Subclasses: 바로 아래 하위클래스

Q. final이라면? 하위클래스 자체가 없는 것!! final클래스는 상속불가이기 때문에

4. 상속구조 확인

 

API(Application Programming Interface : 응용 프로그래밍 인터페이스)문서 --> Packages의 java.util(어디에 있는지 명시해줘야 함) --> class의 Calendar로 확인

 

(2) 추상클래스의 객체 생성 방법

① 하위 클래스를 참조 (가장 일반적 방법 50%정도 사용)

ex) Calendar cal = new Calendar(); >> x

Calendar cal = new GregorianCalendar(); >> o

 

Q. 하위 클래스가 없다면?

② 자신의 객체를 return하는 static method 이용

static은 객체 생성없이 메소드 호출 가능

ex) Calendar cal = Calendar.getInstance(); //

* getInstance() 는 자신의 컴퓨터의 현재 날짜를 Calendar 객체로 만들어서 값을 리턴해주는 메소드

 

Q. a,b도 없다면?

java.lang(아무것도 안해도 내꺼처럼 사용할 수 있다.) --> Process 영어 설명 읽어보기

③ 외부클래스를 참조

ex) Runtime이 먼저 필요

Runtime r = Runtime.getRuntime(); //Runtime의 객체 리턴

Process p = r.exec("command");

 

④ 자신의 생성자 이용 (경우에 따라서 가능한 경우) - dynamic 동적 객체 생성 >> 자바만의 특징

import java.util.Calendar; //어디에 있는지 위치 명시해 줘야 함
import java.util.GregorianCalendar;

public class CalenderTest {
	public static void main(String[] args) {
		//Calendar cal = new Calendar(); //error : 추상클래스라서 
		//1.하위 클래스 참조
		//Calendar cal = new GregorianCalendar(); //하위클래스 참조
		
		//2.static method
		Calendar cal = Calendar.getInstance();
		int y = cal.get(Calendar.YEAR);
		int m = cal.get(Calendar.MONTH) + 1; //MONTH는 반드시 +1 해주기.. index에서 1월은 0이다..
		int d = cal.get(Calendar.DAY_OF_MONTH);
		int apm = cal.get(Calendar.AM_PM);
		int h = cal.get(Calendar.HOUR_OF_DAY);
		int mi = cal.get(Calendar.MINUTE);
		int s = cal.get(Calendar.SECOND);
		System.out.println("지금은 " + y + "년 " + m + "월 " + d + "일 " + (apm == 0? "오전 " : "오후") + h + "시 " + mi + "분 " + s + "초입니다.");
	}		
}
---------- run ----------
지금은 2019년 11월 1일 오전 0시 6분 48초입니다.
public class ProcessTest {
	public static void main(String[] args) throws Exception{
	
	//3.외부클래스 참조
	Runtime r = Runtime.getRuntime(); 
	Process process = r.exec("calc.exe"); //계산기 띄우기
	Thread.sleep(3000); //3000/1000 = 3초안에 계산기 꺼진다.
	process.destroy();
	}
}
import java.awt.*;
import java.awt.event.*;


public class WindowTest extends Frame {
	
	Button b = new Button("눌러");

	public WindowTest(){
		super("추상클래스 생성 테스트");
		setLayout(new FlowLayout());
		add(b);

		Toolkit tk = Toolkit.getDefaultToolkit();
		Dimension ds = tk.getScreenSize();
		int width = ds.width;
		int height = ds.height;

		setLocation(width/2-200,height/2-150);
		setSize(400,300);
		setVisible(true);
		
		//4. 동적 객체 생성 
		WindowAdapter wa = new WindowAdapter(){
			public void windowClosing(WindowEvent e){
				System.out.println("프로그램을 종료합니다.");
				System.exit(0);
			}

			public void windowIconified(WindowEvent e){
				System.out.println("최소화합니다.");
			}
		}
		addWindowListener(wa);
	}

	public static void main(String[] args){
		new WindowTest();
	}
}

 

(3) 인터페이스(Interface) : 껍데기, 작업지시서, 명세서, 약속(전부 다 추상메소드로 되어 있다>> 모든 메소드는 override해야 함)

 

***추상클래스와 비교***

추상클래스는 ???

> 내가 필요한 것들은 구현해놓고, 못하는 것들은 구현을 해라

 

인터페이스는??

> 모든 것을 구현해라

 

Q. 왜 만들어졌을까?

>반드시 구현해야 하는 클래스가 여러개 있을 경우 사용

>추상클래스는 추상메소드를 모두 override 했어야 했다.

>클래스는 다중 상속이 불가능하고 일대일 관계만 성립하지만, interface는 다중 implements가 가능하기 때문에 자주 사용된다.

 

- 개발 코드는 객체의 내부 구조를 알 필요가 없기 때문에 인터페이스의 메소드만 알고 있으면 ok~

역할)

개발 코드가 객체에 종속되지 않게 하여 객체를 교체할 수 있도록 하는 역할

개발 코드 변경 없이 리턴값 or 실행 내용이 다양해 질 수 있다.(다형성)

 

ex) 클래스인 도형을 상속받아 사각형의 넓이, 원의 넓이와 둘레를 구한다고 가정해보자.

(둘레 클래스와 넓이 클래가 따로 존재한다고 가정)

>> 사각형의 넓이는 부모 클래스인 도형의 메소드를 상속받아 사용할 수 있지만,

원은 넓이만 상속받고 둘레는 다중 상속받을 수가 없기 때문에, 따로 구현해야만 하는 문제가 발생한다.

 

1.변수 or 구현메소드 or 생성자가 존재하지 x

상수 or 추상메소드는 존재 o

>> 상수와 추상메소드만 갖는 클래스의 일종

 

2.형식)

접근제어자 interface InterfaceName {

// 상수;

[public static final] 타입 상수명 = 값; // 상수는 모두 대문자!! 초기값을 반드시 줘야 한다.!!

 

// 추상 메소드(매개변수); {실행블록 x}

[public abstract] 리턴타입 메소드명(매개변수);

 

// 디폴트 메소드() {...}; // 자바 8부터 추가됨.

[public] default 리턴타입 메소드명(매개변수);

 

// 정적 메소드() {...}; // 자바 8부터 추가됨.

[public] static 리턴타입 메소드명(매개변수);

}

 

3.스스로 객체 생성 불가능...

>> 클래스에 implements(구현) 후 사용가능 (구현한 클래스를 참조해서 객체 생성)

ex) class Television implements RemoteControl{....}

RemaoteControl rc = new Television();

rc.turnOn(); -------> Television의 turnOn() 실행

 

4.implements keyword 사용

형식)

접근제어자 class ClassName [extends ClassName] implements In1, In2, In3....

 

interface가 가진 모든 추상 메소드를 override

}

 

5.interface는 다중 implements가 가능

 

6. 인터페이스 변수와 구현 객체

ex) class Television implements RemoteControl{....}

RemoteControl rc;

rc = new Television();

 

7. 익명 구현 객체 : 이름이 없는 구현 클래스 선언과 동시에 객체 생성 -- 중첩클래스에서 다시 나옴

사용)

인터페이스 변수 = new 인터페이스(){

//인터페이스에 선언된 추상 메소드를 모두 재정의하는 실체 메소드 선언

}

 

> 언제 사용?

- UI 프로그래밍(Swing,Android,java FX)에서 이벤트를 처리하기 위해 주로 사용

- 임시 작업 스레드를 만들기 위해 사용

 

8.

상위

class

class

interface

interface

 

extends

x

implements

extends

하위

class

interface

class

interface

 

*Interface : 상수와 추상메소드만 갖는 클래스의 일종이기 때문에 구지 abstract를 붙일 필요가 없다.

public interface DohyungRound { 

	//double round = 10; //상수가 되서 다른 곳에서 변경 or 사용할 수 없기 때문에!! 
                         //인터페이스는 변수를 가질 수 없다는 것이 증명!
	public double calcRound();
}
public interface DohyungArea { 
	
	public double calcArea(); 

}
public class Rect implements DohyungArea{
	int width;
	int height;

	public Rect(){
		this(4,3);
	}

	public Rect(int width, int height){
		this.width = width;
		this.height = height;
	}

	public double calcArea(){
		return width * height;
	}

	void info(){
		System.out.println("사각형입니다.");
	}
}
public class Circle implements DohyungArea, DohyungRound { //클래스의 다중 상속은 불가능하지만, 다중 implements는 가능

	int radius;

	public Circle(){ 
		radius = 4;
	}

	public Circle(int radius){ 
		this.radius = radius;
	}

	public double calcArea(){
		return Math.pow(radius,2)*Math.PI;
	}
	
	public double calcRound(){
		return 2*Math.PI*radius;
	}
}
public class MatheMatics {

	static void printDohyung(Rect rect) {
		double area = rect.calcArea();
		System.out.println("가로가 " + rect.width + "이고 세로가 " + rect.height + "인 사각형의 넓이는 " + area + "입니다.");
	}

	static void printDohyung(Circle circle) {
		double area = circle.calcArea();
		double round = circle.calcRound();
		System.out.println("반지름이 " + circle.radius + "인 원의 넓이는 " + area + "이고 둘레는 " + round + "입니다.");
	}

	public static void main(String[] args) {
		
		Rect r1 = new Rect();

		printDohyung(r1);

		Rect r2 = new Rect(7, 5);

		printDohyung(r2);

		Circle c1 = new Circle();
		printDohyung(c1);

		Circle c2 = new Circle(6);
		printDohyung(c2);	
	}	
}
---------- run ----------
가로가 4이고 세로가 3인 사각형의 넓이는 12.0입니다.
가로가 7이고 세로가 5인 사각형의 넓이는 35.0입니다.
반지름이 4인 원의 넓이는 50.26548245743669이고 둘레는 25.132741228718345입니다.
반지름이 6인 원의 넓이는 113.09733552923255이고 둘레는 37.69911184307752입니다.
import java.awt.*;
import java.awt.event.*;

public class WindowListenerTest extends Frame implements WindowListener {
	
	Button b = new Button("눌러");

	public WindowListenerTest(){
		super("interface 생성 테스트");
		setLayout(new FlowLayout());
		add(b);

		Toolkit tk = Toolkit.getDefaultToolkit();
		Dimension ds = tk.getScreenSize();
		int width = ds.width;
		int height = ds.height;

		setLocation(width/2-200,height/2-150); //중앙에 오게 하기
		setSize(400,300);
		setVisible(true);
		
		//WindowListener w1 = new WindowListenerTest();
		//WindowListener w1 = this;
		addWindowListener(this);
	}

	//모든 메소드를 override 해야함!!!
	public void	windowActivated(WindowEvent e){}

	public void	windowClosed(WindowEvent e){}

	public void	windowClosing(WindowEvent e){
		System.exit(0);
	}

	public void	windowDeactivated(WindowEvent e){}

	public void	windowDeiconified(WindowEvent e){}

	public void	windowIconified(WindowEvent e){}

	public void	windowOpened(WindowEvent e){}

	public static void main(String[] args) {
		new WindowListenerTest();
	}
}

 

(4) 인터페이스의 default method --> java 8부터 생김..

(기존 인터페이스는 추상메소드와 상수만 가질 수 있었다...)

① default 키워드를 이용하여 추상메소드가 아닌 default 메소드가 구현 가능하다.

사용) 하위클래스 참조하여 객체 생성

② static 키워드를 이용하여 메소드 구현 가능하다.

사용) 인터페이스명.메소드명();

Q. 왜 추가 되었나?

> 인터페이스 내에서는 추상클래스만 올 수 있었기 때문에 인터페이스 내에서 구현이 불가능했다.

하지만, default나 static 키워드를 사용한 메소드가 인터페이스 내에서 구현가능하게 됨으로써, 인터페이스 내는 물론이고, 이를 구현하고자 하는 클래스에서도 default 메소드를 오버라이드하여 사용할 수 있게 되었다.

 

cf) 인터페이스를 사용하는 목적은 ?

>> 디자인의 측면에서, Client 입장에서는 자신이 사용하는 구체적인 클래스를 몰라도, 인터페이스에 정의된 메서드를 사용하는 객체라는 것이 보장되어 있기 때문에 구체적인 클래스의 변경이 일어나더라도 Client의 코드수정은 불필요!!! 구현 객체의 같은 동작을 보장하기 위한 목적이 있다.

 

(5) 추상클래스 vs 인터페이스

<공통점>

1. 추상메소드를 가지고 있다. ---> 하위클래스에서 구현해야 한다.

2. 데이터 타입이 목적이다. 객체생성이 목적이 아니라 데이터 타입을 정의하는 것이 목적이다.

3. 객체 생성은 'anonymose'를 이용해야 한다.

<차이점>

1. 상속, 구현 - 추상메소드는 상속을 통한 사용이고, 인터페이스는 구현을 통한 사용이다.

2. 구성요소 차이 - 추상클래스는 일반 클래스와 동일하게 변수와 메소드의 모든 기능을 사용할 수 있지만,

인터페이스는 상수와 추상메소드만 존재한다.

3. 단일상속, 다중구현 - 추상클래스는 상속이므로 단일 상속만 지원하고, 인터페이스는 다중구현이 가능하다.

 

 

(1) 추상 클래스 (Abstract Class) : 공통된 특성을 추출해서 만든 클래스

 

Q. 왜 추상클래스를 만들까?

> ex) 본사에서 메뉴만 정해주고 가격은 정해주지 x --> 각 매장에서 가격을 정해서 사용해라

---> 즉, 추상적으로 정의할 테니, 사용자가 꼭 '강제적'으로 overriding(재정의) 하라는 의미!!

ex) 어떤 메소드는 override하고, 어떤 메소드는 override를 하지 않을 경우, 본사에서 가격을 정하지 않았기 때문에 0원이 발생하는 경우가 존재한다. 따라서 모든 추상메소드를 override 해야 함!!!!

> 추상클래스를 상속 받은 실체 클래스의 공통된 필드와 메소드 이름을 통일할 목적으로 생성

= 여러 사람이 실체 클래스를 설계할 경우, 제각기 필드와 메소드 이름을 가질 수 있기 때문에 통일

> 실체 클래스 작성시 시간 절약

> 하위클래스에서 상위클래스의 메소드를 재정의 할 필요가 없을 때는 일반메소드 주로 사용

(ex) 식당에서 모든 사람들이 먹는 메뉴들)

> 하위클래스에서 상위클래스의 메소드를 각 상황에 맞게 재정의 할 필요가 있을 때 추상메소드 주로 사용

(ex) 식당에서 각각의 사람들이 먹는 메뉴들)

 

(2) 추상 메소드(abstract method)를 하나 이상 가진 클래스

* 추상 메소드란?

> method의 body(구현부,{중괄호})가 없는 method

--> 상속받는 자식 클래스에 기능을 위임하는 개념

> abstract keyword(modifier) 사용

> 추상 클래스 내부에는 일반 메소드 구현도 가능하다.

 

형식)

접근제어자 abstract ReturnType methodName ([args]); - 매개변수 생략 가능

 

ex)

public void a(); >> o - a라는 추상 메소드를 만들 것이다.

public void b() {} >> x - 아무 일도 하지 않는 일반 메소드

 

추상클래스 형식)

접근제어자 abstract class ClassName {

 

field

 

constructor

 

method

- 구현 method(){}

- abstract 추상 method();

}

 

**2. 추상클래스는 하위 클래스를 제어하기 위해 사용한다. (2,3번 함께 생각)

**3. 추상클래스는 자신의 생성자로 객체 생성이 불가능하고, 부모 클래스로만 사용된다.

>> 2+3 : 추상클래스는 하위클래스에 상속 후 사용 가능 --> 추상클래스를 상속받는 클래스는 '반.드.시' 추상메소드를 override해야 한다. (강제적으로!!!)

ex)

>> 다형성 : 하위 클래스를 참조하여 상위 클래스의 객체를 생성한다.

 

4. 추상클래스의 객체 생성 방법

a. 하위 클래스를 참조 (가장 일반적 방법 50%정도 사용)

b. 자신의 객체를 return하는 static method 이용

c. 외부클래스를 참조

d. 자신의 생성자 이용 (경우에 따라서 가능한 경우)

 

(3) 클래스 형변환

 

** 부모 타입으로 자식을 가리킬 수 있다. 이 경우 부모가 가지고 있는 필드 or 메소드만 사용이 가능하다.

Dohyung d1 = new Rect();

d1.calcArea();

d1.calcRound();

Q. 부모가 자식의 필드나 메소드를 사용하고 싶다면?? 클래스 형변환을 하면 OK~~~

Rect rect = (Rect) d1;

 

- Animal 추상클래스 만들기

 

public abstract class Animal {
	public String kind;

	public void breathe(){
		System.out.println("숨을 쉰다");
	}

	public abstract void sound();//추상 메소드는 추상 클래스에서만 사용 가능
	                             //동물들의 울음소리는 다 다르기 때문에 추상 메소드로 만들어주기
}
public class Dog extends Animal {
	public Dog(){
		this.kind = "포유류";
	}
	
	@Override
	public void sound(){
		System.out.println("멍멍");
	};
}
public class Cat extends Animal {
	public Cat(){
		this.kind = "포유류";
	}
	
	@Override
	public void sound(){
		System.out.println("야옹");
	};
}
public class AnimalExample {
	public static void main(String[] args) {
		Dog dog = new Dog();
		Cat cat = new Cat();

		dog.sound();
		cat.sound();
		System.out.println("----------------");

		Animal animal = null; // animal이라는 변수 생성
		animal = new Dog(); //자식객체를 만들어서 부모 변수에 대입 (자동타입변환)
		animal.sound(); // override한 자식 메소드 실행 : 멍멍

		animal = new Cat();
		animal.sound(); //  override한 자식 메소드 실행 : 야옹
	}
}

 

- Dohyung 추상클래스 만들기

public abstract class Dohyung { //Dohyung.java:1: error: Dohyung is not abstract and does not override abstract method calcRound() in Dohyung
								//추상클래스로 만들기(강제성)
	
	public abstract double calcArea(); //추상메소드로 만들기

	public abstract double calcRound();
}
public class Rect extends Dohyung{
	int width;
	int height;

	public Rect(){
		this(4,3);
	}

	public Rect(int width, int height){
		this.width = width;
		this.height = height;
	}

	public double calcArea(){
		return width * height;
	}

	public double calcRound(){
		return (width + height) * 2;
	}

	void info(){
		System.out.println("사각형입니다.");
	}
}
public class Circle extends Dohyung {

	int radius;

	public Circle(){ //반지름 = 4
		radius = 4;
	}

	public Circle(int radius){ //외부 값 입력
		this.radius = radius;
	}

	public double calcArea(){
		return Math.pow(radius,2)*Math.PI;//Math.pow(radius,2) : 제곱근, Math.PI : 파이값
	}
	
	
	public double calcRound(){
		return 2*Math.PI*radius;
	}
}

 

- 실행클래스

public class MatheMatics {

	static void printDohyung(Rect rect) {
		double area = rect.calcArea();
		double round = rect.calcRound();
		System.out.println("가로가 " + rect.width + "이고 세로가 " + rect.height + "인 사각형의 넓이는 " + area + "이고 둘레는 " + round + "입니다.");
	}

	static void printDohyung(Circle circle) {
		double area = circle.calcArea();
		double round = circle.calcRound();
		System.out.println("반지름이 " + circle.radius + "인 원의 넓이는 " + area + "이고 둘레는 " + round + "입니다.");
	}

	public static void main(String[] args) {
		//int area = 0;
		//int round = 0;
		//default 생성자를 이용한 넓이와 둘레를 구하시오.
		Rect r1 = new Rect();

		//가로가 4이고 세로가 3인 사각형의 넓이는 12이고 둘레는 14입니다.
		/*
		area = r1.calcArea();
		round = r1.calcRound();
		System.out.println("가로가 " + r1.width + "이고 세로가 " + r1.height + 
			"인 사각형의 넓이는 " + area + "이고 둘레는 " + round + "입니다.");
		*/
		printDohyung(r1);

		//가로 7, 세로 5인 사각형의 넓이와 둘레를 구하시오. 
		Rect r2 = new Rect(7, 5);

		//가로가 7이고 세로가 5인 사각형의 넓이는 35이고 둘레는 24입니다.
		/*
		area = r2.calcArea();
		round = r2.calcRound();
		System.out.println("가로가 " + r2.width + "이고 세로가 " + r2.height + 
			"인 사각형의 넓이는 " + area + "이고 둘레는 " + round + "입니다.");
		*/
		printDohyung(r2);

		Circle c1 = new Circle();
		printDohyung(c1);

		Circle c2 = new Circle(6);
		printDohyung(c2);

		//Dohyung d1 = new Dohyung(); error 추상클래스는 자신의 생성자로 객체 생성 할 수 x
		Dohyung d1 = new Rect(); // 추상클래스는 하위클래스를 참조해서 객체를 생성한다.
		//d1.info();
		//System.out.println("가로가 " + d1.width + "이고 세로가 " + 
		//	d1.height + "인 사각형의 넓이는 " + d1.calcArea());
		System.out.println("도형의 넓이는 " + d1.calcArea());

		Rect r = (Rect) d1;
		System.out.println("가로가 " + r.width + "이고 세로가 " + r.height + "인 사각형의 넓이는 " + r.calcArea());

		Circle c = (Circle) d1;
		System.out.println("반지름이 " + c.radius + "인 사각형의 넓이는 " + r.calcArea());
	}
}
---------- run ----------
가로가 4이고 세로가 3인 사각형의 넓이는 12.0이고 둘레는 14.0입니다.
가로가 7이고 세로가 5인 사각형의 넓이는 35.0이고 둘레는 24.0입니다.
반지름이 4인 원의 넓이는 50.26548245743669이고 둘레는 25.132741228718345입니다.
반지름이 6인 원의 넓이는 113.09733552923255이고 둘레는 37.69911184307752입니다.
도형의 넓이는 12.0
가로가 4이고 세로가 3인 사각형의 넓이는 12.0
Exception in thread "main" java.lang.ClassCastException: Rect cannot be cast to Circle
	at MatheMatics.main(MatheMatics.java:58)

 

                                                      1번            ------------>    2번 ----------------> 3번 순으로 생성

 

Heap

Object

(최상위클래스)

Dohyung

calcArea()

calcRound()

Rect

info()

Stack

 

d1

r

 

****

-Dohyung d1 = new Dohyung();

error? 추상클래스는 자신의 생성자로 객체 생성 할 수 x

 

-Dohyung d1 = new Rect(); // 추상클래스는 하위클래스를 참조해서 객체를 생성한다.

d1.info(); // error : 도형클래스에는 info가 없기 때문에 에러

 

-Rect r = (Rect) d1; //d1을 Rect로 변환하면 대입 가능하다.

 

-Circle c = (Circle) d1;

error ? Circle은 객체가 만들어지지 않았기 때문

 

 

+ Recent posts