주말공부 or 복습

주말복습3(접근제어자 , 인터페이스,내부클래스, 예외처리)

동곤일상 2025. 2. 23. 20:00
반응형

1) 접근제어자

 

2) 인터페이스

 

2-1) 람다

3) 내부클래스

 

4)예외처리

 

 


1) @ @ 접근제어자 @ @

 private < (defalut) < protected < public

 

* private      :    동일한 클래스내에서만 접근 허용

* (default)   :    같은 패키지 내에서만

* protected :    같은 패키지 내에서만 ( 상속관계는 다른패키지도 가능)

* public       :    all

 

클래스에는 public , (default) 만 사용이 가능함

객체생성을 막고싶다면 생성자를 private으로 막아놓자

 


예시

package ex8_modifier.test;
public class Modifier2  {
	private int v1=10;
	 		int	v2=20;
	protected int v3=30;
	public int v4 = 40;
	
	 public void method() {
		System.out.println(getClass()+"클래스의 method()");
		System.out.println("v1 : "+v1);
		System.out.println("v2 : "+v2);
		System.out.println("v3 : "+v3);
		System.out.println("v4 : "+v4);
	}
}

 

다른패키지

package ex8_modifier;

import ex8_modifier.test.Modifier2;
 class Modifier1{
	private int v1 = 100;
	        int v2 = 200;
	protected int v3 =300;
	public int v4 = 400;
	public void method() {
		System.out.println(getClass()+" 클래스의  method()");
		System.out.println("v1 : "+v1);
		System.out.println("v2 : "+v2);
		System.out.println("v3 : "+v3);
		System.out.println("v4 : "+v4);
	}
}
//-----------------------------------------------------------------------------------
class Modifier3 extends Modifier2{
	
	void method2() {
		System.out.println("ex8_modifier.Modifier3클래스의 method2");
//		System.out.println("v1 : "+v1);  private이므로 접근X
//		System.out.println("v2 : "+v2);  default 접근불가
		System.out.println("v3 : "+v3);  //상속관계이므로 다른패키지여도 접근가능
		System.out.println("v4 : "+v4); //public
	}
	
	@Override 
	//부모의 method()가 public이기 때문에 
	//접근제어자를 맞춰주자 더 좁은범위로설정할순없다
	public void method() {
		System.out.println("v3 : "+v3);  //상속관계이므로 다른패키지여도 접근가능
		System.out.println("v4 : "+v4); //public
		}
}

//-----------------------------------------------------------------------------------
public class ModifierEx1 {
	public static void main(String[] args) {
		Modifier1 m1 = new Modifier1();
		m1.method();
		System.out.println("ModifierEx1 클래스의 main 메서드에서 호출");
//		System.out.println("m1.v1 : "+m1.v1); private은 같은 클래스에서만 접근가능
		System.out.println("m1.v2 : "+m1.v2);//v2
		System.out.println("m1.v3 : "+m1.v3);
		System.out.println("m1.v4 : "+m1.v4);
		
		Modifier2 m2 = new Modifier2();//다른패키지임
		m2.method();
//		System.out.println("m2.v1 : "+m2.v1); private
//		System.out.println("m2.v2 : "+m2.v2);  default(같은패키지만 접근가능)
//		System.out.println("m2.v3 : "+m2.v3); protected(같은패키지만접근 가능 + 상속관계는 다 접근가능)
		//The field Modifier2.v2 is not visible
		System.out.println("m2.v4 : "+m2.v4);
		
		Modifier3 m3 = new Modifier3();
		m3.method2();	
	}
}

class ex8_modifier.Modifier1 클래스의 method()

v1 : 100

v2 : 200

v3 : 300

v4 : 400

ModifierEx1 클래스의 main 메서드에서 호출

m1.v2 : 200

m1.v3 : 300

m1.v4 : 400

 

class ex8_modifier.test.Modifier2클래스의 method()

v1 : 10

v2 : 20

v3 : 30

v4 : 40

m2.v4 : 40

 

ex8_modifier.Modifier3클래스의 method2

v3 : 30

v4 : 40

 


Singleton ( private 생성자 이용 )

 생성자의 접근제어자를 private : 객체의 갯수제한
 객체의 갯수를 한개만 생성

package ex8_modifier;

class SingleObject{
	private static SingleObject obj = new SingleObject();
	private SingleObject() {};//생성자
	//기본생성자 제공 불가 . 생성자에 접근 현재 클래스에서만허용
	int value=100;
	public static SingleObject getObj() {
		return obj;
	}
}
public class SingletonEx1 {
	public static void main(String[] args) {
//		SingleObject o = new SingleObject();
		SingleObject o1 = SingleObject.getObj();
		SingleObject o2 = SingleObject.getObj();
		System.out.println("o1.value : "+o1.value);
		System.out.println("o2.value : "+o2.value);
		o1.value = 200;  //객체는 하나임
		//참조변수를 100개를 만들어도 참조하는 객체는 하나뿐
		System.out.println("== o1.value = 200 실행 후 == ");
		System.out.println("o1.value : "+o1.value);
		System.out.println("o2.value : "+o2.value);
        
        System.out.println("o1.address : "+o1.hashCode());
		System.out.println("o2.address : "+o2.hashCode());
		
//		Math m = new Math(); 객체생성불가능
//		Math 클래스의 모든멤버는 Static
	}
}

