2. 오버라이딩
2.1 오버라이딩이란? overide->덮어쓰다
상속받은 조상의 메서드를 자신에 맞게 내용을 변경하는 것
상속받은 메서드를 그대로 사용하기도 하지만, 자손 클래스 자신에 맞게 변경해야 할때 조상의 메서드를 오버라이딩함
+
재정의라는 의미
부모가 가지고있는 메서드를 그대로 가져와서 body만 바뀌는 경우
method의 (method시그니처) name, return type, argument list가 같아야한다.
public String getDetails() { //method시그니처
return super.getDetails() + "\ndepartment:" + department; //method 바디
}
class Point {
int x;
int y;
String getLocation() {
return "x:"+x+", y:"+y;
}
}
class Point3D extends Point {
int z;
String getLocation() {
return "x:"+x+", y:"+y+", z:"+z;
} //선언부 말고 구현부(내용)만 변경가능함
}
public class OverrideTest {
public static void main(String[] args) {
Point3D p = new Point3D();
p.x =3;
p.x =5;
p.x =7;
System.out.println(p.getLocation());
}
} //새로운 메서드를 제공하는 것보다 오버라이딩 하는것이 바른 선택
2.2 오버라이딩의 조건
1. 선언부가 조상 클래스의 메서드와 일치해야 한다.(이름, 매개변수, 변환타입이 같아야 함)
2. 접근 제어자를 조상 클래스의 메서드보다 좁은 범위로 변경할 수 없다.
3. 예외는 조상 클래스의 메서드보다 많이 선언할 수 없다.
조상 클래스의 메서드를 자손 클래스에서 오버라이딩할 떄
1. 접근 제어자를 조상 클래스의 메서드보다 좁은 범위로 변경할 수 없다.
2. 예외는 조상 클래스의 메서드보다 많이 선언할 수 없다.
3. 인스턴스메서드를 static메서드로 또는 그 반대로 변경할 수 없다.
2.3 오버로딩 / 오버라이딩
오버로딩 : 기존에 없는 새로운 메서드를 정의하는 것 new
오버라이딩 : 상속받은 메서드의 내용을 변경하는 것 change, modify
class Parent {
void parentMethod() {}
}
class Child extends Parent {
void parentMethod() {} //오버라이딩
void parentMethod(int i) {} //오버로딩
void childMethod() {} //메서드정의
void childMethod(int i) {} //오버로딩
void childMethod() {} //에러. 중복정의
}
2.4 super
(this랑 비슷, 조상멤버를 가리킴)
-자손 클래스에서 조상 클래스로부터 상속받은 멤버를 참조하는데 사용되는 참조변수이다.
-멤버변수와 지역변수의 이름이 같을 때 this로 구분했듯이 조상의 멤버와 자신의 멤버를 구분할 때 super사용
-객체 자신을 가리키는 참조변수. 인스턴스 메서드(생성자)내에만 존재
this-lv/iv구분
super-조상멤버/자기멤버 구분
*super(참조변수임) 랑 super()랑 완전 다른거임
class SuperTest {
public static void main(String args[]) {
Child c = new Child();
c.method();
}
}
class Parent {
int x=10;
}
class Child extends Parent {
int x=20;
void method() {
System.out.println("x="+x);
System.out.println("this.x="+ this.x); //자손클래스에 선언된 멤버변수x
System.out.println("super.x="+ super.x); //조상클래스로부터 상속받은 멤버변수x
}
}
조상클래스의 메서드의 내용에 추가적으로 작업을 덧붙이는 경우는 super를 사용해 조상클래스의 메서드를 포함시키는 것이 좋다! (아래와 같이)
class Point {
int x;
int y;
String getLocation() {
return x+y;
}
}
class Point3D extneds Point{
int z;
String getLocation() {
//return x+y+z; //오버라이딩
return super.getLocation() + z; //조상의 메서드 호출
}
}
2.5 super() - 조상 클래스의 생성자
조상의 생성자를 호출할 때 사용
조상의 멤버는 조상의 생성자를 호출해서 초기화
(자손은 조상의 멤버를 초기화 못함. 생성자를 호출해서 해야 함)
-자손클래스의 멤버가 조상 클래스의 멤버를 사용할 수 있기때문에 조상의 멤버를 먼저 초기화 해야함
*Object클래스를 제외한 모든 클래스의 생성자 첫 줄에 생성자, this()또는super() 를 호출해야 한다.
그렇지 않으면 컴파일러가 자동적으로 super(); 를 생성자의 첫 줄에 삽입한다.
class Point {
int x, y;
Point(int x, int y) {
this.x =x;
this.y= y;
}
}
class Point2D extends Point {
int z;
// Point3D(int x, int y, int z) {
// this.x =x; //조상의 멤버를 초기화
// this.y =y; //조상의 멤버를 초기화 이게 불가능함
// this.z =z;
// }
//조상의 멤버를 자손이 초기화 시키는게 불가능해서 다음과 같이 초기화 한다
Point3D(int x, int y, int z) {
super(x, y); //조상클래스의 생성자 Point(int x, int y)를 호출
this.z=z; //자신의 멤버를 초기화
}
}
public class Ex7 {
public static void main(String[] args) {
Point3D p3 = new Point3D();
System.out.println(p3.x);
System.out.println(p3.y);
System.out.println(p3.z);
}
}
class Point {
int x = 10;
int y = 20;
Point(int x, int y){
this.x = x; //다른 생성자를 호출하지 않아서 자동으로 super();추가됨
this.y = y;
}
}
class Point3D extends Point {
int z = 30;
Point3D() {
this(100, 200, 300);
}
Point3D(int x, int y, int z){
super(x, y); //조상의 Point(int x, int y)를 호출함
this.z = z;
}
}
3.package 와 import
3.1패키지 package
-서로 관련된 클래스의 묶음
-클래스는 클래스 파일 (*.class), 패키지는 폴더. 하위 패키지는 하위 폴더
-클래스의 실제 이름(full name)은 패키지를 포함(java.lang.String)
같은 이름의 클래스일 지라도 서로 다른 패키지에 속하면 패키지명으로 구별가능함.
-하나의 소스파일에는 첫 번째 문장으로 단 한 번의 패키지 선언만을 허용한다.
-모든 클래스는 반드시 하나의 패키지를 속해야 한다.
-패키지는 점(.)을 구분자로 하여 계층구조를 구성할 수 있다.
-패키지는 물리적으로 클래스 파일(.class)을 포함하는 하나의 디렉토리이다.
3.2 패키지의 선언
-패키지는 소스파일의 첫 번째 문장으로 단 한번 선언
-같은 소스 파일의 클래스들은 모두 같은 패키지에 속하게 된다.
-패키지선언이 없으면 이름없는(unnamed) 패키지에 속하게 된다.
package 패키지명;
*클래스패스classpath
-클래스파일의 위치를 알려주는 경로
-환경변수 classpath로 관리하며, 경로간의 구분자는 ';'를 사용
classpath(환경변수)에 패키지의 루트를 등록해줘야 함.
3.3 import문
-클래스를 사용할 때 패키지이름을 생략할 수 있다.
-컴파일러에게 클래스가 속한 패키지를 알려준다.
-ctrl+shift+o 임포트문생성 단축키
-java.lang패키지(기본패키지)의 클래스는 import하지 않고도 사용할 수 있다.
3.4 import문 선언
import 패키지명.클래스명;
or
import 패키지명.*; //*는 모든 클래스를 의미
import문은 패키지문과 클래스선언의 사이에 선언한다.
소스파일(*java)의 구성 순서
1.package문
2.import문
3.클래스선언
*import문은 컴파일 시에 처리되므로 프로그램의 성능에 영향없음
3.5 static import문
-static멤버를 사용할 때 클래스 이름을 생략할 수 있게 해준다.
import문을 사용하면 클래스의 패키지명을 생략할 수 있는 것과 같이 static import문을 사용하면 static멤버를 호출할 때 클래스 이름을 생략할 수 있다.
import static java.lang.Integer.*; //Integer 클래스의 모든 메서드 ,*는 모든 static멤버
import static java.lang.Math.random; //Math.random()만. 괄호 안붙임
import static java.lang.System.out; //System.out에서 out만으로 참조가능
이와같이 static import문을 선언하면 다음과 같이 간략하게 생략 가능하다.
System.out.println(Math.random());
//이 문장을
out.println(random()); //으로 바꿀 수 있다.
4.제어자
4.1 제어자란? modifier
-클래스와 클래스의 멤버(멤버변수, 메서드)에 부가적인 의미 부여
접근제어자 : public, protected, (default), private ->4개중 하나만 붙임
그 외 : static, final, abstract, native, trasient, synchronized, volatile, strictfp
-하나의 대상에 여러 제어자를 같이 사용가능(접근 제어자는 하나만)
public class ModiferTest {
public static final int WIDTH=200;
//접근제어자가 맨 왼쪽에 씀
4.2 static- 클래스의, 공통적인
-static이 붙은 멤버변수, 메서드, 초기화 블럭은 인스턴스가 아닌 클래스에 관계된 것이기 대문에 인스턴스를 생성하지 않고도 사용 가능하다.
static이 사용될 수 있는 곳 - 멤버변수, 메서드, 초기화 블록
멤버변수 -모든 클래스에 공통적으로 사용되는 클래스변수가 된다.
-클래스변수는 인스턴스를 생성하지 않고도 사용 가능하다.
-클래스가 메모리에 로드될 때 생성된다.
메서드 -인스턴스를 생성하지 않고도 호출이 가능한 static메서드가 된다.
-static메서드 내에서는 인스턴스멤버를 직접 사용할 수 없다.
4.3 final - 마지막의, 변경될 수 없는
-거의 모든 대상에 사용될 수 있다.
final이 사용될 수 있는 곳 - 클래스, 메서드, 멤버변수, 지역변수
클래스 -변경될 수 없는 클래스, 확장될 수 없는 클래스가 된다. 그래서 다른 클래스의 조상이 될 수 없음.
메서드 - 변경될 수 없는 메서드, final로 지정된 메서드는 오버라이딩을 통해 재정의 될 수 없다.
멤버변수, 지역변수 - 변수 앞에 final이 붙으면 값을 변경할 수 없는 상수가 된다.
*생성자를 이용한 final멤버 변수의 초기화
-final이 붙은 변수는 상수이므로 일반적으로 선언과 초기화를 동시에 하지만, 인스턴스 변수의 경우 생성자에서 초기화 되도록 할 수 있다.
-클래스 내에 매개변수를 갖는 생성장를 선언해, 인스턴스 생성할 때 매개변수로부터 제공받는 것
4.4 abstract - 추상의, 미완성의
-메서드의 선언부만 작성하고 실제 수행내용은 구현하지 않은 추상 메서드를 선언하는데 사용
-추상클래스는 아직 완성되지 않은 메서드가 존재하는 '미완성 설계도'이므로 인스턴스를 생성할 수 없다.
abstract가 사용될 수 있는 곳 - 클래스, 메서드
클래스 - 클래스 내에 추상 메서드가 선언되어 있음을 의미한다.
메서드 - 선언부만 작성하고 구현부는 작성하지 않은 추상 메서드임을 알린다.
abstract class AbstractTest { //추상클래스(추상 메서드를 포함한 클래스)
abstract void move(); //추상메서드(몸통없음) 미완성 메서드
}
4.5 접근제어자 access modifier
-해당하는 멤버, 클래스를 외부에서 접근하지 못하도록 제한하는 역할
4개 중 하나만 사용가능
private - 같은클래스 내에서만 접근이 가능
(default) - 같은 패키지
protected - 같은 패키지 + 다른 패키지의 자손클래스
public - 접근제한no
접근범위 넓음 public > protected > (default) > private 좁음
package pkg1;
class MyParent {
private int prv; //같은 클래스
int dft; //같은 패키지
protected int prt; //같은 패키지 + 자손(다른패키지)
public int pub; //접근제한 없음
public void printMembers() {
System.out.println(prv); // ok
System.out.println(dft); // ok
System.out.println(prt); // ok
System.out.println(pub); // ok
}
}
public class MyParentsTest {
public static void main(String[] args) {
MyParent p = new MyParent();
System.out.println(prv); // 에러
System.out.println(dft); // ok
System.out.println(prt); // ok
System.out.println(pub); // ok
}
}
접근 제어자를 이용한 캡슐화
접근제어자를 사용하는 이유?
-외부로부터 데이터를 보호하기 위해서
-외부에는 불필요한, 내부적으로만 사용되는, 부분을 감추기 위해서
iv를 직접접근을 막고 메서드를 이용해 간접접근을 허용하고 값을 보호
class Time {
private int hour; //0~23사이의 값을 가져야함
private int minute;
private int second;
public void setHour(int hour) {
if(hour < 0 || hour > 23) return;
//100이 입력되면 true가 되어 return되어 빠져나감 아래문장으로 넘어가지 못함
this.hour = hour;
}
public int getHour() {return hour;};
}
public class TimeTest{
public static void main(String[] args) {
Time t = new Time();
t.hour = -100;
t.setHour(21); //hour의 값을 21로 변경
System.out.println(t.getHour()); //21출력
t.setHour(100); //hour의 값을 100으로 변경
System.out.println(t.getHour()); //21출력. 100은 유효한 값이 아니기 때문에
}
}
4.6 제어자의 조합
제어자를 조합해서 사용할떄 주의할 점
1. 메서드에 static과 abstract를 함께 사용할 수 없다.
2. 클래스에 abstract와 final을 동시에 사용할 수 없다.
3. abstract메서드의 접근 제어자가 private일 수 없다.
4. 메서드에 private와 final을 같이 사용할 필요는 없다.
'JAVA' 카테고리의 다른 글
JAVA | instanceof연산자, 매개변수 다형성, 객체 배열로 다루기 (0) | 2022.02.03 |
---|---|
JAVA | 다형성, 참조변수의 형변환 (0) | 2022.01.28 |
JAVA | 상속, 포함관계 (0) | 2022.01.24 |
JAVA | 변수와 메서드, 오버로딩, 생성자 (0) | 2022.01.23 |
JAVA | 객체지향, 인스턴스, 변수와 메서드 (0) | 2022.01.22 |