익명 객체

오늘·2021년 3월 18일
0

Java

목록 보기
22/42

익명객체

-익명 객체 : 이름이 없는 객체
-단독 생성 불가 : 클래스 상속하거나 인터페이스 구현해야만 생성가능
-사용 위치 : 필드나 로컬변수의 초기값, 매개변수의 매개값으로 주로 대입

상속관계 : 부모-자식 / 상위-하위
연결관계 : 인터페이스 - 구현클래스


익명 자식객체 생성

부모 타입으로 필드나 변수 선언 후, 자식 객체를 초기값으로 대입할 경우를 생각해보자. 부모를 상속해 자식클래스를 선언하고, new 연산자로 자식 객체를 생성한 후, 필드나 로컬 변수에 대입하는것

// 자식 클래스 선언
class Child extends Parent {	}

class A {
	// 필드에 자식 객체 대입
    	Parent field = new Child();
        void method() {
        // 로컬 변수에 자식 객체 대입
        Parent local = new Child();
    }
}

but. 자식 클래스가 재사용되지 않고, 오로지 해당 필드와 변수의 초기값으로만 사용할 경우라면 익명 자식 객체를 생성해 초기값으로 대입하는 것이 좋다

부모클래스 필드변수 = new 부모클래스 (매개값, ...) {
	// 필드
    	// 메소드
};

주의할 점은 하나의 실행문이기에 저렇게 세미콜론(;)을 붙여야한다는 것이다.


연습해보기 01

// 1. 부모 클래스를 만들어준다
class Parent {
void pM() {	}
void pM1()	{	}
}



class A {
	// 부모 객체 생성과 동시에 자식 객체 생성
	Parent p = new Parent() {
		String cName;
		boolean gender;

		void cM1() {	}
		void cM2() {	}

		// 익명 자식객체는 외부에서 호출할 수 없기때문에
		// 오버라이딩한 메소드에서 사용
		@Override
		void pM() {
			cName="강아지";
			cM1();
		}
		@Override
		void pM1() {
			cName="고양이";
			cM2();
		}
	};
    
    
    	// 클래스 내의 다른 메소드
    	void aMethod() {
		// 익명 객체의 것들이기에
        	// 그 메소드를 넘어가면 호출 불가
//		p.cName = "홍길동";
//		p.gender = true;
//		p.cM1();
		// 이건 부모 클래스의 것을 오버라이딩 한거니 사용 가능
		p.pM();
		p.pM1();
	}
}

연습해보기 02 - 익명 자식 객체 생성

방법 1. 필드 초기값으로 대입

부모가 될 Person을 받아와 객체 생성을 하고 자식인 익명 객체 구현

Person field = new Person() {
	// 익명클래스의 메소드는 오버라이딩한 메소드에서 사용하기 위해 작성
	void work() {
		System.out.println("출근합니다");
	}
	@Override
	void wake() {
		System.out.println("6시에 일어납니다");
		// 익명 자식 클래스 메소드 호출
		work();
	}
};

방법 2. 로컬 변수값으로 대입

-클래스 내에 메소드를 만들고, 그 안에 상위 클래스를 new로 객체 생성한 뒤 실행내용을 그 안에 작성하고 사용한다.
-내용을 실행하기 위해서는 메소드 안에 작성한 걸 호출해놔야 한다.

void method1() {
	//로컬 변수값으로 대입
	Person localVar = new Person() {
		void walk() {
			System.out.println("산책합니다");
		}
		@Override
		void wake() {
			System.out.println("7시에 일어납니다");
			// 익명 자식 클래스 메소드 호출
			walk();
		}
	};
	//로컬 변수 사용
	localVar.wake();
}

방법 3. 매개값으로 처리

매개값을 받는 메소드를 만든 후, 부모 클래스의 것으로 연결한다.

// 매개값으로 Person을 받아 변수 person에 저장
// 들어오는 값을 person.wake()에 받는다
void method2(Person person) {
	person.wake();
}

구현 클래스에서 사용하는 모습을 보자

