728x90
반응형
CollEx07_01.java
package collectionex;

import java.util.*;
import java.util.Map.Entry;

public class CollEx07_01 {

	public static void main(String[] args) {
		HashMap<Integer, String> hm = new HashMap<>();//객체 생성만 된 상태
		hm.put(0, "하늘");
		hm.put(1, "바람");
		hm.put(2, "가지");
		hm.put(3, "태양");
		System.out.println(hm + "\n"); //객체주소값이 아닌 값이 출력
		System.out.println("hm.get(3): " + hm.get(3));
		System.out.println("hm.get(3): " + hm.get("3"));//없는 key값 호출 시 null값 반환
		for (int key : hm.keySet()) {
			System.out.println("key : " + key + ", value : " + hm.get(key));
		}
		for(int i=0 ; i<hm.size();i++) {
			System.out.println("[" + i + "번]의 값:" + hm.get(i));
		}
		//entrySet 메서드는 key, value를 볼 수 있게 해준다.
		for (Entry<Integer, String> s : hm.entrySet()) {
			System.out.println(s.getKey() + ", " + s.getValue());
		}
	}

}​

 

{0=하늘, 1=바람, 2=가지, 3=태양}

hm.get(3): 태양
hm.get(3): null
key : 0, value : 하늘
key : 1, value : 바람
key : 2, value : 가지
key : 3, value : 태양
[0번]의 값:하늘
[1번]의 값:바람
[2번]의 값:가지
[3번]의 값:태양
0, 하늘
1, 바람
2, 가지
3, 태양​
Hashtable  
key, value 각각에 null을 허용하지 않는다.
입력시 빨간줄은 없지만 오류값 출력됨
ht.put("world", 321)
  ht.keySet()
   
   
CollEx08.java
Hashtable
package collectionex;

import java.util.*;
import java.util.Hashtable;
import java.util.Map.Entry;

public class CollEx08 {

	public static void main(String[] args) {
		Hashtable<String, Integer> ht = new Hashtable<>();
		ht.put("world", 321);
		ht.put("hello", 123);
//		//key, value 각각에 null을 허용하지 않는다. 입력시 빨간줄은 없지만 오류값 출력됨
//		ht.put("hello", null);
//		ht.put(null, 123);
		for (String key : ht.keySet()) {
			System.out.println(ht.get(key));
		}
		for (Entry<String, Integer> entry : ht.entrySet()) {
			System.out.println("key : " + entry.getKey() + "value : " + entry.getValue());
		}
		Hashtable<Integer, Integer> ht1 = new Hashtable<>();
		ht1.put(1, 123);
		ht1.put(2, 321);

		for(int i = 1 ; i <= ht1.size(); i++) {
			System.out.println(ht1.get(i));
		}
	}

}​
123
321
key : hellovalue : 123
key : worldvalue : 321
123
321​
CollEx09.java
package collectionex;

import java.util.*;

public class CollEx09 {
	public static void main(String[] args) {
		Set<Integer> set = new HashSet<Integer>();
		//HashSet 형성
		set.add(3);
		set.add(2);
		set.add(1);
		set.add(1);
		System.out.println("0번: " + set); //순번 랜덤. 중복값 덮어쓰기
		System.out.println("set.size(): " + set.size()+ "\n");
		//iterator 일렬로 나열된 객체를 가져와서 잘라냄, map자료형에서는 사용불가

		set = new HashSet<Integer>(Arrays.asList(2,1,3));
		//Arrays.asList(value) 
		List<Integer> ls = Arrays.asList(2,1,3); 
		//로도 객체 생성 가능하나 순서대로 형성됨
		for(int a : ls) {
			System.out.println("ls: "+ a);
		}

		System.out.println("\n"+"1번: " + set);
		System.out.println(set);
		Iterator<Integer> iter = set.iterator();
		while(iter.hasNext()) {
			System.out.print(iter.next());
		}
		System.out.println();
		
		Set<Integer> linkedSet1 = new LinkedHashSet<Integer>(Arrays.asList(3,1,2));
//		Set<Integer> linkedSet1 = new LinkedHashSet<Integer>(Arrays.asList(2,1,3));
		System.out.println("2번: " + linkedSet1); //전체출력 [1,2,3]
		
		Iterator iter1 = linkedSet1.iterator(); //Iterator 사용
		while(iter1.hasNext()) {
			System.out.print(iter1.next());
		}
		System.out.println();
	}
}​
0번: [1, 2, 3]
set.size(): 3

