[JAVA]_중간고사 대비

전희주·2023년 4월 14일
1

JAVA

목록 보기
13/24

💖 O/X 출제 예상

O/X

  • 추상클래스의 추상메서드는 반드시 abstract 지정필수
  • 추상 클래스를 상속받는 자식 클래스에서는 추상 클래스의 추상 메서드를 구현해야 하며, 구현하지 않는다면 컴파일러가 오류 발생. (✨ 추상 메서드 재정의 필수) (O)
  • 추상 클래스라고 해서 반드시 추상메서드를 가지고 있는 것은 아님. (역은 성립) (O)
  • 추상 클래스에는 최소한 하나의 추상 메소드가 있어야 한다 (X)
  • 추상 메소드가 있더라도 해당 클래스가 꼭 추상 클래스가 될 필요는 없다 (X)
  • 추상 클래스는 직접 new 연산자로 객체를 생성할 수 없다. (O)
  • 추상 클래스는 부모 클래스로만 사용된다. (O)
  • 추상 메소드는 선언부만 있고, 실행 블록을 가지지 않는다 (O)
  • 추상 메소드는 자식 클래스에서 재정의해서 실행 내용을 결정해야 한다 (O)
  • 추상 메소드를 재정의하지 않으면 자식 클래스도 추상 클래스가 되어야 한다 (O)
  • 부모의 생성자와 private로 선언된 객체에 대해서는 상속이 불가능.(O)
  • 클래스에서 클래스로 다중 상속은 불가능. 단일 상속만 가능.(O)
  • 인터페이스에서 인터페이스로 다중 상속은 가능. (O)
  • 클래스에 여러 인터페이스 다중 구현 가능. (O)
  • 정수 타입 필드는 0, 실수 타입 필드는 0.0, boolean 필드는 false로 초기화 (O)
  • 참조 타입은 객체를 참조하고 있지 않은 상태인 null로 초기화 (O)
  • 참조변수의 메모리 생성 위치는 스택이다 (O) (stack)
    • 변수는 스택 영역에, 객체는 힙 영역에 저장된다.
  • NullPointerException은 초기화되지 않은 참조 변수에서 발생한다 X
    • (NULL로 초기화된 참조변수가 있지도 않은 객체의 데이터(필드)나 메소드를 사용할 시 발생)
  • 필드 사용: 클래스 내부의 생성자와 메소드에서는 바로 사용이 가능하나, 클래스 외부에서 사용할 경우에는 반드시 객체를 생성하고 참조 변수를 통해 사용해야 한다. (O)
  • 클래스에 명시적으로 선언한 생성자가 1개라도 있으면, 컴파일러는 기본 생성자를 추가하지 않음. (O)
  • 생성자의 오버로딩 => 매개변수의 타입, 개수, 순서가 다르게 선언
    • 매개변수의 타입, 개수, 선언 순서가 같을 경우, 단순히 매개 변수의 이름만 바꾸는 것은 생성자 오버로딩이 아니다 (O)
  • 객체를 생성하려면 생성자 호출이 반드시 필요한 것은 아니다. (X)
  • 생성자는 다른 생성자를 호출하기 위해 this() 를 사용할 수 있다. (O)
  • 매개값의 타입( byte )과 매개 변수의 타입 (int)이 달라도, byte는 int로 자동 타입 변환되기 때문에, 컴파일 에러가 발생하지 않는다. (O)
  • 리턴 타입만 다르고 매개 변수가 동일하다면 오버로딩 메서드가 아니다 (O)
  • 인스턴스 필드는 생성자에서 초기화될 수 없다 (X)
  • final 필드와 상수는 생성자에서 초기화될 수 있다 (X)
  • default 접근 제한은 해당 클래스 내부에서만 사용을 허가한다 (X)
    • 동일 패키지 내 접근 허용
  • public, protected, default, private 순으로 접근이 강화된다 (O)
  • protected 접근 제한은 default와 달리, 다른 패키지에 속한 클래스가 해당 클래스의 자식 클래스라면 호출할 수 있다 (O)
  • final 클래스, final 필드, final 메소드는 모두 상속과 관련이 있다 (X)
  • final 메소드를 가진 클래스는 부모 클래스가 될 수 없다 (X)
  • 부모 메서드를 자식 클래스에서 재정의시, 접근 제한을 더 강하게 정의할 수 없다 (O)
  • 부모 클래스에 기본 생성자가 없고 매개변수가 있는 생성자만 있다면, 자식 생성자에서 반드시 부모 생성자 호출을 위해 super(매개값...)를 명시적으로 호출해야 한다 (O)
  • 모든 객체는 클래스의 생성자를 호출해야만 생성되며, 부모 생성자는 자식 생성자의 맨 첫 줄에서 호출된다 (O)
    • 부모의 기본 생성자가 명시적으로 선언되지 않았다면 컴파일러는 기본 생성자를 생성
  • 자식 객체는 부모 타입으로 자동 타입 변환된다 (O)
  • 부모 객체는 항상 자식 타입으로 강제 변환된다 (X)
  • 자동 타입 변환을 이용해서 필드와 매개변수의 다형성을 구현한다 (O)
  • 강제 타입 변환 전에 instanceof 연산자로 변환가능한지 검사하는 것이 좋다 (O)
  • 부모 타입으로 자동 타입 변환된 이후에는 부모 클래스에 선언된 필드와 메서드만 접근이 가능하다 (O)
  • 모든 부모 타입을 자식 타입으로 강제 변환할 수 있는 것은 아니다 (O)
    • 자식 타입이 부모 타입으로 자동 타입 변환한 후, 다시 자식 타입으로 변환할 때 강제 타입 변환을 사용할 수 있다.
    • 강제 타입 변환은 자식 타입이 부모 타입으로 변환되어 있는 상태서만 가능하기에, 처음부터 부모 타입으로 생성된 객체는 자식 타입으로 변환할 수 없다.
    • 자식타입 변수 = (자식타입) 부모타입 ;
  • 자식은 부모 타입으로 자동 타입 변환이 될 수 있고, 메소드가 재정의되어 있을 경우 재정의된 자식 메소드가 호출되는 다형성이 특징이 존재한다. (O)
  • 인터페이스 타입의 로컬 변수는 선언할 수 없다 (X)
  • 구현 객체가 인터페이스 타입으로 변환되는 것은 자동타입변환에 해당 (O)
  • 정적 멤버 클래스는 바깥 클래스의 객체가 없어도 사용될 수 있다 (O)
  • 로컬 클래스는 static 키워드를 이용해서 정적 클래스로 만들 수 있다 (X)
  • final 특성을 가진 매개 변수나 로컬 변수만 로컬 클래스 내부에서 사용할 수 있다(O)

  • 자바 프로그램 개발 과정
    • 1) 소스파일 작성 (.java)
    • 2) javac 명령러로 컴파일 수행
    • 3) java 명령어로 실행
    • 4) 실행 결과 확인
  • 문자열 안에는 주석을 만들 수 없다 (O)
  • 기본적으로 소스파일과 바이트코드 파일이 저장되는 폴더가 다르다 (O)
  • JDK 버전과는 상관없이 module-info.java 파일이 필요하다 (X)
  • 자동 형 변환/ 강제 형 변환
    • 자동 형 변환: 작은 타입이 큰 타입으로 저장될 때 발생 (O)
    • 강제 형 변환: 큰 타입을 작은 타입으로 쪼개어 저장할 때 발생 (O)
  • char 타입의 (+)의 허용 범위가 short 타입보다 더 큼 (O)
    • char 자료형은 0부터 65535까지의 값을 표현
  • 문자열을 char 타입으로 강제 형 변환할 수 없음 (O)
  • byte 끼리의 연산 결과는 int (O)
  • short 끼리의 연산 결과는 int (O)
  • 형식 문자열에 포함될 값이 2개 이상일 경우에는 값의 순번($)을 알려주어야 한다 (O)
    • System.out.printf("이름: %1$s, 나이: %2$d", "김자바", 25);
  • 연산식은 하나 이상의 값을 산출할 수도 있다 (X)
  • 컴파일 에러 발생
    • byte b = 5;
    • b = - b ; // (부호 연산을 하므로 결과는 int 타입이 되는데, byte에 저장하려고 해서 오류)
  • switch 문에서 사용할 수 있는 변수의 타입은 int 만 가능하다 (X)
    • char, String도 가능
  • String은 클래스이므로 참조타입이다. (O) (객체)
  • 큰타입과 작은타입의 연산은 큰타입으로 반환 (O)
  • int보다 작은 자료형의 연산 결과는 int (O)
  • 인스턴스 변수/static 변수와 로컬 변수는 같은 변수명을 사용할 수 있다.(O)
  • 객체(인스턴스)는 힙에 할당되고, 참조형 변수는 해당 객체(인스턴스)의 주소를 참조하기 때문에 스택에 할당된다.(O)
  • 인스턴스 변수: 힙 영역 (Heap) 할당 (O)
  • final 메소드를 가진 클래스는 부모 클래스가 될 수 없다 (X)
  • final 클래스는 final 필드가 반드시 있어야 한다 (X)
  • static 메서드에서 주의할 점은 인스턴스 변수, this 사용불가 (O)
    • ==> 이유는 아직 생성 안됨.
  • static 변수(클래스 변수), 프로그램 실행 시 method area에 생성, 단 한번 생성 (O)

