본문 바로가기

기록/자바_국비

[배운내용정리] 1119 자바 국비교육

728x90

2020년 11월 19일 9시 ~ 15시 30분 zoom으로 수업 진행

 

11월 24일 프로그래밍 시험


저번 시간에 했던 상속 내용 되짚어보기

package com.test.part02_override.book.run;

import com.test.part02_override.book.model.vo.Book;

public class Run {

	public static void main(String[] args) {
		
		Book b1 = new Book("수학의 정석", "김수학", 100);
		Book b2 = new Book("자바의 정석", "박자바", 300);
		
		//System.out.println("b1 = " + b1.toString());
		//System.out.println("b2 = " + b2.toString());
		
		System.out.println("b1 = " + b1);
		System.out.println("b2 = " + b2);
		//toString() 했을 때와 같은 결과값이 나온다
		//객체만 호출했을 경우 jvm이 자동적으로 toString()을 붙여버린다
		
		//System.out.println("b1 == b2 " + b1 == b2); 객체의 비교는  == 이 아니라 .equals() 를 사용
		System.out.println("b2 == b1 : " + b2.equals(b1));//false
		
		Book b3 = b1;//b1이 가진 주소값을 b3에 얕은 복사시킴
		System.out.println("b1 == b3 : " + b1.equals(b3));//true
		
		Book b4 = new Book("수학의 정석", "김수학", 100);//다른 변수에 존재하는 내용물이 같은 두 변수 비교
		//System.out.println("b1 == b4 : " + b1.equals(b4));//false -> equals() 오버라이딩 전
		System.out.println("b1 == b4 : " + b1.equals(b4));//true -> equals() 오버라이딩 후
		//오버라이딩 중요햄
		System.out.println("b1의 hashCode() : " + b1.hashCode());//
		System.out.println("b4의 hashCode() : " + b4.hashCode());// hashCode() 오버라이딩 전 둘의 값이 달랐음
		//내부의 값은 같지만, 주소는 다름 -> 동등객체 라고 한다.
		//주소도 같고 내부의 값도 같으면 -> 동일 객체라고 한다. 
		// 위의 경우는 동등객체
		
		//hashCode를 오버라이드 시켜서 둘을 동일 객체로 만들어보자
		//두 객체의 동등성과 동일성을 확보하자
		System.out.println("b1의 hashCode() : " + b1.hashCode());
		System.out.println("b4의 hashCode() : " + b4.hashCode());// hashCode() 오버라이딩 후 둘의 값이 같아졌다
		//이제 둘은 같은 객체가 된 것이다

	}

}

 

 

package com.test.part02_override.book.model.vo;

public class Book {

	private String title;
	private int price;
	private String author;
	
	
	public Book() { 	}
	
	public Book(String title, String author, int price) {
		this.title = title;
		this.author = author;
		this.price = price;
	}
    
	public String getTitle() {
		return title;
	}
	public void setTitle(String title) {
		this.title = title;
	}
	public int getPrice() {
		return price;
	}
	public void setPrice(int price) {
		this.price = price;
	}
	public String getAuthor() {
		return author;
	}
	public void setAuthor(String author) {
		this.author = author;
	}
	
    
	//1. toString() 오버라이딩
	@Override
	public String toString() {
		return title + " , " + author + " , " + price;
	}
	
    
	//2. equals() 오버라이딩
	@Override
	public boolean equals(Object obj) {
		//객체의 주소가 같으면 같은 객체이다
		if(this == obj) {
			return true;
		}
		
		//전달받은 객체가 null일 경우 무조건 다른 객체
		if(obj == null) {
			return false;
		}
		
		//Book형으로 형변환
		Book other = (Book)obj;
		
		//title
		if(title == null) {
			if(other.title != null) {
				return false;	
			}
		}
		else if(!title.equals(other.title)) {
			return false;
		}
		//author
		if(author == null) {
			if(other.author != null) {
				return false;	
			}
		}
		else if(!author.equals(other.author)) {
			return false;
		}
		//price
		if(price != other.price) {
			return false;	
		}
		
		//모든조건 통과시 두 객체는 같은 객체
		return true;
	}
	
    
	//3. hashCode() 오버라이딩
	@Override
	public int hashCode() {
		//원래는 java.lang.String의 hashCode를 내가 원하는 대로 오버리이딩 시킴
		//같은 값(문자열)을 가진 객체의 경우 같은 주소값을 갖게 되는 코드
		return (author + price + title).hashCode();
	}
	
	
}

 


 

package com.test.silsub0;