ls: 2
ls: 1
ls: 3

1번: [1, 2, 3]
[1, 2, 3]
123
2번: [3, 1, 2]
312​
CollEx10.java
package collectionex;

import java.util.*;
import java.util.Iterator;

public class CollEx10 {

	public static void main(String[] args) {
		Set<Student> stSet = new HashSet<Student>();
		Student st = new Student("홍길동", 1, 1); //&100
		stSet.add(new Student ("홍길동", 1, 1));//&200
		stSet.add(new Student ("전우치", 2, 1));//&300
		stSet.add(st);//&100
		stSet.add(st);//&100
		//중복값을 허용하지 않기에 //&100이 덮어쓰기 됨
		Iterator<Student> it = stSet.iterator();
		
		System.out.println("stSet.size(): "+ stSet.size());
		while (it.hasNext()) {
			Student s = it.next();
			System.out.println(s.name + "님은 " + s.ban + "반, " + s.no + "번 입니다.");
			}
		System.out.println();
		
		stSet.remove(st);
		//객체생성 후 해당 객체(주소값)을 통해서 삭제
		it = stSet.iterator();
		while (it.hasNext()) {
			Student s = it.next();
			System.out.println(s.name + "님은 " + s.ban + "반, " + s.no + "번 입니다.");
			}
		}
}​
stSet.size(): 3
홍길동님은 1반, 1번 입니다.
전우치님은 2반, 1번 입니다.
홍길동님은 1반, 1번 입니다.

홍길동님은 1반, 1번 입니다.
전우치님은 2반, 1번 입니다.​

익명 클래스 (Anonymous)

- Inner class로 이름이 없는 클래스
- 클래스 정의와 동시에 객체를 생성 할 수 있다.
   
- Interface, AbstractClass 모두 익명 클래스로 객체를 만들 수 있다.
: 부모 클래스의 이름이나 구현하고자 하는 인터페이스의 이름을 사용해서 정의하기 때문에 하나의 클래스로 상속받는 동시에 인터페이스를 구현하거나 둘 이상의 인터페이스를 구현할 수 없다. 오로지 단 하나의 클래스를 상속받거나 단 하나의 인터페이스만을 구현할 수 있다.

- 이름이 없기 때문에 생성자를 가질 수 없다.
- 인터페이스와 추상 클래스 내부의 모든 추상 메소드를 반드시 오버라이딩 해야함

- 마지막}(종료중괄호) 뒤에 종료 ;(세미콜론)을 꼭 넣어준다.
- 외부에서 익명클래스의 멤버필드에는 접근 불가.

- 익명클래스 내부에 기술가능한 static의 경우
1. static final 로 선언한 상수(일반 변수 static)은 불가
2. 외부 변수는 Effectively final나 final만 가능.
Effectively final : 외부에 일반 변수라도 값 변경이 전혀 안 된 변수
new 부모클래스명(){
           //익명클래스 기술
}

new 구현인터페이스명(){
           //익명클래스 기술
}
 
- 익명클래스를 사용하는 이유:
프로그램 내에서 한 번만 객체로 만드는데 사용되는 클래스를 굳이 정의할 필요가 없기 때문
AWT, SWING, GUI 이벤트 처리에 쓰임
외부에서 익명클래스의 멤버필드에 접근이 안되므로, 클래스 안에서 모두 처리되어야 하는 경우만 익명클래스를 사용한다.
   
     
AnnoyEx01Test.java
Anonymous
package innerex;

abstract class AnnoyEx01Abstract {
	public String s; //자동초기화값 null
	public abstract void doSomething(); 
	//abstract method 상속받은 자식을 통해 재정의 해야 함
}

class ASub extends AnnoyEx01Abstract {
	@Override
	public void doSomething() {
		System.out.println("ASub클래스 doSomething()메소드 호출");
	}
}

public class AnnoyEx01Test {