o1.value : 100

o2.value : 100

== o1.value = 200 실행 후 ==

o1.value : 200

o2.value : 200

 

o1.address : 1746572565

o2.address : 1746572565 

//주소값이 같은것을확인 (참조가 같음)

 


2 ) @@ 인터페이스 @@

인터페이스의 특징 

객체화 불가 -> 구현클래스로 객체화 된다. 

클래스간은 상속이고, 클래스와 인터페이스의 관계는 구현이다. 

implements 예약어로 표현한다. 다중구현이 가능하다. 

인터페이스간의 상속도 가능하다. 인터페이스간의 상속은 다중 상속이 가능하다.

 

인터페이스의 모든 멤버의 접근제어자는 public이다. 

인터페이스의 모든 멤버 변수는 final이 붙은 상수다

 

 

클래스가 클래스를 상속받으면서 인터페이스까지 구현하려면

class A extends B implements C;

( 상속 먼저받고 구현을 하자 )

 

인터페이스

1.인터페이스의 멤버는 상수 추상메서드 defalut메서드 , static메서드만 가능 

 

2.인터페이스의 멤버의 접근제어자는 모두 public !!(생략해도 public) 

상수 [ public static final ]자료형 상수명

추상메서드  [public abstract ] 리턴타입 메서드명(매개변수목록); 

default 메서드 : [public] 구현부 가능한 메서드 인스턴스메서드

static 메서드 : [public] 구현부 가능한 메서드 클래스메서드 

 

3. 객체화 불가 : 구현클래스의 객체화를 통해서 객체화가능 

 

4. 클래스와 인터페이스는 구현(implements)로표현 , 다중구현 가능. 

 

5. 인터페이스간의 상속(extends)로 표현함 , 다중상속가능 

 

 

인터페이스 및 구현체(인터페이스를 구현하는 클래스)

interface Printerable{
	/* public static final */ int INK = 100;//상수는 대문자가 관례임
	/*public abstract*/void print();
	default void sort() {  //default메서드
		System.out.println("정렬페이지 출력");
	}
	static void sort2() {
		System.out.println("정렬페이지2");
	}
}
//----------------------------------------------------------------------------------

interface Scannerable{
	void scan();}

//----------------------------------------------------------------------------------
interface Faxable{
	String FAX_NO = "02-1111-2142";
	void send(String no);
	void receive(String no);
}

//----------------------------------------------------------------------------------

//인터페이스간의 다중상속
interface Complexerable extends Printerable,Scannerable,Faxable{} 

//--------------------------------------------------------------------------------------

//구현클래스 : 인터페이스를 구현한 클래스 (다중구현 가능)
//인터페이스의 추상메서드를 무조건 오버라이딩해서 사용해야함

class Complexer implements Printerable,Scannerable,Faxable,Complexerable{
	//implements Complexerable

	int ink;
	public Complexer() {
		this.ink = INK;
	}

	@Override
	public void print() {
		System.out.println("프린트 합니다  , 남은 잉크량 : "+--ink);
	}

	@Override
	public void scan() {
		System.out.println("이미지 스캔");
	}

	@Override
	public void send(String no) {
		System.out.println(FAX_NO+"에서 "+no+"로 FAX 전송");

	}

	@Override
	public void receive(String no) {
		System.out.println(no+"는 "+FAX_NO+"에게 FAX를 받았어요");

	}
}

 

구동클래스

 

인터페이스 형 <--- 구현체 형변환 가능

( 구현체의 멤버는 사용할 수 없음)

(자신의멤버만 사용가능)

public class InterfaceEx1 {