public class Main {

	public static void main(String[] args) {
		
		Car c1 = new SportsCar("노란");
		c1.accelPedal();//30증가
		System.out.println(c1);
		//객체를 부모 객체로 선언을 해도, 데이터 할당을 자식 객체로 했기 때문에 자식 객체의 메소드를 사용한다
		System.out.println("--------------------");
		
		SportsCar s1 = new SportsCar("as");
		s1.accelPedal();//30증가
		System.out.println(s1);
		
		System.out.println("--------------------");
		
		Car c2 = new SUV("검은");
		c2.accelPedal();
		System.out.println(c2);//15증가
		c2.accelPedal();
		c2.accelPedal();
		System.out.println(c2);//현재속도 45
		c2.breakPedal();
		c2.breakPedal();
		c2.breakPedal();
		c2.breakPedal();
		System.out.println(c2);//현재속도 0
	}

}

 

 

package com.test.silsub0;

public class Car {
	
	private String color;
	private int speed;
	
	
	public Car() {	}
	
	public Car(String color) {
		this.color = color;
	}
	
	public Car(String color, int speed) {
		this.color = color;
		this.speed = speed;
	}

	
	//getter setter
	public String getColor() {
		return color;
	}
	public void setColor(String color) {
		this.color = color;
	}
	public int getSpeed() {
		return speed;
	}
	public void setSpeed(int speed) {
		this.speed = speed;
	}

	
	@Override
	public String toString() {
		return "현재 속도는 " + speed + " 입니다.";
	}
	
	public void accelPedal() {
		System.out.println("속도가 올라갑니다");
		setSpeed(getSpeed() + 10);
		
	}
	
	public void breakPedal() {
		setSpeed(getSpeed() - 10);
		
		if(getSpeed() > 0) {
			System.out.println("속도가 줄어듭니다.");
		}
		else {
			setSpeed(0);
			System.out.println("멈췄습니다.");
		}
		
	}
	
	
}

 

 

package com.test.silsub0;

public class SportsCar extends Car{
	//car의 메소드와 필드를 상속 받은 상태
	
	public SportsCar() {
		System.out.println("SportsCar 생성");
	}
	
	public SportsCar(String color) {
		super(color);
		
		System.out.println(color + " 색 sportsCar 생성");
	}
	
	@Override
	public void accelPedal() {
		System.out.println("속도가 더 빨리 올라갑니다");
		super.setSpeed(super.getSpeed()+30);
	}
	
	@Override
	public void breakPedal() {
		
		super.setSpeed(super.getSpeed()-30);
		
		if(super.getSpeed() > 0) {
			System.out.println("속도가 더 빨리 감소합니다");
		}
		else {
			super.setSpeed(0);
			System.out.println("차가 멈췄습니다.");
		}
	}
	
	
}

 

 

package com.test.silsub0;

public class SUV extends Car {

	public SUV() {   }
	
	public SUV(String color) {
		super(color);
		System.out.println(color + " 색 suv 생성");
	}
	
	@Override
	public void accelPedal() {
		System.out.println("속도가 적당히 올라갑니다.");
		super.setSpeed(super.getSpeed() + 15);
	}
	
	@Override
	public void breakPedal() {
		super.setSpeed(super.getSpeed() - 15);
		
		if(super.getSpeed() > 0) {
			System.out.println("속도가 적당히 줄어듭니다.");
		}
		else {
			super.setSpeed(0);
			System.out.println("차가 멈췄습니다.");
		}
	}
	
	
}

 


다형성(Polymorphism)

 객체지향 프로그래밍의 3대 특징 중 하나로 ‘여러 개의 형태를 갖는다’ 는 의미

 하나의 행동으로 여러 가지 일을 수행하는 개념

 상속을 이용한 기술로 부모 타입으로부터 파생된 여러 가지 타입의 자식 객체를

 부모 클래스 타입 하나로 다룰 수 있는 기술

+ 상위 타입으로 하위 타입의 객체를 사용 할 수 있음

 

변수 하나가 여러 타입의 객체를 받는다

 

클래스 형변환

업 캐스팅( up casting )

 상속 관계에 있는 부모, 자식 클래스 간에 부모 타입의 참조형 변수가

모든 자식 타입의 객체 주소를 받을 수 있음

//sonata 클래스는 car 클래스의 후손

Car c = new Sonata();

//sonata 클래스 형에서 Car 클래스 형으로 바뀜

자식 객체의 주소를 전달받은 부모타입의 참조변수를 통해서 사용할 수 있는 후손의 정보는

