JAVA

 2. 내부 클래스(inner class)
    클래스 내부에... 『public class 클래스명』

  - static 중첩 클래스와 마찬가지로 프로그램 구조를 보다 더 간단하고 알아보기 쉽도록 할 수 있다.
  - 외부 클래스의 메소드에서 내부 멤버 클래스를 사용하기 위해서는 반드시 내부 멤버 클래스 객체를 생성해 주어야 함
  - 외부 클래스의 멤버 변수와 메소드를 객체 생성 없이 바로 사용하는 것이 가능하다.
  - 내부 멤버 클래스는 외부에서 단독으로 객체를 생성하여 사용할 수 없다.
     즉, 내부 멤버 클래스는 외부 클래스의 인스턴스 생성이 선행되어야 한다는 것이다.
  - static 으로 선언된 변수 또는 메소드를 가질 수 없다.


내부 클래스(inner class)의 예시

/*===========================
  ■■■ 클래스 고급 ■■■
  - 중첩 클래스(내부 클래스)
=============================*/

class Test2
{
	static int a = 10;	// 전역변수, Test2의 멤버변수, static변수(클래스 변수)
	int b = 20;			// 전역변수, Test2의 멤버변수, instance변수

	void write()		// ▶ 첫 번째 write() 메소드
	{
		System.out.println("write()... ①");
		final int c = 30;	// 지역변수, 상수화된 변수(값이 변하지 않는 수)
		int d = 40;			// 지역변수, 값이 수시로 변할 수 있는 변수

		// 메소드 안에 존재하는 또다른 클래스(local class, 지역 클래스)
		class LocalTest
		{
			void write() // ▶ 두 번째 write() 메소드
			{
				System.out.println("write()... ②");
				System.out.println("a : " + a);
				System.out.println("b : " + b);
				System.out.println("c : " + c);
				System.out.println("d : " + d);
			}
		}
		
		// ※ 변수 c 와 변수 d 는 둘 다 지역변수이지만...
		//    c 는 final 변수이기 때문에
		//    두 번째 write() 메소드에서 언제 접근하더라도
		//    고정된 값임을 보장받을 수 있다.
		//	  반면에 d 는 그 값이 수시로 변동될 수 있는 상황이므로
		//	  LocalTest 클래스의 인스턴스 생성 시점을
		//    보장받을 수 없기 때문에 d 에 접근하는 것은 피해야 하는 것이다

		//d = 10;

		LocalTest ob1 = new LocalTest();
		ob1.write();	//-- 두 번째 write() 메소드 호출

		//d += 10;
	}
}

public class Test128
{
	public static void main(String[] args)
	{
		Test2 ob = new Test2();
		ob2.write();	//-- 첫 번째 write() 메소드 호출

	}
}

// 실행 결과
/*
write()... ①
write()... ②
a : 10
b : 20
c : 30
d : 40
계속하려면 아무 키나 누르십시오 . . .
*/

   1. static 중첩 클래스(중첩 내부 클래스)
      클래스 내부에... 『public static class 클래스명』

  내부 클래스를 감싸는 외부 클래스의 {} 안에 static을 붙인 새로운 클래스를 설계하는 것으로 모든 접근제어지시자를 사용할 수 있다. static 중첩 클래스가 포함하고 있는 메소드에서는 외부 클래스의 인스턴스 변수나 인스턴스 메소드에는 접근할 수 없고, 클래스 변수와 클래스 메소드만 접근할 수 있다.

  - 프로그램의 구조를 보다 더 간단하고 알아보기 쉽게 구성할 수 있다.
  - static 으로 선언된 내부 클래스이다.
  - 중첩 클래스의 객체는 중첩 클래스를 포함하고 있는 외부 클래스의 객체와 동등하다.
  - 외부 클래스의 클래스 변수와 클래스 메소드는 바로 접근하여 사용하는 것이 가능하다.
  - 중첩 클래스와 중첩 클래스를 포함하고 있는 외부 클래스의 객체를 생성하여 서로 접근하는 것이 가능하다.
  - 중첩 클래스를 외부에서 단독으로 사용하는 것이 가능하다.


static 중첩 클래스(중첩 내부 클래스)의 예시

class Test
{
	static int a = 10;								// static
	int b = 20;

	public static class StaticNested				// static
	{
		int c = 30;

		void write()
		{
			System.out.println("write()...");
			System.out.println("a : " + a);
			//System.out.println("b : " + b);		//-- 에러 발생
			System.out.println("c : " + c);
		}
	}

	void print()
	{
		StaticNested sn = new StaticNested();
		sn.write();

	}
}

