package com.zoo;
Zoo.java
package com.zoo;
public class Zoo {
public void tiger() {
System.out.println("무서운 호랑이");
}
protected void giraffe() {
System.out.println("목이 긴 기린");
}
void elephant() {
System.out.println("뚱뚱한 코끼리");
}
private void lion() {
System.out.println("멋진 사자");
}
}
package com.apple;
Apple.java
package com.apple;
import com.zoo.Zoo;
public class Apple {
public static void main(String[] args) {
System.out.println("빨강 사과");
//Zoo 클래스의 tiger() 호출
Zoo zoo = new Zoo();
zoo.tiger();
//zoo.giraffe();
//zoo.elephant();
//zoo.lion();
}
}
→ 다른 패키지이므로 public으로 정의된 tiger()만 불러올 수 있다.
package com.zoo;
Zoo2.java
package com.zoo;
public class Zoo2 {
public static void main(String[] args) {
//Zoo 클래스의 tiger() 호출
Zoo zoo = new Zoo();
zoo.tiger();
zoo.giraffe();
zoo.elephant();
//zoo.lion();
}
}
→ 같은 패키지이므로 private으로 정의된 lion() 빼고는 다 가능하다.
(public, protected, default 다 가능하다.)
package com.zoo.safari;
Safari.java
package com.zoo.safari;
import com.zoo.Zoo;
public class Safari extends Zoo {
public static void main(String[] args) {
//Zoo 클래스의 tiger() 호출
Zoo zoo = new Zoo(); //부모는 자식에 뭐가 있는지 잘 모름.
zoo.tiger();
//zoo.giraffe();
//zoo.elephant();
//zoo.lion();
Safari safari = new Safari(); //자식으로 생성해야함.
safari.tiger();
safari.giraffe();
//safari.elephant();
//safari.lion();
//단 Sub 클래스로 생성해야만 한다
//Super클래스로 생성하면 접근이 안된다 ★★★★★
}
}
이 경우는 Zoo - 부모 / Safari - 자식 관계이다.
- Zoo zoo = new Zoo();
다른패키지여도 상속관계면은 protected로 정의된 giraffe()가 무조건 사용가능한거 아닌가?라는 의문이 들 수 있다.
하지만 이 코드의 경우에는 부모 Zoo가 상속을 해준 경우라도
부모는 자식 안에 뭐가 있는지 모른다.
그러므로 이 경우는 첫 번째와 동일하게 다른 패키지에 있어도 사용가능한 public으로 정의된 tiger만 불러올 수 있는 것이다.
- Safari safari = new Safari();
이처럼 자식으로 생성을 해야지만 비로소 부모 클래스에 접근이 가능해지고 protected로 정의된 giraffe()가 사용이 가능해지는 것이다.
ObjectMain.java
package inheritance;
import java.util.ArrayList;
class Test extends Object{
@Override
public String toString() {
return getClass() + "@개바부";
}
}
//-------------
public class ObjectMain {
public static void main(String[] args) {
Test test = new Test();
System.out.println("객체 test = " + test); //클래스@16진수
System.out.println("객체 test = " + test.toString()); //위와 같음.
System.out.println("객체 test = " + test.hashCode()); //10진수
System.out.println();
String str = "apple";
System.out.println("객체 str = " + str); //클@16진수==> 문자열
System.out.println("객체 str = " + str.toString());
System.out.println("객체 str = " + str.hashCode()); //의미없는 숫자(믿지말기)
System.out.println();
String aa = new String("apple");
String bb = new String("apple");
System.out.println("aa==bb : " + (aa==bb)); //참조값 비교(주소비교), false
System.out.println("aa.equals(bb) : " + aa.equals(bb)); //문자열 비교, true
System.out.println();
Object cc = new Object();
Object dd = new Object();
System.out.println("cc==dd : " + (cc==dd));//참조값 비교(주소비교), false
//Object는 주소값 물어보는 것, /참조값 비교(주소비교), false
System.out.println("cc.equals(dd) : " + cc.equals(dd));
System.out.println();
Object ee = new String("apple");
Object ff = new String("apple");
System.out.println("ee==ff : " + (ee==ff));//참조값 비교(주소비교), false / ==는 무조건 주소비교
//문자열 비교, true equals는 오버라이딩하고 있으므로 뭘 가리키던 상관없음. -> 무조건 문자열 비교
System.out.println("ee.equals(ff) : " + ee.equals(ff));
System.out.println();
ArrayList<String> list = new ArrayList<String>();
list.add("호랑이");
list.add("사자");
System.out.println(list); //클@16진수 ==> [항목] (주소가 이렇게 나옴)
// ArrayList는 항목에 뭐가들어갔는지가 중요하므로 주소를 보여주는것이지만 [호랑이, 사자] 이런식으로 나옴.
//주소값을 오버라이딩해서 항목을 위에처럼 보이게 하는 것
}
}
/*
class Object {
public boolean equals(Object obj){} //참조값 비교
public String toString(){}// 클@16진수
public int hashCode(){} //10진수
}
@Override
class String extends Object{
public boolean equals(Object obj){} //문자열 비교
public String toString(){} //문자열
public int hashCode()[} //믿지말기. 표현할 수 있는 문자열은 무한대이기떄문에 10진수 표현을 다 할 수 없다.
}
*/
객체 test = class inheritance.Test@개바부
객체 test = class inheritance.Test@개바부
객체 test = 1450495309
객체 str = apple
객체 str = apple
객체 str = 93029210
aa==bb : false
aa.equals(bb) : true
cc==dd : false
cc.equals(dd) : false
ee==ff : false
ee.equals(ff) : true
[호랑이, 사자]
중첩클래스 : has~a 관계
다른 클래스 내부에 정의 되는 클래스를 중첩클래스(nested class)라고 한다.
중첩클래스는 독립적으로 오브젝트로 만들어질 수 있는 스태틱 클래스(static class)와 자신이 정의된 클래 스의 오브젝트 안에서만 만들어질 수 있는 내부 클래스(inner class)로 구분된다.
내부클래스는 다시 범위에 따라 세 가지로 구분된다.
멤버필드처럼 오브젝트 레벨에 정의되는 멤버 내부 클래스(member inner class)
메소드 레벨에서 로컬 변수를 선언하여 사용하듯 선언된 메소드 내에서만 사용 가능한 로컬 내부 클래스(local inner class),
그리고 이름을 갖지 않는 익명 내부 클래스(anonymous inner class)
Member Inner Class
안쪽에 있는 클래스는 바깥쪽 클래스의 모든 멤버에 접근 가능
하지만 바깥쪽 클래스는 안쪽의 클래스의 멤버에 접근 불가능
단 안쪽의 클래스로 객체를 선언하면 접근 가능하다.
Outer.java
package nested;
public class Outer {
private String name; //private 내 클래스 안에 있으면 언제든 사용가능
public void output() {
//객체생성하면 사용가능 new Inner() -> 일시적으로 사용하는 것
// 클래스가 겹치므로 getAge 이렇게 안 해도됨 this.name -> this 생략가능
System.out.println("이름 = " + this.name + "\t나이 = " + new Inner().age);
//age라고 하면 참조할 수 없음. -> new Inner().age로 해야함.
}
바깥에서는 안에 있는 멤버에게 접근할 수 x
→ Inner클래스에 객체를 생성하면 접근이 가능해진다.
→ new Inner().age
class Inner {
private int age;
public void disp() {
//클래스와 클래스가 포함관계로 잡혀있는 것 / 상속x
//this.name - error Outer.this.name -> Outer 소속의 this다 ★★★★★
System.out.println("이름 = " + Outer.this.name + "\t나이 = " + this.age);
}
}//class Inner
Inner 클래스에서는 상속받은 것처럼 맘대로 바깥에 접근 가능
이 경우에는 name이라고만 해서 써도 되지만 this.name이라고 하면 안 된다.
→ name이 Inner 클래스 안에 있는 것은 아니기 때문이다.
this를 쓰고싶다면 아래와같이
Outer.this.name 'Outer 소속의 this다'라고 밝혀주고 써야함.
public static void main(String[] args) {
Outer outer = new Outer();
outer.name = "홍길동"; //private이어도 같은 클래스 안이므로 사용 가능.
outer.output();
System.out.println();//이름 = 홍길동 나이 = 0
Outer.Inner inner = outer.new Inner();
inner.age = 25;
inner.disp();
System.out.println();//이름 = 홍길동 나이 = 25
Outer.Inner inner2 = outer.new Inner();
inner2.age = 30;
inner2.disp();//이름 = 홍길동 나이 = 30
System.out.println();
//빈공터에 Inner 만든거
//새로운 Outer 만드는 것 참조하는 값 없고 name에는 null 값 들어가있음.
Outer.Inner inner3 = new Outer().new Inner();
//inner3.name = "코난" - error 얘는 static 구역 안에 있으므로 안됨.
//같은 클래스 안에서만 가능함.
inner3.age = 35;
inner3.disp(); //이름 = null 나이 = 35
}
}//class Outer
inner와, inner2는 같은 Outer안에 만든 것이고
inner3는 새로운 Outer를 생성하고 만든 것이므로 name에는 null이 들어가있는 것 확인하기 !!
이름 = 홍길동 나이 = 0
이름 = 홍길동 나이 = 25
이름 = 홍길동 나이 = 30
이름 = null 나이 = 35
AbstractTest.java (추상메소드를 가지고 있는 추상클래스 경우)
package nested;
public abstract class AbstractTest { //추상메소드 가지고 있으면 반드시 추상클래스여야 함.
//추상클래스여도 추상메소드를 안 가지고 있을 수도 있음.
String name;
//POJO 형식
public String getName() {
return name;
}
//abstract 생략하면 안됨.
public abstract void setName(String name); // 추상 메소드
}
AbstractMain.java
package nested;
public class AbstractMain {//extends AbstractTest
//{ implements InterA -> 안에 있는 메소드 다 오버라이딩해야함.
//대신해주는 메소드도 없음.
public static void main(String[] args) {
// AbstractTest at = new AbstractTest(); - error 추상메소드 new X
//상속해서 호적까지 바꿔서 사용처리하는건 귀찮 - 오버라이드도 해줘야하고
//AbstractTest at = new AbstractMain(); //자식클래스를 이용해서 해야함.
AbstractTest at = new AbstractTest() { //이름이 없다 class 클{이렇게 줘야되는데 없다
//이렇게하면 언제든지 사용할 수 있다. -> 익명 Inner class
@Override
public void setName(String name) {} //메소드에 구현부가 있다 -> 클래스
// 메소드의 구현부를 처리하는건 클래스밖에 없다.
};
추상클래스라 new가 안되므로 익명 inner클래스 사용해야함.
추상클래스는 오버라이드도 해줘야함.
InterA.java (인터페이스 경우)
package nested;
public interface InterA {
//abstract 생략가능 인터페이스 안에는 무조건 추상만 들어가므로 생략 가능
public abstract void aa();
public void bb();
}
AbstractMain.java
InterA in = new InterA() {//new 다음에 클래스와야되는데 인터페이스가 오면 안됨.
@Override //익명 inner class
public void aa() {}
@Override
public void bb() {}
};
인터페이스라 new가 안되므로 익명 inner클래스 사용해야함.
인터페이스도 오버라이드 해줘야함.
AbstractExam.java (추상메소드가 없는 추상클래스 경우)
package nested;
public abstract class AbstractExam { //추상이므로 new 안됨.
//추상 클래스이지만 추상메소드 없을 수도 있다.
public void cc() {} //오버라이드를 당할 애들 -> 빈 body로 만들어야함.
public void dd() {} //빈 body
}
AbstractMain.java
AbstractExam ae = new AbstractExam() {
//개발자가 원하는 메소드만 Override
};
}
}
추상클래스라 new가 안되므로 익명 inner클래스 사용해야되지만
원하는 메소드만 가져와서 Override 해주면 됨.
'JAVA' 카테고리의 다른 글
DAY 10 - instanceOf / 추상클래스 / final (2024.07.16) (0) | 2024.08.12 |
---|---|
DAY 11 - interface / iterator (2024.07.17) (0) | 2024.08.12 |
DAY 13 - Collection / Generic / Interface / Exception / 입출력처리 (2024.07.19) (0) | 2024.08.12 |
DAY 14 - 입출력처리 / 객체 직렬화 / 프로세스 / Thread (1) | 2024.08.12 |
DAY 15 - Thread / Synchronized (2024.07.23) (0) | 2024.08.09 |