원래 부모 타입이었던 멤버만 참조 가능

자식 -> 부모

 

다운 캐스팅(down casting)

 자식 객체의 주소를 받은 부모 참조형 변수를 가지고 자식의 멤버를 참조해야 할 경우,

 부모 클래스 타입의 참조형 변수를 자식 클래스 타입으로 형 변환하는 것

 자동으로 처리되지 않기 때문에 반드시 후손 타입 명시해서 형 변환

//sonata 클래스는 car 클래스의 후손

Car c = new Sonata();

((Sonata)c).moveSonata();

 클래스간의 형 변환은 반드시 상속 관계에 있는 클래스끼리만 가능

부모 -> 자식

 

 

instanceof 연산자

 현재 참조형 변수가 어떤 클래스 형의 객체 주소를 참조하고 있는지 확인 할 때 사용

 클래스 타입이 맞으면 true, 틀리면 false 반환

if(레퍼런스 instanceof 클래스타입) {

    //true일때 처리할 내용, 해당 클래스 타입으로 down casting

}

 

if(c instanceof Sonata) {

    ((Sonata)c).moveSonata();

} else if (c instanceof Avante)

{

    ((Avante)c).moveAvante();

} else if (c instanceof Grandure)

{

    ((Grandure)c).moveGrandure();

}

 

 

객체배열과 다형성

다형성을 이용해 상속 관계에 있는 하나의 부모 클래스 타입의 배열 공간에 여러 종료의 자식 클래스 객체 저장 가능

Car[] carArr = new Car[5];

 

carArr[0] = new Sonata();

carArr[1] = new Avante();

carArr[2] = new Grandure();

carArr[3] = new Spark();

carArr[4] = new Morning();

 

매개변수와 다형성

 다형성을 이용하여 메소드 호출 시 부모타입의 변수 하나만 사용해 자식 타입의 객체를 받을 수 있다

public void execute() {

    driveCar(new Sonate());

    driveCar(new Avante());

    driveCar(new Grandure());

}

public void driveCar(Car c) {   }

 

바인딩

 실제 실행할 메소드 코드와 호출하는 코드를 연결 시키는 것

 프로그램이 실행되기 전 , 컴파일이 되면서 모든 메소드는 정적 바인딩 됨

 

동적 바인딩

 컴파일 시 정적 바인딩된 메소드를 실행할 당시의 객체 타입을 기준으로 바인딩 되는 것

Car c = new Sonata();

c.accel(); //정적으로 바인딩 된 상태 -> 컴파일 시 객체 타입을 기준으로 바인딩 된다.

//컴파일 후 실행시 sonata의 accel()이 실행되는 모습 확인 가능

 

동적 바인딩 특징

 상속 관계로 이루어져 다형성이 적용된 경우, 메소드 오버라이딩이 되어 있으면

 정적으로 바인딩 된 메소드 코드보다 오버라이딩 된 메소드 코드를 우선적으로 실행

 

추상 클래스 ( abstract class )

 몸체 없는 메소드를 포함한 클래스

 추상 클래스일 경우 클래스 선언부에 abstract 키워드 사용

[접근제한자] abstract class 클래스명 {   }

 

추상 메소드 ( abstract method )

 몸체 없는 메소드

 추상 메소드의 선언부에 abstract 키워드 사용

 상속 시 반드시 구현해야 하는, 오버라이딩이 강제화되는 메소드

[접근제한자] abstract 반환형 메소드명(자료형 변수명);

 

추상클래스 특징

abstract 키워드를 이용해 상속받을 경우 필수적으로 만들어야 하는 친구라는 걸 명시 해야한다. 이 키워드가 붙으면 해당 메소드를 반드시 재작성 해야함

1. 미완성 클래스 ( abstract 키워드 사용 )

   자체적으로 객체 생성 불가 -> 반드시 상속하여 객체 생성

2. abstract 메소드가 포함된 클래스는 반드시 abstract 클래스

 abstract 메소드가 없어도 abstract 클래스 선언

3. 클래스 내에 일반 변수, 메소드 포함 가능

4. 객체 생성은 안되지만 참조형 변수 타입으로는 사용 가능

 

추상클래스 장점

 일관된 인터페이스 제공

 꼭 필요한 기능 강제화 (공통적이나 자식클래스에서 특수화 되는 기능)

 

인터페이스

 상수형 필드와 추상 메소드만을 작성할 수 있는 추상 클래스의 변형체

 메소드의 통일성을 부여하기 위해 추상 메소드만 따로 모아 놓은 것

 상속 시 인터페이스 내에 정의된 모든 추상 메소드를 구현 해야함

