JAVA Programming

Growing_HJ·2024년 5월 28일

일기장

목록 보기
7/51

2024.05.23.THU. <D + 3>
A. 생성자
=> 인스턴스가 생성될 때 호출되는 '인스턴스 초기화 메소드'임.
=> 인스턴스의 초기화 작업에 주로 사용됨.
=> 인스턴스 생성 시, 실행되어야 할 작업을 위해서도 사용됨.
A-1. 생성자의 특징 : 구조가 메소드와 유사, 차이점은 반환값이 없음 (void 사용 X)

  • 작성 방법: 생성자의 이름이 클래스 이름과 동일해야 함.
  • 생성자를 통한 인스턴스 생성
    ex) java MyMath mm = new MyMath(); // 현재의 생성자는 코드에 없음, 컴파일러가 기본적으로 제공해줌 !!
    A-2. 기본 생성자 (default constructor)
  • 컴파일 시 소스파일에 생성자가 하나도 정의가 되지 않은 경우, 컴파일러가 제공함.
    A-3. 매개 변수가 있는 생성자
  • 인스턴스마다 각기 다른 값으로 초기화해야 하는 경우 사용.
  • 오버로딩도 적용 가능.
  • 인스턴스 변수 초기화 (생성자 사용 전) java d1.value = 100;
  • 인스턴스 변수 초기화 (생성사 사용 후) java Data1(100);
  • 생성자에서 다른 생성자 호출.
    => 클래스 내에 여러가지 생성자가 있는 경우.
  • 생성자를 사용한 인스턴스의 복사.
  • 현재 사용하고 있는 인스턴스와 같은 상태를 갖는 인스턴스를 하나 더 만들고자 할 경우 (원본 인스턴스와 복사 인스턴스)
    ==> 상태가 동일함. (고유정보가 동일하다는 의미는 아님.!) !!!
  • 복사생성자(참조형) -> 생성자의 매개변수를 해당 클래스의 참조변수를 받으면 구현이 가능하다.
    ex) 생성자 예제코드
// 생성자가 있는 클래스
class Data{
	int value;
	
	//디폴트 생성자
	/**
	 * 해당 클래스에서 생성자가 하나도 없으면, 컴파일러가 제공해주지만,
	 * 클래스에 다른 생성자가 하나라도 있으면, 컴파일러가 기본 생성자를 제공하지 않음 
	 * 따라서, 기본생성자를 사용하려면 명시적으로 추가하면 됨**/
	Data(){
		//Data(50) 		=> 생성자 이름으로 생성자내에서 호출이 불가하다.
		this(50);	  //=> 생성자 이름 대신에 this() 사용,
		value = 100;
		//Data(200); 	=> 생성자 이름으로 생성자 내에서 호출 불가,
		//this(200);	=> 초ㅛ기화 작업은 맨 앞에서 할 것. 생성자의 본질은 초기화 하는 것!! 
	}
	// 매개변수가 있는 생성자
	Data(int x){
		value = x;
	}
	// 생성자도 함수의 한 형태이므로, 오버로딩된다.
	Data(long x){
		value = (int)x;
	}
}
public class Constructor {
	public static void main(String[] args) {
		// TODO Auto-generated method stub
		// 인스턴스 생성하기.
		Data d1 = new Data();
		System.out.println("d1.value = " + d1.value);
		
		Data d2 = new Data();
		System.out.println("d2.value = " + d2.value);
		
		Data d3 = new Data(777);
		System.out.println("d3.value = " + d3.value);
		
	}

}

B. 변수의 초기화

  • 멤버변수의 초기화는 기본값으로 초기화됨.
  • 지역변수는 반드시 초기화가 필수임.
  • 멤버변수의 초기화 방법
    B-1. 명시적 초기화
ex) 
class car{
	DoorType dt = new DoorType(); } 
  • 참조변수.멤버변수 = 100; 의 형태
    B-2. 초기화 블록
  • 인스턴스 변수 초기화 블록 : 인스턴스 변수가 대상임
  • 클래스 (static) 변수 초기화 블록 : 클래스 변수가 대상
  • 동작
    => 클래스가 메모리에 처음 로딩될 때 한번만 수행되며,
    인스턴스 초기화 블록은 생성자와 같이 인스턴스를 생성할 때마다 수행됨.
    인스턴스 초기화 블럭은 생성자 보다 먼저 초기화 블럭이 수행됨.
    초기화 블록 예제코드)
