JAVA

DAY 10 - instanceOf / 추상클래스 / final (2024.07.16)

summ.n 2024. 8. 12. 19:07

 

 

 

instanceof

: casting(형 변환)이 되는지 안 되는지를 판별

: 객체에 원하는 클래스 타입이 메모리 할당되었는지 안 되었는지를 확인


InstanceOf.java

package inheritance;
//같은 패키지 안에 같은 클래스 파일 잡을 수 없다.

class AAA{}
class BBB extends AAA{}
//--------------
public class InstanceOf {

	public static void main(String[] args) {
		AAA aa = new AAA();
		BBB bb = new BBB(); //부모꺼까지 잡음
		AAA aa2 = new BBB(); //부모꺼까지 잡음 / 부모꺼 참조하겠다.
		
		AAA aa3 = aa;
		if(aa instanceof AAA)
			System.out.println("1. TRUE");
		else
			System.out.println("1. FALSE");
		
		AAA aa4 = bb; //부모는 모든 자식 클래스 참조할 수 있으므로 가능
		if(bb instanceof AAA)
			System.out.println("2. TRUE");
		else
			System.out.println("2. FALSE");
		
		BBB bb2 = (BBB)aa2;
		if(aa2 instanceof BBB)
			System.out.println("3. TRUE");
		else
			System.out.println("3. FALSE");
		
		//BBB bb3 = (BBB)aa;// error - ClassCastException
		if(aa instanceof BBB)
			System.out.println("4. TRUE");
		else
			System.out.println("4. FALSE");
	}

}
 
1. TRUE
2. TRUE
3. TRUE
4. FALSE
 

AAA aa = new AAA();

aa 객체는 메모리에 AAA만 잡는다. 그러므로

 

BBB bb3 = (BBB)aa; error - ClassCastException

위와 같은 경우에 error가 뜨는 것이다. 왜냐 메모리에 BBB가 전혀 없기 때문이다.


추상클래스 - Sub class 제어

1. 추상화 작업

 

2. 메소드에 body { } 가 없는 메소드를 추상메소드라고 한다.

추상메소드에는 abstract 라는 키워드를 써야 한다.

추상메소드는 {} body 없이 ;를 써야한다.

 

3. 추상메소드가 있는 클래스는 반드시 추상클래스이어야 한다.

 

4. 추상메소드가 없는 추상클래스를 의미상의 추상클래스라고 한다.

의미상의 추상클래스의 메소드는 모두 빈body로 되어 있다.

 

5. 추상클래스는 자신의 클래스로 메모리 생성을 할 수 없다

=> 생성하려면

가. Sub Class를 이용 (반드시 Sub Class가 추상메소드를 Override 해야 한다)

나. 메소드를 이용

 

6. 추상메소드는 반드시 Sub Class에서 Override 꼭 해 주어야 한다.

Override를 안하면 Sub Class 마저도 abstract 가 되어야 한다


NumberMain.java

package abstract_;

import java.text.DecimalFormat;
import java.text.NumberFormat;
import java.util.Locale;

public class NumberMain {