💖 실습 출제 예상

call by value, call by reference 실습

package p07;


class Cat{
	
	// 필드 입력 
	String name;
	int age;
	
	// 생성자 입력 
	public Cat(String name, int age) {
		this.name = name;
		this.age = age;
		System.out.println("Cat 생성자");
	}
}//end Cat


class Test3{
	
	// 메서드 입력 
	// call by value
	public void a(int n) {
		n = 100;  
	}
	
	/* call by value reference
	 
    	public void a(int[] arr, int index, int value) {
        	arr[index] = value;
    	}
    
	 */
	
	// call by value reference
	public void b(Cat x) {
		x.age = 20;
	}
}

// 핸들링 클래스 
public class TestMain {
	public static void main(String[] args) {
		
		// 필드 입력
		int num = 10;
		
		//기본형 처리
		System.out.println("메서드 호출전, 원본 값 출력:" + num); // 10
		
		// 메소드 호출 위한 객체 생성 
		Test3 t = new Test3();
		t.a(num); // call by value ( 원본에 영향이 없다. )
		System.out.println("메서드 호출후, 원본 값 출력:" + num); // 10
     //####################################################################		
		
		// 메소드 호출 위한 객체 생성 
		// 참조형
		Cat c = new Cat("야옹이", 2);
		//참조형 처리
		System.out.println("메서드 호출전, Cat의 age 값 출력:" + c.age);  // 2
		t.b(c);  // call by value reference ( 파라미터에 참조형 변수(주소)를 전달)
		System.out.println("메서드 호출후, Cat의 age 값 출력:" + c.age);  // 20
	}
}




