U E D R , A S I H C RSS

한자공/시즌3/20140721 (rev. 1.26)

한자공/시즌3/20140721


1. 일시

  • 오후 12 : 10 ~ 오후 1 : 50

2. 참가자

유재범 참석
최다인 불참
이지수 참석
김용준 참석
김정민 참석

3. 진행 상황

  • 유재범 학우의 발표
    • JAVA의 정석 7-5~

3.1. 발표 내용

  • 클래스 중첩 : 여러 클래스를 관리 할 때 클래스 안에 다시 클래스를 선언하여 중첩시키는 것.

Outer 객체1 = new Outer(); //Outer 클래스 객체 생성 방법
Outer.Inner 객체2 = 객체1.new Inner(); //Inner 클래스 객체 생성 방법
  • 컴파일러를 돌리고 윈도우 탐색기를 이용하면 Outer$Inner.class 라는 파일도 있을 것이다. 이 파일이 바로 중첩된 클래스를 나타내는 것이다.
  • Inner 클래스에서는 Outer 클래스의 멤버를 이용할 수 있다. 하지만 Outer 클래스에서 Inner 클래스의 멤버를 이용하려면 객체를 직접 선언해야 한다.
    • Outer 내부에서 Inner의 멤버를 사용하기 위해 객체를 선언하려면 현재 클래스의 객체를 대변하는 this가 있어야 한다.
      • static 메서드 내부에서는 일반 중첩 클래스의 객체가 선언 될 수 없다는 것
      • 또 Inner 내부에 static과 관련된 멤버를 선언하는 것도 컴파일 에러를 발생시킨다
  • 정적 중첩 클래스 : 중첩 클래스 내부에서 static과 관련된 멤버를 선언할 수 있는 클래스
    • 일반 중첩 클래스 내부에는 static과 관련된 멤버를 선언할 수 없다. 그러나 Outer 클래스의 멤버를 단지 이용만 할 때에는 static이든 아니든 관계 없이 이용 할 수 있다.

class Outer{
	static class Inner{
		..........
	}
}
  • 정적 중첩의 클래스는 static의 특성상 객체를 독립적으로 만들 수 있다.
    • Outer.Inner 객체 = new Outer.Inner();
  • Outer 클래스의 객체가 없어도 Inner 클래스의 객체를 만들 수 있다.
  • 또한 static 멤버를 선언 할 수 있고 static 메서드도 만들어 사용 할 수 있다.
    • 그래서 Inner 클래스 내부에 static을 선언하여 사용하고 싶다면 정적 중첩 클래스를 사용해야 한다. 객체 선언 방식은 위와 같은 방식으로만 발생시킬 수 있따.
    • Outer 클래스의 멤버는 static일 경우에만 사용할 수 있다. 이것은 마치 일반 멤버를 static 메서드 내부에서 사용할 수 없는것과 유사하다

public class Round12_Ex04 {
	public static class Inner3{
		public static void main(String[] ar){
			System.out.println("Inner 클래스 내부의 main 메서드");
		}
	}
}
  • 위와 같은 경우 java Round12_Ex04로 실행하면 main() 메서드가 Inner 클래스 내부에 있기 때문에 찾을 수 없어 JVM이 main()을 찾을 수 없다는 에러가 뜬다. 그래서 실행 시킬때에는 java Round12_Ex04$Inner3으로 실행을 해야 한다.
    • 이것은 실제 메서드가 있는 곳을 지칭하는 것이다.
  • 지역 중첩 클래스 : 특정 메서드에 한정적인 용도로 사용할 클래스로 등장
    • 일반적으로 보통 클래스와 동일하나 접근 제한자와 지정 예약어를 사용할 수 없다는 형태이다.
    • 만일 일반 중첩 클래스처럼 main() 메서드의 멤버를 사용하려면 그 멤버는 반드시 final로 선언되어 있어야만 한다.
    • 컴파일을 하면 Round12_Ex06.class 외에 Round12_Ex06$1Inner5.class라는 클래스가 생성된다.
    • 일반 중첩 클래스와 유사하가 static 멤버를 선언하지 못한다.
  • 익명 중첩 클래스 : class라는 예약어와 클래스 명을 가지지 않고 단지 instance의 생성과 내용부의 정의만 가지고 있는 클래스
    • 지역 중첩 클래스의 변형된 형태
    • 다만 여기에 사용되는 중첩 클래스는 이미 기존에 존재 하는 것이어야 한다.
    • 또한 이 내에서 사용 할 수 있는 외부 데이터도 final로 선언되어 있어야 한다.
    • 내용부가 서로 다른 특정 메서드의 실행을 주관 하기 위해서 사용
      • 접근 제한자의 사용에 주의해야 한다. 자기 자신의 멤버일지라도 정의되는 영역이 다르기 때문이다.