[접근제한자] interface 인터페이스명 {

    //상수도 멤버로 포함할 수 있음

    public static final 자료형 변수명 = 초기값;

 

    //추상 메소드만 선언 가능

    [public abstract] 반환자료형 메소드명([자료형 매개변수]);

    //public abstract가 생략되기 때문에

    //오버라이딩 시 반드시 public 표기해야 함

}

 

인터페이스 특징

 1. 모든 인터페이스의 메소드는 묵시적으로 public이고 abstract

 2. 변수는 묵시적으로 public static final

    따라서 인터페이스 변수의 값 변경 시도 시 컴파일 에러 발생

 3. 객체 생성은 안되나 참조형 변수로는 가능

 

인터페이스 장점

 상위 타입 역할로 다형성을 지원하여 연결

 해당 객체가 다양한 기능 제공 시에도 인터페이스에 해당하는 기능만을 사용하게 제한 가능

 공통 기능 상의 일관성 제공

 공동 작업을 위한 인터페이스 제공

 

구분

추상 클래스

인터페이스

상속

단일 상속

다중 상속

구현

extends

implements

추상 메소드

abstract 메소드 0개 이상

모든 메소드가 abstract

abstract

명시적 사용

묵시적으로 abstract

객체

객체 생성 불가

객체 생성 불가

용도

참조 타입

참조 타입

 


 

package com.poly.test01;

public class MTest {

	public static void main(String[] args) {
		Cat cat = new Cat();
		Dog dog = new Dog();
		
		cat.bark();
		dog.bark();
		
		cat.eat("참치");
		dog.eat("뼈다귀");

	}

}

 

package com.poly.test01;

public abstract class Animal {

	//추상 메소드
	//상속 시 상속 받는 class가 반드시 구현 해야한다
	public abstract void bark();
	
	//추상클래스는 일반 메소드도 생성 가능하다
	public void eat(String animal) {
		System.out.println(animal + " 먹는다.");
	}
}

 

package com.poly.test01;

public class Cat extends Animal{
	
	@Override
	public void bark() {
		//abstract 메소드 구현 필수
		System.out.println("야옹");
	}
	
	@Override
	public void eat(String animal) {
		super.eat("^" + animal + "^");
	}

}

 

package com.poly.test01;

public class Dog extends Animal{
	
	@Override
	public void bark() {
		System.out.println("멍멍");
	}
	
	@Override
	public void eat(String animal) {
		super.eat("@" + animal + "@");
	}

}

 


package com.poly.test02;

import java.util.Scanner;

public class MTest {

	public static void main(String[] args) {
		

		Scanner sc = new Scanner(System.in);

		System.out.println("선택 [ 1 고양이 , 2 송아지, 3 강아지] ");
		int select = sc.nextInt();

		Base b = null;

		switch (select) {
			case 1:
				b = new Cat();
				break;
			case 2:
				b = new Cow();
				break;
			case 3:
				b = new Dog();
				break;
		}
		
		//동적 바인딩을 통해 실행하려는 객체가 이상 없이 실행된다.
		b.start();
		b.stop();

	}

}

 

package com.poly.test02;

public abstract class Base {

	
	public abstract void start();
	public abstract void stop();
	
	
	public Base() {
		System.out.println("Base 생성");
	}
	
}

 

package com.poly.test02;

public class Cat extends Base{
	
	
	@Override
	public void start() {
		System.out.println("고양이 걷는다");
	}
	
	@Override
	public void stop() {
		System.out.println("고양이 멈췄다");
	}

}

 

package com.poly.test02;

public class Cow extends Base{
	
	
	@Override
	public void start() {
		System.out.println("송아지 걷는다");
	}
	
	@Override
	public void stop() {
		System.out.println("송아지 멈췄다");
	}

}

 

package com.poly.test02;

public class Dog extends Base{
	
	
	@Override
	public void start() {
		System.out.println("강아지 걷는다");
		
	}
	
	@Override
	public void stop() {
		System.out.println("강아지 멈췄다");
	}

}

 


package com.poly.test03;

import java.util.Scanner;

public class MTest {

	public static void main(String[] args) {
		
		Cat c = new Cat();
		c.bark();
		c.eat("참치");

		Dog d =new Dog();
		d.bark();
		d.eat("뼈다구");
	}

}

 

package com.poly.test03;

public interface Animal {

	//abstracrt 키워드 생략
	public void start();
	public void stop();
	