this 실습

package p02;

public class Cat {

	String name;
	int age;
	String sex;
	
	public Cat() {
		this("야옹",2); //반드시 첫라인
		System.out.println("Cat 기본생성자");
	}

	public Cat(String name, int age) {
		// 오버로딩 생성자 호출 this( 인자리스트)   
		//  Cat 클래스의 생성자 중에서 이름, 나이, 성별을 모두 인자로 받는 다른 생성자를 호출하는 코드
		this(name, age, "암컷"); //반드시 첫라인
		System.out.println("Cat (String name, int age) 생성자");
	}


	
	public Cat(String name, int age, String sex) {
		//인스터스 변수 이름과 로컬 변수 이름이 동일한 경우 →   this.변수명
		this.name = name;
		this.age = age;
		this.sex = sex;
		//System.out.println("String name, int age, String sex");
	}
	
	
	
	
}

2차원 배열 출력 실습

package exam02;

public class ArrayTest6 {

	public static void main(String [] args) {
		
		for (String s : args) {
			System.out.println(s);
		}
		
		
		
		// 2차원 배열 출력 실습 
		int[][] arr;
		arr = new int [][] {{1, 2}, {3, 4}, {5, 6}};

		for (int i = 0; i < arr.length; i++) {
		    for (int j = 0; j < arr[i].length; j++) {
		        System.out.print(arr[i][j] + " ");
		    }
		    System.out.println();
		}
		System.out.println();
		
		int[][] arr2;
		arr2 = new int [][] {{1, 2, 3}, {4, 5, 6}, {7, 8, 9}};

		for (int[] i2 : arr2) {
		    for (int j2 : i2 ) {
		        System.out.print(j2 + " ");
		    }
		    System.out.println();
		}

		
	}
}

instanceof 실습 (고양이 나이만 확인)


package p05;

public class TestPet2 {

