1. 형변환(Type Casting)
* 묵시적 형변환 (업캐스팅)
- 작은 범위의 데이터를 큰 범위의 할당하는 경우와 같이 값의 변화가 발생하지 않는 변환
double d = 12.34;
int i = 1234;
// double > int : 묵시적 형변환
d = i;
d = 1234.0
* 강제적 형변환 (다운캐스팅)
- 큰 범위의 데이터를 작은 범위에 할당하는 경우는 값의 변화가 일어날 수 있기 때문에 변환하고자 하는 변수명 앞에
(데이터형)을 지정한다
double d = 12.34;
int i = 1234;
// double > int : 묵시적 형변환
i = d; // [x]
i = (int)d;
i = 12
* 다운캐스팅의 경우 타입을 지정해 주지 않으면 에러가 난다.
2. 내부클래스(InnerClass)
* 내부 클래스란 ??
- 클래스안의 클래스를 내부 클래스 혹은 Inner클래스 혹은 중첩 클래스, Nested클래스라 한다.
- 내부 클래스는 외부 클래스의 변수이나 메서드를 자신의 것처럼 자유롭게 사용가능
ㄴ 단,내부 정적 클래스만이 외부의 non-static멤버를 사용 못함
- 내부 정적 클래스만 제외하고 모든 내부클래스가 정적 멤버를 가질 수 없다.
- GUI에서 이벤트 처리 할때 주로 사용한다 (내부 클래스 중에서도 주로 내부 무명클래스를 사용)
※ 외부클래스를 인스턴스화(객체화 즉 new)하면 외부클래스가 heap영역에 메모리가 생기고
내부클래스는 new해줘야 메모리에 생긴다. 고로 내부 클래스에서는 외부 클래스가 먼저 메모리에 생김으로
외부클래스의 모든 멤버를 사용할 수 있다. 단, 외부클래스에서는 내부클래스의 멤버를 사용하려면
new(내부 클래스도 설계도임으로)해서 사용해야 한다.(원칙)
단, 내부정적 클래스는 외부 클래스보다 먼저 메모리에 생긴다.
* 내부 클래스의 종류
- 클래스가 정의되는 위치에 따른 분류
ㄴ 클래스 안에 정의된 클래스
ㄴ 내부 멤버 클래스 (static이 안붙음)
ㄴ 내부 정적 클래스 (static이 붙음)
ㄴ 메소드 안에 정의된 클래스
ㄴ 내부 로컬 클래스 (이름이 있는 클래스)
ㄴ 내부 무명 클래스 (이름이 없는 클래스, 무명 클래스)
* 내부 멤버 클래스 (non-static 클래스)
- static 멤버를 가질 수 없다
- 객체 생성 : 외부 클래스의 객체를 먼저 생성 후 그 외부 객체로 내부 객체를 생성한다
Outer ot = new Outer();
Outer.Inner in = ot.new Inner()
- 클래스 생성시 클래스 파일 이름은 Outer$Inner.class가 된다
class Outer {
class Inner {
}
}
* 내부 정적 클래스 (static 클래스)
- 원래 클래스 앞에는 지정자 static이 못 붙지만 클래스 안의 클래스는 가능하다. 이를 내부 정적 클래스라 한다
- static 멤버를 가질 수 있다
- 그러나 외부의 instance형 즉 non-static멤버에는 접근 불가
- 객체 생성 : 정적 클래스 이기때문에 외부 클래스 이름으로 생성한다. 즉, 외부클래스를 먼저 생성할 필요가 없다
Outer1.Inner1 in = new Outer1.Inner1();
- 클래스 생성시 파일이름은 Outer1$Inner1.class 가 된다
class Outer1 {
static class Inner1 {
}
}
* 내부 로컬 클래스
- 메소드 안에 지역변수처럼 들어가는 이름이 있는 클래스
- static멤버를 가질 수 없다
- 지역변수처럼 메소드 안에서만 사용가능. 즉, 메소드 안에서 객체를 생성한다
- 메소드 안에서 객체를 생성해야 한다
- 클래스 생성시 파일이름은 Outer3$인덱스숫자Inner3.class가 된다
여기서 인덱스는 서로 다른 메소드에 같은 이름의 클래스가 올 수 있기때문에 인덱스로 구분
class Outer3 {
void func() {
class Inner3 {// 내부로컬 클래스
}
Inner3 in = new Inner3(); // 메소드 안에서 객체 생성
}
}
* 내부 익명 클래스
- 이름이 없는 클래스
- 상위 클래스를 상속 받아서 오버라이딩 할 경우 주로 사용한다
- GUI에서 이벤트 처리할때 주로 사용
- 클래스 생성시 파일이름은 Outer4$인덱스숫자.class
class Outer4 {
public void printA() {
System.out.println("A출력");
}
}
- main메소드에서 Outer4 생성시 아래 { }안에 클래스 멤버 구성하듯이 멤버를 구성한다
- 주로 상위클래스의 메소드 오버라이딩
- 밑에는 Outer4가 상위 클래스가 된다
Outer4 ot = new Outer4() {
};
- 예제
Outer4 ot = new Outer4() {// 부모객체타입 선언하고 자식개채(무명 클래스)로 생성
public void printA(){
System.out.println("오버라이딩");
}
public void printNew(){
System.out.println("새로 추가된 메서드");
}
};
ot.printA();//오버라이딩 출력
ot.printNew();//찾을 수 없다는 컴파일 에러
*오버라이딩이 아닌 메서드는 추가해 봐야 사용 못한다 에러발생
interface MyInter {
void printNumber();
}
public class Outer5 {
public static void main(String[] args) {
// 인터 페이스 인스턴스화 가 아니라 무명 클래스 즉 MyInter를
// implements하는 무명 클래스 생성 하는 것임
// 원래는 new 자식클래스명 implements MyInter이나 이름이 없기때문에 new MyInter()로 표현
MyInter mi=new MyInter() {
public void printNumber(){
System.out.println("익명 클래스");
}
};
mi.printNumber();
}
}
* 내부 멤버 클래스
class OuterClass {
// [멤버변수]
// 인스턴스형 멤버변수]
int outerInstanceVar;
int sameVar = 100;
// 내부 클래스 인스턴스화 하기]
// 방법1] 내부 클래스 타입의 멤버변수 선언과 동시에 인스턴스화
// InnerClass inner = new InnerClass();
// 방법2]
// 2-1] 내부 클래스 타입의 멤버변수 선언
InnerClass inner;
public OuterClass() {
inner = new InnerClass();
System.out.println("외부 클래스의 생성자");
}// OuterClass()
// 정적 멤버변수]
static int outerStaticVar;
// [멤버메소드]
// 인스턴스형 멤버메소드]
void outerInstanceMethod() {
// 내부 클래스 인스턴스화 전]
// System.out.println(innerInstanceVar);[x]
// innerInstanceMethod();[x]
// 내부 클래스 인스턴스화 후]
System.out.println(inner.innerInstanceVar);// [o]
// inner.innerInstanceMethod();[o] - recursive발생
System.out.println(InnerClass.INNER_MAX_INT);// [o]
}// outerInstanceMethod()
static void outerStaticMethod() {
// System.out.println(inner.innerInstanceVar);
// [x] 멤버 메소드에서 인스턴스멤버 접근불가 및 내부클래스의 멤버 접근 불가
// 상수접근 가능
System.out.println(InnerClass.INNER_MAX_INT);
}// outerStaticMethod()
// [내부 멤버클래스]
public class InnerClass {
// [멤버변수]
// 인스턴스형 멤버변수]
int innerInstanceVar;
int sameVar = 1;
// [내부 클래스의 생성자]
public InnerClass() {
System.out.println("내부 클래스의 생성자");
}
// 인스턴스형 메소드]
void innerInstanceMethod() {
// 내부클래스 에서는 외부의 모든 멤버 사용 가능(중요)!!
System.out.println(outerInstanceVar);
System.out.println(outerStaticVar);
outerInstanceMethod();
outerStaticMethod();
// 내부 멤버변수 = 내부 멤버변수
// 내부 클래스안에서 this는 내부 클래스지칭
// 내부 클래스 안에서 외부클래스.this는 외부 클래스
this.sameVar = sameVar;
// 외부 멤버변수 = 내부 멤버변수
OuterClass.this.sameVar = sameVar;
}// innerInstanceMethod()
// [정적멤버] - 정적멤버(상수제외)는 가질수 없다. 단, static이 붙은 상수는 가질 수 있다
// static int innerStaticVar; [x] 메소드도 같음
public static final int INNER_MAX_INT = Integer.MAX_VALUE; // [o]
}// innerclass
}// class
public class InnerMemberClass {
public static void main(String[] args) {// 외부 인스턴스화 안하고 내부 인스턴스화는 절대 불가
// 내부 클래스의 상수 접근 - 외부 클래스가 아니라 별개의 클래스에서
System.out.println(InnerClass.INNER_MAX_INT);
// 외부 클래스가 아닌 별개의 다른 클래스에서는 내부 멤버 클래스가 안보인다
// 즉, 직접 인스턴스화 불가
// InnerClass inner = new InnerClass();[x]
// 1] 외부 클래스는 무조건 먼저 인스턴스화
OuterClass outer = new OuterClass();
// 외부 클래스가 아닌 다른 클래스에서 내부 클래스로 접근하려면 외부 클래스 생성 후 접근 가능
// 방법1] 외부 클래스의 멤버 변수로 내부 클래스 타입을 선언후 객체생성
// (선언과 동시에 객체생성 혹은 외부클래스의 생성자에서 객체생성) 외부클래스의
// 인스턴스 변수로 접근
outer.inner.innerInstanceMethod();
// 방법2] 외부클래스를 이용해서 직접 내부클래스 인스턴스화
OuterClass.InnerClass inner = outer.new InnerClass();
inner.innerInstanceMethod();
}// main
}// class
* 내부 정적 클래스
class Member {
// 1] 멤버 변수는 private
// 필수 항목]
private String id;
private String name;
// 선택 항목]
private String tel;
private String addr;
// 2] 내부 정적 클래스타입을 인자로 받는 생성자 정의
public Member(Builder builder) {
// 멤버변수 초기화]
this.id = builder.id;
this.name = builder.name;
this.tel = builder.tel;
this.addr = builder.addr;
}// Member(Builder builder)
public void print() {
System.out.println(String.format("아이디 : %s, 이름 : %s, 전화번호 : %s, 주소 : %s", id, name, tel, addr));
}
// 3] 내부 정적 클래스
public static class Builder {
// 4] 외부 클래스와 같은 멤버변수를 갖는다
// 필수 항목]
private String id;
private String name;
// 선택 항목]
private String tel;
private String addr;
// 5] 내부 클래스 인자생성자(필수항목만 받는 생성자)
public Builder(String id, String name) {
this.id = id;
this.name = name;
}// (String id, String name)
// 6] 멤버변수를 초기화 하는 세터 메소드(반환타입은 빌더)
public Builder setTel(String tel) {
this.tel = tel;
return this;
}// setTel(String tel)
public Builder setAddr(String addr) {
this.addr = addr;
return this;
}// setAddr(String addr)
// 7] 외부 클래스 타입을 반환하는 정적 메소드 생성
public Member build() {
return new Member(this);
}// build()
}// Builder class
}// Member class
public class InnerStaticBuilderApp {
public static void main(String[] args) {
// 필수항목만 갖고 객체 생성
Member member1 = new Member.Builder("kim", "김길동").build();
member1.print();
Member member2 = new Member.Builder("park", "박길동").setTel("010").build();
member2.print();
Member member3 = new Member.Builder("lee", "이길동").setTel("010").setAddr("가산동").build();
member3.print();
}// main
}// class
* 내부 익명 클래스
class Person {
String name;
// 인자생성자]
public Person(String name) {
this.name = name;
}// Person(String name)
void print() {
System.out.println("이름 : " + name);
}// print()
}// Person class
class Student extends Person {
String stNumber; // 자식에게서 새롭게 확장한 멤버변수]
// 인자생성자]
public Student(String name, String stNumber) {
super(name);
this.stNumber = stNumber;
}// Student(String name, String stNumber)
// 자식에서 새롭게 확장한 멤버 메소드]
String get() {
return String.format("학번 : %s ", stNumber);
}// get()
@Override
void print() {
super.print();
System.out.println(get());
}// print()
}// Student extends Person
// [추상클래스]
abstract class AbstractClass {
abstract void abstractMethod();
}
// [인터페이스]
interface Inter {
void abstractMethod();
}
public class InnerAnonymousClass {
public static void main(String[] args) {
// [이름이 있는 자식클래스의 일반적인 이질화 형태]
Person person = new Student("홍길동", "2018학번");
// 오버라이딩]
person.print();
// [자식에게서 새롭게 확장한 멤버 접근] - 형변환 (다운캐스팅)
((Student) person).stNumber = "2019학번";
System.out.println(((Student) person).get());
// [Person을 상속받은 익명 클래스 정의 및 생성]
// Person타입의 인스턴스변수에 Person을 상속받은 익명클래스를 생성해서 그 주소를 할당
// new Person(){}; -> new 무명 extends Person{};
// - 이름이 없기때문에 부모클래스의 이름을 빌려서 생성했다고 생각하자
Person anony = new Person("가길동") {
// [멤버변수]
int newvar; // 익명클래스에서 새롭게 확장한 멤버
// [멤버메소드]
void newmethod() {
System.out.println("익명 클래스에서 새롭게 확장한 메소드");
}
@Override
void print() {
System.out.println("익명 클래스에서 오버라이딩");
}
};// 익명클래스
anony.print();
// [자식에서 새롭게 정의한 멤버 접근]
// 다운캐스팅 - (자식클래스명) 부모타입인스턴스변수
// 클래스명이 없으므로 다운캐스팅 불가
// 고로 자식에서 새롭게 정의한 멤버 접근 불가
// * 익명클래스는 오버라이딩이 목적
Student anony_st = new Student("김길동", "2019학번") {
// [멤버변수]
int age = 1; // 자식에서 새롭게 추가한 멤버
// [오버라이딩]
@Override
String get() {
return "이름 : " + name + " , " + super.get() + "나이 : " + age;
}
@Override
void print() {
super.get();
}
};
anony_st.print();
// 추상클래스를 상속받은 익명 클래스]
// new 무명 extends AbstractClass(){}
AbstractClass ac = new AbstractClass() {
@Override
void abstractMethod() {
}
};
// 인터페이스를 상속받은 익명 클래스]
// new 무명 implements Inter(){}
Inter inter = new Inter() {
@Override
public void abstractMethod() {
System.out.println("추상메소드 오버라이딩 : 인터페이스");
}
};
}// main
}// class
'개발 > JAVA' 카테고리의 다른 글
20. JAVA 쓰레드 (Thread) (0) | 2020.06.08 |
---|---|
19. JAVA 예외(Exception) / try~catch~finally (0) | 2020.06.08 |
17. JAVA 인터페이스 (Interface) / 컬렉션 (Collection) (0) | 2020.06.08 |
16. JAVA 배열 (Array) / 헤테로지니어스 (Heterogeneous, 이질화) (0) | 2020.06.08 |
15. JAVA 패키지 / 패키지 배포 (0) | 2020.06.08 |