KOSTA 10일차) 컬렉션 ArrayList / lang 패키지 / 쓰레드 / 인터페이스 / 추상클래스

해버니·2023년 2월 27일
0

KOSTA

목록 보기
9/32
post-thumbnail

🌹 복습

상속
왜 사용해? → 재사용


업캐스팅
메모리는 자식인데 부모의 것을 가져다 쓰는 것
타입은 부모이지만 오버라이딩된 새 버전의 메서드 사용 가능.
부모클래스에 정의된 멤버 변수, 메서드만 사용 가능



다운캐스팅


→ 업캐스팅과 다운캐스팅 두 개를 복합적으로 사용하면서 다형성을 구현












🌹 추상클래스

포켓몬 클래스 (PocketMon.java)

package pocketmon;

public class PocketMon {
	protected String name;
	protected int hp;
	protected int exp;
	protected int lv;

	public void eat() {
		System.out.println(name + " 육회를 먹는다.");
	}

	public void sleep() {
		System.out.println(name + " 전기장판에서 잠을 잔다.");
	}

	public boolean play() {
		System.out.println(name + " 노래방을 갔다!.");
		return true;
	}

	public boolean exc() {
		System.out.println(name + " 운동한다.");
		return true;
	}

	public void levelUp() {
		System.out.println("lv : " + lv + " / 어디까지 성장했나 확인 ~.~");
	}

	public void check() {
		System.out.println("name : " + name + " / hp : " + hp + " / exp : " + exp + " / lv : " + lv);
	}
}

위 소스는 **하위 상속**을 해주기 위해 **공통 변수**를 만들어 준 것이다. 여기서는 메세지만 출력을 하는데 있어도 되고 없어도 되는 별 일 안 하는 소스이고, 피카츄, 이상해씨, 꼬부기에게 상속을 하기 위해 존재하는 것이다. 물론 메세지를 출력해줘도 되지만 필수불가결하지는 않다.



❓ 왜 추상메서드를 만들어요 ❓
① 하위 클래스에 상속을 하기 위해서
하위 클래스에 추상 메서드를 제공하여 각 하위 클래스마다 적합하게 재정의해 사용할 수 있도록 함

② 하위 클래스에 아웃라인을 제공
추상메서드가 갖고있는 메서드를 하위클래스가 다 구현을 해야 정상적으로 돌아간다.









package pocketmon;

public abstract class PocketMon2 {
	protected String name;
	protected int hp;
	protected int exp;
	protected int lv;

	// 메서드 선언 : 추상 메서드 : 구현안하고 선언만 
	abstract public void eat();

	abstract public void sleep();

	abstract public boolean play();

	abstract public boolean exc();

	abstract public void levelUp();

	public void check() {
		System.out.println("name : " + name + " / hp : " + hp + " / exp : " + exp + " / lv : " + lv);
	}
}

추상클래스는 이러한 추상메서드(abstract)를 **1개라도** 포함한 클래스를 말한다. 추상메서드는 구현하지 않고 선언만 한 메서드로 abstract 키워드를 붙여줘야 한다. 각각 추상메서드도 abstract를 붙여줘야하고 선언문만 가지고 있다.

위 소스에선 객체를 생성하지 않을거니까 구현하지 않아도 된다.

그리고 추상클래스는 객체를 생성할 수 없다.
→ 완성이 안 됐기 때문에 객체 생성 불가









package oop2;

abstract class Parent {
	public abstract void f1();

	public void f2() {
		System.out.println("parent f2()");
	}
}

class Child extends Parent {

	@Override
	public void f1() {
		// TODO Auto-generated method stub
		System.out.println("Child에서 추상 메서드 구현");
	}
	
	public void f3() {
		System.out.println("Child에서 f3()");
	}

}

public class ParentMain {
	public static void main(String[] args) {
		// Parent p=new Parent(); → 추상 클래스는 객체 생성 불가
		Child c = new Child();
		c.f1();
		c.f2();
		c.f3();

		Parent pc = new Child(); // 주로 업캐스팅해서 사용한다.
		pc.f1(); // 재정의된 메서드가 실행된다. 
		pc.f2();
		
		((Child)pc).f3(); // 다시 자식을 쓰고 싶다면 다운 캐스팅
	}
}