	public static void main(String[] args) {

		// 배열
		Pet [] pets = { 
						new Cat("야옹1", "암컷", 2),
						new Dog("망치1","암컷",4, "불독"),
						new Cat("야옹2", "암컷", 2),
				        new Dog("망치2","암컷",1, "치와와"),
				        new Cat("야옹3", "암컷", 2)
				      };
		
		for (Pet pet : pets) {
			System.out.println(pet.getPet()); // 동적바인딩
		}
		System.out.println();
		
		//고양이만 출력하시오? ==>  (변수 instanceof 타입) 연산자
		for (Pet pet : pets) {
			if(pet instanceof Cat) {
				System.out.println("Cat:" + pet.getPet()); 
			}
		}
	
		System.out.println();
		//고양이의 age 만 출력하시오 ? ==> instanceof + 형변환
		for (Pet pet : pets) {
			if(pet instanceof Cat) {
				Cat c = (Cat)pet;
				System.out.println("Cat 나이:" + c.getAge()); 
			}
		}
		/////////////////////////////////////////////////////////////
		System.out.println();
		// 고양이만 출력 다른 표기 
		for (Pet pet  : pets) {
			if (pet  instanceof Cat) { // x가 Cat 클래스의 인스턴스인지 확인
				System.out.println("Cat:" +((Cat) pet ).getPet()); // Cat 타입으로 캐스팅하여 getPet() 사용
					}
		}
				
		System.out.println();
		// 고양이의 age 만 출력	 다른 표기 
		for (Pet pet  : pets) {
			if (pet  instanceof Cat) { // x가 Cat 클래스의 인스턴스인지 확인
				System.out.println("Cat 나이:" +((Cat) pet ).age); // Cat 타입으로 캐스팅하여 age 필드 사용
					}
				}
	}
}
  • Cat c = (Cat) pet; 형 변환 이유
    • pet 변수가 Cat 클래스 타입의 객체를 참조하고 있다는 것은, Cat 클래스가 Pet 클래스의 자식 클래스이기 때문에 가능
    • 그러나 pet 변수는 Pet 클래스 타입으로 선언되어 있기 때문에, Cat 클래스의 멤버인 getAge() 메서드를 직접 호출할 수는 없음.
    • 따라서 pet 변수를 Cat 클래스 타입으로 형변환하여 getAge() 메서드를 호출해야 함.
    • 이렇게 하면 pet 변수가 참조하는 객체가 Cat 클래스의 인스턴스라는 것이 보장되기 때문에, getAge() 메서드를 호출할 수 있게 됨.

💖 Workshop 오답 노트 및 출제 예상

public class ArrayTest09 {
	public static void main(String[] args) {

        int[] arr3 = new int[5];
        int randNum = 0; 
        int sum = 0; 		// 총합계산을 위한 변수

        // continue를 이용한 방법
        top :
        for(int i =0 ; i < 5; ) { 
            randNum  = (int)(Math.random()*10 +1);

            //같은 값이 들어있는지 비교하기 위한 for
            for (int j = 0; j <= i; j++) {        
                
                //같은 값이 있으면 다시 난수 발생시킨다.
                if(randNum == arr3[j]) {
                    continue top;
                }
            }

            //같은 값 없으면 배열에 값 넣어줌
            //넣어주고 다음 배열 위치로 넘어감
            arr3[i] = randNum; 
            i++;
        }



        // 결과의 출력
        for(int k : arr3) {
            System.out.print(k + " ");
            sum += k;
}
        System.out.println();
        System.out.println("sum = " + sum);        
        System.out.println("avg = " + ( (double)sum/ arr3.length ) );        
    }
}
  • 배열 최댓값 구하기
//다음과 같이 제공된 배열에서 최대값과 최소값을 구하는 코드 작성.
//   int [] score= {99,34,67,22,11,9};
import java.util.Random;
import java.util.Scanner;

public class ArrayTest07 {
	public static void main(String[] args) {

		Random ran = new Random();
		Scanner scan = new Scanner(System.in);

		System.out.println("키의 최댓값을 구합니다.");
		System.out.print("사람 수 : ");
		int num = scan.nextInt();				

		int[] height = new int[num];			

		for (int i = 0; i < num; i++) {			
			height[i] = 100 + ran.nextInt(90);
			System.out.println("사람 " + (i+1)+": " + height[i]);
		}
		int max = height[0];
		for (int i = 1; i < height.length; i++)
			if (height[i] > max) {
				max = height[i];
			}
		System.out.println("최댓값은 " + max + "입니다.");
	}
}

  • 2차원 배열 요소 역으로 출력