	public static void main(String[] args) {
		//		Printerable.INK = 150; 인터페이스상수 == final

		Complexer c = new Complexer();
		System.out.print("Complexer.sort : ");
		c.sort(); //default메서드는 객체화 시 사용이가능함
		System.out.printf("Printerable.sort2() : ");
		Printerable.sort2();
		
		System.out.println("Printerable.INK : "+Printerable.INK);
		System.out.println("Complexerable.INK : "+Complexerable.INK);
		System.out.println("Complexer.INK : "+Complexer.INK);
		
		System.out.println("Faxable.FAX_NO : "+Faxable.FAX_NO);
		System.out.println("Complexerable.FAX_NO : "+Complexerable.FAX_NO);
		System.out.println("Complexerable.FAX_NO"+Complexer.FAX_NO);
		String num = "010-8248-8421";
		
		c.print();
		c.scan();
		c.send(num);
		c.receive(num);
		System.out.println("복합기 프린트 남은 잉크량 : "+c.ink);
		System.out.println("===");
		
		if(c instanceof Complexerable) {
			System.out.println("@@ c가 참조하고 있는 객체 Complexerable객체 @@");
			Complexerable co = c;
			//인터페이스 <= 구현클래스 형변환 (자동형변환 가능 )
			co.print();
			co.scan();
			co.send(num);
			co.receive(num);
			//System.out.println("복합기 남은 잉크량 : "+co.ink);구현체의 기능을 사용할순없음
			
			
			if(c instanceof Printerable) {
				System.out.println("@@ c가 참조하고 있는 객체 Printerable객체 @@");
				Printerable p = c;
				//인터페이스 <= 구현클래스 형변환 (자동형변환 가능 )
				p.print();
				System.out.println("Printerable.INK : "+Printerable.INK);
//				p.scan(); 자신의멤버가 아님
//				p.send(num);
//				p.receive(num);
				//System.out.println("복합기 남은 잉크량 : "+co.ink);구현체의 기능을 사용할순없음
			}System.out.println("=================");
			
			if(c instanceof Scannerable) {
				System.out.println(" @@ c가 참조하고 있는 객체 Scannerable객체 @@");
				Scannerable s = c;
//				s.print();  //자신의멤버가아님
				s.scan(); 
//				s.send(num);
//				s.receive(num);
				//System.out.println("복합기 남은 잉크량 : "+co.ink);구현체의 기능을 사용할순없음
			}System.out.println("=================");
			
			
			if(c instanceof Faxable) {
				System.out.println("@@ c가 참조하고 있는 객체 Faxable객체 @@");
				Faxable f = c;
//				f.print();  //자신의멤버가아님
//				f.scan(); 
				f.send(num);
				f.receive(num);
				System.out.println("Faxable.FAX_NO"+Faxable.FAX_NO);
				//System.out.println("복합기 남은 잉크량 : "+co.ink);구현체의 기능을 사용할순없음
			}System.out.println("=================");
			
			if(c instanceof Object) {
				System.out.println("@@ c가 참조하고 있는 객체 Object객체 @@");
				Object o = c;
//			    o.print();     //자신의멤버가아님
//			    o.scan(); 
//				o.send(num);
//				o.receive(num);
				//System.out.println("복합기 남은 잉크량 : "+co.ink);구현체의 기능을 사용할순없음
			}System.out.println("=================");

		}
	}
}

 

Complexer.sort : 정렬페이지 출력

Printerable.sort2() : 정렬페이지2

Printerable.INK : 100

Complexerable.INK : 100

Complexer.INK : 100

Faxable.FAX_NO : 02-1111-2142

Complexerable.FAX_NO : 02-1111-2142

Complexerable.FAX_NO02-1111-2142

프린트 합니다 , 남은 잉크량 : 99

이미지 스캔

02-1111-2142에서 010-8248-8421로 FAX 전송

010-8248-8421는 02-1111-2142에게 FAX를 받았어요

복합기 프린트 남은 잉크량 : 99

===

@@ c가 참조하고 있는 객체 Complexerable객체 @@

프린트 합니다 , 남은 잉크량 : 98

이미지 스캔

02-1111-2142에서 010-8248-8421로 FAX 전송

010-8248-8421는 02-1111-2142에게 FAX를 받았어요

@@ c가 참조하고 있는 객체 Printerable객체 @@

프린트 합니다 , 남은 잉크량 : 97

Printerable.INK : 100

=================

@@ c가 참조하고 있는 객체 Scannerable객체 @@

이미지 스캔

=================

@@ c가 참조하고 있는 객체 Faxable객체 @@

02-1111-2142에서 010-8248-8421로 FAX 전송

010-8248-8421는 02-1111-2142에게 FAX를 받았어요

Faxable.FAX_NO02-1111-2142

=================

@@ c가 참조하고 있는 객체 Object객체 @@

=================


인터페이스의 default , static메서드

* -java8 이후에 사용가능한 메서드

* 인터페이스에서 구현부가 존재하는 메서드다.

* --default 메서드 : 인스턴스멤버 (객체화가 되어야 사용가능 )

* --static 메서드 : 클래스멤버 ( 인스턴스명.메서드 로 호출가능)

*

다중구현이 가능

    추상메서드 중복된 경우 : 하나만 오버라이딩

   default 메서드가 중복된 경우 : 오버라이딩필요

   default 메서드가 중복되지 않으면 : 오버라이딩 필수X

   static메서드는 중복되어도 상관없음. 인터페이스명.메서드로 접근

package chap8;
interface MyInterface1{
	void method();
	default void method1() {
		System.out.println("MyInterface1의 default메서드 : method1");
	}
	static void method2() {
		System.out.println("MyInterface1의 static메서드 : method2");
	}}
//-------------------------------------------------------------------------------

interface MyInterface2{
	void method();
	default void method1() {
		System.out.println("MyInterface2의 default메서드 : method1");
	}
	static void method2() {
		System.out.println("MyInterface2의 static메서드 : method2");
	}}

//-------------------------------------------------------------------
class Parent{
	public void pmethod() {
		System.out.println("Parent클래스의 멤버 메서드 : pmethod");
	}
}
//----------------------------------------------------------------------------