public class AnonymousEx {
	public static void main(String[] args) {
		Anonymous anony = new Anonymous();
		// wake()는 자식 객체에 있지만
        	// 오버라이딩 한 것이기에 사용 가능한 것
		// 익명 객체 필드 사용
		anony.field.wake();
		
		
		// 익명 객체 로컬 변수 사용
		anony.method1();
		
		
		// 익명 객체 매개값 사용
		// 매개값으로 new Person()을 올려 익명 객체 구현함
		anony.method2(new Person() {
			void study() {
				System.out.println("공부합니다");
			}

			@Override
			void wake() {
				System.out.println("8시에 일어납니다");
				study();
			}
		}
		// 잘보자. } 이거 아니고 )이거다
		);
	}
}

실행모습


연습해보기 03 - 익명 자식 객체 생성

필드의 초기값 익명 객체 연습

public class AnonyEx {
	public static void main(String[] args) {
		A field1 = new A() {
			int childField = 10;
			void childM() {
				System.out.println("익명 구현 메소드 구역");
			}
			@Override
			void aM() {
				System.out.println("익명 자식 구현 객체 값 : " + childField);
				// 익명 자식 구현 메소드 값 호출
				childM();
			}
		};
		field1.aM();
	}
}


class A {
	void aM() {	}
}

로컬변수 익명 객체 연습

public class AnonyEx2 {
	public static void main(String[] args) {
		A1 local = new A1() {
			double d = 3.14;
			void dA() {
				System.out.println("로컬 익명 객체 메소드");
			}
			@Override
			void a1M() {
				System.out.println("익명 로컬 변수 d의 값 : " + d);
				// 익명 메소드 호출
				dA();
			}
		};
		local.a1M();
	}
}


class A1 { 
	void a1M() {	}
}

익명 자식 객체를 매개 값으로 보냄

public class AnonyEx3 {
	public static void main(String[] args) {
		BussinesLogic bl = new BussinesLogic(new A2() {
			// A의 필드
			int num = 10;
			byte num2 = 20;
			char ch = 'C';

			// A의 메소드
			void aChild() {
				System.out.println("A의 메소드 부분");
			}

			@Override
			void a2M() {
				System.out.println("num + 10 : " + (num + 10));
				System.out.println("byte + 20 : " + (num2 + 20));
				System.out.println("char ch : " + ch);
				aChild();
			}
		});
		
	}
}


class BussinesLogic {
	// 생성자
	// 오버로딩 함
	public BussinesLogic() {	}
	public BussinesLogic(A2 a) {	}
}

class A2 {
	void a2M() {	}
}

연습해보기 04 - 익명 객체 구현

  1. 인터페이스 작성
public interface RemoteControl {
	public void turnOn();
	public void turnOff();
}
  1. 필드 초기값, 로컬 변수값
public class Anonymous {
	// 필드 초기값으로 대입
	RemoteControl field = new RemoteControl() {
		@Override
		public void turnOn() {
			System.out.println("Tv를 켜겠습니다");
		}
		
		@Override
		public void turnOff() {
			System.out.println("Tv를 끄겠습니다");
		}
	};
	
	void method1() {
		// 로컬 변수값으로 대입
		RemoteControl localVar = new RemoteControl() {
			@Override
			public void turnOn() {
				System.out.println("Audio를 켭니다");
			}
			
			@Override
			public void turnOff() {
				System.out.println("Audio를 끕니다");
			}
		};
		// 로컬변수 호출
		localVar.turnOn();
	}
	
	void method2(RemoteControl rc) {
		rc.turnOn();
	}
}
  1. 호출하는 클래스
public class AnonymousEx {
	public static void main(String[] args) {
		Anonymous anony = new Anonymous();
		// 익명 객체 필드
		anony.field.turnOn();
		
		// 익명 객체 로컬 변수 사용
		anony.method1();
		
		// 익명 객체 매개값 사용
		anony.method2(new RemoteControl() {
			@Override
			public void turnOn() {
				System.out.println("스마트 티비를 켭니다");
			}
			@Override
			public void turnOff() {
				System.out.println("스마트 티비를 끄겠습니다");
			}
		});
		
		// 익명 객체 필드
		anony.field.turnOff();
	}
}

실행 모습


연습해보기 05 - 익명 객체 구현

  1. 인터페이스 작성
interface In {
	void play();
	void stop();
}

2. 다른 메소드에서 로컬 변수 호출이 가능할까?

로컬 변수에 익명 구현 객체 만들기
매개변수를 인터페이스로 주고 받을 수 있을까?