public class ArrayTest05 {
	public static void main(String[] args) {

		int[][] arr = { { 20, 30, 10 }, { 50, 40, 60 }, { 80, 80, 90 } };
		for (int i = arr.length - 1; i >= 0; i--) {
			for (int j = arr[i].length - 1; j >= 0; j--) {
				System.out.print(arr[i][j] + " ");
			}
		}
	}
}
import java.util.Scanner;
Scanner scanner = new Scanner(System.in);
//추가 기능에 해당되는 메서드 지정
	//검증 작업
	// 은닉화(encapsulation)
	private boolean ageCheck(int age) {
		boolean result = false;
		if(age > 0 && age < 20) {
			result = true;
		}
		return result;
	}
	
	public void setAge(int age) {
		//검증작업
		if(ageCheck(age)) {
			this.age = age;			
		}else {
			System.out.println("입력 age 값 다시 확인 필요");
		}
	}
  • 중첩 클래스
package p01;

class Outer{
	
	public int n = 10;
	protected int n2 = 20;
	int n3 = 30;
	private int n4 = 40;
	static int n5 = 50;
	
	
	public void a() {
		Inner inner = new Inner(); // 로컬 클래스 
		inner.b();
	}
	
	// 인스턴스 멤버 클래스 
	// Member Inner Class
	
	class Inner{
		int x = 10;
		//static int k = 10;  // static 사용 불가
		public void b() {
			System.out.println(n);
			System.out.println(n2);
			System.out.println(n3);
			System.out.println(n4);  // private 접근 가능
			System.out.println(n5);
			System.out.println(x);
		}
	}//end Inner
	
}//end Outer



public class TestMain {
	public static void main(String[] args) {
		// Inner 사용 방법 1 - Outer생성하고 outer의 메서드 이용해서 Inner를 사용할 수 있다.
		Outer outer = new Outer();
		// 로컬 클래스 객체 생성을 위한 메소드 호출 (메소드 실행해야만 사용) 
		outer.a();
		System.out.println();
		
		// Inner 사용 방법 2 - 직접 호출
		Outer outer2 = new Outer();
		// 인스턴스 멤버 클래스 객체 생성 (Outer 객체 생성해야만 사용)
		Outer.Inner inner = outer2.new Inner();
		inner.b();
		
		
	}

}
package p02;

class Outer{
	public int n = 10;
	protected int n2 = 20;
	int n3 = 30;
	private int n4 = 40;
	static int n5 = 50;
	
	public void a() {}
	//Member Inner Class
	static class Inner{
		int x = 10;
		static int k = 10;  // static 사용 불가
		public void b() {
//			System.out.println(n);
//			System.out.println(n2);
//			System.out.println(n3);
//			System.out.println(n4);  // private 접근 가능
			System.out.println(n5);
			System.out.println(x);
		}
	}//end Inner
}//end Outer
public class TestMain {
	public static void main(String[] args) {
	
		// Outer 생성할 필요가 없음.
		Outer.Inner inner = new Outer.Inner();
		inner.b();
		
		
	}

}
  • 익명 클래스
package p03;

interface Flyer{
	public abstract void a();
}
//이름있는 클래스
class Bird implements Flyer{
	@Override
	public void a() {
		System.out.println("Bird.a()");
	}
}
public class TestMain {
	public static void main(String[] args) {
		//이름있는 클래스
		Flyer f = new Bird();
		f.a();
		
		//익명 클래스 (이름없는 클래스, anonymous class)
		Flyer f2 = new Flyer(){
			@Override
			public void a() {
				System.out.println("Anonymous.a()");
			}
		};
		f2.a();
		
		Flyer f3 = new Flyer() {
			@Override
			public void a() {
				System.out.println("Anonymous22.a()");
			}
		};
		f3.a();
		
		
	}
}
  • 익명 클래스 람다 표현식
package p01;

@FunctionalInterface
interface Flyer{
	public abstract void a();
}
@FunctionalInterface
interface Flyer2{
	public abstract void b(int n, int n2);
}
@FunctionalInterface
interface Flyer3{
	public abstract int c();
}
@FunctionalInterface
interface Flyer4{
	public abstract int d(int n , int n2);
}

public class TestMain {