//구현한 두개의 인터페이스의 이름이똑같은 추상메서드가 존재한다면 한개만 오버라이딩됨
//default메서드는 클래스에서 오버라이딩 시 public으로 바뀌게 됨

class Child extends Parent implements MyInterface1,MyInterface2{
	public void method() {
		System.out.println("Child클래스에서 method() 오버라이딩");
	}
	@Override
	public void method1() {
//		MyInterface1.super.method1(); 
//		MyInterface2.super.method1();
		System.out.println("Child클래스에서 default메서드를 오버라이딩함 : method1");
	}
	@Override
	public void pmethod() {
		System.out.println("자식메서드");
	}
}
//------------------------------------------------------------------------------------

public class InterfaceEx5 {
	public static void main(String[] args) {
		Child c = new Child();
		c.method();
		c.method1();
		c.pmethod();//자식객체 생성 시 부모객체를 가지고있음
		
		Parent p = new Child();
		p.pmethod();//자식에서 오버라이딩했으므로 
		//부모의참조로 자식객체를 생성시 오버라이딩된 메서드가 출력됨
		
		MyInterface1.method2(); //static
		MyInterface2.method2();	
	}
}

Child클래스에서 method() 오버라이딩

Child클래스에서 default메서드를 오버라이딩함 : method1

자식메서드

자식메서드  //부모의참조로 생성한 객체

MyInterface1의 static메서드 : method2

MyInterface2의 static메서드 : method2


2-1 람다식 )

함수적 인터페이스(FunctionalInterface) : 인터페이스의 추상메서드가 한개인 인터페이스

 

@FunctionalInterface 

//함수적 인터페이스로 설정하므로 추상메서드가 1개여야함을 표시(2개입력시 컴파일오류)

 

기본람다방식

 * 함수적 인터페이스(FunctionalInterface) : 인터페이스의 추상메서드가 한개인 인터페이스
 * 함수적 인터페이스만 람다방식으로사용가능
 * 추상메서드가 매개변수 , 리턴타입이 없는경우의 예제
 * fi = () ->{...};
 * 내부의 문장이 하나인경우는 {} 생략가능
 * fi = ()->...

package chap8;


@FunctionalInterface    //함수적 인터페이스로 설정하므로 추상메서드가 1개여야함을 표시
interface LambdaInterface1{
	void method(); //매개변수 없고 리턴타입도 없는경우
//	void method2();
}
//-------------------------------------------------------------------
public class LambdaEx1 {
	
	public static void main(String[] args) {
		LambdaInterface1 f1;
		
//-------------------------------------------------------------------
		// 0. 익명클래스 이용
		
		f1 =new LambdaInterface1() {
			
			@Override
			public void method() {
				System.out.println("기존의 내부객체로 생성함");
			}
		};f1.method();
	
//-------------------------------------------------------------------	-------	
		//1.람다식으로 변경
		
		f1 = ()->{
			String str = "람다방식 1 ";
			System.out.println(str);
		};f1.method();
		
//-------------------------------------------------------------------	-------			
		
		//2.람다방식 : 내부 문장이 한개인경우 {} 생략가능
		
		f1 = ()-> System.out.println("람다방식 2 ");
		f1.method();
		
//-------------------------------------------------------------------	-------	
		//3. LambdaInterface1 인터페이스를 매개변수로받는 static메서드로 람다방식이용
		
		execute(()->System.out.println("excute메서드에서 호출함"));
		
		//execute 함수 이용해 1~100까지의 합 출력
		execute(()->{
			System.out.print("1에서100까지의 합 : ");
			int num =100;
			int sum=0;
			for (int i = 1; i <= num; i++) {
				sum+=i;
			}
			System.out.println(sum);
		});
		
		//excute 함수를 이용해 1~100까지의 짝수합 출력해보기
		execute(()->{
			System.out.print("1에서100까지의 짝수 합 : ");
			int num =100;
			int sum=0;
			for (int i = 1; i <= num; i++) {
				if(i%2==0) {
					sum+=i;
				}
			}
			System.out.println(sum);
			
			
		});
	}
	
	public static void execute(LambdaInterface1 l) {
		System.out.println("excute 시작");
		l.method();
		System.out.println("excute 종료");
	}
}

기존의 내부객체로 생성함

람다방식 1

람다방식 2

 

excute 시작

excute메서드에서 호출함

excute 종료

 

excute 시작

1에서100까지의 합 : 5050

excute 종료

 

excute 시작

1에서100까지의 짝수 합 : 2550

excute 종료


매개변수는 있으나 반환값이 없는 경우


 * 추상메서드의 매개변수가있고 리턴타입은 void인경우
 * (매개변수)->{...};
 * 매개변수가 1개인 경우 () 생략가능
 * 실행구문이 1개인경우 {} 생략가능

package chap8;

interface Lambda2 {
	void method(int a);
}