	public static void main(String[] args) {
		//NumberFormat nf = new NumberFormat();
		//error - Cannot instantiate the type NumberFormat 
        //-> 추상클래스라 직접적으로 생성 안됨.
		
		//Sub class(부모 - 자식 관계)이용하여 생성
		NumberFormat nf = new DecimalFormat();
		
		//1대1관계로 본인꺼 본인이 쓰는것
		//DecimalFormat df = new DecimalFormat();
		
		//3자리마다 ,를 찍고 소수이하 3째짜리까지 제공
		System.out.println(nf.format(12345678.456789)); 
		System.out.println(nf.format(12345678));
		System.out.println();
		
		NumberFormat nf2 = new DecimalFormat("#,###.##원");
		//유효숫자가 아닌 것은 표현하지 않는다.
		System.out.println(nf2.format(12345678.456789)); 
		System.out.println(nf2.format(12345678));
		System.out.println();
		
		NumberFormat nf3 = new DecimalFormat("#,###.00원");
		//0를 강제로 표시
		System.out.println(nf3.format(12345678.456789)); 
		System.out.println(nf3.format(12345678));
		System.out.println();
		
		//기본이 3자리마다 ,를 찍고 소수이하 3째짜리까지 제공 => 소수이하 2째자리로 변경
		//메소드 이용하여 생성
		
		//NumberFormat nf4 = NumberFormat.getInstance(); = new NumberFormat() 역할이랑 똑같음
		
		//메소드 이용하여 생성, ₩ 표시
		NumberFormat nf4 = NumberFormat.getCurrencyInstance(); 
		nf4.setMaximumFractionDigits(2); //소수이하 2째짜리까지만 나오게 바뀜.
		nf4.setMinimumFractionDigits(2); //0을 강제 표시
		System.out.println(nf4.format(12345678.456789)); 
		System.out.println(nf4.format(12345678));
		System.out.println();
		
		//메소드 이용하여 생성
		//NumberFormat nf5 = NumberFormat.getInstance(Locale.US);
		
		//메소드 이용하여 생성, $ 표시
		NumberFormat nf5 = NumberFormat.getCurrencyInstance(Locale.US); 
		System.out.println(nf5.format(12345678.456789)); 
		System.out.println(nf5.format(12345678));
		System.out.println();
		
	}

}
 
12,345,678.457
12,345,678

12,345,678.46원
12,345,678원

12,345,678.46원
12,345,678.00원

₩12,345,678.46
₩12,345,678.00

$12,345,678.46
$12,345,678.00

 

추상클래스는 new해서 직접적으로 생성 안된다는거 기억 !!

 


AbstractTest.java

package abstract_;

public abstract class AbstractTest { //POJO 형식(Plain Old Java Object)
	String name; //default나 protected로 만들어야함.
	
	public AbstractTest() {}
	
	public AbstractTest(String name) {
		super();
		this.name = name;
	}

	public String getName() { //구현
		return name;
	}

	public abstract void setName(String name); //추상메소드 -> 추상클래스로 선언해야함.
}
 

추상메소드가 있으면 반드시 추상클래스여야하지만 !!

추상클래스라고 추상메소드가 꼭 있어야하는 것은 아니다. 없을 수도 있음.

 

AbstractMain.java

package abstract_;

public class AbstractMain extends AbstractTest{ //오버라이드 안 하면 error
//abstract 또 붙이면 - 못 해!! 하면 밑에 자식이 오버라이드해야함.
	
	@Override
	public void setName(String name) {
		this.name = name;
	}
	
	public static void main(String[] args) {
		//AbstractTest at = new AbstractTest();//error 추상클래스는 new할 수 x(생성할 수 x)
		//부모는 자식클래스 생성합니다. 부모 = 자식
		AbstractTest at = new AbstractMain();
		
		at.setName("홍길동"); //호출 -> 오버라이드됐으므로 자식꺼 호출됨.
		System.out.println("이름 = " + at.getName());
	}

}
 
이름 = 홍길동
 

AbstractTest at = new AbstractTest();

-> error 추상클래스는 new할 수 x(생성할 수 x)

 

부모는 자식클래스 생성한다. 부모 = 자식

AbstractTest at = new AbstractMain();

 

 

setName()은 오버라이드됐으므로 이럴 때는 무조건 자식에게 우선권 !!!


ShapeTest.java (abstract로 고친 코드)

package abstract_;

import java.util.Scanner;

abstract class ShapeTest{
	protected double area;
	Scanner scan = new Scanner(System.in);
	
	public ShapeTest() {
		System.out.println("ShapeTest 기본생성자");
	}
	public abstract void calcArea();
	public abstract void dispArea(); //내가 메모리에 갖고있을 필요가 없다.
	//자식들이 강제성으로 같은 이름으로 오버라이드해줘야함.
	//부모는 추상으로 강압적인 것만 제공해주면 됨.
}
 

calcArea() /dispArea() → 자식들은 강제성으로 오버라이드 필수 !

 

밑에 코드는 저번과 동일

class SamTest extends ShapeTest{
	protected int base, height;
	
	public SamTest() {
		System.out.println("SamTest 기본생성자");
		
		System.out.print("밑변 : ");
		base = scan.nextInt();
		
		System.out.print("높이 : ");
		height = scan.nextInt();
	}
	