public class BlockEx {
	static int staticVar = 0; //static 변수
	// 클래스 변수 초기화 블럭
	static {
		System.out.println("StaticVar = " + staticVar);
		System.out.println("클래스 변수 초기화 블럭 호출");
	}
	
	// 인스턴스 변수 초기화 블럭
	static {
		System.out.println("인스턴스 변수 초기화 블럭 호출");
	}
	public BlockEx() {
		System.out.println("생성자 호출");
	}
	public static void main(String[] args) {
		System.out.println("Staticvar(block()) = " + staticVar);
		// 초기화 블럭 및 생성자 진행 순서 확인
		BlockEx block = new BlockEx();
	}
}
  • 멤버변수의 초기화 시점
  • 클래스 변수: 클래스가 처음 로딩될 때 단 한번 초기화.
  • 인스턴스 변수: 인스턴스가 생성될 때 마다 각 인스턴스별로 초기화
  • 멤버변수의 초기화 우선순위
  • 클래스 변수 : 기본값 -> 명시적 초기화 -> 클래스 초기화 블럭
  • 인스턴스 변수 : 기본값 -> 명시적 초기화 -> 인스턴스 초기화 블럭 -> 생성자
    멤버변수 & 인스턴스변수 예제코드)
// 클래스 멤버 변수, 인스턴스 멤버 변수(Card  class)
class Card{
	// 클래스 변수의 대상: 카드의 크기
	// 인스턴스 변수의 대상 : 숫자, 무늬
	private String kind;
	private int number;
	
	// 클래스 멤버 변수(폭, 넓이) => 객체를 생성하지 않고도 사용이가능
	static int width = 100; // 폭
	static int height = 230; // 넓이
}
public class Member {
	public static void main(String[] args) {
		// TODO Auto-generated method stub
		// 클래스 변수와 인스턴스 변수
		Card c1 = new Card();
		System.out.println(c1.height);
		/**
		 * 참조변수를 통한 멤버변수 사용은 인스턴스화가 되어야만 가능하다
		 * -> 즉, 에러가 나는 이유는 인스턴스화가 되지 않았기 때문에 오류가 발생하는 것,
		 * 따라서, 클래스 변수의 접근은 참조변수를 사용하면 안되고, 클래스 이름으로 접근해야 함.**/
		System.out.println(Card.height);
		System.out.println(Card.width);
		
		Card.height = 100;
		System.out.println(Card.height);
	}
}

C. 상속

  • 조상 클래스: 부모 클래스, 상위 클래스, 기반 클래스 (super class)
  • 자식 클래스: 자손 클래스, 하위 클래스, 파생 클래스
  • 장점
  • 상속을 통하면 보다 적은 양의 코드로 새로운 클래스를 작성.
  • 코드의 추가 및 변경이 매우 용이해짐.
  • 단점
  • 강결합의 가능성이 있을 수 있음.
    강결합 - 가장 좋은 코드 - 결합도가 낮고 응집도가 높은 코드 => 코드 품질 향상 => 유지보수, 테스트에 용이. + 생산성 향상,
    <참고>
  • 결합도가 낮음 => 클래스간의 관계가 약함. ( 문법적인 요소로 활용하면 쌉가능 )
    -> 코드 수정시 사용되는 곳에 다른 영향이 없도록 코드를 작성.
  • 응집도가 높음 => 관련 기능을 한 곳에 관리가 되도록 함. ( 도메인 지식이 필요! )
  • 관계
  • 논리적으로 합당한 관계
    => 상속관계 : is - a 관계 [~는 ~이다.]
    --> 사람, 학생 : 학생은 사람이다. => extends 사용 (학생 extends 사람)
    권총, 경찰 : 경찰은 권총을 가지고 있다. => 논리적 성립이 불가
    => 포함관계 : has - a 관계 [~은 ~ 가지고 있다.]
    --> 사람, 학생 : 학생은 사람을 가지고 있다.
    권총, 경찰 : 경찰은 권총을 가지고 있다. => 논리적 성립이 가능 => 멤버변수의 가능성
  • 문법적 관계
  • extends (확장)
  • 단일 상속, 멀티 상속
  • 단일 상속: 기반 클래스가 하나. => JAVA
  • 멀티(다중) 상속: 기반 클래스가 여러개 => C++
  • JAVA에서 멀티 상속처럼 사용하고 싶은 경우
    is - a(상속) + has - a (포함) => 문법) extends, 멤버변수
    상속 예제코드)
