작업중: In progress 태그: Dev, 백엔드프로그래밍, 웹&모바일, 자바프로그래밍기초 학습일: 01/27/2023
package com.eomcs.oop.ex11;
-
다른 클래스 안에 정의된 클래스
-
해당 클래스 안에서만 사용된다.
⇒ 특정 클래스 안에서만 사용되는 클래스가 있다면 중첩 클래스로 선언해라. 노출 범위를 좁히는 것이 유지보수에 좋다.
패키지 멤버 클래스 (top level class) 접근 범위
- public 으로 공개된 클래스는 다른 패키지에서 접근 할 수 있다.
- public 으로 공개되지 않은 클래스는 다른 패키지에서 접근할 수 없다.
- (package-private; modifier 가 없다) : 다른 패키지 접근 불가!≠ public
따라서, 같은 패키지 내에 존재하거나, public 으로 공개된 클래스거나
-
static nested class
⇒ 바깥 클래스의 인스턴스에 종속되지 않는 클래스.
⇒ top level class 와 동일하게 사용한다.
-
non-static nested class = inner class (논스태틱중첩클래스 = 인스턴스중첩클래스)
⇒ 바깥 클래스의 인스턴스에 종속되는 클래스.
⇒ 중첩 클래스에서 바깥 클래스의 인스턴스 멤버를 사용한다.
⇒ 바깥 클래스의 인스턴스 없이 생성할 수 없다.
-
local class
⇒ 특정 메서드 안에 정의되어 그 메서드 안에서만 사용되는 클래스
⇒ 객체 생성코드 + 클래스 정의
⇒ 접근 제한자를 붙일 수 없다.
-
anonymous class (익명클래스)
⇒ 클래스 이름이 없기 때문에 생성자를 정의할 수 없고,
컴파일러가 디폴트 생성자를 자동 생성한다. (수퍼클래스와 동일하게)
(초기화를 원하면 "인스턴스 블록"을 사용)
⇒ 모든 클래스의 생성자는 항상 수퍼 클래스의 생성자를 첫 줄에 먼저 호출한다.
⇒ (클래스를 정의 하는 문법 + 인스턴스를 만드는 문법) 동시에 해야 한다.
⇒ 단 한 개의 인스턴스만 생성해서 사용할 경우 익명 클래스를 적용한다.
-
문법
**
new** 수퍼클래스() {수퍼 클래스를 상속 받은 익명 클래스 정의}
**
new** 인터페이스() {인터페이스를 구현한 익명 클래스 정의}
-
주의!
new extends 수퍼클래스 implements 인터페이스 {익명 클래스 정의} ← 이런 문법은 없다.
수퍼 클래스를 지정하거나 인터페이스를 지정하거나 둘 중 하나만 해야 한다.
-
# 예제 Object obj = new Object() { // Object 클래스를 상속 받은 익명 클래스를 만들고, // m1() 메서드를 추가한다. public void m1() { System.out.println("Hello!"); } };
-
cf. 컴파일 후에 중첩클래스는 모두 추출되어,
바깥클래스에 중첩클래스는 없다. > navigator 확인 가능 eg. A$X
Nest Members / Host 정보만 기재된다.
-
local class
[바깥클래스명]$[정의된순서][로컬클래스명].class
⇒ 정의된 순서이지, 나열된 순서가 아니다.
-
static
-
클래스 정의와 인스턴스 생성
바깥클래스명.중첩클래스명…
- 레퍼런스 선언
- 인스턴스 생성
-
선언할 수 있는 멤버
- 스태틱/논스태틱 모두 가능
-
다른 멤버(필드, 메서드)에 접근
- 바깥클래스 명으로 접근하며, 같은 클래스일 경우 생략 가능
- 스태틱 멤버(스태틱 중첩 클래스가 포함)는 this 라는 빌트인 변수가 없어서, 인스턴스 멤버에 접근 할 수 없다.
-
다른 멤버가 스태틱 중첩 클래스 사용하기
- 스태틱/논스태틱 멤버 모두 사용 가능
-
중첩클래스가 다른 패키지일 경우, import static 가능
- import로 미리 알려주면, 마치 클래스 멤버인양 클래스명 없이 사용 가능
- 중첩 클래스를 import 할 때는 static을 적지 않는다.
- wildcard(*) 사용 가능
-
-
inner class
-
클래스 정의와 인스턴스 생성
- 레퍼런스 선언
바깥클래스명.중첩클래스명…
- 인스턴스 생성
바깥 클래스의 인스턴스 주소 없이 생성 불가! 인스턴스 멤버를 사용하려면 반드시 해당 객체가 있어야 한다
⇒ 바깥 클래스 인스턴스 준비
package com.eomcs.oop.ex11.c.0110;
논스태틱중첩클래스는 바깥 클래스의 인스턴스 주소를 저장할 필드를 추가하거나, 생성자를 별도로 만들 필요가 없다.
⇒ 컴파일러 자동 생성
eg. myapp > AbstractList의 Iterator() {}
-
선언할 수 있는 멤버
-
inner class (논스태틱중첩클래스)는 스태틱 멤버를 가질 수 없다.
→ 단, Java16 부터는 inner class도 스태틱 멤버를 가질 수 있다.
…………
-
-
-
local class
-
인스턴스 메서드와 로컬 클래스
- 인스턴스 메서드는 C 인스턴스 주소를 this 변수에 저장한다.
그래서 인스턴스 메서드 안에 정의된 로컬 클래스는 바깥 클래스의 인스턴스를 사용할 수 있다.
-
스태틱 메서드와 로컬 클래스
- 스태틱 메서드는 C2 인스턴스 주소를 저장할 this라는 변수가 없다.
그래서 바깥 클래스의 인스턴스를 사용할 수 없다.
.class 파일을 확인해보면 바깥 클래스의 인스턴스를 보관할 필드가 선언되어 있지 않다.
또한 생성자에도 바깥 클래스의 인스턴스를 받는 파라미터가 선언되어 있지 않다.
-
로컬 클래스에서 사용하는 로컬 변수에 대한 제약 조건
- final 또는 final 처럼 사용해야 한다.
-
-
anonymous class
-
인터페이스의 경우 static으로 선언하지 않아도 스태틱 멤버에서 사용할 수 있다. => 인터페이스는 규칙을 정의한 것이기 때문에 인스턴스 멤버라는 개념이 존재하지 않는다.
-
익명 클래스로 인터페이스 구현하기
문법:
인터페이스명 레퍼런스 = new 인터페이스명() {};
- 파라미터 없이 호출하는 익명 클래스의 기본 생성자를 호출한다.
- 파라미터를 가지고 생성자를 호출한다면, 그 파라미터를 받는 수퍼클래스의 생성자를 호출할 것이다.
// 실무용 new A() { @Override public void print() { System.out.println("Hello!"); } }.print();
-
익명 클래스도 클래스라, 기본 생성자가 생성된다.
-
파라미터가 있는 수퍼 클래스를 상속 받는다면?
⇒ 익명 클래스의 객체를 만들 때 호출하는 생성자는
수퍼 클래스에 존재하는 생성자여야 한다.
= 컴파일러는 호출하는 수퍼클래스의 생성자와 동일한 파라미터를 갖는 생성자를, 익명 클래스에 추가한다.
-
-
수퍼 클래스와 인터페이스를 동시에 지정할 수 없다
-
여러 개의 인터페이스를 구현할 수 없다
-
모든 클래스의 생성자는 항상 수퍼 클래스의 생성자를 첫 줄에 먼저 호출한다.
-
익명 클래스가 놓이는 자리
-
스태틱 필드의 값을 준비할 때 익명 클래스를 사용할 수 있다.
-
인스턴스 필드의 값을 준비할 때 익명 클래스를 사용할 수 있다.
-
로컬 변수의 값을 준비할 때 익명 클래스를 사용할 수 있다.
-
파라미터 자리에 바로 삽입 가능하다. ⇒람다까지 응용 가능
package com.eomcs.oop.ex11.e; 450
test step4 : 람다문법 활용 : 메서드 1개짜리 인터페이스를 구현하는 경우 클래스 껍데기 지우고, 오버라이드 지우고 메서드명 지우고 화살표 문장이 한개면 중괄호, 세미콜론 생략 가능
-
-
cf. review
스태틱중첩클래스
컴파일러가 기본 생성자 추가
인스턴스중첩클래스
컴파일러가 바깥 클래스의 객체 주소를 받는 레퍼런스
생성자에서 바깥 클래스의 인스턴스를 받을 수 있도록 파라미터와 저장 코드를 추가
바깥 클래스의 객체 주소를 넘기는 코드로 자동 변경
package com.eomcs.oop.ex12;
411 중요
로컬(또는 익명 로컬) 클래스 안에서 바깥 메서드의 로컬 변수를 사용하면 컴파일러는 자동으로 그 값을 보관하기 위해 필드를 추가한다. 또한 그 값을 받을 수 있도록 생성자를 변경한다. 따라서 개발자가 직접 필드나 생성자를 정의할 필요가 없다.
중요!!!! 여기서 rate는 컴파일러가 생성한 필드를 가리킨다. 바깥 메서드의 파라미터가 아니다.
추상 메서드가 한 개 있는 인터페이스를 "functional interface”
⇒ 여러 개의 메서드가 있다 하더라도 추상 메서드가 한 개이면 된다.
⇒ 인터페이스가 아닌 추상 클래스는 람다 구현의 대상이 아니다!
람다 문법으로 인터페이스 구현하기 ⇒ 메서드 한 개짜리 인터페이스를 좀 더 간결하게 구현하기 위해 만든 문법이다.
cf.
람다와 .class 파일
⇒ 람다는 별도의 .class 파일을 생성하지 않는다.
⇒ 컴파일러는 람다 코드를 해당 클래스의 스태틱 메서드로 정의한다.
⇒ 그리고 리플렉션 API를 사용하여 이 메서드를 호출하도록 변경한다.
⇒ 람다 문법이 초기에 등장했을 때는 익명 클래스로 변환되었다.
⇒ 그러나 최근에는 메서드로 변환한 후 호출하는 방식으로 바뀌었다.
-
한 문장일 때는 중괄호를 생략할 수 있다.
- 물론 중괄호를 명확히 적어도 된다.
- 파라미터가 없다고 괄호를 생략할 수는 없다.
-
여러 문장을 실행하는 경우 블록 {}으로 감싸라! (블록을 생략할 수 없다.)
-
파라미터가 있을 경우
- 파라미터는 괄호() 안에 선언한다.
- 파라미터 타입을 생략할 수 있다.
- 파라미터가 한 개일 때는 괄호도 생략할 수 있다.
- 파라미터가 여러 개일 때는 괄호를 생략할 수 없다.
-
리턴문에 적용
-
리턴 값은 return 명령을 사용하여 처리한다.
-
한 문장으로 된 **표현식(=값을 리턴하는 한 문장의 코드)**인 경우 괄호 생략할 수 있다.
⇒ 문장은 문장인데 값을 리턴하는 문장을 '표현식(expression)' 이라 부른다.
⇒ 단 괄호를 생략할 때 return 키워드도 생략해야 한다. 있으면 컴파일 오류!
cf. Math.max() 도 값을 리턴하니깐, 표현식으로 간주한다.
cf. 값을 리턴해야 하는데 람다 문장에서 값을 리턴하지 않으면 컴파일 오류!
-
-
익명 클래스를 사용할 수 있는 곳에는 모두 람다 사용 가능
- 스태틱필드, 인스턴스필드, 로컬변수, 파라미터, 리턴값, 리턴문장 모두
기존에 작성한 클래스의 스태틱 메서드를 재활용하기
⇒ 인터페이스의 메서드 규격과 일치하는 메서드가 있다면,
그 메서드를 람다 구현체로 대체할 수 있다.
⇒ 규격? 메서드 시그너처 (메서드의 파라미터 타입/개수/순서, 리턴 타입)
⇒ 문법: 클래스명::메서드명
⇒ 시그너처가 다르면 불가능
📍 리턴타입이 다를 때, 형변환이 된다면 가능하다 0530 참고 int ⇒ double int ⇒ float …int ≠> short
메서드 레퍼런스를 지정할 때 리턴 타입의 규칙:
같은 리턴 타입
암시적 형변환 가능한 타입
auto-boxing 가능한 타입
void
결론, 메서드 레퍼런스가 가리키는 실제 메서드를 호출한 후 그 메서드가 리턴한 값이 인터페이스에 정의된 메서드의 리턴 값으로 사용할 수 있다면 문제가 없다.
메서드 레퍼런스를 지정할 때 파라미터 타입 규칙: => 인터페이스 규칙에 따라 받은 값을 실제 메서드에 그대로 전달할 수 있다면 가능하다.
Iterator next() 꺼내는 값 타입 고정하기 / List 와 나머지 또한
List 인터페이스를 구현하는 시점에서 다룰 데이터의 타입을 지정한다. 예) List
…
<제네릭>의 존재 이유
<타입이름을저장하는변수> : 타입 레퍼런스