중첩클래스

아기코딩단2·2022년 3월 28일
0

top level class - 패키지에 소속된 클래스다.
public / private(현재 패키지에서만 적용가능 / 자식 패키지는 사용불가(modifier 없다)) - top level pakage 는 이 두가지 밖에 없음

is not visible = 볼 수 없다는 뜻

중첩클래스 - 유지보수가 편리하다. 중첩되는 클래스가 작을 경우 사용하면 좋음
static 붙으면 다 스태틱 멤버임
안붙으면 non-static nested class = inner class

바깥 클래스에 종속되는 inner class 를 만들 경우 스태틱빼라

static안붙으면 인스턴스 멤버

특정 메서드 안에서만 사용하는 클래스 - local class

익명 클래스 - new 명령어로 인스턴스를 생성할 수 없다 / 클래스를 정의하는 문법과 인스턴스를 만드는 문법이 결합되어 있다. 즉 클래스를 정의하는 동시에 인스턴스를 생성해야한다. 그리고 생성자도 정의 불가

Object(수퍼클래스 또는 인터페이스 명) obj = new Object() {
// Object 클래스를 상속 받은 익명 클래스를 만들고,
// m1() 메서드를 추가한다.
public void m1() {
System.out.println("Hello!");
}
};

객체 생성 후 세미콜론 없으면 익명클래스를 만드는 거라고 생각하면 됨
익명 클래스는 외부에서 호출불가
즉 익명클래스는 리플렉션 api? 로 호출가능

non-static-class = inner class

로컬변수는 modifier 없음 (private, public, protected)

작은 클래스를 패키지로 관리하지말고 하나의 클래스 안에 담에서 사용하기 위해서 중첩클래스를 사용함

랭귀지마다 코딩스타일을 따라가라

inner class 에서 outer 클래스를 조작할 때도 필요하고 바깥에서도 쓰고싶으면 관리 차원에서 패키지로 구분하기 보다는 관리차원에서 패키지 밑에 안두고 클래스 안에 묶어둔 것임

static 중첩클래스는 import 해서 inner 클래스를 사용할 수 있음

같은 클래스 안에 static class 에서는 클래스명을 생략할 수 있음

static method 는 this 라는 내장 변수가 없음

static 멤버는 instance 멤버로 접근 할 수 없다.

instance method 는 local 변수에 this 존재

스태틱 중첩 클래스도 스태틱 메서드처럼 다른 스태틱 멤버를 그대로 사용할 수 있다.
Why? X 클래스는 B2의 스태틱 멤버이기 때문이다

static 멤버는 non-static 멤버 참조불가

인스턴스 멤버는 스태틱 멤버 접근가능

import 하면 굳이 길게 안써줘도 됨. 즉 바로 사용할 클래스 이름만 써주면 됨 D.X.m1() => X.m1()
즉 컴파일러가 컴파일 할 때 알아서 붙여줌 변수명이든 메서드 명이든(멤버)

그냥 다 import 해주면 편리함(간략하게 해주는 역할)
static 멤버의 경우 필드와 메서드까지 import 가능 static 필드와 메서드를 import 하려면 import static 하면됨

import static com.eomcs.oop.ex11.b.sub.M.m2; <= 이런식으로

그냥 wildcard 쓰면 한번에 지정가능 근데 이건 비추

패키지 멤버클래스를 top level class 라고 부른다.

non-static-nested class = inner class

중첩클래스를 만들 때는 처음에 static 붙이는 것이 좋음 이후에 static 을 뗄지 말지 고민해야함

수퍼클래스의 생성자를 호출하는 involk 문장을 집어넣어줌

inner class 는 this 변수를 사용할 수 있음

jdk 16부터는 inner class 안에서 static 변수 사용가능

obj = outer.new X(); => 컴파일러가 new A.X(outer) 로 바꿔준다 근데 우리가 직접 이렇게 써주면 안됨

inner class 의 객체를생성할 때는 바깥 클래스의 주소가 필요하다
new A2().newX() 하면inner class 의 객체를 생성하겠다는 뜻

바깥클래스명.this 이렇게 하면 바깥클래스에 접근가능 즉 바깥클래스에 접근하려면 바깥클래스명.this.해주면 됨

inner 클래스는 바깥 객체의 주소도 가지고 잇음 this$0

System.out.printf("v1 = %d\n", v1); // 로컬 변수 // 안붙이면 제일 가까운 곳에서 찾음
System.out.printf("this.v1 = %d\n", this.v1); // 인스턴스 변수
System.out.printf("B3.this.v1 = %d\n", B3.this.v1); // 바깥 객체의 인스턴스 변수

inner class 객체 생성하면 안에 this$0 이라는 변수가 잇는데 여기에 outer 객체의 주소가 있다

this 생략 생각 잘해라~ 현재 클래스의 주소가 담겨져 있음

그냥 클래스는 this 내장변수가 있는 거고?? this 생각 잘해라~

void m2() {
// 인스턴스 메서드는 인스턴스 주소를 담고 있는 this 변수가 있다.
// 그래서 inner class 를 사용할 수 있다.
X obj = this.new X();
obj.test();

X obj2 = new X(); // 인스턴스 필드나 메서드와 마찬가지로 this를 생략할 수 있다.
obj2.test();

}

static 메서드는 인스턴스를 담고 있는 this 변수가 존재하지 않는다. 그래서 인스턴스를 생성 불가능
레퍼런스 선언만 가능