class Inner6{
	int y = 200;
	public Inner6(){
		this.disp();
	}
	public void disp(){}
}
public class Round12_Ex07 {
	public static void main(String[] ar){
		final int x = 100;
		new Inner6(){
			public void disp(){
				System.out.println("Default 생성자");
				System.out.println("x = " + x);
				System.out.println("y = " + y);
			}
		};
	}
}
  • 위 예시를 컴파일 후 탐색기로 클래스 파일을 찾아보면 Inner6.class, Round12_Ex07.class, Round12_Ex07$1.class. 이렇게 3개가 생성이 된다.
    • 이 중 마지막이 익명 중첩 클래스인다 이름에서 알 수 있듯이 익명이기에 숫자로 그 클래스를 표시한다.
    • 만약 main() 메서드 내부에 다른 익명 중첩 클래스가 있다면 이 클래스는 Round12_Ex07$2.class가 될 것이다.
  • 익명 중첩 클래스는 내부에 생성자를 작성할 수 없다.
    • 만약 작성하면 invalid 메서드 declaration 이렇게 뜰 것이다.
  • 다형성 : 여러개의 개별적 클래스를 하나의 부모 클래스 객체로 통합하여 관리하여 그 효율성을 높인 것
    • 예 : 배열
    • 다형성의 표현

A ap = new A();
A bp = new B();
A cp = new C();
  • 여기서 중요한 것은 자신의 클래스 객체가 아니지만 자신의 부모 클래스라면 인스턴스를 부모 객체에 담을 수 있다는 것이다.

class A3{
	public String toString(){
		return "A3 클래스";
	}
}
class B3{
	public String toString(){
		return "B3 클래스";
	}
}
public class Round13_Ex01 {
	public static void main(String[] ar){
		A3 ap = new A3();
		B3 bp = new B3();
		System.out.println("ap = " + ap);
		System.out.println("bp = " + bp);
	}
}
  • 위 클래스 A3, B3는 언뜻 보면 연관이 되어 있지 않지만 사실 다형적인 표현을 사용할 수 있다.
    • 왜냐하면 모두 Object를 부모로 두기 때문이다. 그래서 이를 아래와 같이 사용 할 수도 있다.

public class Round13_Ex01 {
	public static void main(String[] ar){
		Object[] obj = new Object[2];
		obj[0] = new A3();
		obj[1] = new B3();
		for(int a = 0; a<obj.length; a++){
			System.out.println("abj[" + a + "] = " + obj[a]);
		}
	}
}
  • 다형적인 표현에서 멤버에 대한 접근 규정
    • 부모 클래스가 가지고 있는 모든 멤버들에 접근할 수 있다.
      • 단, 자식 클래스에서 메서드 오버라이딩을 했다면 오버라이딩이 된 자식의 멤버에 접근이 된다.
    • 멤버 필드의 경우 부모 클래스의 멤버 필드에만 접근 할 수 있다.
      • 자식 클래스의 멤버 필드는 오버라이딩이 된 자식 클래스의 메서드에 의해서만 접근 할 수 있다.
  • 다형성에서 멤버 필드로의 접근
    • 필드는 다형성으로 표현 되었을 때는 객체를 통해 부모 클래스의 멤버 필드에만 접근 할 수 있다.
    • 상위 하위 모두 동일한 이름의 필드라 하더라도 상위 클래스의 멤버 필드의 것만 접근 할 수 있다.
  • 다형성에서 메서드로의 접근
    • 우선은 상위 클래스의 메서드에 접근 할 수 있고 하위 클래스의 메서드에는 접근 할 수 없다.
    • 하지만 상위와 하위에 동시에 있는 오버라이딩이 된 메서드에 대해서는 하위의 멤버를 실행 할 수 있다.

