[JAVA] Day 13 - 인터페이스 / 자료형(기본형/참조형) / instance of / 다형성

sue·2023년 11월 30일
0

📒국비학원 [JAVA]

목록 보기
10/20
post-thumbnail

인터페이스 (Interface) :

여러 클래스가 같은 규칙을 따르게 하여 일관성있게 만드는 설계도

  • interface와 class는 각각 한 파일씩 만들어야하는게 정석임 (편의상 하나의 파일안에 같이 만들 수 있음)
  • 자료형.변수 = X일 땐, public static fianl(=상수)가 생략됨.
  • 추상클래스 의 일종 / 정의만 있고 구현은 자식 클래스에서 해야함
  • 변수 : static fianl(=상수)만 정의할 수 있음
  • 하나 이상의 Interface를 implements클래스인터페이스의 모든 메소드를 Override(재정의)해야함. (강제성 - 무조건 부모꺼 메소드 다 Override해야함)
  • Interface가 다른 Interface를 상속받을 수 있음. (이때, extends를 사용)
  • 클래스와는 다르게다중구현이 가능함 (ex, class FruitImpl implements Fruits, bucket, person)
  • 인터페이스 내 변수,메서드는 자동으로 특정한 접근 제어자들이 할당- (public static final)
  • 인터페이스 내 선언된 메서드는 자동으로 public abstract이 생략되어있음
  • 자식이 독자적으로 가지고 있는 메서드는 부모는 못씀

자료형?

: 데이터 종류 분리 (기본형 / 참조형)

  • 기본형 : (int,boolean,double...) 메모리에 직접 값 저장 / 값에 대해서 직접적인 접근 가능
  • 참조형 : (class, Interface, array[], instance, Sting...) Object 객체를 다루기 위한 데이터 타입 -> 객체가 어딘가 메모리에 저장되어 있는데, 이 객체를 활용해서 값을 변경할 때는 저장된 주소를 통해 변경 / 실제 값이 저장된 *메모리 주소

Java의 모든 클래스는 암묵적으로 가장 큰 부모인 Object 클래스를 상속받음.

