관리 메뉴

나구리의 개발공부기록

자바의 정석 기초편 ch7 - 10 ~ 16[참조변수 super, 생성자super(), 패키지, 클래스 패스, import문, static import문] 본문

유튜브 공부/JAVA의 정석 기초편(유튜브)

자바의 정석 기초편 ch7 - 10 ~ 16[참조변수 super, 생성자super(), 패키지, 클래스 패스, import문, static import문]

소소한나구리 2023. 11. 23. 18:06

1) 참조변수 super

  • 객체 자신을 가리키는 참조변수이며 부모클래스(상위 클래스)의 멤버에 접근할 때 사용함
  • 부모클래스의 멤버(super)와 자기자신의 멤버(this)를 구분할 때 사용함
  • this가 자기 자신의 인스턴스 멤버를 가리킨다면 super는 부모 클래스의 인스턴스를 가리킨다고 보면 됨
  • 인스턴스 메서드나 생성자에서만 사용할 수 있으며 스태틱 메서드에는 사용할 수 없음
class ex7_2 {
	public static void main(String args[])
    	Child c = new Child();
        c.method();
    }
}

class Parent { int x = 10; }	// super.x

class Child extends Parent {
	int x = 20;	// this.x

	void method() {
	System.out.println("x=" +x);	         // 가까운 참조변수 x 값 출력
	System.out.println("this.x=" +this.x);	 // this.x 값 출력
	System.out.println("super.x=" +super.x); // super.x 값 출력
	}
}

출력값
x=20
this.x=20
super.x=10

 

(1) 예제1

  • 자손 클래스에 선언된 멤버가 없는 경우 this, super 모두 같은값을 가리킴
  • 상속받은 Child 클래스에 x변수가 없으므로 this를 사용해도 상속받은 부모클래스의 멤버를 가리킴
class ex7_2 {
	public static void main(String args[])
    	Child c = new Child();
        c.method();
    }
}

class Parent { int x = 10; }	// super.x , this.x 둘다 가능

class Child extends Parent {

	void method() {
	System.out.println("x=" +x);	// 가까운 참조변수 x 값 출력 -> 상속클래스의 x 값을 가르킴
	System.out.println("this.x=" +this.x);	 // this.x 값 출력
	System.out.println("shper.x=" +super.x); // super.x 값 출력
	}
}

출력값
x=10
this.x=10
super.x=10

2) super()

  • 조상의 생성자를 호출할 때 사용
  • 상속은 조상의 생성자와 초기화블럭이 상속 되지 않기 때문에 조상의 생성자를 호출할 경우 super()로 호출해야 함
  • 자손의 클래스에서 조상의 멤버를 직접 초기화 하는 방식보다 super()를 호출해서 초기화 하는 방식을 권장함

(1) 예제

  • Point3D클래스에서 직접 조상의 멤버를 Point3D 생성자로 초기화려고하면 에러가 발생함
  • 정상적으로 조상의 멤버를 초기화 하려면 조상클래스에 생성자를 정의해두고 자손 클래스에서 super()로 조상 클래스의 생성자를 호출하여 멤버를 초기화 해야함
class Point {
	int x, y;

	Point(int x, int y) {
		this.x = x;
		this.y = y;
    }
}

// 조상의 멤버를 초기화 할 때 아래처럼 하면 에러 발생
class Point3D extends Point {
	int z;
    
	Point3D(int x, int y, int z) {
		this.x = x;	// 에러 발생, 이유는 아래에서 설명
		this.y = y;	// 위와 동일
		this.z = z;
 	}
}

// 정상적인 조상 멤버 초기화 방법 -> super() 조상의 멤버를 호출
class Point3D extends Point {
	int z;
    
	Point3D(int x, int y, int z) {
		super(x,y);	// 조상의 생성자 Point(int x, int y)를 호출
		this.z = z;
 	}
}

 

(2) 추가조건(중요)

  • 생성자의 첫 줄에 반드시 생성자를 호출하지 않으면 컴파일러가 생성자의 첫 줄에 super();를 자동으로 삽입함
  • 조상 클래스에 기본생성자가 없이 매개변수가 있는 생성자만 만들고 자손 클래스에서 생성자를 만들면 마찬가지로 컴파일러가 super()를 자동으로 호출함
  • 그러나 조상클래스에 기본생성자를 만들어 주지 않았으므로(매개변수가 있는 생성자를 직접 만들면 컴파일러가 자동으로 기본 생성자를 생성하지 않음) 자손 클래스의 생성자에서 직접 조상 클래스의 멤버에 값을 초기화하려고하면 에러가 발생함
  • 이것이 자손 클래스에서 조상 클래스 멤버를 초기화할 때 직접 초기화 하지말고 super()를 사용하라는 이유이며, (1)번 예제의 컴파일 에러가 발생한 이유임

(3) 문제해결

  • 1. 조상 클래스에 기본 생성자를 생성하여 컴파일 에러가 발생하는 문제를 해결하면 직접 조상의 멤버에 값을 초기화 할 수 있음
  • 2. 자손 클래스에서 super(x, y);로 조상 클래스의 매개변수가 있는 생성자를 호출하여 초기화하면 조상 클래스의 기본 생성자가 없어도 동작함
  • 최종적으로 super()를 사용하여 조상 클래스의 멤버에 값을 초기화 하더라도 기본적으로 매개변수가 있는 생성자를 생성할 경우 기본 생성자를 만드는 습관을 들이는 것을 권장함
class TestPoint4 {
	int x;
	int y;

//	TestPoint4() {}	// 문제해결: 1. 조상 클래스에 기본 생성자 생성
	TestPoint4(int x, int y) {
//		super();	// 생략 됨, 컴파일시 오브젝트 클래스의 기본생성자를 자동으로 호출 -> OK
		this.x = x;
		this.y = y;
	}
	