class A6{
	public void aaa(){
		System.out.println("aaa");
	}
	public void bbb(){
		System.out.println("bbb");
	}
}
class B6 extends A6{
	public void bbb(){
		System.out.println("bbb1");
	}
	public void ccc(){
		System.out.println("ccc");
	}
}
public class Round13_Ex11 {
	public static void main(String[] ar){
		A6 ap = new B6();
		ap.aaa();//상위 클래스의 메서드에 접근
		ap.bbb();//오버라이딩 된 하위 클래스에 접근
		//ap.ccc();//하위 클래스의 메서드에 접근
	}
}
  • 다형성은 어떤 값이 올지 예상을 하면 어렵지 않다고 한다.

class A{ ...}
class B extends A{...}
public class C{
	public static void main(String[]ar){
		A ap = new B();
		B bp = ap;
	}
}
  • 위와 같은 경우 에러가 발생한다. 에러를 발생하지 않게 하기 위해서는 B bp = (B)ap로 명시적으로 캐스팅을 해야 한다.
  • 하지만 아직 문제는 있다. 만약 A ap = new A();라는 문맥이었다면 Exception in thread "main" java.lang.ClassCastException:A라는런타임 에러가 발생한다. 이럴 때 instanceof라는 예약어가 참으로 유용하다.
    • instanceof 연산자 : 참조변수가 참조하는 인스턴스의 실제 타입을 체크하는데 사용
      • 이항 연산자이며 피연산자는 참조형 변수와 타입, 연산 결과는 true, false이다.
      • instanceof의 연산 결과가 true이면 해당 타입으로 형변환이 가능하다.

class A{}
class B extends A{}
public class Test{
	public static void main(String[] ar){
		A ap = new B();
		B bp = null;
		if(ap instanceof B){//형식 : 객체 instanceof 변환할 클래스
			bp = (B)ap;
			System.out.println("형 변환이 가능하다.");
		}
		else{
			System.out.println("형 변환이 불가능 하다");
		}
	}
}

  • abstract(추상, 추상 메서드, 추상 클래스) : 부모클래스를 직접 사용하지 않고 자식을 통해서만 사용할 목적으로 혹은 단지 묶어 주기만 할 목적으로 클래스를 만들 때 추상 클래스를 사용한다.
    • 접근_제한자 abstract class 클래스명 extends 상위_클래스 implements 상위_인터페이스{...}
    • 추상 클래스는 일반 클래스의 모든 기능을 할 수 있다. 다만 그 자신의 객체만큼은 발생시키지 못한다.
      • 이것은 주로 다형성을 표현할 목적으로 많이 사용하는데 이런 것을 "디자인 목적"이라고 한다. 쉽게 하나의 제품을 만들 때 참고하는 디자인 혹은 모델이라고 생각해두자.
      • 만약 추상 클래스가 추상 메서드를 가지고 있다면 그것은 반드시 오버라이딩 되어야 한다.
    • 추상 클래스는 일반 클래스의 멤버 이외에 추상 메서드를 가질 수 있다.
      • 접근_제한자 abstract 결과형_리턴값 메서드명(매개_변수들) throws 예외 클래스들;
        • 여기서 중요한 것은 마지막에 세미클론으로 끝난다는 것이다. 즉, 내용부를 가지지 않고 이름만 있는 메서드이다.
          • 이런 이유는 다형성의 표현에서 오버라이딩이 되었음을 의미하는 것인데 이것은 반드시 오버라이딩이 되어야만 한다.
    • 추상메서드를 만드는 이유는 상속받는 하위 클래스에게 디자인이 되어 있는 메서드를 재정의 하라고 명령을 내리기 위해서다.
    • 추상클래스를 통해 인스턴스를 발생시키려고 하면 에러가 발생한다.

  • 인터페이스 : 단일 상속의 제약을 보완하기 위해 자바에서 제안한 새로운 개념의 클래스. 이를 통하 자바는 다중 상속을 할 수 있게 되었다.
    • 접근_제한자 interface 인터페이스 명 extends 상위_인터페이스{ 내용부 }

    • 인터페이스는 다중 상속이 가능하다는 특징이 강하게 나타난다.
    • 인터페이스의 정의
      • 1. 다중 상속을 위한 클래스의 대안
      • 2. 다형성에 의한 클래스 제어
    • 인터페이스의 내부에 포함 될 수 있는 멤버들은 일반 클래스와 조금 차이난다.
    • 인터페이스 포함 멤버
      • 필드 : 무조건 public static final 멤버 필드이다. 모두 기재하든 static만 기재하든 기재를 하지 않든 모두 public static final로 인식한다.
      • 메서드 : 무조건 public abstract 멤버 메서드다. 고로 정의부를 가질 수 없다. 인터페이스도 다형성이 목절이므로 자동으로 모든 메서드가 abstract가 된다.
      • 정적 중첩 클래스 : 인터페이스가 가지는 중첩 클래스에는 자동적으로 static이 붙어 정적 중첩 클래스만 가질 수 있다는 개념이 되어버린다. 물론 중첩 클래스 내부에는 일반 클래스처럼 할수 있다.(생성자 생성, 정의부가 있는 메서드 생성 등)
    • 인터페이스에는 생성자 조차 없다. 어떤 의미로는 제한적인 클래스라고 생각 할 수도 있다.
    • 추상 메서드를 포함 하고 있고 생성자도 없어 객체를 발생 시킬 수 없다.
      • 필드 : 인터페이스에서 필드를 사용하려면 직접 값을 할당하는 방식으로 한다.