abstract class Parent {} 는 추상클래스이다.

public abstract void f1(); 은 추상메서드이고 구현하지 않은 메서드이다.
왜 만들었어? 상속하기 위해 (목적)

public void f2(){}도 있는데 구현 메서드를 포함할 수 있다.

class Child extends Parent{} Child가 객체를 만들려면 상속받은 추상메서드를 "모두" 구현해야 한다.














🌹 인터페이스

추상클래스한 개만이라도 추상이면 되는데 인터페이스모든 메소드가 다 추상이어야 한다.

인터페이스는 완전추상클래스이다.
상수추상메서드로만 구성
→ 객체 못 만듦. 상속 목적
→ 잭 역할. 동일한 인터페이스를 상속받아서 다양한 형태로 구현한 객체들을 교체해서 사용하도록 연결해주는 이음매 역할을 한다.




인터페이스가 아주 아주 중요하다.
회사에서 유지보수가 좋기 때문에 인터페이스 기반으로 개발을 많이 한다.
레고로 변신 로봇을 만드는 본드같은 역할을 하고 부품 교체하는 그 경계면을 만들어주는 것이 인터페이스이다.



interface 이름 {

}

상속 키워드 : implements
다중상속가능







다중 상속이 언제, 왜 필요한가?
→ 쓰레드를 구현할 때?

쓰레드는 멀티태스킹을 구현하는 그런 것 ↔ 유니태스킹의 반대

유니태스킹 : 옛날엔 작업을 한 번에 한 번씩 밖에 못했고, ui도 없었고 프로그램을 실행하려면 명령문을 쳐야되고, 그 명령문이 완료될 때까지 다른 명령문을 못 띄어놓는다.

하지만 지금은 음악도 듣고 영상도 보고 게임도 하고 여러개가 동시에 실행이 된다. 그것이 멀티태스킹이다.

쓰레드를 자바에서 만들어주는 클래스가 Thread이다.
















🌹 쓰레드를 구현하는 두 가지 방법

① Runnable

implements Runnable을 통해서 Runnable 인터페이스를 구현할 수 있다.
재사용성이 높고, 코드의 일관성을 유지할 수 있어서 Thread보다 더 효율적인 방법이다.
클래스가 아닌 인터페이스이다.



package oop2;

import java.awt.Frame;

class Test extends Frame implements Runnable {

	@Override
	public void run() {
		// 쓰레드를 실행코드를 작성하는 메서드
		// TODO Auto-generated method stub
		System.out.println("run");
		for (int i = 1; i <= 10; i++) {
			// setTitle은 Frame것이다. 
			this.setTitle(i + "번째 타이틀");
			try {
				Thread.sleep(1000);
			} catch (InterruptedException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}
	}
	// Frame 윈도우 그려주는거
	// 다중상속이 기본으로 안되기 때문에 하나는 interface로 상속을 받는ㄴ것
	// 다중상속을 할수 있게 class로도 제공해주고 interface로도 제공해주고..

}

public class InterTest3Main {

	public static void main(String[] args) {
		// TODO Auto-generated method stub
		Test t = new Test();
		t.setSize(300, 200); // 윈도우 가로, 세로 길이 설정
		t.setVisible(true); // 윈도우를 보이기 설정
		Thread th = new Thread(t); // 쓰레드 생성
		th.start(); // 쓰레드 실행
	}

}




② Thread

상속을 받아 사용해야 하기 때문에 다른 클래스를 상속받아 사용할 수 없다는 단점이 있다.
따라서 일반적으로는 Runnable 인터페이스를 구현해서 스레드를 사용한다.

extends Thread 라고 쓴다.














lang 패키지

자주 사용이되는 클래스들을 제공해주는 패키지이다.

1) Object

자바의 모든 클래스가 상속받는 대모 클래스
멤버변수 없이 메서드로만 구성된 클래스
Object 클래스가 갖는 메서드는 모든 클래스가 갖는다.