public class Test127
{
	public static void main(String[] args)
	{
		Test ob1 = new Test();
		ob1.print();
		//--==>>write()...
		//		a : 10
		//		c : 30

		StaticNested ob2 = new StaticNested();
		//--==>> 에러 발생

		// ※ 중첩 내부 클래스는 외부에서 단독으로 객체를 생성한다.
		//    단, 위와 같은 방법으로 객체를 생성해서는 안되고
		//    클래스 메소드를 호출하는 것과 같은 방식을 통해
		//    접근하여 인스턴스를 생성할 수 있도록 처리해야 한다.

		//Test.a
		Test.StaticNested ob2 = new Test.StaticNested();
		ob2.write();
		//--==>> write()...
		//		 a : 10
		//		 b : 30
	}
}

○ 중첩 클래스(내부 클래스)

   중첩 클래스란 클래스 안에 다른 클래스가 설계되어 있는 형태로 클래스 내부에서만 사용할 보조 클래스가 필요한 경우 클래스를 중첩하여 프로그램의 구조를 보다 더 간단하고 알아보기 쉽도록 만들 수 있는데 이러한 클래스를 중첩 클래스(내부 클래스)라 한다. 이는 특정 클래스를 자신의 클래스 내부적인 용도로만 사용할 목적으로 쓰이는데 특정 클래스를 마치 자신의 멤버 변수나 메소드처럼 사용할 수 있게 한다.

○ 중첩 클래스의 종류(4가지)
   
   1. static 중첩 클래스(중첩 내부 클래스)
      클래스 내부에... 『public static class 클래스명』

  내부 클래스를 감싸는 외부 클래스의 {} 안에 static을 붙인 새로운 클래스를 설계하는 것으로 모든 접근제어지시자를 사용할 수 있다. static 중첩 클래스가 포함하고 있는 메소드에서는 외부 클래스의 인스턴스 변수나 인스턴스 메소드에는 접근할 수 없고, 클래스 변수와 클래스 메소드만 접근할 수 있다.

  - 프로그램의 구조를 보다 더 간단하고 알아보기 쉽게 구성할 수 있다.
  - static 으로 선언된 내부 클래스이다.
  - 중첩 클래스의 객체는 중첩 클래스를 포함하고 있는 외부 클래스의 객체와 동등하다.
  - 외부 클래스의 클래스 변수와 클래스 메소드는 바로 접근하여 사용하는 것이 가능하다.
  - 중첩 클래스와 중첩 클래스를 포함하고 있는 외부 클래스의 객체를 생성하여 서로 접근하는 것이 가능하다.
  - 중첩 클래스를 외부에서 단독으로 사용하는 것이 가능하다.

   2. 내부 클래스(inner class)
      클래스 내부에... 『public class 클래스명』

  - static 중첩 클래스와 마찬가지로 프로그램 구조를 보다 더 간단하고 알아보기 쉽도록 할 수 있다.
  - 외부 클래스의 메소드에서 내부 멤버 클래스를 사용하기 위해서는 반드시 내부 멤버 클래스 객체를 생성해 주어야 함
  - 외부 클래스의 멤버 변수와 메소드를 객체 생성 없이 바로 사용하는 것이 가능하다.
  - 내부 멤버 클래스는 외부에서 단독으로 객체를 생성하여 사용할 수 없다.
     즉, 내부 멤버 클래스는 외부 클래스의 인스턴스 생성이 선행되어야 한다는 것이다.
  - static 으로 선언된 변수 또는 메소드를 가질 수 없다.

   3. 지역 클래스(로컬 클래스, local class)
      메소드 내부에... 『public class 클래스명』 or 『public static class 클래스명』

  - 클래스의 메소드 안에서 클래스를 정의하는 것으로 내부 멤버 클래스와 유사한 성격을 가지고 있긴 하지만 접근제어지시자는 붙일 수 없다.

   4. 무명 클래스(익명 클래스, annoymous class) 이름 없는 클래스

  - 클래스 또는 인터페이스에 대한 객체를 생성하면서 바로 클래스 또는 인터페이스를 정의하는 클래스
  - 정의하는 부분과 생성하는 부분이 하나로 묶여져 new 수식이 있는 곳에서 바로 클래스 또는 인터페이스를 정의하는 것을 의미한다.

   new
   {
         ...
   };