중첩클래스의 경우 로컬에서 찾아보고 없으면 바깥 클래스에서 찾음

중첩클래스 사용하면 new 명령어로 만들 때 생성자의 파라미터로 안넘겨줘도 된다. 그냥 m1.Player() 이렇게 주면 됨

// 바깥 클래스의 인스턴스를 사용하는 inner 클래스라면
// inner 클래스의 객체를 만드는 역할도
// 바깥 클래스가 하는데 유지보수에 더 낫다.
// => GRASP 설계 기법에서 "정보를 가진자가 그 일을 하라.(Information Expert)"를 적용.

스태틱 메서드 내부의 클래스에서는 외부의 클래스에 접근 할 수 없다.

바깥쪽 클래스의 로컬변수를 따로 백업해둔다.
로컬 클래스에서 메서드의 로컬변수를 사용한다면, 컴파일러는 로컬 클래스에 바깥 메서드의 로컬 변수 값을 저장할 필드를 추가한다. 또한 로컬 클래스의 객체를 생성할 때 생성자에 로컬 변수의 값을 넘겨줄 것이다. 로컬 변수를 잃어버리지 않도록 임시변수에 담아둔다 컴파일러에서 그리고 생성자에서 넘겨준다. (즉 컴파일러가 알아서 임시변수에 담아둠 ex) float val$interest;) => 자스의 클로져랑 비슷함

// Field descriptor #8 F
private final synthetic float val$interest; <=임시변수 생성

// Method descriptor #10 (F)V
// Stack: 2, Locals: 2
CalculatorFactory$1CalculatorImpl(float arg0); <= 생성자에 임시변수 넣어줌

----------이런식으로 코드를 바꿔줌------------

값을 여러번 할당한 경우에는 로컬변수에 접근할 수 없음 즉 nested클래스에서 접근 불가 <= 컴파일 오류
why? 로컬 객체가 사용하는 로컬 변수는 메서드 호출이 끝났을 때 제거되기 때문이다.


인터페이스의 경우 static 으로 선언하지 않아도 스태틱 멤버에서 사용할 수 있다. => 인터페이스는 규칙을 정의한 것이라서 인스턴스 멤버 개념이 존재하지 않는다.

익명 클래스 = 클래스 정의 문법 + 인스턴스 생성 문법

2) 익명 클래스로 인터페이스 구현하기
=> 인스턴스를 한 번 만 생성할 것이라면,
로컬 클래스로 정의하는 것 보다 익명 클래스로 정의하는 것이 더 낫다.
=> 특히 객체를 사용하려는 곳에 바로 익명 클래스를 정의하면
읽기 쉽기 때문에 소스 코드를 유지보수 하기가 더 좋다.

익명 클래스로 인터페이스 구현하기
문법:
=> 인터페이스명 레퍼런스 = new 인터페이스명() {};

  • 호출하는 생성자는 수퍼 클래스의 생성자이다.

익명 클래스의 생성자가 없기 때문에 수퍼 클래스의 생성자를 호출한다.
=> 객체 생성할 때 항상 생성자를 호출해야 하는데,
클래스에 이름이 없으면 생성자를 만들 수 없다.
따라서 호출할 익명 클래스의 생성자가 없다.
(실제는 내부에 익명 클래스의 기본 생성자가 만들어진다.)
그래서 수퍼 클래스의 생성자를 호출해야 한다.
자바의 모든 클래스는 따로 수퍼 클래스를 지정하지 않으면
java.lang.Object 클래스가 수퍼 클래스로 자동 설정된다.
바로 그 Object 클래스의 생성자를 호출하도록 지정해야 한다.
Object 클래스의 생성자는 기본 생성자 하나 뿐이다.
인터페이스 이름 뒤에 기본 생성자를 호출하는 괄호를 추가한다.

익명 클래스는 인터페이스나 클래스 둘중 하나만 상속 받아야함

public Exam0210$X(com.eomcs.oop.ex11.e.Exam0210 arg0, java.lang.String s); 첫번째 파라미터가 바깥 클래스의 주소를 받음

인스턴스 블럭은 여러 생성자에서 동시에 들어가는 걸 집어 넣어라 걔가 따로 컴파일 되는 게 아니고 생성자에 추가가 됨
먼저 컴파일 되거나 그런 게 아니고 컴파일러가 생성자 앞부분에 추가해줌

익명클래스에서 코드를 추가하고 싶을 때 인스턴스 블럭에 넣으면 된다(생성자의 사용)
익명클래스에서의 인스턴스 블록활용

super 클래스의 생성자가 1빠따로 실행됨

메서드 하나짜리 인터페이스를 functional interface 라고 말함

메서드 레퍼런스는 인터페이스와 그 형식이 같을 때 줄 수 있음 근데 static 은 클래스명 주면 되고 인스턴스는 new 명령어로 객체 주면 됨 메서드 하나만 있어야함 되는 경우도 있는데 추상메서드가 하나면 된다 인터페이스에서 defalult로 정의된 것이 있으면 가능 // 인터페이스만 가능(람다랑 메서드 레퍼런스) 추상클래스 그런 거 안댐ㅇㅇ

상수를 문자열로 정의하면 메모리를 많이 차지하기 때문에 숫자열로 지정한다.(메모리를 조금 차지하기 때문)

중첩클래스의 경우 소문자로 쓰는 경우 많음 why? 변수처럼 사용하는 것처럼 보이기 위해서

profile
레거시 학살자

0개의 댓글