자바제어자1, 클래스 상속과 다형성,

jaegeunsong97·2023년 1월 14일
0
post-thumbnail

2023_1_14_TIL

인스턴스 필드와 정적 필드

class A {
	int m = 3;
    static int n = 5;
}

인스턴스 메소드와 정적 메소드

  • 인스턴스 메소드 -> 인스턴스 메소드 영역
  • 정적 메소드 -> 클래스 영역

정적 메소드 안에서 사용할 수 있는 필드와 메소드

  • static은 객체의 생성 없이 사용 가능 / instance는 객체의 생성으로 사용
    • 정적 메소드 안에서 인스턴스 멤버 사용 -> 결국 정적 메소드도 객체 생성 후 사용
  • 따라서 효율성이 떨어지기 때문에 정적 메서드 내부에 정적 멤버만 올 수 있음(특징)

정적 초기화 블록

  • 정적 필드는 생성자 호출 전에 사용가능 = 생성자에서는 정적 필드 초기화 불가능
  • 클래스가 메모리에 로딩될 때 가장 먼저 실행 -> 클래스 로딩 시점에 바로 초기화
class A {
	int a;
    static int b;
    
    static {
    	b = 5;
        System.out.println("클래스가 로딩될 때 static block 실행");
    }
    
    A() {
    	a = 3;// 인스턴스 필드 초기화 위치
    }
}

public class ...
	public static void main(String[] args) {
    	System.out.println(A.b);// 클래스가 로딩될 때 static block 실행 -> 5
    }

상속의 장점

  • 1개의 객체를 여러가지 모양으로 표현 = polymorphism

상속할 때의 메모리 구조

class A {
	int m;
    void abc(){...}
}
class B extends A {
	int n;
	void bcd(){...}
}

B b = new B();
  • 부모 클래스 객체 생성 -> 자식 클래스 객체 생성
  • 이후, 자식 클래스 필드, 메소드 추가
  • 자식 클래스 객체 내부에는 부모 클래스 객체가 포함 -> 부모 클래스의 멤버 사용 가능

생성자의 상속 여부

  • 생성자인지 메소드인지 알 수 없기 때문에 -> 상속 X

메모리로 이해하는 다운캐스팅

  • 선언되 타입 = 실제 객체에서 자신이 선언된 타입의 객체를 가리키는 것

B b = new B();
b.abc();// O
b.bcd();// O

A a = new B();
a.abc();// O
a.bcd();// X

메서드 오버라이딩


오버로딩, 오버라이딩 차이점

class A {
	void print1() {...}
    void print2() {...}
}
class B extends A {
	void print1() {...}// 오버라이딩
    void print2(int a) {...}// 오버로딩
}

메소드 오버라이딩과 접근 지정자

  • 상속관계의 오버라이딩 -> 상속 받은 메소드의 접근 지정자와 동일 or 넓은 접근 지정자

인스턴스 필드의 중복, 정적 필드의 중복

  • 인스턴스 필드 중복
class A {int m = 3;}
class B extends A {int m = 4;}
  • 정적 필드 중복
class A {static int m = 3;}
class B extends A {static int m = 4;}

정적 메소드의 중복

  • 인스턴스 메소드 오버라이딩 이유 -> 동일한 공간에 메소드를 저장해서
  • 정적 메소드는 각자 클래스 내부에 존재 = 다른 공간에 저장
class A {
	static void print() {...}
}
class B extends A {
	static void print() {...}
}

Object 클래스의 주요 메소드

  • toString()
    • 패키지명.클래스명@해시코드
      • 따라서 사용시에 오버라이딩 후 재정의 필요
      • 오버라이딩 X 출력 -> 패키지명.클래스명@해시코드 형태 출력
  • equals(Object obj)
    • 객체의 스택 메모리값을 비교(주소를 비교하는 것)
      • 따라서 사용시에 오버라이딩 후 재정의 필요
public boolean equals(Object obj) {//  주소비교 -> 데이터 값 비교
	if (obj instanceof B) {
    	if (this.name == ((B) obj).name)// 다운 캐스팅
        	return true;
    }
}
  • hashCode()
    • Object의 hashCode()메소드 -> 고윳값
      • hashCode() + equals() -> '오버라이딩' 필요
    • 객체의 위치와 연관된 값
      • 두 객체의 hashCode() 비교
      • hashCode() 동일하면 -> equals() 메소드 호출
class A {
	String name;
    A(String name) {this.name = name;}
    
	@ override
    public boolean equals(Object obj) {
    	if (obj instanceof A) {
        	if (this.name == ((A) obj).name)
            	return true;
        }
        return false;
    }
    
    @ override
    public String toString()
    	return name;
}
class B {
	String name;
    B(String name) {this.name = name;}
    
	@ override
    public boolean equals(Object obj) {
    	if (obj instanceof B) {
        	if (this.name == ((B) obj).name)
            	return true;
        }
        return false;
    }
    
    @ override
    public int hashCode()
    	return name.hashCode();
    
    @ override
    public String toString()
    	return name;
}

public class ...
	public static void main(String[] args) {
    	HashMap<Integer, String> hm1 = new HashMap<>();
        hm1.put(1, "데이터1");
        hm1.put(1, "데이터2");
        hm1.put(2, "데이터3");
        // -> 1 = 데이터2, 2 = 데이터3
        
        HashMap<A, String> hm2 = new HashMap<>();
        hm2.put(new A("첫 번째"), "데이터1");
        hm2.put(new A("첫 번째"), "데이터2");
        hm2.put(new A("두 번째"), "데이터3");
        // -> 첫 번째 = 데이터2, 두 번째 = 데이터3, 첫 번째 = 데이터1
        
        HashMap<B, String> hm3 = new HashMap<>();
        hm3.put(new B("첫 번째"), "데이터1");
        hm3.put(new B("첫 번째"), "데이터2");
        hm3.put(new B("두 번째"), "데이터3");
		// -> 첫 번째 = 데이터2, 두 번째 = 데이터3
    }
}
profile
현재 블로그 : https://jasonsong97.tistory.com/

0개의 댓글