interface A1{
	int w = 10;
	static int x = 20;
	final int y = 30;
	public static final int z = 40;
}
public class Round14_Ex01 {
	public static void main(String[] ar){
		//A1 ap = new A1();
		//A1.w = 100;
		System.out.println("w = " + A1.w);
		System.out.println("x = " + A1.y);
		System.out.println("y = " + A1.x);
		System.out.println("z = " + A1.z);
	}
}
  • 메서드 : 무조건 public abstract이기 때문에 무조건 하위 클래스에 의해 오버라이딩이 되어야 한다.
    • 그리고 public 접근자가 생략되어 있으므로 오버라이딩 시에는 반드시 접근자를 public으로 해야 한다.

interface A2{
	void aaa();
	public abstract void bbb();
}
class B2 implements A2{
	void aaa(){
		System.out.println("aaa 메서드");
	}
	public void bbb(){
		System.out.println("bbb 메서드");
	}
}
public class Round14_Ex02 {
	public static void main(String[] ar){
		B2 bp = new B2();
		bp.aaa();
		bp.bbb();
	}
}
  • 정적 중첩 클래스 : 인터페이스에 마지막으로 있을 수 있는 멤버는 정적 중첩 클래스와 중첩 인터페이스이다. 클래스가 중첩 될 경우 무조건 public, static이기에 정적 중첩 클래스가 되는 것이다.
    • 따라서 외부에서 그 클래스에 대한 객체를 발생시킬 때에는 정적 중첩 클래스 객체 생성 방식을 따르게 된다.

interface T3{
	int x = 100;
	class B3{
		private int y;
		public B3(){
			this.y = 200;
		}
		public void disp(){
			System.out.println("x = " + x);//A.x
			System.out.println("y = " + y);//this.y
		}
	}
}
public class Round14_Ex03 {
	public static void main(String[]ar){
		T3.B3 bp = new T3.B3();
		bp.disp();
	}
}
  • int x 역시 public static final 이기 때문에 disp() 메서드에서 사용할 수 있는 것이다.
  • abstract와 인터페이스
    • 공통점
      • 1. 디자인의 개념으로 다형성을 표현하기에 아주 적당한 형태이다.
      • 2. 객체를 발생 시킬 수 없다.
      • 3. 추상 메서드를 포함하고 있고, 그 메서드를 오버라이딩을 해야만 하위 클래스의 객체가 발생한다.
      • 4. 표현의 방식에서 효율성을 고려하여 다형적인 표현을 주목적으로 한다.
    • 차이점

  • 만약 단지 하위클래스들을 통합 관리하기 위한 목적만 있고 상위 클래스로서 아무런 역할도 할 필요 없다면 abstract보다는 인터페이스가 더 효율적이다.

4. 다음 진행

  • 이지수
    • 8단원 예외처리

5. 과제

  • 그 동안 배운 개념(상속, 다형성 등)을 활용해서 도서 관리 프로그램 만들기(자세한 사항은 추후 공지).

5.1. 유재범

5.2. 최다인

5.3. 이지수

5.4. 김용준

5.5. 김정민

Valid XHTML 1.0! Valid CSS! powered by MoniWiki
last modified 2021-02-07 05:31:31
Processing time 0.0536 sec