	@Override //바로 밑에있는 줄에만 먹힘.
	public void calcArea() {
		area = base * height / 2.;
	}
	
	@Override
	public void dispArea() {
		System.out.println("삼각형 넓이 = " + area);
	}
}
//------------
class SaTest extends ShapeTest{
	protected int width, height;
	
	SaTest(){
		System.out.println("SaTest 기본생성자");
		System.out.print("가로 : ");
		width = scan.nextInt();
		
		System.out.print("세로 : ");
		height = scan.nextInt();
	}
	@Override
	public void calcArea() {
		area = width * height;
	}
	@Override
	public void dispArea() {
		System.out.println("사각형 넓이 = " + area);
	}
}
//------------
class SadariTest extends ShapeTest{
	protected int top, bottom, height;
	
	SadariTest(){
		System.out.println("SadariTest 기본생성자");
		System.out.print("윗변 : ");
		top = scan.nextInt();
		
		System.out.print("밑변 : ");
		bottom = scan.nextInt();
		
		System.out.print("높이 : ");
		height = scan.nextInt();
	}
	@Override
	public void calcArea() {
		area = (top + bottom) * height / 2.;
	}
	@Override
	public void dispArea() {
		System.out.println("사다리꼴 넓이 = " + area);
	}
}
//------------
public class ShapeMain {

	public static void main(String[] args) {/*
		//1:1관계, 결합도 100%로 묶임. SamTest()클래스를 부르려면 sam 리모콘 필요
		SamTest sam = new SamTest(); 
		sam.calcArea();
		sam.dispArea();
		System.out.println();
		
		SaTest sa = new SaTest();
		sa.calcArea();
		sa.dispArea();
		System.out.println();
		
		SadariTest sad = new SadariTest();
		sad.calcArea();
		sad.dispArea();
		System.out.println();*/
		
		ShapeTest shape;
		//다형성, 부모는 모든 자식클래스 참조할 수 있다.
		shape = new SamTest(); //만능리모콘 shape -> 모두 제어가능.
		shape.calcArea();
		shape.dispArea();
		System.out.println();
		
		shape = new SaTest();
		shape.calcArea();
		shape.dispArea();
		System.out.println();
		
		shape = new SadariTest(); 
		shape.calcArea();
		shape.dispArea();
		System.out.println();
	}
}
 
ShapeTest 기본생성자
SamTest 기본생성자
밑변 : 2
높이 : 5
삼각형 넓이 = 5.0

ShapeTest 기본생성자
SaTest 기본생성자
가로 : 4
세로 : 4
사각형 넓이 = 16.0

ShapeTest 기본생성자
SadariTest 기본생성자
윗변 : 8
밑변 : 5
높이 : 3
사다리꼴 넓이 = 19.5

 

Today.java

package abstract_;

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;
import java.util.GregorianCalendar;
import java.util.Scanner;

public class Today {
	
	public static void main(String[] args) throws ParseException {
		Date date = new Date();
		System.out.println("오늘 날짜 : " + date);
		
		SimpleDateFormat sdf = new SimpleDateFormat("y년 MM월 dd일 HH시 mm분 ss초");
		System.out.println("오늘 날짜 : " + sdf.format(date));
		System.out.println();
		
		//내 생일 => 19910505 => yyyyMMddHH
		Scanner scan = new Scanner(System.in);
		SimpleDateFormat input = new SimpleDateFormat("yyyyMMddHH");
		
		/*
		System.out.print("생일 날짜 입력 (yyyyMMddHH) : ");
		String birth = scan.next();
		
		Date birth_date = input.parse(birth); //String => Date 변환
		System.out.println("내 생일 : " + birth_date);
		System.out.println("내 생일 : " + sdf.format(birth_date));
		System.out.println();
		*/
		
		//시스템의 날짜와 시간을 기준으로 생성
		//Calendar cal = new Calendar();
		//Calendar cal = new GregorianCalendar(); //Sub class 사용
		Calendar cal = Calendar.getInstance(); //메소드 이용
		
		//int year = cal.get(Calendar.YEAR);
		int year = cal.get(1);
		//int month = cal.get(Calendar.MONTH) + 1; //1월-0, 2월-1, ~~~
		int month = cal.get(2) + 1;
		int day = cal.get(Calendar.DAY_OF_MONTH);
		int week = cal.get(Calendar.DAY_OF_WEEK); //일요일-1, 월요일-2, ~~~
		String weekOfDay = null;
		
		switch(week) {
		case 1:
			weekOfDay = "일";	
			break;
		case 2:
			weekOfDay = "월";
			break;
		case 3:
			weekOfDay = "화";
			break;
		case 4:
			weekOfDay = "수";
			break;
		case 5:
			weekOfDay = "목";
			break;
		case 6:
			weekOfDay = "금";
			break;
		case 7:
			weekOfDay = "토";
			break;
						
		}	
		
		int hour = cal.get(Calendar.HOUR_OF_DAY);
		int minute = cal.get(Calendar.MINUTE);
		int second = cal.get(Calendar.SECOND);
		
		System.out.println(year + "년 " 
						+ month + "월 " 
						+ day + "일 " 
						+ weekOfDay + "요일 "
						+ hour + ":"
						+ minute + ":"
						+ second);
		
	}
}
 