class Parent { int age; }
class Child1 extends Parent{}
class Child2 extends Parent{}
  • Object 클래스
  • Object 클래스는 모든 클래스 상속 계층도의 최상위에 있는 조상(기반) 클래스.
    ex) class Tv {}
    -> 컴파일러가 아래의 코드로 변경.
    ex) class Tv extends Object {}
  • Object 에서 제공되는 메소드를 활용할 수 있도록 하면 좋음.
    => 재사용성 향상, 유지보수성 향상.
  • 오버라이딩 (Overriding) with6.
  • 기반 클래스로부터 상속받은 메소드의 내용을 변경하는 것.
    조건: 메소드의 이름이 동일해야 함. 매개변수도 동일해야 함. 반환타입도 동일해야 함.
  • 오버로딩 (Overloading)과 오버라이딩(Overriding)
  • 오버로딩 : 상속관계가 아님. 기존에 없는 메소드를 새로 정의하는 것.
  • 오버라이딩 : 상속관계이다. 파생된 클래스쪽에서 부모 메소드와 동일한 것을 수정하여 정의하는 것.
    오버라이딩&오버로딩 예제 코드 )
class Point2{
	int x, y;
	Point2 (int x, int y){
		this.x = x;
		this.y = y;
	}
	String getLocation() {
		return "x: " + x + ", y " + y;
	}
}
class Point3D extends Point2{ //파생된 클래스, 3차원
	int z;
	//오버로딩하기.
	Point3D (int x){
		super(x,0);
	}
	Point3D (int x, int y){
		/**Point3D 는 파생된 클래스임으로, 기반 클래스인 Point가 없이는 존재할 수 없음
		따라서 Point가 먼저 인스턴스로 생성되어야 Point3D 의 인스턴스를 생성할 수 있음
		그래서, 파생 클래스의 생서앚에서 반드시 첫 줄에 기반 클래스의
		생성자를 호출하여, 기반 클래스의 인스턴스를 먼저 생성하게 해야 함. **/
		super(x, y); // + this: 자기 참조 연산자, [this() => 생성자 호출]
	}
	// 오버라이딩하기.
	/**좌표 출력시,
	 * 1. 재사용을 생각할 것. (기반클래스의 메소드를 사용)
	 * 2. 파생 클래스 상태 정보는 파생클래스가 출력 => 추가적인 코드 작성 
	 * 추전되는 오버라이딩 : 부모 클래스의 메소드를 사용,
	 * 조상 클래스의 메솓 내부의 내용이 변경되더라도, 변경된 내용이 파생 클래스에 영향을 주지 않고
	 * 자종적으로 반영이 되게 함. **/
	String getLocation() {
		return super.getLocation() + ", z: " + z;
	}
}

D. super

  • 모든 인스턴스 메소드에는 자신이 속한 인스턴스의 주소가 지역변수로 저장됨.
  • 이것이 참조변수인 this와 super임
  • this 예약어 사용 목적: 멤버변수와 지역변수의 차이를 두기 위함.
  • super 사용 이유 : 클래스간의 관계에서 기반 멤버와 파생 멤버를 구분하기 위함.
  • super() - 생성자
  • 자손 클래스의 인스턴스를 생성하면, 자손의 멤버와 조상의 멤버가 모두 합쳐진
    하나의 인스턴스가 생성됨.=> 파생 클래스에서 조상 클래스의 멤버를 사용할 수 있게 됨.- 인스턴스 생성시 선택
  • 클래스 : 어떤 클래스의 인스턴스를 생성할 것인가? => 클래스 설계 관점
  • 생성자 : 선택한 클래스의 어떤 생성자를 이용해서 인스턴스를 생성할 것인가? => 상태 설계
    super 예제코드
class Parent2 {
	int x = 10;
	int y = 10;
}
class Child extends Parent2{
	int y = 20;
	void method1() {
		System.out.println("x = " + x);
		System.out.println("this.x = " + this.x);
		System.out.println("super.x = " + super.x);
	}
	void method2() {
		System.out.println("y = " + y);
		System.out.println("this.y = " + this.y);
		System.out.println("super.y = " + super.y);
	}
}

0개의 댓글