1차시 접근지정자
접근 지정자의 접근 범위
접근지정자의 종류: public protected default(없음) private
1. public (공개)
- 동일 패키지의 클래스, 자식 클래스 접근 가능
- 다른 패키지의 클래스, 자식 클래스 접근 가능
- 그냥 public은 공개된 접근 지정자라서 다 접근 가능
2. protected (상속 관계에서 사용)
- 상속 관계라면 패키지가 다르더라도 접근 가능
- 동일 패키지의 클래스, 자식 클래스 접근 가능
- 다른 클래스의 자식 클래스 접근 가능 (상속된 거니까!)
- 다른 패키지의 클래스 접근 불가능
3. default (없음) (접근지정자 생략!)
- 같은 패키지에선 접근 가능
- 동일 패키지의 클래스, 동일 패키지의 자식 클래서 접근 가능
- 다른 패키지의 클래스, 자식 클래스 접근 불가능
4. private
- 자기자신의 클래스에서만 접근 가능
- 동일 패키지의 클래스, 자식 클래스, 다른 패키지의 클래스, 자식 클래스 모두 접근 불가능
- private 접근지정자로 선언된 멤버변수와 메서드는 설정자와 접근자를 통해서 접근
접근 지정자 사용 시 주의 사항
1. private 멤버는 자식 클래스에 상속 X
2. 클래스 멤버는 어떤 접근 지정자로도 지정할 수 있지만, 클래스는 protected와 private으로 지정 불가능
3. 메서드를 오버라이딩할 때 부모 클래스의 메서드보다 가시성을 더 좁게 할 수는 없다.
= 접근지정자를 축소할 수 없다! = 접근지정자를 동일하게 하거나 확장하는 것은 가능하다.
접근 지정자의 접근 범위 예시
/* 각종 접근 지정자를 사용하는 클래스 (기준) */
package sec06;
public class One {
private int secret = 1; //private 접근 지정자
int roommate = 2; //default 접근 지정자
protected int child = 3; //protected 접근 지정자
public int anybody = 4; //public 접근 지정자
public void show() { //멤버 메서드
}
}
/* 동일 패키지 (sec06)에 있는 자식 클래스 */
package sec06;
//같은 패키지기 때문에 import문 쓸 필요 x
public class One1 extends One {
//상속 관계니까 객체 만들 필요 x
void print() { //default 접근지정자
// System.out.println(secret); //private이니까 상속 자체도 안 됨
System.out.println(roommate); //실행 가능 (default 접근 지정자)
System.out.println(child); //실행 가능 (protected 접근 지정자)
System.out.println(anybody); //실행 가능 (public 접근 지정자)
}
// void show() { //에러남. 가시성이 달라진 것!
// }
//부모는 public인데 default로 가시성을 좁힌 거임 그래서 오류남
} //오버라이딩 할 거면 public해야 됨
//확장도 가능하긴 한데 public은 어차피 최상위니까 더이상 확장 X
public void show() { //부모 메서드와 같은 접근 지정자를 사용해서 오류 X
}
//예를 들어 부모에서 접근 지정을 default로 하면 여기서는 default public protected 가능
//private만 안 됨
/* 동일 패키지에 있는 클래스 (상속 관계는 X) */
package sec06;
public class Two { //상속 관계 없음
//상속 관계가 없으므로 객체를 이용해서 접근해야 함
void print() { //One 클래스에 접근
One o = new One(); //클래스가 public이니까 클래스를 이용해 객체 생성 접근 가능
// System.out.println(o.secret); //private라서 접근 불가능 애초에 상속 관계도 안 됨
System.out.println(o.roommate);
System.out.println(o.child);
System.out.println(o.anybody);
}
}
/* 다른 패키지 (sec06.other)에 있는 자식 클래스 */
package sec06.other;
import sec06.One; //다른 패키지에 있는 클래스 상속하기 위해서 import 문 꼭 필요!
public class One2 extends One { //상속 관계
void print() {
// System.out.println(secret); //private이니까 상속 자체도 안 됨
// System.out.println(roommate); //default는 패키지가 다르면 안 됨
System.out.println(child); //protected니까 상속 관계면 가능
System.out.println(anybody); //public은 그냥 다 가능
}
}
/* 다른 패키지 (sec06.other)에 있는 클래스 (상속 관계는 X) */
package sec06.other;
//import 문 생략 불가능, import 문 생략하면 sec06에 있는 클래스 사용 X
//클래스 사용 X인 경우 객체 생성 X -> 11번 라인에서 오류 발생
import sec06.One;
public class Three { //독립된 클래스에선 반드시 객체를 통해서 접근해야 함
void print() {
One o = new One();
// System.out.println(o.secret); //private이니까 x
// System.out.println(o.roomate); //같은 패키지 x
// System.out.println(o.child); //상속 관계 x
System.out.println(o.anybody);
}
}
2차시 final과 객체의 타입 변환
final 클래스
- 더이상 상속될 수 없는 클래스
- 대표적인 final 클래스로는 String 클래스
//class ChildString extends String {} //String은 final 클래스로 부모 클래스가 될 수 없음
class Good { //부모 클래스
}
class Better extends Good { //자식 클래스
}
final class Best extends Better { //자식 클래스 //final 클래스로 지정되어 더이상 상속 X
}
// class NumberOne extends Best {} //클래스 선언 불가능
public class FinalClassDemo {
public static void main(String[] args) {
// new NumberOne();
new Best();
}
final 메서드
- final 클래스는 클래스 내부의 모든 메서드 오버라이딩 불가능
- 오버라이딩은 상속 관계에서만 가능하므로 메서드 앞에 final이 붙으면 오버라이딩 불가능!
final 필드
- 상수: 변경할 수 없는 데이터를 담는 변수
- 상수 PI를 선언하고 싶으면 final double PI = 3.14;
class Chess { //부모 클래스
enum ChessPlayer { //enum 열거형
WHITE, BLACK
}
final ChessPlayer getFirstPlayer() { //final 메서드
return ChessPlayer.WHITE; //WHITE 반환
}
}
class WorldChess extends Chess { //Chess 클래스를 상속한 자식 클래스
// ChessPlayer getFirstPlayer() {} //ChessPlayer()는 final 메서드이기 때문에
//오버라이딩 불가능!
}
public class FinalMethodDemo { //메인 메서드를 갖는 public 클래스
public static void main(String[] args) { //메인 메서드
WorldChess w = new WorldChess(); //w 객체 생성
//w.getFirstPlayer();
System.out.println(w.getFirstPlayer()); //WHITE 출력
}
}
객체의 타입 변환
- 참조 타입인 객체도 상속 관계일 경우, 기초 타입 데이터처럼 타입 변환 가능
- 객체 타입 변환도 자동 타입 변환과 강제 타입 변환이 있다.
자동 타입 변환 - Upcasting (업 캐스팅)
- 업캐스팅하는 이유: 공유하기 위해서!
- 업캐스팅을 하는 경우, 부모 타입의 멤버는 부모, 자식 모두가 볼 수 있으나
자식 타입의 멤버는 자식에서만 볼 수 있음
- 즉 부모가 바라보는 영역은 자기자신으로 한정, 자식이 바라보는 영역은 부모에서 자식까지
/* 업 캐스팅 예시 */
public class UpcastDemo {
public static void main(String[] args) {
Person p; //객체 p 생성 - new 안 했으니까 아직 공간은 확보 X
Student s = new Student(); //객체 s 생성 - new 해서 메모리 할당 받음
//오른쪽에서 생성된 Student() 크기 만큼이 s가 바라보는 크기
p = s; //타입(형)이 맞지 않음. 왼쪽은 부모, 오른쪽은 자식
//자동으로 타입 변환, 업캐스팅 발생!
//p=(Person)s와 동일
// p.number = 1; //number와 work()는 부모 타입에 없는 멤버이므로
// p.work(); //부모 타입 변수에서 볼 수 없음
p.whoami();
}
}
강제 타입 변환 - DownCasting (다운 캐스팅)
- 적어도 한 번의 업캐스팅이 되어야 다운캐스팅이 가능!
Person p = new Person(); //객체 p 생성
Student s = (Student) p; //전자는 자식, 후자는 부모로 타입이 다름
//강제로 타입 변환을 하면 오류 발생 = 업캐스팅을 안 해서 오류 발생
//오류 발생하지 않으려면
//1번 라인을 Person p = new Student();로 수정
/* 다운 캐스팅 예시 */
public class DowncastDemo {
public static void main(String[] args) {
Student s1 = new Student(); //객체 생성 (타입 같음)
Person p = s1; //업캐스팅 //전자는 부모, 후자는 자식
//p가 자식의 공간을 바라보진 않지만 기억은 하고 있기 때문에 다운 캐스팅 가능
Student s2 = (Student) p; //다운캐스팅 //강제 타입 변환
}
}
타입 변환된 객체의 구별
(참조) 변수 instanceof(boolean 값 반환) 타입(클래스 이름 혹은 인터페이스 이름)
public class InstanceofDemo {
public static void main(String[] args) {
Student s = new Student(); //객체 생성
Person p = new Person(); //객체 생성
System.out.println(s instanceof Person); //s에서 Person 클래스가 보이는지 //true
System.out.println(s instanceof Student); //true
System.out.println(p instanceof Student); //false
// System.out.println(s instanceof String); //상속 관계에서만 타입 이야기 가능
downcast(s);
}
static void downcast(Person p) { //업캐스팅
if (p instanceof Student) {
Student s = (Student) p; //다운캐스팅
System.out.println("ok, 하향 타입 변환");
}
}
}
타입 변환을 이용한 다형성
/* 오버라이딩 여부에 따른 타입 변환의 영향 */
class Vehicle { //부모 클래스
String name = "탈 것";
void whoami() {
System.out.println("나는 탈 것이다.");
}
//static 키워드가 붙으면 업캐스팅 발생 시, 부모 것을 실행
static void move() { //static 키워드가 붙은 메서드
System.out.println("이동하다.");
}
}
class Car extends Vehicle { //Vehicle 클래스르 상속한 자식 클래스
String name = "자동차";
void whoami() { //메서드 오버라이딩
System.out.println("나는 자동차이다.");
}
static void move() {
System.out.println("달리다.");
}
}
public class OverTypeDemo {
public static void main(String[] args) {
Vehicle v = new Car(); //업캐스팅
System.out.println(v.name); //Vehicle의 name 필드 접근 //필드는 오버라이딩 X
v.whoami(); //메서드 오버라이딩했으므로 자식 메서드 실행 //나는 자동차이다.
v.move(); //정적 메서드이므로 부모 객체의 메서드 호출 //이동하다.
}
}
'Study > JAVA' 카테고리의 다른 글
[JAVA] 10주차_인터페이스 구현과 타입 변환, 기본 패키지, Wrapper 클래스, java.util 패키지 (자바 스터디) (0) | 2022.05.07 |
---|---|
[JAVA] 9주차_추상 클래스와 인터페이스, 인터페이스의 상속, 인터페이스 구현과 타입 변환 (0) | 2022.05.01 |
[JAVA] 6주차_상속 (메서드 오버라이딩, 패키지와 부모 생성자, Triangle 클래스와 Member 클래스) (0) | 2022.04.08 |
[JAVA] 5주차_동적배열과 상속 (동적배열과 객체배열, 상속, Rectangle 클래스, OddEven 클래스) (0) | 2022.04.03 |
[JAVA] 4주차_정적멤버, 문자열, 배열 (this와 정적멤버, 문자열, 배열) (0) | 2022.03.25 |