※ 성적 처리 프로그램을 구현한다. 단, 인터페이스를 활용할 수 있도록 한다.

 실행 예) 
 인원 수 입력(1~10) : 2
 1번째 학생의 학번 이름 입력(공백 구분) : 2012170 안혜지
 국어 영어 수학 점수 입력   (공백 구분) : 90 100 85
 2번째 학생의 학번 이름 입력(공백 구분) : 2012112 윤홍준
 국어 영어 수학 점수 입력   (공백 구분) : 85 70 65

 2012170 안혜지   90   100   85   275   91
                             수    수    우
 2012112 윤홍준   85    70   65   220   73
                             우    미    양

 계속하려면 아무 키나 누르세요...

 속성만 존재하는 클래스 → 자료형 활용


/*===========================
  ■■■ 클래스 고급 ■■■
  - 인터페이스(Interface)
=============================*/
import java.util.Scanner;

class Record
{
	String hak, name;		//-- 학번, 이름
	int kor, eng, mat;		//-- 국어, 영어, 수학 점수
	int tot, avg;			//-- 총점, 평균(편의상 정수 처리)
}

interface Sungjuk
{
	public void set();		//-- 인원 수 구성
	public void input();	//-- 상세 데이터 입력
	public void print();	//-- 결과 출력
}

// 문제 해결 과정에서 설계해야 할 클래스
class SungjukImpl implements Sungjuk
{
	Scanner sc = new Scanner(System.in);

	int n;		// 학생수를 저장할 변수
	Record[] rc;
	
	@Override
	public void set()
	{
		// Scanner 인스턴스 생성
		
		System.out.print("인원 수 입력(1~10) : ");
		n = sc.nextInt();
		
		// Record 인스턴스 생성
		rc = new Record[n]; 
		for (int i = 0; i < n; i++)
		{
			rc[i] = new Record();
		}
	}

	@Override
	public void input()
	{		
		for (int i = 1; i <= n; i++)
		{
			System.out.printf("%d번째 학생의 학번 이름 입력(공백 구분) : ", i);
			rc[i-1].hak = sc.next();
			rc[i-1].name = sc.next();
			System.out.printf("국어 영어 수학 점수 입력   (공백 구분) : ");
			rc[i-1].kor = sc.nextInt();
			rc[i-1].eng = sc.nextInt();
			rc[i-1].mat = sc.nextInt();
		}
	}
	// 2012170 안혜지	90   100   85   275   91
	//					수	  수   우
	// 2012112 윤홍준   85    70   65   220   73
	//					우    미   양

	@Override
	public void print()
	{
		calc();
		
		String[] grade = {"수","우","미","양","가"};
		int[] num = {90,80,70,60,0};
		for (int i = 0; i < n; i++)
		{
			System.out.println(rc[i].hak + " " + rc[i].name + "   " + rc[i].kor + "   " + rc[i].eng + "   " + rc[i].mat + "   " + rc[i].tot + "   " + rc[i].avg);			
			
			int[] studentScore = {rc[i].kor, rc[i].eng, rc[i].mat};
			//System.out.printf("%15c",' ');
			for (int j = 0; j < studentScore.length; j++)
			{
				for (int k = 0; k < num.length; k++)
				{
					if ( studentScore[j] > num[k])
					{
						System.out.printf("%s   ", grade[k]);
						break;
					}
				}
			}
			System.out.println();
		}
	}
	// 추가로 구현할 메소드
	public void calc()
	{
		for (int i = 0; i < n; i++)
		{
			rc[i].tot = rc[i].kor + rc[i].eng + rc[i].mat;
			rc[i].avg = rc[i].tot / 3;
		}
	}
	/*
	public void suumi()
	{
		
	}
	*/
}

// main() 메소드를 포함하고 있는 외부 클래스(동일 패키지)
public class Test126
{
	public static void main(String[] args)
	{
		SungjukImpl ob = new SungjukImpl();

		// 문제 해결 과정에서 작성해야 할 ob 구성
		ob.set();
		ob.input();
		ob.print();
	}
}

○ 『extends』 vs 『implements』
   클래스 extends 클래스
   클래스 implements 추상클래스

   인터페이스 extends 인터페이스
   인터페이스 extends 인터페이스, 인터페이스

   추상클래스 implements 인터페이스
   추상클래스 implements 인터페이스, 인터페이스

   클래스 implements 인터페이스
   클래스 implements 인터페이스, 인터페이스

※ 인터페이스는 클래스와는 달리 다중 상속이 가능하며,
   인터페이스 자체도 상속된다.

※ 인터페이스의 멤버 변수인 데이터는
   접근제어지시자를 명시하지 않아도 기본 상수(primitive constant)인
   static final 의 변경자로 설정된다
   클래스에서 인터페이스를 추가하여 사용할 경우
   인터페이스 안에서 정의된 모든 메소드를 구현해 주어야 하며
   인터페이스를 구현하는 클래스는
   인터페이스의 상위 인터페이스가 제공하는 추상 메소드를 포함한
   모든 메소드를 구현하지 않을 경우
   추상(abstract) 클래스로 선언해야 한다.