package langtest;

class MyClone implements Cloneable {
	int a;
	int b;

	public MyClone() {
	}

	public MyClone(int a, int b) {
		this.a = a;
		this.b = b;
	}

	@Override
	protected Object clone() throws CloneNotSupportedException {
		// TODO Auto-generated method stub
		return super.clone();
		// 이 안은 바꿀 필요없고 그냥 사용하면 된다.
	}

	@Override
	public String toString() {
		return "MyClone [a=" + a + ", b=" + b + "]";
	}
}

public class CloneTest {
	public static void main(String[] args) {
		MyClone m1 = new MyClone(1, 2);
		MyClone m2 = new MyClone();
		m2.a = m1.a;
		m2.b = m1.b;

		System.out.println(m1 + " / 참조값 : " + m1.hashCode());
		System.out.println(m2 + " / 참조값 : " + m2.hashCode() + "\n");

		// clone()으로 객체 복사
		try {
			MyClone m3 = (MyClone) m1.clone();
			System.out.println(m1 + " / 참조값 : " + m1.hashCode());
			System.out.println(m3 + " / 참조값 : " + m3.hashCode());
		} catch (CloneNotSupportedException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}

	}
}





package langtest;

class Member {
	String id;
	String pwd;

	public Member() {
	}

	public Member(String id, String pwd) {
		this.id = id;
		this.pwd = pwd;
	}

	@Override
	public String toString() {
		return "Member [id=" + id + ", pwd=" + pwd + "]";
	}

	@Override
	public boolean equals(Object obj) {
		// 왜 object를 쓸까? 어떤 한 타입을 지정할 수는 없다.
		// 다 담을 수 있게 타입을 업캐스팅을 해서 받아올 수 있게.
		// object파라미터로 받아온 멤버가 맞느냐 그럼 다운 캐스팅
		// 현재 객체와 pwd id 가 같으면 true 같지 않으면 false를 반환하도록
		// TODO Auto-generated method stub
		if (obj instanceof Member) {
			Member m = (Member) obj;
			if (this.id.equals(m.id) && this.pwd.equals(m.pwd)) {
				return true;
			} else {
				return false;
			}
		}
		return super.equals(obj);
	}

}

public class Equals {

	public static void main(String[] args) {
		// TODO Auto-generated method stub
		Member m1 = new Member("abc", "abc111");
		Member m2 = new Member("abc", "abc111");
		Member m3 = new Member("abc", "abc123");
		Member m4 = m1;

		System.out.println("m1==m2: " + (m1 == m2));
		System.out.println("m1.equals(m2)" + m1.equals(m2));
		System.out.println("m1==m3: " + (m1 == m3));
		System.out.println("m1.equals(m3)" +m1.equals(m3));
		System.out.println("m1==m4: " + (m1 == m4));
		System.out.println("m1.equals(m4)" +m1.equals(m4));
	}

}

① clone : 메모리 복사. 객체를 복사. 많이 쓰지는 않는다.

② equals : 객체가 같은지 다른지 비교.
같으면 true, 다르면 false
문자뿐만 아니라 객체를 비교할 수 있는 것이다.

==으로 객체를 비교하면 참조값 비교
equals로 객체를 비교하면 객체의 값을 (멤버변수값) 비교
Object 클래스의 equals는 ==으로 객체 비교


③ hashcode : 참조값 반환


④ getClass : Class를 반환하는 메서드.
Class 클래스 정보 객체
Class에 대한 정보를 알 수 있는 클래스이다.


⑤ toString : 객체에 대한 설명 문자열을 반환하는 메소드.
클래스명@참조값


6, 7, 8은 쓰레드와 관련된 것.
⑥ wait
⑦ notify : 하나만 깨우기
⑧ notifyAll : 전체를 깨우기


Object에서는 equals, hashcode, toString을 자주 쓴다.








2) String

문자열 처리 클래스
C에선 String클래스가 없었다.
char형 배열을 이용해 문자열을 처리했기 때문에 굉장히 불편했다.
사람의 이름도 텍스트이고 대부분의 이름도 텍스트이기때문에
C++,이나 자바로 넘어오면서 String을 기본으로 제공해주기 때문에
문자열을 처리하는 번거로움을 우리가 느끼지 않고 쉽게 다룰 수 있다.