public class LambdaEx2 {
	public static void main(String[] args) {

		Lambda2 l;
		
		l=x->{
			System.out.println(x+" * 3 : "+x*3);
			};
		l.method(4);

		calc(l,5); //위에서정의한 method의 방식을사용함 (num*3)
		calc((x)->System.out.println(x+" * 9 : "+x*9), 5);
	}
	
	private static void calc(Lambda2 f ,int num) {
		f.method(num);
	}
}

4 * 3 : 12

5 * 3 : 15

5 * 9 : 45

 


매개변수와리턴값 모두 존재할 떄의 람다식

package chap8;

interface LamdaInterface3{
	int method(int x, int y);
}
public class LambdaEx3 {
	public static void main(String[] args) {
		LamdaInterface3 f = (x,y)->{
			return x+y;
		};
		System.out.println("두수의 합 : "+f.method(2, 5));

		f=(x,y) -> x + y;
		System.out.println("두수의합 : "+f.method(2, 3));

		f=(x,y) -> x * y;
		System.out.println("두수의 곱 : "+f.method(10, 2));

		f=(x,y) -> x / y;
		System.out.println("두수의 몫 : "+f.method(240, 2));

		f=(x,y) -> x & y;
		System.out.println("두수의 나머지 : "+f.method(10, 4));

		f=(x,y) -> {
			if(x>y) {return x;}
			else {return y;}
		};
		System.out.println("두수 중 큰 수: "+f.method(10, 4));

		f=(x,y)->(x<y)?x:y;
		System.out.println("두수 중 작은 수: "+f.method(10, 4));
	}
}

두수의 합 : 7

두수의합 : 5

두수의 곱 : 20

두수의 몫 : 120

두수의 나머지 : 0

두수 중 큰 수: 10

두수 중 작은 수: 4



 3) @@ 내부클래스 : 클래스내부에존재하는 클래스 @@


 * 인스턴스내부클래스 : 객체화가 되기 위해서는 외부클래스의 객체화 필요  -> 
 *                                 외부클래스참조변수.new 내부클래스명();
 *                                 new 외부클래스().new 내부클래스();
 *                                 
 * static 내부클래스 : 객체화가 되기 위해서는 -> new 외부클래스명.내부클래스명();
 * 
 * 지역 내부클래스  : 메서드 내부에서 선언된 내부클래스
 *   선언된 메서드 내에서만 사용할 수 있다.
 * 
 * 내부클래스 특징
 * 1.참조자료형으로 사용됨 . 외부클래스명.내부클래스명
 * 2. 객체화가능 
 * 멤버소유가능 , 생성자 구현가능

3. 외부클래스의멤버임.
.외부클래스의 private멤버에 접근가능
.인스턴스내부클래스 : 인스턴스멤버
.static내부클래스 : 클래스멤버
 */

package chap9;

import chap9.Outer1.InstanceInner;
import chap9.Outer1.StaticInner;

class Outer1{
	int iv=40;
	static int cv=30;
	
	class InstanceInner{//내부클래스
		int iv=100;
		static int cv = 10;
		final static int MAX = 200;
		int outerIv= Outer1.this.iv;//바깥클래스 멤버 접근법
	}
	
	static class StaticInner{//static 내부클래스
		int iv=300;
		static int cv = 400;
		final static int MAX = 500;
        //바깥클래스의 참조를알아야 접근가능
	}
	
	void method() {//Outer1의 멤버
		
		class LocalInner{//Local내부클래스
			int iv=600;
			static int cv = 700;
			final static int MAX = 800;
			}
		LocalInner lc = new LocalInner();//객체화
		
		System.out.println("====="+lc.getClass()+"====");
		System.out.println("lc.iv : "+lc.iv);
		System.out.println("lc.cv : "+LocalInner.cv);
		System.out.println("LocalInner.MAX : "+LocalInner.MAX);
		System.out.println("this.iv : "+this.iv);//외부클래스(자신의클래스) 멤버 접근가능
	}
	
	void method2() {
//		LocalInner lc = new LocalInner();
		//오류발생 , method()내부에서만 호출가능한 내부클래스
	}
}
public class InnerEx1 {
	public static void main(String[] args) {
		Outer1 outer1 = new Outer1();
		
		InstanceInner i = outer1.new InstanceInner();//인스턴스내부클래스 생성법1
		InstanceInner i2 = new Outer1().new InstanceInner();//생성법2
		System.out.println("======= 내부클래스 =======");
		System.out.println("i.iv : "+i.iv);
		System.out.println("i.cv : "+InstanceInner.cv);
		System.out.println("outerIv : "+i.outerIv);
		System.out.println("InstanceInner.MAX : "+InstanceInner.MAX);
		
		StaticInner s = new Outer1.StaticInner();//static클래스 생성법
		System.out.println("======static 내부 클래스=======");
		System.out.println("s.iv : "+s.iv);
		System.out.println("s.cv : "+StaticInner.cv);
		System.out.println("StaticInner.MAX : "+StaticInner.MAX);
		StaticInner s2 = new StaticInner();//그냥 클래스만으로도 생성가능
		
		
		outer1.method();//지역클래스는 메서드안에서만사용됨
	}
}