	public static void main(String[] args) {
		int aa = 5; //지역변수 재선언불가. 클래스 멤버필드에서 선언된 멤버변수를 최초 한 번은 재선언 가능함
		final int AA = 7;
		//      A                       P                  C
		AnnoyEx01Abstract myClass = new ASub() {
			private int a =15;            //P-C 멤버필드 가려짐
			String s = "AnnonymousClass";  //P-C 멤버필드 가려짐
			final int AA = 0;             //P-C 멤버필드 가려짐
//			static final int AA = 0;
//			static int st = 0;
			
			@Override
			public void doSomething() {   //P-C 자식메소드 사용
//				aa = a + aa; //a지역 + aa멤버 
				//aa 익명클래스 외부에서 호출되는 멤버변수는 Effectively final로 단 한번도 값이 변경이 되지않아야 한다.
				super.doSomething();
				System.out.println("내부 익명 클래스의 doSomething메소드");
				System.out.println("s : "+ s); 
				System.out.println("a : "+ a);
				System.out.println("aa : "+ aa); //외부변수도 호출가능
				System.out.println("AA : "+ AA);
				etcMethod();
			}
			public void etcMethod() {
				System.out.println("기본 메소드입니다.");
			}
		};
		myClass.doSomething();
//		myClass.etcMethod();
//		aa = aa + 15;
		System.out.println("aa: "+ aa);
		System.out.println(myClass.s); //abstract class에 있는 s가 출력됨
//			
		}
}​
ASub클래스 doSomething()메소드 호출
내부 익명 클래스의 doSomething메소드
s : AnnonymousClass
a : 15
aa : 5
AA : 0
기본 메소드입니다.
aa: 5
null​
AnnoyEx02Test.java
Anonymous
package innerex;

abstract class AnnoyEx02Abstract {
	public abstract void doSomething(); 
}
public class AnnoyEx02Test {
	public static void md(AnnoyEx02Abstract n) {
		n.doSomething();
	}
	public static void main(String[] args) {
		AnnoyEx02Test a = new AnnoyEx02Test();
		int aa = 5; //지역변수
		final int AA = 7; //지역상수
		
		a.md(new AnnoyEx02Abstract() { 
		//static키워드가 붙은 호출명은 클래스명을 제대로 명시하는게 좋음(노란줄)
			//추상클래스는 객체생성이 불가하나 익명/자식클래스에서 생성 후 오버라이드 가능
			private int a = 15;
			String s = "AnnoymousClass";
			static final int AA = 0;
			//static int st = 0;
			@Override
			public void doSomething() {
//				aa = a + aa;
				System.out.println("내부 익명 클래스의 doSomething메소드");
				System.out.println("s : "+ s); 
				System.out.println("a : "+ a);
				System.out.println("aa : "+ aa); //외부변수 출력
				System.out.println("AA : "+ AA);
			}
		});
	}
}​
내부 익명 클래스의 doSomething메소드
s : AnnoymousClass
a : 15
aa : 5
AA : 0​
AnonyEx03Test.java
Anonymous
package innerex;

class AnonyEx03 {
	void amd() {System.out.println("AnonyEx03클래스의 amd()메소드 호출");}
	void cmd() {System.out.println("AnonyEx03클래스의 cmd()메소드 호출");}
}
public class AnonyEx03Test {
	public static void main(String[] args) {
		AnonyEx03 ac3 = new AnonyEx03() { // P-C 
			int c = 5;
			void amd() {System.out.println("익명클래스의 cmd() 메소드");	}
			void cmd() {
				System.out.println("익명클래스의 cmd() 메소드");
			}
		};
		ac3.amd();
		ac3.cmd();
	}
}​
익명클래스의 cmd() 메소드
익명클래스의 cmd() 메소드​
AnonyEx03Test.java
Anonymous
package innerex;

interface AnonyEx04Abstract {
	String s = "상수";   //public static final 숨겨져있음
	void doSomething(); //public abstract
	void etcMethod();   //public abstract
}