package langtest;

public class StringTest {

	public static void main(String[] args) {
		// TODO Auto-generated method stub
		
		// String 생성의 다양한 종류
		String s1 = "abcdefu";
		String s2 = new String(s1);
		String s3 = new String("345");
		char[] ch = { 'h', 'e', 'l', 'l', 'o' };
		String s4 = new String(ch);
		byte[] b = { 'h', 'e', 'l', 'l', 'o' };
		//byte 아스키코드가 저장이 됨.
		String s5 = new String(b);

		System.out.println("s1 : " + s1);
		System.out.println("s2 : " + s2);
		System.out.println("s3 : " + s3);
		System.out.println("s4 : " + s4);
		System.out.println("s5 : " + s5);
	}

}




package langtest;

public class StringMethod {

	public static void main(String[] args) {
		// TODO Auto-generated method stub

		String a = "abcdefua";
		String b = "def,mango,banana,apple";
		System.out.println("a : " + a);
		System.out.println("b : " + b);
		System.out.println("a.charAt(1) : " + a.charAt(1));
		System.out.println("a.concat(b) : " + a.concat(b)); // 결합
		System.out.println("a.indexOf(\"c\") : " + a.indexOf("c"));
		System.out.println("a.lastIndexOf(\"a\") : " + a.lastIndexOf("a"));
		System.out.println("a.length() : " + a.length());
		System.out.println("a.replace(\"abc\", \"efu\") : " + a.replace("abc", "efu"));
		System.out.println("a.toUpperCase() : " + a.toUpperCase());
		System.out.println("a.substring(2, 6) : " + a.substring(2, 6));

		String[] arr = b.split(",");
		for (int i = 0; i < arr.length; i++) {
			System.out.println(arr[i]);
		}
	}

}

equals : 문자열 비교


charAt() : 문자열 하나가 어느 위치에 있는지


concat() : 두 개의 문자 결합


indexOf() : 하나의 문자열이 몇 번째에 위치해있는지


lastIndexOf() : 하나의 문자가 어느 위치에 있는지 (last기준으로)


length() : 문자열의 길이


replace() : 문자열 교체


toUpperCase() : 대문자로 toLowerCase() 소문자로


substring(2, 5) : 문자열 자르기 2부터 5까지


split() : 문자열 자르기







3) StringBuilder

문자열 처리 클래스



2) String와 차이는?

String a = "aaa";
String b = "bbb";
String c = a + b;

a는 문자열 상수, b도 문자열 상수


String에서는
a+b를하면 새로운 메모리를 할당을 해서 "aaa"와 "bbb" 새로 합친 것을 메모리 할당을 한다.
그러면 확장하고 이사를 해야해서 속도가 느려진다.


StringBuilder에서는
String 클래스와 다르게 StringBuilder는 내부에 버퍼를 가지고 있어서 문자열을 결합하거나 조작하는게 빠르다.



package langtest;

import java.util.Scanner;

public class StringBuilderTest {

	public static void main(String[] args) {
		// TODO Auto-generated method stub
		StringBuilder sb = new StringBuilder();
		sb.append("aaa"); // 문자열 끝에 추가
		sb.append("bbb");
		sb.append("ccc");
		System.out.println(sb.toString()); // aaabbbccc
		System.out.println("sb.indexOf(\"ab\") : " + sb.indexOf("ab")); // sb.indexOf("ab") : 2
		System.out.println("sb.indexOf(\"aa\") : " + sb.indexOf("aa")); // sb.indexOf("aa") : 0
		System.out.println("sb.indexOf(\"bc\") : " + sb.indexOf("bc")); // sb.indexOf("bc") : 5
		sb.insert(2, "kkk");
		System.out.println(sb.toString()); // aakkkabbbccc
		sb.delete(3, 5);
		System.out.println(sb); // aakabbbccc
		
		Scanner sc=new Scanner(System.in);
		String txt="";
		StringBuilder sb2=new StringBuilder();
		while(true) {
			System.out.println("멈추려면 stop입력");
			txt=sc.next();
			if(txt.startsWith("stop")) {
				break;
			}
			sb2.append(txt+"\n");

		}
		System.out.println(sb2.toString());
	}

}








