접근지정자, 상속
기본적으로 package가 다르면 서로 접근이 불가능하다.
이것을 가능하게 하는 방법이 import 문을 사용하는 것이다.
문법:
import 패키지명.패키지명2.클래스명; ==> ex) com.google.Object (일반적으로 도메인을 거꾸로)
import 패지지명.패키지명2.*; ==> * 에스크리터는 패키지 안 클래스 모두를 사용한다는 의미.// 권장하지 않음
why? 어떤 클래스를 사용하는지 모르기 때문.
패키지명을 안써도 디폴트 패키지가 자동으로 만들어진다.
api 문서를 보면 알 수 있겠지만, java.lang 패키지는 따로 import 시키지 않아도 된다. -> 많이 쓰여서 알아서 import 됨
패키지는 클래스 관리를 용이하기 위해 사용한다. -> 그만큼 파일을 잘 관리할 것.
패키지명이 다르면, 클래스명이 동일하더라도 사용 가능하다.(com.stu.student, com.stu1.student 은 사용 가능)
==> 단 클래스명이 동일할 경우, 하나는 import로 사용가능하지만, 나머지 하나는 다이랙트로 입력해줘야한다.
ex) Student 동일 클래스명으로 다른 패키지 stu1, stu2에 있을때
import stu1;
Student s1 = new Student(); -- stu1 패키지
stu2.Student s2 = new stu2.Student(); -- stu2 패키지
JAVA에서 제공하는 API 패키명이 java로 시작하기 때문에, 패키지명 작명 시 java로 시작하면 안된다.
접근지정자
1. public : + 제약x 서로 다른 패키지도 접근 가능.
2. protected # 같은 패키지만 접근 가능, 패키지가 달라도 접근 가능할 경우는 상속 관계여야한다.
3. default 같은 패키지만 접근 가능
4. private: - 같은 클래스에서만 접근 가능
위 접근지정자 순으로 public -> private (1~4번순)으로 갈수록 제약이 커진다
static
클래스 작성의 경우 outer 클래스 및 inner 클래스가 있음
위 두가지 클래스를 동시 사용시 inner 클래스에서만 사용 가능하다.
메서드에서 사용할 시, 객체 생성 없이 메서드를 사용하기 위함.
변수: 프로그램 내에서 특정 데이터 값을 계속 유지할 목적이라면 static 변수가 적합.
static 키워드는 프로그램 실행 시 단 한번 생성됨. (method area 메모리 영역)
인스턴스 메서드 및 변수는 객체 생성(new)시 생성 -- heap 메모리 영역 , 객체 소멸시 삭제
static 키워드의 경우 클래스명으로 바로 접근 가능하다
인스턴스 키워드의 경우 객체 명으로 접근 가능하다.
static에서 힙쪽으로는 접근 x
힙에서는 static으로 접근 가능
why? static은 이미 생성이 돼있는 상태이고, 힙은 new 생성시 후에 만들어지기 때문이다.
메모리 구조
메소드 에어리어(method area) { 클래스 영역, static 영역, 상수 영역(final, contant) .. 으로 구성됨.}
객체의 소멸 ==> 자바의 가비지컬렉션(GC)가 더 이상 필요하지 않는 객체를 수집하여 메모리에서 제거시킴.
ex) Student s = new Student("홍길동"); ---> 아래 이순신으로 새로운 정보를 입혔으므로 GC가 삭제시킴.
Student s = new Strudent("이순신");
초기화 블럭
기본적으로 실행문은 블럭안에 있어야 한다.
ex) system.out.println(); == > 메서드 안에서나 생성자 안. 클래스 중괄호도 블럭이라고 생각할 수 있지만 안된다. 무조건 생성자 이상의 블록에서 실행 가능.
인스턴스 블럭은 호출하지 않으면 실행되지 않는다.
스태틱 블럭은 호출하지 않아도 실행된다.
상속(중요!)
JAVA 의 클래스 간 관계
{
has a 관계 ==> 멤버
is a 관계 == > 상속
}
상속은 extends 키워드를 사용하여 부모클래스의 정보를 자식 클래스에서 사용하게 된다.
UML에서 상속 관계는 실선 화살표 심볼이다.
문법:
public class 자식클래스명 extends 부모클래스명{
}
부모 클래스에도 또 부모클래스가 있는데, Object 클래스(최상위 클래스)가 있다. 인스턴스 object와 다름.(대, 소문자)
=> A클래스가 B 클래스의 부모 클래스면, 실제로는 은연으로 extends Object 클래스가 삽입된다.
ex) public class A (extends Object) {}; <- 소괄호 안은 은연으로 생략돼있음.
상속은 단일상속만 지원한다. 단, 상속 불가한 경우가 있다.
1. 부모 생성자 -> 자식은 부모 생성자를 상속 받을 수 없다.
2. private -> private는 애초에 자기 자신(멤버)만 쓸 수 있기 때문에 상속 관계에서도 자식클래스에서 사용할 수 없다.
+++상속 내용 추가
1. 클래스들간의 관계중 'is a' 관계이다.
2. 상속이 적용되면 부모의 요소 중 생성자 및 private으로 지정된 요소를 제외하고 나머지는 자식이 그냥 사용 가능하다.
3. 명시적으로 상속받지 않은 클래스는 자동으로 Object 클래스를 상속 받는다.(Object = 최상위 클래스)
====> Object 클래스는 모든 클래스의 부모이다.
4. 단일 상속만 지원
5. UML 표기법은 실선 화살표, 코드로는 extends 키워드를 이용한다. 부모 A < ㅡ 자식 B
6. 타입으로 따지면 부모가 더 큰 타입, 자식은 작은 타입
7. 항상 new 한 자식 클래스보다 부모의 기본 생성자를 먼저 생성한다.(자식 클래스가 부모 클래스의 생성자를 사용할 순 없지만, new 자식 클래스로 힙에 생성을 할 경우 부모 기본 생성자가 자동으로 생성되어 안에 내용을 실행한다.
-> 부모 클래스를 생성하는 코드가 자동으로 삽입됨. 그렇다고 new 부모클래스()는 아니다.. new 부모클래스()의 경우는
다른 클래스에서 사용하는 것이고, 자식에서는 super() 형식으로 부모 생성자를 호출하기 위해서 자동으로 삽입된다.
super(); ==> 부모의 기본 생성자 호출 코드
*** 모든 클래스의 자식생성자 첫 라인에서 부모 생성자를 호출하는 코드가 자동으로 삽입된다. ==> super(); ***
만약 super()를 명시적으로 작성한다면 반드시 첫 라인에서 작성할것. -> 이렇게 안하면 에러 난다.
*** 어떠한 클래스에서든 자기 자신(멤버)쪽에서 초기화 하는 것이 객체지향 관점에서 보기 좋다.***
-> 부모 클래스의 매개변수를 자식클래스에서 초기화를 해도 문법상 문제 없으나, 객체지향적으로 옳지 않다
상속을 쓰는 이유는 중복 코드의 발생을 최소화하기 위해서다.
1) 상속 x ==> 중복 코드 발생 높아짐
2) 상속 o ==> 중복 코드를 최소, 재사용성이 높아진다. => 부모 클래스에서 한 번만 만들어주면 되기 때문에