public class AnonyEx04Test {
	public static void main(String[] args) {
		int aa = 5;
		final int AA = 7;
		
		AnonyEx04Abstract myClass = new AnonyEx04Abstract() {
		//interface는 객체생성이 불가하지만 자식/익명클래스를 통해 생성 및 재정의
			private int a = 15;
			String s = "AnnonymousClass";  
//			s = "하하하"; //익명클래스내 멤버필드에서는 재선언 불가. 메소드 내에서는 가능
//			final int AA = 0;             
			static final int AA = 0;
//			static int st = 0;
//			static String s = "AnnonymousClass"; 
			//static은 상수앞에만 명시가능  
			
			@Override
			public void doSomething() {   //P-C 자식메소드 사용
//				aa = a + aa; //a지역 + aa멤버 
				System.out.println("내부 익명 클래스의 doSomething메소드");
				System.out.println("s : "+ s); 
				System.out.println("a : "+ a);
				System.out.println("aa : "+ aa); //외부변수도 호출가능
				System.out.println("AA : "+ AA);
				etcMethod();
			}
			@Override
			public void etcMethod() {
				System.out.println("기본 메소드입니다.");				
			}
		};
		myClass.doSomething();
		myClass.etcMethod();
//		aa = aa + 15;
		System.out.println("aa: "+ aa);
		System.out.println(myClass.s); //P-C abstract class에 있는 s가 출력됨
	}
}​
내부 익명 클래스의 doSomething메소드
s : AnnonymousClass
a : 15
aa : 5
AA : 0
기본 메소드입니다.
기본 메소드입니다.
aa: 5
상수​

이너클래스(Inner Class)

외부에서 접근할 수 있다.
- instatnce : 내부클래스 - static 내부 클래스
클래스 안이나 메소드 안에 선언된 또 다른 클래스를 말함
- 클래스 선언 시 static 제어자를 사용할 수 있다.
- 클래스 선언 시 접근제어자를 모두 사용할 수 있다. e 내부 클래스
 : 클래스의 멤버 위치에 선언된 일반 클래스
: 클래스의 멤버 위치에 선언된 static 클래스
외부에서 접근할 수 없다.
- local 내부 클래스  : Method 안에 선언된 static 클래스
InnerEX01.java
InstanceInner
StaticInner
package innerex;

//Outer
class Outer {
	int data = 0;
	static int data1 = 50;
	
	void myMethod() {
		System.out.println("Outer 클래스의 메소드 data : "+ data);
	}
//InstanceInner
	class InstanceInner{
//	private class InstanceInner으로 선언시 Outer Class이내에서만 선언하며 사용가능
		int iv = 100;
		
		void myMethod() {
			System.out.println("InstanceInner 클래스의 메소드 data : "+ data + ", iv: " + iv);
		} 
	}
//StaticInner
	static class StaticInner {
	//static 상속안됨
		int iv = 200; //instance변수
		static int cv = 300; //static변수만 메모리 공유 
		//Outer.StaticInner.cv 외부에서 접근가능. 그 외 클래스는 객체생성통한 접근가능
		
		void myMethod() {
			System.out.println("StaticInner 클래스의 메소드 data1 : "+ data1);
//			System.out.println("StaticInner 클래스의 메소드 data : "+ data); //에러
//			//클래스 외부 데이터인 경우는 static만 올 수 있다.
			System.out.println("StaticInner 클래스의  iv : "+ iv + ", cv: " + cv);
		} 
	}
}

public class InnerEX01 {

	public static void main(String[] args) {
		Outer outer = new Outer();
		//내부클래스 객체 생성
		Outer.InstanceInner instanceInner = outer.new InstanceInner();
		System.out.println("instanceInner.iv : " + instanceInner.iv);
		
		System.out.println();
		System.out.println("Outer.StaticInner.cv : " + Outer.StaticInner.cv);
		Outer.StaticInner.cv  = 50; //공유
		System.out.println("Outer.StaticInner.cv : " + Outer.StaticInner.cv);
		
		Outer.StaticInner staticInner = new Outer.StaticInner();
		System.out.println("staticInner.iv : " + staticInner.iv);
		System.out.println("staticInner.cv : " + staticInner.cv);
		System.out.println();
		
		outer.myMethod();
		instanceInner.myMethod();
		staticInner.myMethod();
		
		Outer.StaticInner staticInner1 = new Outer.StaticInner();
		staticInner.iv = 50;
		staticInner1.cv = 999;
		System.out.println("staticInner.iv : " + staticInner.iv);//50
		System.out.println("staticInner1.iv : " + staticInner1.iv);//200
		System.out.println("staticInner.cv : " + staticInner.cv);//999
		System.out.println("staticInner1.cv : " + staticInner1.cv);//999
		
	}
}​
instanceInner.iv : 100

Outer.StaticInner.cv : 300
Outer.StaticInner.cv : 50
staticInner.iv : 200
staticInner.cv : 50