4) 랩퍼클래스

기본타입의 값을 클래스 타입으로 감싸주는 클래스이다.

Object[] arr = new Object[5];
arr[0] = "abde";
arr[1] = new Float(1.23f);
arr[2] = new Integer(1); // int 

기본값을 object를 넣고 싶어서 클래스로 감싸는 것이다.
위에서 Integer()로 감싸주는게 랩퍼클래스이다.




오토박싱과 오토언박싱으로 인해서 지금은 간단하게

arr[1] = 1.23f;
arr[2] = 1;

로 선언해줘도 오류가 나지 않는다.
우리는 랩퍼클래스는 사용하진 않지만 오토박싱 오토언박싱이 일어나고 있다는 사실을 알고 있으면 된다.











컬렉션

① List

값만 저장, 순서 있음
Vector, ArrayList, LinkedList 등등
이중에 ArrayList가 가장 중요하다!


package langtest;

import java.util.ArrayList;

public class ArrayList1 {

	public static void main(String[] args) {
		// TODO Auto-generated method stub
		
		// arraylist 생성. 타입, 크기 제약이 없다.
		// 크기를 지정해줘도 되지만 그 크기보다 더 넣을 수 있음
		ArrayList list = new ArrayList();
		list.add("abc");
		list.add(1);
		list.add(3.45f);
		list.add(23.45);
		
		System.out.println("데이터 개수 : "+list.size());
		for(int i=0;i<list.size();i++) {
			System.out.println(list.get(i));
		}
	}

}





package langtest;

import java.util.ArrayList;

public class ArrayList2 {

	public static void main(String[] args) {
		ArrayList<String> list = new ArrayList<>();
		// <타입> : 제너릭. 타입한정자
		list.add("aaa"); // 마지막 데이터로 추가
		list.add(0, "bbb"); // 지정한 인덱스에 데이터 끼워넣기
		list.add("ccc");
		list.add("ddd");
		list.set(2, "abcd"); // 인덱스 위치의 값을 지우고 추가.

		System.out.println("*** 전체 데이터 ***");
		for (int i = 0; i < list.size(); i++) {
			System.out.print(list.get(i) + " ");
		}
		System.out.println();

		System.out.println("\n*** ddd 찾고 삭제 ***");
		if (list.contains("ddd")) { // contains : 있나 없나 true false
			int idx = list.indexOf("ddd"); // indexOf : 값의 위치를 찾아준다. 없으면 -1 반환
			System.out.println("ddd는 " + idx + "번방에 있음");
			list.remove(idx); // remove(방번호) : 방번호 데이터 한 개 삭제
		}
		// contains equals 재정의 안 하면 제대로 동작을 못한다.
		

		System.out.println("\n*** aaa삭제 ***");
		list.remove("aaa"); // remove(삭제할 데이터): 데이터 찾아서 삭제
		// 삭제할 것이 있으면 삭제하고 true 반환, 삭제할 것이 없으면 false 반환
	
		System.out.println("\n*** 전체 데이터 ***");
		for (int i = 0; i < list.size(); i++) {
			System.out.print(list.get(i) + " ");
		}
		System.out.println();

		System.out.println("\n*** 데이터 비었는지 확인 ***");
		if (list.isEmpty()) {
			System.out.println("비었음");
		} else {
			System.out.println("안 비었음");
		}

		System.out.println("\n*** 데이터 비우기 ***");
		list.clear();
		System.out.println("\n*** 데이터 비었는지 확인 ***");
		if (list.isEmpty()) {
			System.out.println("비었음");
		} else {
			System.out.println("안 비었음");
		}
	}

}








② Map

빠른 검색을 지원하기 위해서 키와 값을 쌍으로 저장하는 방식
값의 순서가 없다.




0개의 댓글