※ 형식
   - 인터페이스는 메소드를 선언만 하고 정의는 없다.
   - 인터페이스를 implements 할 경우 반드시 하위 클래스는
     인터페이스의 모든 메소드를 오버라이딩(Overriding)해야 한다.
   - 인터페이스는 자동적으로 다음과 같이 처리된다.
     멤버 변수 : public static final
     메소드 : public abstract
   - 다중 상속은 콤마 (『,』)로 구분되며
     여러 개의 인터페이스를 상속할 수 있다.
   - 인터페이스끼리 상속할 경우는 『extends』 키워드를 사용한다.

※ 인터페이스의 선언
   인터페이스는 클래스의 내부 구현을 제외한 참조형만 선언한 것이므로
   메소드를 선언만 하고 정의는 할 수 없다.
   또한 클래스에서의 변수는 값이 변할 수 있지만
   인터페이스에서의 변수는 상수처럼 값이 바뀔 수 없기 때문에
   선언 시에 미리 값을 할당해 놓아야 한다

※ 인터페이스의 구현
   인터페이스는 클래스를 위한 템플릿이기 때문에
   사용 가능한 인터페이스가 되기 위해서는 
   자바 프로그램에서 인터페이스를 구현해 주어야 하는데
   이러한 기능을 하는 것이 『implements』 예약어이다.

※ 클래스는 동시에 두 개 이상의 인터페이스를 implements 할 수 있다~!!!


// 인터페이스
interface ADemo
{
	public void write();
}

// 인터페이스
interface BDemo
{
	public void print();
}

// ※ 클래스는 다중 상속을 지원하지 않지만,
//    인터페이스는 다중 상속을 지원한다.
// 인터페이스 - 두 인터페이스(ADemo, BDemo)를 상속받은 인터페이스
interface CDemo extends ADemo, BDemo
{
	public void test();
	//public void print();
	//public void write();
}
// 클래스
//class DemoImpl
// 두 인터페이스(ADemo, BDemo)를 상속받은 인터페이스(CDemo)를 구현한 추상 클래스
//abstract class DemoImpl implements CDemo
// 두 인터페이스(ADemo, BDemo)를 상속받은 인터페이스(CDemo)를 구현한 후
// 모든 메소드를 재정의한 클래스
class DemoImpl implements CDemo
{
	@Override
	public void test()
	{
		System.out.println("test()...");
	}
	
	@Override
	public void write()
	{
		System.out.println("write()...");
	}

	@Override
	public void print()
	{
		System.out.println("print()...");
	}
}
// 클래스
public class Test125
{
	public static void main(String[] args)
	{	
		// 두 인터페이스를 상속받은 인터페이스를 구현하고
		// 모든 메소드를 재정의한 클래스에 대한 인스턴스 생성
		DemoImpl ob = new DemoImpl();

		ob.test();
		ob.write();
		ob.print();
	}
}

// 실행 결과
/*
test()...		
write()...
print()...
계속하려면 아무 키나 누르십시오 . . .
*/
/*===========================
  ■■■ 클래스 고급 ■■■
  - 인터페이스(Interface)
=============================*/

// 인터페이스
interface Demo
{
	public void write();
	public void print();
}

// 클래스 - 인터페이스를 구현하는 추상 클래스
//class DemoImpl implements Demo
abstract class DemoImpl implements Demo
{
	@Override
	public void write()
	{
		System.out.println("write() 메소드 재정의 ...");
	}
	
	//public void print();
	
}

// 클래스
//class DemoImplSub extends DemoImpl
// 추상 클래스를 상속받는 추상 클래스
//abstract class DemoImplSub extends DemoImpl
// 추상 클래스를 상속받는 클래스
class DemoImplSub extends DemoImpl
{
	@Override
	public void print()
	{
		System.out.println("print() 메소드 재정의 ...");
	}
}

// 클래스 - main() 메소드를 포함하고 있는 외부의 다른 클래스(동일 패키지)
public class Test124
{
	public static void main(String[] args)
	{
		//Demo ob1 = new Demo();
		//-- 인터페이스 → 인스턴스 생성 불가
		//DemoImpl ob2 = new DemoImpl();
		//-- 추상클래스 → 인스턴스 생성 불가
		DemoImplSub ob3 = new DemoImplSub();

		ob3.write();
		ob3.print();
	}
}

// 실행 결과
/*
write() 메소드 재정의 ...
print() 메소드 재정의 ...
계속하려면 아무 키나 누르십시오 . . .
*/

+ Recent posts