Outer 클래스의 메소드 data : 0
InstanceInner 클래스의 메소드 data : 0, iv: 100
StaticInner 클래스의 메소드 data1 : 50
StaticInner 클래스의  iv : 200, cv: 50
staticInner.iv : 50
staticInner1.iv : 200
staticInner.cv : 999
staticInner1.cv : 999​
 
InnerEX02.java
package innerex;

public class InnerEX02 {
	
		private int data = 30;
		void display() {
			class Local { //지역 이너클래스
				void msg() {
					System.out.println(data);
					display2();
				}
			}
			Local l = new Local();
			l.msg();
		}
		class InstanceInner{
			int iv = 100;
			
			void myMethod() {
				display();
//				msg();
				System.out.println("InstanceInner 클래스의 메소드 data : " + data + ", iv: " + iv);
			}
		}
		void display2() {
			System.out.println("display2() 메소드 호출");
		}
		
		public static void main(String[] args) {
			InnerEX02 obj = new InnerEX02(); //static이 없어서 객체 새로 생성함.
			obj.display();
			InnerEX02.InstanceInner obj1 = obj.new InstanceInner();
			obj1.myMethod();
		}
}​
30
display2() 메소드 호출
30
display2() 메소드 호출
InstanceInner 클래스의 메소드 data : 30, iv: 100​

람다식 함수 (Ramda)

- 이름 없는 함수
- 함수의 구현과 호출만으로 프로그램을 만들 수 있는 방식이다.
- Interface만 이용 가능
- 외부에 정의된 변수를 참조할 때, final 또는 Effectively final변수만 가능하다.
- 함수 내부에서 지역변수 선언시 static(x)불가, final, 일반 변수만 가능
- 인터페이스 메소드를 참조하여 만들 경우 해당 인터페이스 내부에는 메소드가 한개만 선언되어 있어야 한다.
여러개 인 경우 에러 발생됨
- 람다식 메소드는 호출되면 익명클래스가 자동으로 생성된다.(눈에는 보이지 않음)
- 마지막 }(종료중괄호) 뒤에 종료 ;(세미콜론)을 꼭 넣어준다.
- java 8버전부터 지원됨
문법
(매개변수목록) -> {함수몸체} ;
한 줄 명령인 경우 중괄호 생략이 가능하다.

리턴타입 메소드명(매개변수...) {
        실행코드들...;
}
RamdaEx01.java
package collectionex;

interface Ramda01 {
	int getMax(int num1, int num2);
//	int add(int num1, int num2);
//인터페이스 메소드를 참조하여 만들 경우 해당 인터페이스 내부에는 메소드가 한개만 선언되어 있어야 한다.
}
//class RamdaCh implements Ramda01 {
//
//	@Override
//	public int getMax(int num1, int num2) {
//		return (num1>=num2) ? num1:num2;
//	}
//}

public class RamdaEx01 {
	public static void main(String[] args) {
//		Ramda01 max = new RamdaCh();
//		int r = max.getMax(10, 20);
//		
		//람다식을 인터페이스형 max변수에 대입
		Ramda01 max = (x,y) -> (x>=y) ? x:y; //->재정의 기호 //한 줄일 경우 return {}생략가능
		//인터페이스 메소드를 참조하여 만들 경우 해당 인터페이스 내부에는 메소드가 한개만 선언되어 있어야 한다.
//		메인메소드에 기재되어야 할 본 호출문		
//		Ramda01 max = new Ramda01(); {
//			@Override
//			public int getMax(int num1, int num2) {
//				return (num1>=num2) ? num1:num2;
//			}
//		};
		
		int r = max.getMax(10, 20);
		//인터페이스형 변수로 메소드 호출
		System.out.println(r);
	}

}
20
RamdaEx02.java
package innerex;

interface Ramda2{
	public static final int a = 5;
	public abstract void makeString(String s1, String s2);
}

public class RamdaEx02 {