======= 내부클래스 =======

i.iv : 100

i.cv : 10

outerIv : 40

InstanceInner.MAX : 200

======static 내부 클래스=======

s.iv : 300

s.cv : 400

StaticInner.MAX : 500

=====class chap9.Outer1$1LocalInner====

lc.iv : 600

lc.cv : 700

LocalInner.MAX : 800

this.iv : 40

 


내부클래스의 접근

package chap9;

import chap9.Outer2.InstanceInner;
import chap9.Outer2.StaticInner;

class Outer2{
	private int outeriv = 10;
	private static int outercv=20;
	
	class InstanceInner{
		int iiv = outeriv;
		int iiv2 = outercv; //인스턴스멤버 -> 클래스멤버 (접근 가능)
	}
	
	static class StaticInner{
//		static int scv = outeriv;   클래스멤버->인스턴스멤버 (호출불가능) //객체화해야함
		static int scv = new Outer2().outeriv;
		static int scv2 = outercv;
		int siv2 = outercv;
	}
	/*
	 * 지역내부클래스에 사용되는 메서드의 지역변수는 상수화되어야함
	 * 지역변수의 변경이 없는경우는 상수로 판단함
	 * 지역변수의 변경은 안됨
	 */
	void method(int pv) {
		int lv=100;
//		lv++;지역변수의 변경은 안됨
		class LocalInner{
			int liv = outeriv;
			int liv2 = outercv;
			void method(int num) {
				System.out.println("===== LocalInner 클래스 =====");
				System.out.println("outeriv : "+outeriv);
				System.out.println("outercv : "+outercv);
				System.out.println("liv : "+ ++liv);//내부클래스의 멤버변수
				System.out.println("liv2 : "+ ++liv2);//내부클래스의 멤버변수
				System.out.println("num :  "+ ++num);//내부메서드의 지역변수 100-->101
				System.out.println("pv : "+pv);//외부메서드의 지역변수 : pv
				System.out.println("lv : "+lv); // 외부메서드의 지역변수 . 100
			}
		}
		LocalInner l = new LocalInner();
		l.method(100);
	}
}

public class InnerEx2 {
	public static void main(String[] args) {
		Outer2 outer2 = new Outer2();
//		outer2.outeriv;    호출불가  private멤버
		
		//InstacneInner, StaticInner 내부의멤버출력하기
		System.out.println("===== InstanceInner 클래스 =====");
		InstanceInner i = outer2.new InstanceInner();
		System.out.println("i.iiv : "+ ++i.iiv);
		System.out.println("i.iiv2 : "+ ++i.iiv2);

		
		System.out.println("===== StaticInner 클래스 =====");
		StaticInner s = new Outer2.StaticInner();
		System.out.println("StaticInner.scv : "+Outer2.StaticInner.scv);
		System.out.println("StaticInner.scv : "+Outer2.StaticInner.scv2);
		System.out.println("s.siv2 : "+s.siv2);
		
		outer2.method(90);
	}
}

===== InstanceInner 클래스 =====

i.iiv : 11

i.iiv2 : 21

===== StaticInner 클래스 =====

StaticInner.scv : 10

StaticInner.scv : 20

s.siv2 : 20

===== LocalInner 클래스 =====

outeriv : 10

outercv : 20

liv : 11

liv2 : 21

num : 101

pv : 90

lv : 100

 

익명클래스

익명클래스에는 함수적인터페이스가 필요함

(람다를 이용하기위해)

지역클래스와 마찬가지로 메서드 내에서생성한다

그러므로 외부클래스에멤버에속함

(외부클래스의 인스턴스멤버에접근가능)

package chap9;

/*
 * 람다 객체에서의 this
 */

@FunctionalInterface
interface LambdaInterface{
	void method();
}

class Outer{
	public int iv=10;

	void method() {
		final int iv = 40;//바뀌면안됨
//		iv++;\
		LambdaInterface f;
		f = ()->System.out.println("@@람다객체에서의 this@@");
		f.method();
		
		f =()->{
			System.out.println("iv : "+iv);//외부메서드의 지역변수는 상수화가 필요함
			System.out.println("this.iv : "+this.iv);//Outer클래스의 멤버변수 호출
			System.out.println("Outer.this.iv : "+Outer.this.iv);//Outer클래스의 멤버변수 호출2
		};
		f.method();
		
		
	}
	
}
public class InnerEx4 {
	public static void main(String[] args) {
		new Outer().method();
		
	}
}

@@람다객체에서의 this@@

iv : 40

this.iv : 10

Outer.this.iv : 10


정적내부클래스 관련 문제)

package nested.test;
public class OuterClass1 {
// 여기에 NestedClass를 구현해라. 그리고 hello() 메서드를 만들어라.
}
package nested.test;
public class OuterClass1Main {
public static void main(String[] args) {
// 여기에서 NestedClass의 hello() 메서드를 호출하라.
}
}

 

정답

package chap9.test;

public class OuterClass1 {
	