=> 모든 객체는 Object 클래스의 멤버를 상속받을 수 있음.
이 중에서 equals 메서드도 Object클래스임.
if 어떤 클래스에 다른 클래스를 상속받지 않아보이면 -> 컴파일러는 자동으로 Object를 상속받도록 함. (생략가능)
ex) public class Test1 { = ublic class Test1 extends Object{


🔎 [Eclipse] - [package] - [class] 생성


📌 Note Code


  • TestA와 TestB 둘다 클래스임 (=자료형) / 자료형에 자료형을 넣는건 불가능
  • 자료형 - ① 기본형(int,boolean,double...) ② 참조형 (String - 문자열,배열 - [])
  • 상속관계 (부모 <-> 자식) [O]
    int <-> Integer (같은 자료형)관계 [O]
    남남은 어떠한 방법으로도 사용불가능 [X] (사용하려면 객체생성밖에 방법이 없음)



1. TestA와 TestB의 변수는 서로 대입 못하는가?

Test1

💻 입력

class Test {

class TestA{
	public void print() {
		System.out.println("A 클래스");
	}
}

class TestB{
	public void print() {
		System.out.println("B 클래스");
	}
}


public class Test1 {

	public static void main(String[] args) {

		
		TestA a = new TestA();
		TestB b; 
		TestA c;
		
		c=a;
		
		//b=a; , X
		//b = (TestB)a; , TestA,B는 서로 남남이기때문에 대입 X

	}

}



📌 Note Code


  • 부모랑 자식이랑 같은 메서드를 가지고 있다해도 -> 부모는 자식꺼 사용 불가능 & 자식꺼 무조건 사용
  • 생성자를 찾으러가면 자식 안에 super();가 있음 -> 부모 SuperTest의 생성자 찾으러가서 (오버로딩된 생성자 업으니_기본생성자) -> super 찾음 그러면 부모 object 찾으러감 -> 거꾸로 생성자 읽고 읽고 읽어서 상속 + 객체생성 성립
  • 암시적형변환 : 데이터 타입간의 변환 / 큰 ← 작은 데이터 타입으로 형변환(=Upcast - 무조건 상속관계에서만 성립 / 데이터 손실 x)



2. 메서드 / 상속 / Upcast / Downcast을 활용해서 출력하기

Test2

💻 입력


class SuperTest{
	
	public int a = 10, b = 20;

	public void write() {
		System.out.println("부모클래스 write()");
	}

	public int hap() {
		return a + b ; 
	}

}

class SubTest extends SuperTest {

	public int b = 100, c = 200;

	public void print() {
		System.out.println("자식클래스 print()");
	}

	@Override
	public int hap() {
		return a + b + c;
	}
	
}

public class Test2 {

	public static void main(String[] args) {

		SubTest ob1 = new SubTest(); 
		
		System.out.println(ob1.b);
		
		SuperTest ob2 = ob1; //부모화, upcast (암시적형변환)
		
		System.out.println(ob2.b);
		
		System.out.println("합: "+ob2.hap()); //부모화했더라도 메서드는 (오버라이드한)자식꺼 씀 
		
		ob2.write();
	
		//ob2.print(); 부모.자식이라서 에러
		((SubTest)ob2).print(); // (자식화)print(); = downcast
	}

}


💡 **출력**
100
20
합: 310
부모클래스 write()
자식클래스 print()



📌 Note Code


  • 자료형.변수 = X일 땐, public static fianl(=상수 : 모든 인스턴스에서 동일한 값을 가짐)가 생략됨.
    why? Interface는 자식이 오버라이드할거라서 가져다 써야하는데, final이 붙으면 자식이 못가져다가 쓰니까
  • class가 상속하려고 할땐 implements 사용
  • 오버라이드시 무조건 public이 붙음



3. Interface를 활용해서 과일종류와 가격을 출력하여라

Test3

💻 입력


interface Fruits{

	String Won = "원"; // (public static final - 생략) String Won = "원";

	//public abstract 생략
	int getPrice(); 
	public String getName();
	
}

class FruitImpl implements Fruits { //FruitImpl = 가독성을 위해 클래스 이름 => implements 구현 했다는 뜻
	
	@Override
	public int getPrice() {//오버라이드시 무조건 public이 붙음 (자식꺼)
		return 1000;
	}

	@Override
	public String getName() {
		return "사과";
	}
	
	public String getItems() {//독자적 (자식만 사용)
		return "과일";
	}
	
}

public class Test3 {

	public static void main(String[] args) {

		FruitImpl ob1 = new FruitImpl();
		
		System.out.println(ob1.getItems());
		System.out.println(ob1.getName());
		System.out.println(ob1.getPrice()+Fruits.Won); // won = static변수를 부를때 class이름을 붙인다!!!
		
		Fruits ob2 = ob1; //upcast (부모 <- 자식)
		System.out.println(ob2.getName()); //원랜 부모지만 무조건 자식꺼 출력
		//System.out.println(ob2.getItem()); 불가능 - 자식클래스에서 독자적으로 사용하므로
	}

}


💡 **출력**
100
20
합: 310
부모클래스 write()
자식클래스 print()



📌 Note Code


  • 기본생성자 + 오버로딩 생성자 둘다 꺼내면 둘 중 하나로 객체생성하겠음 / 오버로딩 생성자만 꺼내놓으면 오버로딩생성자로만 객체 생성하겠음

  • 기본 생성자

public TestImpl() {
		
	}
	
  • 생성자 오버로딩 (생성과 동시에 값을 초기화시킴)
public TestImpl (String hak,String name,int kor,int eng) {
		this.hak = hak;
		this.name = name;
		this.kor = kor;
		this.eng = eng;
	}
  • 기본 생성자(생성자오버로딩x) + public void set( ) 메서드 만들기
    why?
    나중에 객체의 데이터값을 변경(값 초기화)해주고싶으면, private때문에 우회접근이 필요하니까
    ② 외부에서 객체의 데이터를 변경하려면, set 메서드와 같은 메서드를 제공
public void set(String hak,String name,int kor,int eng) {
		this.hak = hak;
		this.name = name;
		this.kor = kor;
		this.eng = eng;
	}
  • Java의 모든 클래스는 암묵적으로 가장 큰 부모인 Object 클래스를 상속받음.
    => 모든 객체는 Object 클래스의 멤버를 상속받을 수 있음.
    이 중에서 equals 메서드도 Object클래스임.
  • ob1.equals(ob2) = TestImpl 클래스에서 오버라이딩된 equals 메서드를 호출하게 되는 것이 아니라, Object 클래스의 equals 메서드를 호출



4. 주소번지에 있는 데이터값을 비교하여 동일인물인지 출력하여라

Test4

💻 입력


interface Test{
	
	//instance(전역변수) 초기값 = 0,null - 기본적으로 각각의 초기값을 갖음
	//abstract 무조건 생략
	public int total(); // - int 타입이므로 아래 오버라이드도 int타입으로 입력해야함
	public void write();
	
}

class TestImpl implements Test{

	private String hak,name;
	private int kor,eng;
	
    //기본생성자
	public TestImpl() {
		
	}
	
	//우회도로
	//생성자 오버로딩 : 생성 즉시 값을 초기화 함
	public TestImpl(String hak,String name,int kor,int eng) {
		this.hak = hak;
		this.name = name;
		this.kor = kor;
		this.eng = eng;
	}
    
	//우회도로
	//기본 생성자 + set메서드 : 나중에 데이터 값 초기화 하기 위함
	public void set(String hak,String name,int kor,int eng) {
		this.hak = hak;
		this.name = name;
		this.kor = kor;
		this.eng = eng;
	}
	
	
	@Override
	public int total() {
		return kor+eng;
	}

	@Override
	public void write() { 
		System.out.println(hak+","+name+","+total());
	}


	
    //Object ob=ob2 (부모 = 자식 , upcast)
    //주변에 반드시 object 있음
    
	@Override
    public boolean equals(Object ob) { //Object의 메서드를 오버라이딩 함
		
		boolean flag = false; // boolean의 초기값 = false , 지역변수 초기값 = 쓰레기값
		
		if(ob instanceof TestImpl) {// instanceof = ob가 쓰고있는 순수 태생이 TestImpl이니?
		
			TestImpl t = (TestImpl)ob; //자식으로 바꿔서 넣어라 = downcast= 형변환해서 넣어
			
			// ob1.hak과  (string타입 =>equals로 비교- 주소비교)(ob2.hak) 데이터값이 같냐 = 같다
			// &&  t = ob2. / this = ob1
			
			//equals = [hak과 name]string의 equals
			if(this.hak.equals(t.hak) && t.name.equals(this.name)) {
				flag = true;
			}

		}
		
		return flag;
	}
	
	// = public boolean equals(Object ob) {	}
	
	
	
}


public class Test4 {

	public static void main(String[] args) {

		TestImpl ob1 = new TestImpl("2015105","배수지",80,90); //생성자 오버라이드
		TestImpl ob2 = new TestImpl("2015105", "배수지", 100, 100);
		
		//ob1 안에 있는 equals 위로 찾아가서 매개변수 ob2를 넣으라는 뜻 equals(Object ob2가 되므로 upcast)
		if(ob1.equals(ob2)) { //true
			
			System.out.println("ob1과 ob2는 동일인물임");
		}else {
			System.out.println("ob1과 ob2는 동일인물이 아님");
			
		}
		
		ob1.write();
		ob2.write();
	}

}


💡 **출력**
ob1과 ob2는 동일인물임
2015105,배수지,170
2015105,배수지,200



📌 Note Code




5. 다형성을 활용해 과일 종류와 가격을 출력하여라

Test5

💻 입력


import java.util.Scanner;

interface FruitA{
	
	String Won = "원"; // public static abstract가 생략이 되어있음
	
	public int getPrice();
	public String getName();
	

}


interface ItemFruit extends FruitA{ 
	
	public String getItems();
	
}

class Orange implements ItemFruit{ //일반 class가 interface를 구현하려면 implements   //상속되면 다 누적되니까~ Itemfruit는 위에 fruitA를 상속받기때문에

	@Override
	public int getPrice() {
		return 1000;
	}

	@Override
	public String getName() {
		return "오렌지";
	}

	@Override
	public String getItems() {
		return "과일";
	} 
	
}

class Apple implements ItemFruit{

	@Override
	public int getPrice() {
		return 2000;
	}

	@Override
	public String getName() {
		return "사과";
	}

	@Override
	public String getItems() {
		return "과일";
	}
	
}



public class Test5 {

	//인스턴스메서드
	public void packing(ItemFruit ob) { // 이유? 아래 86-89 코딩이 똑같으므로 한메서드 만들고 거기서 빼서 쓰게끔
		
		System.out.println(ob.getItems());
		System.out.println(ob.getName());
		System.out.println(ob.getPrice()+FruitA.Won);
	}
	
	
	
	public static void main(String[] args) {

		Scanner sc = new Scanner(System.in);
		
		Test5 t = new Test5(); //인스턴스메서드라 객체생성해야함
		//주소를 대입연산자로 넣어놓기만 함
		
		System.out.println("1.사과 2.오렌지?");
		int n = sc.nextInt();
		
		if(n==1) {
			t.packing(new Apple()); //new 주소를 올려놓음 -> ob.getItems()에서 찾아서 씀 / 메모리에 올려놓고 10번지 = ob에 넣어놓게됨
		}else if (n==2) {
			t.packing(new Orange());
		}

		
		
		//Orange ob2 = new Orange();
		//ItemFruit ob1; //부모
		//ob1 = ob2; //부모<-자식 (upcast)
	
		/*---------------------------------------
		ItemFruit ob; 
		ob= new Orange();//upcast를 통해 객체 생성 - 부모의 이름으로 객체 생성할때 
		//부모 메서드 = 자식 메서드 똑같아야함 (자식이 독자적으로 하나 더 있어도 에러남)
		
		System.out.println(ob.getItems());
		System.out.println(ob.getName());
		System.out.println(ob.getPrice()+FruitA.Won);
		System.out.println("----------------------------");
		
		
		//Apple ob2 = new Apple();
		
		ob = new Apple(); //변수의 이름은 중요치않음
		
		System.out.println(ob.getItems());
		System.out.println(ob.getName());
		System.out.println(ob.getPrice()+FruitA.Won);
		System.out.println("----------------------------");
		
		
		//--------------line 91부터와 똑같은 구조
		
		int a;
		a=10;
		System.out.println(a);//a출력하고나면 보존할 필요 없음
		
		
		a=20;//덮어씀
		System.out.println(a);
		*/
		
	}

}


💡 **출력**
1.사과 2.오렌지?
2
과일
오렌지
1000원


0개의 댓글