class BL {
	// 필드로 익명 구현 객체 만들기
	In infield = new In() {
		@Override
		public void stop() {
			System.out.println("필드 멈춤");
		}
		@Override
		public void play() {
			System.out.println("필드 실행");
		}
	};
	
	// 로컬 변수에 익명 구현 객체 만들기
	// 만약 변수 선언을 메소드 밖에 한다면
	In local;
	void blM1() {
		// 익명객체 내부에서 매개변수나 로컬 변수를 사용할 경우
		// 이 변수들은 final을 생략해도 final의 특성을 가진다
		// 1. 변수 a 를 10이라 초기화했다
		int a = 10;
		local = new In() {
			@Override
			public void stop() {
				System.out.println("로컬 멈춤");
				// 2. 익명객체 내부에서 다른 값에 a를 연산하여 넣는 것은 가능하나
				int b = a + 10;
				// a 그 자체의 값을 변경하는 것은 불가능
				// a += 10;
			}

			@Override
			public void play() {
				System.out.println("로컬 실행");
			}
		};
	}
	// 다른 메소드에서 로컬변수 호출도 가능하다
	void yes() {
		local.stop();
		local.play();
	}
	
	
	// 매개변수를 인터페이스로 주고받는 메소드
	void blM2(In i) {
		i.stop();
		i.play();
	}
// 매개변수값 으로 익명 구현 객체 만들기
	void yes2() {
		blM2(new In() {
			@Override
			public void play() {
				System.out.println("매개변수값 실행");
			}
			@Override
			public void stop() {
				System.out.println("매개변수값 정지");
			}
		});
	}
}
  1. 호출하는 메인 클래스
public class AnonyEx {
	public static void main(String[] args) {
		BL bl = new BL();
		
		bl.infield.play();
		bl.infield.stop();
		
		System.out.println("-----------------");
		
		bl.blM1();
		bl.yes();
		
		System.out.println("------------------");
		
		bl.blM2(new In() {	
			@Override
			public void stop() {
				System.out.println("메인에서 매개변수 넘겨준 중지");
			}
			
			@Override
			public void play() {
				System.out.println("메인에서 매개변수 넘겨준 실행");
			}
		});
		System.out.println("------------------");
		
		bl.yes2();
	}
}

실행 모습


메소드 안에 익명 구현 메소드가 있다면 변수는 final로

메소드 안에 익명구현 객체를 포함하고 있다면, 그 매소드의 매개변수와 지역변수는 자동 final 로 간주된다.
단, 메소드 밖에서 설정한 변수인 field 값은 변경 가능

예제)

public interface Calcu {
	public int sum();
}


// 메소드 안에 익명구현 객체를 포함하고 있다면
// 그 매소드의 매개변수와 지역변수는 자동 final 로 간주된다
class Anonymous {
	private int field;
	
	public void method(final int arg1, int arg2) {
		final int var1 = 0;
		int var2 = 0;
		
		// 메소드 밖에서 설정한 변수인 field 값은 변경 가능
		field = 10;
		
		// arg1 = 20;
		// arg2 = 20;
		
		// var1 = 30;
		// var2 = 30;
		
		// 익명 구현 객체에서 변수를 참조하고 있기 때문에
		// 메소드 내에 호출된 변수는 그 상태로 final 고정 되어 값 변경이 불가하다
		Calcu calc = new Calcu() {
			@Override
			public int sum() {
				// field는 전역변수라 값 변경 가능
				field = 30;
				int result = field + arg1 + arg2 + var1 + var2;
				return result;
			}
		};
		
		System.out.println(calc.sum());
	}
}

메소드 내에서 생성된 익명 객체는 메소드 실행이 끝나도 힙 메모리에 존재하기에 계속 사용 가능하다. 매개변수나 로컬변수는 메소드 실행이 끝나면 스택 메모리에서 사라지기 때문에 익명 객체에서 사용할 수 없으므로 문제가 발생한다
-> 익명객체 내부에서 메소드의 매개 변수나 로컬 변수를 사용할 경우, 이 변수들은 final 특성을 가져야한다. 컴파일시 final 키워드가 있다면 메소드 내부에 지역 변수로 복사되지만, final 키워드가 없다면 익명 클래스의 필드로 복사된다.


0개의 댓글