	public static class NestedClass{
		static void hello() {
			System.out.println("Nested클래스의 메서드임");
		}
	}
	
	public static void main(String[] args) {
		NestedClass ne = new OuterClass1.NestedClass();
        //정적내부클래스는 new 외부클래스.정적클래스() 로 생성
		NestedClass.hello();
        //정적메서드는 클래스명.메서드로 접근해야함
	}
}

 


문제 - 익명 클래스를 완성해라

package nested.test;
public interface Hello {
void hello();
}
package nested.test;
class AnonymousMain {
public static void main(String[] args) {
// 여기에서 Hello의 익명 클래스를 생성하고 hello()를 호출해라.
}
}

정답

package chap9.test;

interface Hello{
	void hello();
}

public class AnonymousMain  {
	static void method(Hello h) {
		h.hello();
	}
	
public static void main(String[] args) {

	method(()-> System.out.println("hello"));
	
	Hello h;
	h=()->{
		System.out.println("hello2");
	};
	h.hello();
    }
}

4) 예외처리

* 예외처리 : 발생된 예외를 정상화하는 과정

*

* try {} : 예외 발생 가능성이있는문장

* catch(예외타입 참조변수) {} : try구문에서 예외발생시 호출되는 블럭

* finally{} : 정상,예외 상관없이 꼭 실행

*

* throws : 예외처리의 다른방식(던지기)

* throw : 예외발생

 


 

 

예시를 들어볼게요

 

 

public class ExceptionEx1 {

	public static void main(String[] args) {
		
		try {
			System.out.println(args[0]);
			System.out.println(args[1]);
	
		} catch (ArrayIndexOutOfBoundsException e) {
			e.printStackTrace();//오류내용출력
			System.out.println(e.getClass());//예외명 출력
			System.out.println("command라인에 파라미터값 입력하세요");
		}
		
		finally {
			System.out.println("종료");
		}
	}
}

argument에 아무것도입력하지않았을 때

java.lang.ArrayIndexOutOfBoundsException: Index 0 out of bounds for length 0

at chap10.ExceptionEx1.main(ExceptionEx1.java:18)

class java.lang.ArrayIndexOutOfBoundsException

command라인에 파라미터값 입력하세요

종료

 

argument에 안녕하세요 동곤자바입니다 입력

argument는 띄어쓰기(" ")을 기준으로 배열을 나눔

안녕하세요

동곤자바입니다

종료

 

 


다중 catch


 * catch블럭 : try블럭 내부에서 예외발생시 실행되는 영역
 * 
 * 다중catch
 * --한개의 try블럭에 여러개의 catch블럭 존재
 * -----> try블럭에서 발생되는 예외가 여러종류인 경우 예외별 예외처리가 가능
 * -> 상위 예외클래스(Exceptio)은 catch들 중 하단에 배치해야 함
 * 
 * 
 * 예외 클래스 계층
 * Throwable - Error
 *      - Exception(예외클래스 의 최상단) - RunTimeException(예외처리 생략가능)
 *      - 그 외 Exception (예외처리 생략불가)
 */

package chap10;


public class ExceptionEx2 {
	public static void main(String[] args) {
//		System.out.println(1/0);
		//ArithmeticException이 발생하지만 try문 밖 이므로
		//catch할 수 없음
		
		try {
			String str = "        [ㅎㅎㅎㅎㅎ]      ";
			//trim : 공백제거하는 기능
			System.out.println(str.trim()); 
			
			System.out.println(Integer.parseInt("44"));
			System.out.println(args[0]);//ArrayIndexOutOfBoundsException발생
			System.out.print(1);
			System.out.print(2);
			System.out.print(3/0); //여기서 예외발생 ArithmeticException
			System.out.print(4);
			System.out.print(5);
			} 
		catch (ArithmeticException e) {//try문 안에서 예외발생시 실행
		
			System.out.println("\n 예외 메시지 : "+e.getMessage());
			System.out.println("예외명 : "+e.getClass());
				
		}
		catch (ArrayIndexOutOfBoundsException e) { //또다른 예외를 잡을 수도 있음
			System.out.println("command라인을 입력하세요");
//			e.printStackTrace(); 예외스택을 전부출력
			System.out.println("예외 메시지  : "+e.getMessage());
			System.out.println("예외명 : "+e.getClass());
		}
		catch(NumberFormatException e) {
			System.out.println("예외 메시지 : "+e.getMessage());
			System.out.println("예외명 : "+e.getClass());
			System.out.println(" 숫자만 입력해주세요 !");
		}
		
		catch(Exception e ) {
			//모든 예외를 잡아줌(catch문은 위로갈수록 상세하게 잡아주는게 원칙)
			// 상위 예외클래스는 catch들 중 하단에 배치
			System.out.println("예외 메시지 : "+e.getMessage());
		}
		
		System.out.println(6);//예외와상관없이 실행
	}
}

 

아무것도건들지않고 코드 그대로실행 시

.ArrayIndexOutOfBoundsException

[ㅎㅎㅎㅎㅎ]

44