	public static void main(String[] args) {

		// 익명 클래스
		Flyer f1 = new Flyer() {
			@Override
			public void a() {
				System.out.println("Flyer.a()");
			}
		};
		f1.a();
		
		//람다 표현식(lambda expression ,arrow expression)
		// 자바스크립트: => , 자바: ->
		
		Flyer ff1 = ()->{
			System.out.println("람다1 Flyer.a()");
		};
		ff1.a();
		
		Flyer fff1 = ()->System.out.println("람다2 Flyer.a()");
		fff1.a();
		
	//////////////////////////////////////////////////////
		Flyer2 f2 = new Flyer2() {
			@Override
			public void b(int n, int n2) {
				System.out.println("Flyer2.b()"+n+"\t"+n2);
			}
		};
		f2.b(10, 20);
		System.out.println();
		//람다표현식-1
		Flyer2 ff2 = (int n, int n2)->{
			System.out.println("람다표현식1 Flyer2.b()"+n+"\t"+n2);
		};
		ff2.b(10, 20);
		
		//람다표현식-2
		Flyer2 fff2 = (n,n2)->System.out.println("람다표현식2 Flyer2.b()"+n+"\t"+n2);
		fff2.b(10, 20);
		
		//###################################
		// 익명 클래스
		Flyer3 f3 = new Flyer3() {
			@Override
			public int c() {
				return 100;
			}
		};
		System.out.println(f3.c());
		
		//람다표현식-1
		Flyer3 ff3 = ()->{
			return 100;
		};
		System.out.println(ff3.c());
		
		//람다표현식-2 ( 익숙해져야 된다. )
		Flyer3 fff3 = ()-> 100;
		System.out.println(fff3.c());
		
		System.out.println();
		// #################################
		Flyer4 f4 = new Flyer4() {
			@Override
			public int d(int n, int n2) {
				return n+n2;
			}
		};
		System.out.println(f4.d(100, 200));
		
		//람다 표현식 1
		Flyer4 ff4 = (int n, int n2)->{
			return n+n2;
		};
		System.out.println(ff4.d(100, 200));
		
		//람다 표현식 2 ( 매우 중요하다. 익숙해져야 된다. )
		Flyer4 fff4 =(n,n2)-> n+n2;
		System.out.println(fff4.d(100, 200));
		
		
		
		
	}//end main

}






💖 Appendix (헷갈리는 개념 정리)

※ 상속의 특징

  • 부모의 멤버( 변수 · 메서드 )를 자식이 선언없이 사용가능하다.

    ⇒ 하지만 부모의 생성자와 private로 선언된 객체에 대해서는 상속이 불가능하다.

    • 부모 클래스의 생성자는 상속되지 않습니다. 하지만, 자식 클래스에서 부모 클래스의 생성자를 호출하여 부모 클래스의 멤버 변수를 초기화할 수 있습니다.
  • 부모 타입으로 자동 타입 변환된 이후에는 부모 클래스에 선언된 필드와 메서드만 접근이 가능하다

  • 비록 변수는 자식 객체를 참조하지만, 변수로 접근 가능한 멤버는 부모 클래스 멤버로만 한정된다

  • 메소드가 자식 클래스에서 재정의되었다면 자식 클래스의 메소드가 대신 호출된다. (다형성과 관련된 성질)

  • 작은 크기의 자료형이, 큰 크기의 자료형으로 형 변환되었듯, 하위 클래스가 상속하는 상위 클래스로 자동 형변환이 가능하고, 이럴 경우 핸들링 메서드에서는 상위 클래스의 메서드만 호출 가능하다

    • 단, 하위 클래스에서 상위 클래스의 메서드를 재정의할 경우 핸들링 클래스 실행 시 해당 메서드는 하위 클래스에서 오버로딩한 메서드가 출력된다
  • 자식 타입이 부모 타입으로 자동 타입 변환하면, 부모에 선언된 필드와 메서드만 사용 가능하다는 제약 사항이 따른다.

    • 만약 자식에 선언된 필드와 메소드를 꼭 사용해야 한다면, 강제 타입 변환을 해서 다시 자식 타입으로 변환한 다음 자식의 필드와 메소드를 사용하면 된다.
  • 추상 클래스, 인터페이스 비교

    • ✨ 추상 클래스에서는 명시적으로 public abstract 기재 안하면 에러 발생
  • 클래스는 필드, 생성자, 메소드를 구성 멤버로 가지는 데 비해 인터페이스는 상수 필드와 추상 메소드만을 구성멤버로 가진다.

  • 인터페이스는 객체로 생성할 수 없기 때문에 (추상 클래스와 공통점) 생성자를 가질 수 없다.

  • 인터페이스 타입으로 자동 타입 변환된 매개값을 메소드 내에서 다시 구현 클래스 타입으로 강제 타입 변환해야 한다면 반드시 매개 값이 어떤 객체인지 instanceof 연산자로 확인하고 안전하게 강제 타입 변환을 해야 한다.

  • 객체(인스턴스)는 힙에 할당되고, 참조형 변수는 해당 객체(인스턴스)의 주소를 참조하기 때문에 스택에 할당된다.

  • 인스턴스 변수: 힙 영역 (Heap) 할당

0개의 댓글