	public void bark();
	
	public void eat(String feed);
	
	
}

 

package com.poly.test03;

public class Cat implements Animal{
	
	
	@Override
	public void start() {
		System.out.println("고양이 걷는다");
	}
	
	@Override
	public void stop() {
		System.out.println("고양이 멈췄다");
	}

	@Override
	public void bark() {
		System.out.println("야옹");
		
	}

	@Override
	public void eat(String feed) {
		System.out.println(feed + "먹는다");
		
	}

}

 

package com.poly.test03;

public class Dog implements Animal{
	
	
	@Override
	public void start() {
		System.out.println("강아지 걷는다");
		
	}
	
	@Override
	public void stop() {
		System.out.println("강아지 멈췄다");
	}

	@Override
	public void bark() {
		System.out.println("멍멍");
		
	}

	@Override
	public void eat(String feed) {
		System.out.println(feed + "먹는다");
		
	}

}

package com.poly.test04;

public class MTest {

	public static void main(String[] args) {
		Cat c = new Cat();
		
		c.bark();
		c.eat("참치");
		
		Dog d = new Dog();
		d.bark();
		d.bite();
		
		Eagle e = new Eagle();
		e.fly();
		e.bark();
		e.eat("고기");
	}
	
}

 

package com.poly.test04;

public abstract class Animal {
	public abstract void bark();
	
	public void eat(String feed) {
		System.out.println(feed + "먹는다");
	}

}

 

package com.poly.test04;

public interface Bird {
	public void fly();
}

 

package com.poly.test04;

public class Cat extends Animal{

	@Override
	public void bark() {
		System.out.println("야옹");
		
	}
	
	@Override
	public void eat(String feed) {
		System.out.println("^" + feed +"^ 먹는다" );
	}

}

 

package com.poly.test04;

public class Dog extends Animal{

	@Override
	public void bark() {
		System.out.println("멍멍");
		
	}
	
	public void bite() {
		System.out.println("앙!");
	}

}

 

package com.poly.test04;

public class Eagle extends Animal implements Bird{

	@Override
	public void fly() {
		System.out.println("파닥파닥");
		
	}

	@Override
	public void bark() {
		System.out.println("꿰에엑");
		
	}

}

package com.poly.test05;

public class MTest {

	public static void main(String[] args) {
		Lg_tv l = new Lg_tv();
		
		System.out.println("lgTv 소리 키움 " + l.volUp());
		System.out.println("lgTv 소리 줄임 " + l.volDown());
		
		l.setVol(30);
		
		System.out.println("lgTv 소리 키움 " + l.volUp());
		System.out.println("lgTv 소리 줄임 " + l.volDown());
		l.tvClosed();
		
		
		Samsung_tv s = new Samsung_tv();
		System.out.println("Samsung_tv 소리 키움 " + s.volUp());
		System.out.println("Samsung_tv 소리 줄임 " + s.volDown());
		s.tvClosed();

		
	}

}

 

package com.poly.test05;

public interface Tv {
	
	int volUp();
	int volDown();
	
	//lg tv(+1, -1) 와 samsung tv(+3, -3) 을 만들어서
	//볼륨 업 다운 완성
	
	
	//생성자 호출 시 "tv가 켜졌습니다."
	//tvClosed , "tv가 꺼졌습니다."

}

 

package com.poly.test05;

public class Lg_tv implements Tv{

	private int vol;
	
	public Lg_tv() {
		System.out.println("LG tv가 켜졌습니다.");
	}
	
	public void tvClosed() {
		System.out.println("LG tv가 꺼졌습니다.");
	}
		

	public int getVol() {
		return vol;
	}

	public void setVol(int vol) {
		this.vol = vol;
	}

	@Override
	public int volUp() {
		setVol(getVol() +1);
		
		return getVol();
	}

	@Override
	public int volDown() {
		setVol(getVol() -1);
		
		return getVol();
	}
	
}

 

package com.poly.test05;

public class Samsung_tv implements Tv{

	private int vol;
	
	public Samsung_tv() {
		System.out.println("Samsung_tv가 켜졌습니다.");
	}

	public void tvClosed() {
		System.out.println("Samsung_tv가 꺼졌습니다.");
	}

	public int getVol() {
		return vol;
	}

	public void setVol(int vol) {
		this.vol = vol;
	}
	
	@Override
	public int volUp() {
		setVol(getVol() +10);
		
		return getVol();
	}

	@Override
	public int volDown() {
		setVol(getVol() -10);
		
		return getVol();
	}
}