command라인을 입력하세요

예외 메시지 : Index 0 out of bounds for length 0

예외명 : class java.lang.ArrayIndexOutOfBoundsException

6

 

argument입력 후

(ArtimeticException 발생)

[ㅎㅎㅎㅎㅎ]

44

하이

12

예외 메시지 : / by zero

예외명 : class java.lang.ArithmeticException

6

 

3/0 을 3으로 바꿔서 출력해보겠음

(정상출력)

[ㅎㅎㅎㅎㅎ]

44

하이

123456

 


throws ( 예외던지기)


 * throws : 예외처리
 *  예외던지기 , 예외선언
 *  예외 발생한 메서드에서 발생된 예외를 호출한 메서드로 전달
 *  --> 호출한 메서드에서 예외 발생

package chap10;

public class ExceptionEx4  {
	public static void main(String[] args) {
		
		try {
			fisrt();
		} catch (Exception e) {
			System.out.println("main에서 예외 처리");
			e.printStackTrace();
		}
	}

	private static void fisrt() throws Exception {
		second();
		
	}
	private static void second()  throws Exception {
		try {
			System.out.println(Integer.parseInt("abc"));

			
		} catch (Exception e) {
			System.out.println("second에서 예외처리");
			System.out.println("메시지 : "+e.getMessage());
		}
		
	}

}

 

일단 second()에서 예외가 터질것이다

abc를 int형으로 바꾸려고시도했기때문!!

second에서 예외처리

메시지 : For input string: "abc"

 

second에서 예외를잡지않고 thorws Exception으로

나를 호출했던곳(first)으로 예외를 던져보자

 

fisrt()에서도 예외를 던짐--->main

main에서 예외 처리

For input string: "abc"

 

던지고던져서 결국 main코드까지 예외가던져진 후에

catch로 예외를 잡앗음.


throw (예외발생)

Exception 혹은 RuntimeException을상속받은 클래스를 만들고

 

내가 예외를 직접발생시키고 잡는게 가능함throw new 예외("메시지") 를 통해사용자정의 예외를 만들 수 있음!!!

package chap10;


class LoginFailException extends Exception{
	
	 LoginFailException(String msg) {
		 super(msg);
	}
}

class LoginFailException2 extends RuntimeException{
	
	//예외를 잡지않아도되는 언체크 예외를 상속받음
	
	 LoginFailException2(String msg) {
		 super(msg);
	}
}

public class ExceptionEx8 {
	public static void main(String[] args) {
		String id = "hong89"; //id가 hong이 아님
		String pw = "1120";
		
		try {
			if(!id.equals("hong")|| !pw.equals("1120")) {
				//id가 hong과 다르거나 비밀번호가 1120이 아니라면
				throw new LoginFailException("아이디나 비번오류(체크)");
				//예외 생성
			}
			System.out.println("반갑습니다 hong님(로그인성공)");
			
		} catch (LoginFailException e) {
			System.out.println(e.getMessage());
			//예외처리
		}
		
		
			if(!id.equals("hong")|| !pw.equals("1120")) {
				//id가 hong과 다르거나 비밀번호가 1120이 아니라면
				throw new LoginFailException2("아이디나 비번오류(언체크)");
				//RuntimeException을 상속받았으므로 던지거나 잡지않아도 됨
			}
			System.out.println("반갑습니다 hong님(로그인성공)");
	}
}

 

id오류로 인한

아이디나 비번오류(체크)

Exception in thread "main" chap10.LoginFailException2: 아이디나 비번오류(언체크)

at chap10.ExceptionEx8.main(ExceptionEx8.java:43)

 

언체크예외(RuntimeException) 을 상속받은 

LoginFailException2 는 catch로 잡을 필요가없다!!!


 

예제

 

* 화면에서 1~10사이 숫자 입력받아 숫자만큼 * 출력

* 입력값이 숫자아닌경우 InputMismatchException 예외발생

* 예외발생시 숫자만입력하세요 메시지 출력하기 -> 다시 숫자입력받기

* catch scan.next(); 추가하기

*

* 1~10사이의 숫자가 아닌경우 NumberInputException 클래스의 예외발생하고

* 다시숫자입력받기

public class Exam3_A {
	public static void main(String[] args) {
		while(true) {
			System.out.println("숫자입력하세요(0입력시 종료)");
			Scanner scan = new Scanner(System.in);
			try {
			int num = scan.nextInt();
			if(num==0) {
				break;
			}
			for (int i = 0; i < num; i++) {
				System.out.print("* ");
			}
			}
			catch(InputMismatchException e) {
				System.out.println("메시지 : "+e.getMessage());
				System.out.println("숫자만입력해요");
				scan.next();
			}
		}
	}
}

예외가발생하면 예외메시지를 출력하고

scan.next()로 문자열을 지워줌 

(지우지않을시 무한루프)

숫자입력하세요(0입력시 종료)

5

* * * * * 숫자입력하세요(0입력시 종료)

;

메시지 : null

숫자만입력해요

숫자입력하세요(0입력시 종료)

0