	String getLocation() {	// 메서드	
		return"x:" + x + ", y:" + y;
	}
}

class TestPoint3D extends TestPoint4 {	// Point클래스 상속
	int z;

	TestPoint3D(int x, int y, int z) {
//		super();	// 생략 됨, 컴파일시 조상의 기본생성자를 자동으로 호출함 -> 에러발생

//		this.x = x; 조상 멤버는 직접 초기화 불가능
//		this.y = y; 

		super(x,y);	// 문제해결: 2. 생성자 super(x,y)로 조상의 매개변수 있는 생성자를 호출하여 초기화
		this.z = z;
		
    }
	String getLocation() {	// 메서드 오버라이딩
		return"x:" + x + ", y:" + y +", z:" +z;
	}
}

public class superTest {
	public static void main(String[] args) {
		TestPoint3D p = new TestPoint3D(1,2,3);
		System.out.println(p.getLocation());
	}
}

해결방법
1. TestPoint4 클래스에 기본생성자 입력 -> 참조 코드 확인
2. super()사용 (조상의 생성자 호출) -> 참조 코드 확인

3)패키지(package)

  • 서로 관련된 클래스의 묶는 단위
  • Java8 기준으로 약 4000개 내장 클래스가 있음
  • 컴파일하면 클래스는 파일이름.class로, 패키지는 폴더로, 하위 패키지는 하위 폴더로 생성됨
  • 클래스의 풀네임은 패키지를 포함하여 작성됨
    • ex) String 클래스의 풀네임 = java.lang.String

(1) 패키지 선언

  • 패키지는 소스파일의 첫 번째 문장으로 단 한번 선언
  • 같은 소스 파일의 클래스들은 모두 같은 패키지에 속하게 됨
  • 패키지 선언이 없으면 이름없는 패키지(unnamed, 이클립스,인텔리제이에서는 default package)에 속하게 됨
  • 선언방법
    • Package 패키지 경로 (com.codechobo.book)

(2) 클래스 패스

  • JVM이나 Java 컴파일러가 사용할 클래스 파일의 위치를 알려주는 경로
  • 터미널, cmd 창에서 class파일을 찾아 실행 하고자 할 때 경로를 미리 지정 하지않고 실행할때도 사용함
  • 환경변수(OS) classpath로 관리하면 windows의 경우 경로간의 구분자는 세미콜론(;) 를 사용하고 Unix기반 시스템은 콜론(:)을사용하며 경로를 여러개 설정할 수도 있음
  • 맥에서의 클래스 패스 설정은 별도의 검색이 필요
  • 윈도우에서는 제어판 -> 환경변수 -> 시스템 변수를 이용

4) import문

  • 클래스를 사용할 때 패키지이름을 생략 할 수 있음
  • 컴파일러에게 클래스가 속한 패키지를 알려주는 구문
  • 이클립스 단축키: 커맨드 + 쉬프트 + O , 인텔리제이 단축키 : 옵션 + 엔터 / 맥 기준 단축키 설명
  • import문을 작성하지 않으면 객체를 생성하고자 할때 경로를 전부 작성해줘야함
// import문을 작성 안하면 객체 생성 시 클래스 앞에 패키지 이름을 써 줘야 함,
class ImportTest [
	java.util.Date today = new java.util.Date();
}


// import문을 작성 하면 아래처럼 패키지 이름을 생략 가능
import java.util.Date;

class ImportTest {
	Date today = new Date();
}

 

(1) java.lang패키지(기본패키지)의 클래스는 import하지 않고도 사용할 수 있음

  • String, Object, System, Thread... 등등

(2) import문 작성 방법

  • import java.패키지명.클래스명;
  • import java.패키지명.*;  -> 모든 클래스를 사용
  • *으로 할경우 코드의 명확성이 떨어질 수 있음
  • 패키지 문과 클래스 선언 사이에 선언
  • import문은 컴파일 시에 처리되므로 프로그램의 성능에 거의 영향이 없으므로 사용하고자 하는 클래스는 가급적 선언해서 사용하는 것을 권장함
import java.util.*;	// utill 패키지의 모든클래스
import java.text.*;	// text 패키지의 모든클래스
  • 서로 다른 패키지에 속했지만 이름이 같은 클래스를 import하는 것도 가능
  • 클래스 앞에 패키지 명을 붙여주면 코드가 명확해짐
// 패키지는 다른데 클래스가 동일 할 경우
import java.sql.Date;	
import java.util.Date;	

// 두개의 Date클래스를 모두사용 가능하지만 클래스 앞에 패키지 이름을 직접 적어주면 구분이 명확하게 됨
public class ImportTest {
	public static void main(String[] args) {
    	java.util.Date today = new java.util.Date();
	}
}

 

(3) static import문

  • static멤버를 사용할 때 클래스 이름을 생략할 수 있게 해줌
  • 클래스나 static멤버의 이름이 길 경우 코드가 길어지는데 static import문을 사용하면 코드의 길이를 줄일 수 있음
  • 단, 코드의 명확성이 줄어들 수 있음(어떤 클래스의 메서드를 쓰는지..)
// Integer클래스의 모든 static메서드를 실행할 때 클래스명을 생략 가능
import static java.lang.Integer.*;

// Math클래스의 random메서드를 호출할 때 클래스명을 생략할 수 있음
import static java.lang.Math.random;

// 출력메서드를 사용할 때 System을 생략할 수 있음
import static java.lang.System.out;
out.println(random()); // System.out.println(Math.random());의 코드 길이가 줄어듦

 

 

** 출처 : 남궁성의 정석코딩_자바의정석