	public static void main(String[] args) {
		String s1 = "Hello";
		String s2 = "Java";
		int b = 1;
		Ramda2 concat = (s,v) -> System.out.println(s + ", " + v + Ramda2.a);
													//Ramda2.a static이 있어 접근 가능
		System.out.println(concat.hashCode());
//		Ramda2 concat = new Ramda2() {
//			@Override
//			public void makeString(String s1, String s2) {
//				System.out.println(s1 + ", " + s2 + a); //자동 상속처리
//			}
//		};
		concat.makeString(s1,s2);
		System.out.println(concat.a);
		
		concat = (s, v) -> System.out.println("출력할 값은: "+ s + v);
		concat.makeString(s1,s2);
	}
}​
792791759
Hello, Java5
5
출력할 값은: HelloJava​
RamdaEx03.java
package innerex;

interface Ramda3{
	public abstract void add(int a, int b);
}
//abstract class Ramda3{
//	public abstract void add(int a, int b);
//}

public class RamdaEx03 {
	public static void main(String[] args) {
		int i = 100;
//		static final int j = 5; //지역안에서는 final만 가능
		final int j = 5;
		
		//수행문이 여러 줄인 경우 {} 중괄호 블록을 사용한다.
		Ramda3 result = (p1,p2) -> {
//			i = i + p1 + p2; //익명클래스와 마찬가지로 Effectively final만 가능하다.
			int sum = p1+p2;
			final int mul = p1*p2;
//			static final int mul = p1*p2; //지역안에서는 final만 가능
			
			System.out.println("i는 : "+ i + ", j는 : "+ j);
			System.out.println(p1 +", "+ p2);
			System.out.println("p1과 p2의 합: "+ sum);
			System.out.println("p1과 p2의 곱: "+ mul);
		};
		result.add(5,5);
	}

}​
i는 : 100, j는 : 5
5, 5
p1과 p2의 합: 10
p1과 p2의 곱: 25​
RamdaEx04.java
package innerex;

interface Ramda4{
	public void showString(String string);
}

public class RamdaEx04 {
	public static void main(String[] args) {
		Ramda4 lamda4 = s -> System.out.println(s); //
		lamda4.showString("매개변수로 람다식 전달하기");
		showString(lamda4);
	}
	
	public static void showString(Ramda4 r) {
		r.showString("매개변수로 람다식 이용하여 출력");
	}
}
매개변수로 람다식 전달하기
매개변수로 람다식 이용하여 출력
RamdaEx05.java
package innerex;

interface Ramda5{
	void showString(String str);
}

public class RamdaEx05 {
	public static void main(String[] args) {
		Ramda5 lamda5 = returnString(); //멤버변수로 반환받기
//		Ramda5 lamda5 = s -> System.out.println(s + " Java");
		lamda5.showString("hello");
	}
	public static Ramda5 returnString() {
		return s -> System.out.println(s + " Java");
	}
}

매개변수로 람다식 전달하기
매개변수로 람다식 이용하여 출력​

 

calculator1
계산기
package innerex;

interface Ramdat {
	void cal(int a, int b);
}

public class Ramda_test {
	public static void main(String[] args) {
		Ramdat result = (x, y) -> {
			int add = x + y; 
			int miu = x - y;
			int mul = x * y;
			int div = x / y;
			int div1 = x % y;
			
			System.out.println("x + y = "+ add);
			System.out.println("x - y = "+ miu);
			System.out.println("x * y = "+ mul);
			System.out.println("x / y = "+ div);
			System.out.println("x % y = "+ div1);
	};
	result.cal(1,2);
}
}​
x + y = 3.0
x - y = -1
x * y = 2
x / y = 0
x % y = 1​

calculator2
계산기

package innerex;

interface Ramdat2 {
	void cal(int x, int y);
}

public class Ramda_cal2 {
	public static void main(String[] args) {
		Ramdat2 c = (x, y) -> 
		System.out.println(x + " + " + y + " = "+ (x + y));
		c.cal(1, 2); 
		c = (x, y) -> System.out.println(x + " - " + y + " = "+ (x - y));
		c.cal(1, 2); 
		c = (x, y) -> System.out.println(x + " * " + y + " = "+ (x * y));
		c.cal(1, 2); 
		c = (x, y) -> System.out.println(x + " / " + y + " = "+ (x / y));
		c.cal(1, 2); 
		c = (x, y) -> System.out.println(x + " % " + y + " = "+ (x % y));
		c.cal(1, 2); 
			
			
	};
}
1 + 2 = 3
1 - 2 = -1
1 * 2 = 2
1 / 2 = 0
1 % 2 = 1
728x90
반응형

+ Recent posts