오늘 날짜 : Tue Jul 16 17:53:37 KST 2024
오늘 날짜 : 2024년 07월 16일 17시 53분 37초

생일 날짜 입력 (yyyyMMddHH) : 2001120510
내 생일 : Wed Dec 05 10:00:00 KST 2001
내 생일 : 2001년 12월 05일 10시 00분 00초

2024년 7월 16일 화요일 17:53:43
 

final (상수화)

1. final 변수는 값을 변경할 수 없다.

 

2. final 변수는 반드시 초기값을 주어야 한다.

final 필드는 생성자에서 초기값을 주어야 한다.

static final 필드는 static 구역에서 초기값을 주어야 한다.

 

3. final 변수는 대문자로만 기술

 

4. final 메소드는 Override를 할 수 없다.

 

5. final 클래스는 자식클래스를 가질 수 없다.- 상속이 안된다


enum (열거형)

: 자바의 열거형은 자료형(Data Type)을 의미한다

: 서로 관련 있는 상수들을 모아 놓은 것

: enum 상수들은 묵시적으로 static final status형으로 선언된다

: 먼저 자료형을 선언한 다음에 사용한다

: 대문자로 사용

: 열거된 순서에 따라 0부터 시작

 

FinalMain.java

package inheritance;

enum ColorEnum{ //상수들 나열
	RED, GREEN, BLUE //0, 1, 2로 인식(가위바위보에도 많이 사용)
}
//------------
class Final{
	public final String FRUIT = "사과"; //상수화 - 값을 변경할 수 x
	public final String FRUIT2;
	
	public static final String ANIMAL = "호랑이";//상수화
	public static final String ANIMAL2;//상수화
	
	//public static final int RED = 0;
	//public static final int GREEN = 1;
	//public static final int BLUE = 2;
	
	static{
		ANIMAL2 = "기린";
	}
	
	public Final() {
		FRUIT2 = "딸기";
	}
}
//-------------
public class FinalMain {
	public static void main(String[] args) {
		final int AGE = 25;
		//AGE = 30; - error
		System.out.println("AGE = " + AGE);
		
		final String NAME;
		NAME = "홍길동";
		//NAME = "코난"; - error
		System.out.println("NAME = " + NAME);
		System.out.println();
		
		Final f = new Final();
		System.out.println("FRUIT = " + f.FRUIT);
		System.out.println("FRUIT2 = " + f.FRUIT2);		
		System.out.println();
		
		System.out.println("ANIMAL = " + Final.ANIMAL);
		System.out.println("ANIMAL2 = " + Final.ANIMAL2);
		System.out.println();
		
		System.out.println("빨강 = " + ColorEnum.RED);
		System.out.println("빨강 = " + ColorEnum.RED.ordinal());
		System.out.println();
		
		for(ColorEnum data : ColorEnum.values()) {
			System.out.println(data.ordinal() + " : " + data);
		}
	}
}
 
AGE = 25
NAME = 홍길동

FRUIT = 사과
FRUIT2 = 딸기

ANIMAL = 호랑이
ANIMAL2 = 기린

빨강 = RED
빨강 = 0

0 : RED
1 : GREEN
2 : BLUE