객체 형변환 / 오버라이딩
부모 통해서 자식의 메서드를 호출
메모리에 있는 객체가 형변환하기 위한 충분조건을 갖추고 있는지 확인하는 것.
true / false 반환
public class Person {
public void salary() {
System.out.println("Parent Salary() 호출");
}
}
public class Employee1 extends Person {
@Override
public void salary() {
System.out.println("Employee1 salary() 호출");
}
public void viewEmployee() {
System.out.println("Employee1 viewEmployee() 호출");
}
}
public class Employee2 extends Person {
@Override
public void salary() {
System.out.println("Employee2 salary() 호출");
}
public void viewEmployee() {
System.out.println("Employee2 viewEmployee() 호출");
}
}
public class MainEx01 {
public static void main(String[] args) {
Person p1 = new Employee1();
Person p2 = new Employee2();
// 다형성
// Person salary(x) - Employee salary(o)
p1.salary();
p2.salary();
// instanceof : 형변환 가능한지 확인하기
System.out.println(p1 instanceof Person);
System.out.println(p1 instanceof Person);
System.out.println(p1 instanceof Employee1);
System.out.println(p1 instanceof Employee2);
System.out.println(p1 instanceof Object);
}
}
public class MainEx02 {
public static void main(String[] args) {
// Person p1 = new Person();
Person p1 = new Employee1();
// Employee1 e1 = (Employee1) p1;
// e1.viewEmployee();
System.out.println(p1 instanceof Person);
System.out.println(p1 instanceof Employee1);
if( p1 instanceof Employee1 ) {
Employee1 e1 = (Employee1) p1;
e1.viewEmployee();
} else {
System.out.println("형변환 불가");
}
}
}
추상 - 공통성 (abstraction)
불안전한 클래스이기때문에 인스턴스화가 안된다.
abstract 붙여준다.
추상 메서드를 하나라도 가지고 있는 클래스
상속을 전제로 만든 클래스
추상 메서드를 가질 수 있다 / 있어도 되고 없어도 되고
클래스이름 객체변수 = new 생성자() X 안됨
class 자식클래스이름 extends 추상클래스이름 O
abstract class 클래스이름 {
}
상속에 의해서 구현해줘야한다.
class Parent1 {
Parent1() {
System.out.println("Parent1 생성자 호출");
}
}
// 불완전 클래스여서 사용 안됨.
abstract class Parent2 {
Parent2() {
System.out.println("Parent2 생성자 호출");
}
}
// 상속은 가능하다
class Child2 extends Parent2 {
Child2() {
System.out.println("Child2 생성자 호출");
}
}
public class MainEx11 {
public static void main(String[] args) {
Parent1 p1 = new Parent1();
// 불완전 클래스이기때문에 안됨
// Parent2 p2 = new Parent2();
Child2 c2 = new Child2();
}
}
내용이 선언되지 않은 메서드 ( 선언부만 있고 구현부가 없는)
추상클래스는 가질 수 있다 / 있어도 되고 없어도 되고.
일반 클래스는 추상 메서드를 가질 수 없다.
class Parent1 {
Parent1() {
System.out.println("Parent1 생성자 호출");
}
}
// 불완전 클래스여서 사용 안됨.
abstract class Parent2 {
Parent2() {
System.out.println("Parent2 생성자 호출");
}
// 추상메서드 - 내용선언되지 않은 메서드
void viewParent1(){}
abstract void viewParent2();
}
// 상속은 가능하다
class Child2 extends Parent2 {
Child2() {
System.out.println("Child2 생성자 호출");
}
// 상속에 의해 자식이 구현
void viewParent2() {
System.out.println("Child2 생성자 호출");
}
}
public class MainEx11 {
public static void main(String[] args) {
Parent1 p1 = new Parent1();
// 불완전 클래스이기때문에 안됨
// Parent2 p2 = new Parent2();
Child2 c2 = new Child2();
c2.viewParent2();
}
}
자식 Child2가 부모 Parent2를 상속받고
손자 GrandChild2 가 손자의 부모 Child2를 상속
class Parent1 {
Parent1() {
System.out.println("Parent1 생성자 호출");
}
}
// 불완전 클래스여서 바로 사용 안됨.
abstract class Parent2 {
Parent2() {
System.out.println("Parent2 생성자 호출");
}
// 추상메서드 - 내용선언되지 않은 메서드
void viewParent1(){}
abstract void viewParent2();
}
// 상속은 가능하다
abstract class Child2 extends Parent2 {
Child2() {
System.out.println("Child2 생성자 호출");
}
// 상속에 의해 자식이 구현
// void viewParent2() {
// System.out.println("Child2 생성자 호출");
// }
}
// 자식의 자식(손자) 에게 받아서 구현
class GrandChild2 extends Child2 {
void viewParent2() {
System.out.println("Child2 생성자 호출");
}
}
public class MainEx11 {
public static void main(String[] args) {
Parent1 p1 = new Parent1();
// 불완전 클래스이기때문에 안됨
// Parent2 p2 = new Parent2();
Child2 c2 = new Child2();
c2.viewParent2();
}
}
고도의 추상화
일반 메서드를 가질 수 없고 추상 메서드만 존재하는 것.
상속을 전제로 구현
interface 인터페이스명 {
상수
추상메서드
}
다중으로 받을 수 있음.
일반클래스 implements 인터페이스명,인터페이스명 {
}
// 상속도 가능 / 편법적 다중상속
일반클래스 extends 부모클래스 implements 인터페이스명,인터페이스명 {
}
인터페이스라 바로 실행 안됨.
interface InterA {
// 상수
public static final String STR1 = "홍길동";
// abstract method
public abstract void methodA();
}
public class MainEx12 {
public static void main(String[] args) {
InterA a = new InterA();
}
}
interface InterA {
// 상수
public static final String STR1 = "홍길동";
// abstract method
public abstract void methodA();
}
class ClassA implements InterA {
public void methodA() {
System.out.println("methodA 호출");
}
}
public class MainEx12 {
public static void main(String[] args) {
// InterA a = new InterA();
ClassA a = new ClassA();
a.methodA();
}
}
interface InterA {
// 상수
public static final String STR1 = "홍길동";
// abstract method
public abstract void methodA();
}
class ClassA implements InterA {
public void methodA() {
System.out.println("methodA 호출");
}
}
public class MainEx12 {
public static void main(String[] args) {
// InterA a = new InterA();
ClassA a = new ClassA();
a.methodA();
System.out.println(a.STR1);
}
}
interface InterA {
// 상수
public static final String STR1 = "홍길동";
// abstract method
public abstract void methodA();
// 일반 메서드 선언한다면
void methodB() {}
}
class ClassA implements InterA {
public void methodA() {
System.out.println("methodA 호출");
}
}
public class MainEx12 {
public static void main(String[] args) {
// InterA a = new InterA();
ClassA a = new ClassA();
a.methodA();
System.out.println(a.STR1);
}
}
body가 없다고 에러가 난다
interface InterA {
// 상수
public static final String STR1 = "홍길동";
String STR2 = "박문수";
// abstract method
public abstract void methodA();
// void methodB() {}
void methodB();
}
class ClassA implements InterA {
public void methodA() {
System.out.println("methodA 호출");
}
public void methodB() {
System.out.println("methodB 호출");
}
}
public class MainEx12 {
public static void main(String[] args) {
// InterA a = new InterA();
ClassA a = new ClassA();
a.methodA();
System.out.println(a.STR1);
a.methodB();
}
}
package poly2;
public interface InterA {
public static final String STR1 = "홍길동";
// 앞에 생략 , 짧게 선언 가능
String STR2 = "박문수";
public abstract void methodA();
// 앞에 생략, 짧게 선언 가능
void methodB();
}
package poly2;
public class ClassA implements InterA {
@Override
public void methodA() {
System.out.println("methodA 호출");
}
@Override
public void methodB() {
System.out.println("methodB 호출");
}
}
package poly2;
public class MainEx01 {
public static void main(String[] args) {
ClassA a = new ClassA();
a.methodA();
a.methodB();
}
}
package poly3;
public interface InterA {
public abstract void methodA();
}
package poly3;
public interface InterB {
public abstract void methodB();
}
package poly3;
public class Child implements InterA, InterB {
@Override
public void methodB() {
System.out.println("methodB 호출");
}
@Override
public void methodA() {
System.out.println("methodA 호출");
}
}
package poly3;
public class MainEx01 {
public static void main(String[] args) {
Child c = new Child();
c.methodA();
c.methodB();
}
}
package poly4;
public interface InterA {
public abstract void methodA();
}
package poly4;
public interface InterB extends InterA {
public abstract void methodB();
}
package poly4;
public class Parent {
public void methodC() {
System.out.println("methodC 호출");
}
}
package poly4;
public class Child extends Parent implements InterB{
@Override
public void methodA() {
// TODO Auto-generated method stub
System.out.println("Child methodA 호출");
}
@Override
public void methodB() {
// TODO Auto-generated method stub
System.out.println("Child methodB 호출");
}
@Override
public void methodC() {
// TODO Auto-generated method stub
System.out.println("Child methodC 호출");
}
}
package poly4;
public class MainEx01 {
public static void main(String[] args) {
Child c = new Child();
c.methodA();
c.methodB();
c.methodC();
}
}
package poly5;
public interface Vehicle {
void addFuel();
}
package poly5;
public class DieselSUV implements Vehicle {
@Override
public void addFuel() {
System.out.println("주유소에서 급유");
}
}
package poly5;
public class ElectricCar implements Vehicle {
@Override
public void addFuel() {
System.out.println("급속 충전");
}
}
package poly5;
public class MainEx01 {
public static void main(String[] args) {
Vehicle v = new DieselSUV();
v.addFuel();
v = new ElectricCar();
v.addFuel();
}
}
무엇인가를 나열한다는 뜻, 데이터가 몇 까지 한정된 상수값으로 구성될 때 주로 사용.
따로 값을 지정해주지 않아도 자동적으로 0부터 시작하는 정수값이 할당됨( index번호 같이 )
열거형 데이터 타입은 내부적으로 java.lang.Enum클래스를 상속받고 있다.
따라서 별도로 다른 클래스를 상속받을 수 없다.
class 대신 enum 키워드 사용.
enum내부에는 사용할 값들을 상수형태로 나열, 이 값들을 "enum상수"라고 함
enum Grade {
// SALES부터 0번 번호 붙음
SALES, PART_TIME_JOB, NORMAL
}
public class GradeEnumTest {
public static void main(String[] args) {
// Grade타입 변수 grade 선언후 Grade.SALES상수를 할당. 각각의 상수가 enum타입
Grade grade = Grade.SALES;
// 객체 출력하면 정의된 상수의 이름 출력
System.out.println(grade);
// grade가 Enum의 자손인지 확인, 자손이기때문에 true 출력
System.out.println(grade instanceof Enum);
// grade가 Object의 자손인지 확인, 자손이기때문에 true 출력
System.out.println(grade instanceof Object);
}
}
enum 타입들은 java.lang.Enum클래스를 기본적으로 상속받고 있기 때문에 java.lang.Enum 클래스에 선언된 메서드들의 사용이 가능하다.
enum Tea {
COFFEE, BLACK_TEA, GREEN_TEA
}
public class EnumMethodTest {
public static void main(String[] args) {
// values() : enum타입에 선언된 enum 상수를 배열로 리턴한다.
// values()메서드로 Tea가 가진 모든 상수값을 배열 형태로 리턴받음.
Tea[] teaArray = Tea.values();
for(Tea tea : teaArray) {
// name() : enum상수의 이름을 문자열로 리턴
// enum 상수의 이름을 문자열로 반환 후 출력
String strName = tea.name();
System.out.printf("이름: %s%n", strName);
// ordinal() : 0부터 시작하는 enum 상수의 순서를 리턴.
// enum상수의 ordinal값 출력
System.out.printf("등장 순서: %d %n", tea.ordinal());
// valueOf() : 문자열로 매핑 된 enum 상수 객체를 리턴
// 문자열을 다시 Enum 타입으로
Tea reTea = Tea.valueOf(strName);
System.out.printf("원래의 객체와 같은가?: %b%n", reTea.equals(tea));
}
}
}
컴파일러에게 옵션을 주는 주석
자바에서 제네릭(generic)이란 데이터의 타입(data type)을 일반화한다(generalize)는 것을 의미.
제네릭은 클래스나 메소드에서 사용할 내부 데이터 타입을 컴파일 시에 미리 지정하는 방법.
ArrayList는 기존의 Vector를 개선한 것으로 Vector와 구현원리와 기능적인 측면에서 동일하다고 할 수 있다.
import java.util.ArrayList;
import java.util.List;
import java.util.Vector;
public class ArrayListEx02 {
public static void main(String[] args) {
ArrayList<String> al = new ArrayList<>();
al.add("홍길동");
al.add("박문수");
al.add("이몽룡");
System.out.println(al);
// 0번째 요소 삭제 후 출력
al.remove(0);
System.out.println(al);
Vector<String> v = new Vector<>();
v.add("홍길동");
v.add("박문수");
v.add("이몽룡");
System.out.println(v);
v.remove(0);
System.out.println(v);
// List는 부모이기때문에 바로 사용 가능. / 다형성 원리
List<String> l1 = new ArrayList<>();
l1.add("홍길동");
l1.add("박문수");
l1.add("이몽룡");
System.out.println(l1);
l1.remove(0);
System.out.println(l1);
List<String> l2 = new Vector<>();
l2.add("홍길동");
l2.add("박문수");
l2.add("이몽룡");
System.out.println(l2);
l2.remove(0);
System.out.println(l2);
}
}
다루고자 하는 데이터의 개수가 변하지 않는 경우에 좋음
데이터 개수의 변경이 잦다면 LinkedList 사용이 더 좋음
LinkedList는 각 요소를 Node(노드)로 정의하며 Node는 다음 요소의 참조값과 데이터로 구성이 된다.
각 Node는 다음 Node에 대한 링크 정보를 가지며 데이터를 연속적으로 구성할 필요가 없어진다.
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;
public class ArrayVsLinkedTest {
private static void addTest(String testcase, List<Object> list) {
long start = System.nanoTime();
for (int i = 0; i < 1_000_000; i++) {
list.add(new String("Hello"));
}
long end = System.nanoTime();
System.out.println(testcase + " 소요시간 :" + (end - start));
}
private static void addTest2(String testcase, List<Object> list) {
long start = System.nanoTime();
for (int i = 0; i < 100_000; i++) {
list.add(0, new String("Hello"));
}
long end = System.nanoTime();
System.out.println(testcase + " 소요시간 :" + (end - start));
}
private static void accessTest(String testcase, List<Object> list) {
long start = System.nanoTime();
for (int i = 0; i < 100_000; i++) {
list.get(i);
}
long end = System.nanoTime();
System.out.println(testcase + " 소요시간 :" + (end - start));
}
public static void main(String[] args) {
ArrayList<Object> alist = new ArrayList<Object>();
LinkedList<Object> list = new LinkedList<Object>();
addTest("순차적 추가: ArrayList", alist);
addTest("순차적 추가: LinkedList", list);
addTest2("중간에 추가: ArrayList", alist);
addTest2("중간에 추가: LinkedList", list);
accessTest("데이터 접근: ArrayList", alist);
accessTest("데이터 접근: LinkedList", list);
}
}
HashSet은 Set인터페이스를 구현한 가장 대표적인 컬렉션, Set인터페이스의 특징대로 HashSet은 중복된 요소를 저장하지 않음.
객체를 저장하기 전에 기존에 같은 객체가 있는지 확인 후 없으면 저장, 있으면 저장 안함
HashSet은 저장순서를 유지하지 않으므로 저장순서를 유지하고싶으면 LinkedHashSet을 사용 (나중 공부)
import java.util.HashSet;
import java.util.Set;
public class HashSetEx01 {
public static void main(String[] args) {
HashSet<String> hs1 = new HashSet<>();
Set<String> hs2 = new HashSet<>();
hs1.add("홍길동");
hs1.add("박문수");
hs1.add("임꺽정");
System.out.println(hs1);
// 데이터 몇개 있는지 확인
System.out.println(hs1.size());
// 데이터값 중복값은 중복처리 안해준다.
hs1.add("홍길동");
hs1.add("장길산");
System.out.println(hs1);
}
}
컬렉션에 저장된 요소를 접근하는데 사용되는 인터페이스이다.
Collection 인터페이스에 정의된 메서드로 Collection인터페이스 자손인 List와 Set에도 포함되어 있다.
컬렉션 클래스에 대해 iterator()를 호출하여 Iterator를 얻은 다음 반복문, 주로 while문을 사용하여 컬렉션 클래스의 요소들을 읽어 올 수 있다.
Iterator 인터페이스의 메서드로 자주 사용되며 읽어올 요소가 남아있는지 확인.
요소가 있으면 true, 없으면 false 반환 ( hasNext()는 boolean값 반환 )
다음 데이터를 반환
import java.util.HashSet;
import java.util.Iterator;
import java.util.Set;
public class HashSetEx01 {
public static void main(String[] args) {
HashSet<String> hs1 = new HashSet<>();
Set<String> hs2 = new HashSet<>();
hs1.add("홍길동");
hs1.add("박문수");
hs1.add("임꺽정");
System.out.println(hs1);
// 데이터 몇개 있는지 확인
System.out.println(hs1.size());
// 데이터값 중복값은 중복처리 안해준다.
hs1.add("홍길동");
hs1.add("장길산");
System.out.println(hs1);
// 전체데이터 가져오기
Iterator<String> i = hs1.iterator();
while(i.hasNext()) {
System.out.println(i.next());
}
// 향상된 for문으로 출력해보기 / 출력값은 위의 while문과 동일
for(String str : hs1) {
System.out.println(str);
}
}
}
import java.util.HashSet;
import java.util.Random;
public class RandomEx02 {
public static void main(String[] args) {
// 6개씩 5줄을 출력하는 로또번호 추출기
Random r1 = new Random(System.currentTimeMillis());
HashSet<Integer> lottos = new HashSet<>();
for(int i=0; i<5; i++) {
// 무한루프
while(true) {
lottos.add(r1.nextInt(45) + 1);
if(lottos.size() == 6) {
break;
}
}
System.out.println(lottos.toString());
// set 비우기
lottos.clear();
}
}
}
Map은 key(키)와 value(값)으로 구성된 Entry 객체의 모임
Entry : key와 value를 한 쌍으로 묶은 하나의 데이터를 칭함.
키는 중복될 수 없고, 값은 중복이 가능하다.
HashMap은 키와 값을 각각 Object타입으로 저장 즉 (Object, Object)형태여서 어떠한 객체도 저장 가능.
키는 주로 String을 대문자 또는 소문자로 통일해서 사용.
import java.util.HashMap;
public class HashMapEx01 {
public static void main(String[] args) {
// Key(키)와 value(값)
HashMap<String, String> hm = new HashMap<>();
// 데이터 넣기
hm.put("a", "홍길동");
hm.put("b", "박문수");
hm.put("c", "이몽룡");
System.out.println(hm);
System.out.println(hm.size());
// 키 없으면 추가
hm.put("d", "장길산");
System.out.println(hm);
// 키가 있는데 넣으면 수정
hm.put("c", "임꺽정");
System.out.println(hm);
// 한개씩 데이터 가져오기 / hm.get("key") key값 넣어주면 value값 출력됨.
System.out.println(hm.get("a"));
System.out.println(hm.get("b"));
// 해당 키와 값 제거
hm.remove("c");
System.out.println(hm);
// 전체 제거
hm.clear();
System.out.println(hm);
}
}
Map에 값을 전체 출력하기 위한 메서드 중 keyset()은 key의 값만 필요할때 사용한다.
import java.util.Collection;
import java.util.HashMap;
import java.util.Set;
public class HashMapEx02 {
public static void main(String[] args) {
HashMap<String, String> hm = new HashMap<>();
hm.put("a", "홍길동");
hm.put("b", "박문수");
hm.put("c", "이몽룡");
Set<String> keys = hm.keySet();
System.out.println(keys);
for(String key : keys) {
// key값 출력 / 데이터값도 뽑고 싶으면 "+ hm.get(key)" 해주면 됨
System.out.println(key);
}
// 데이터만 출력하기
Collection<String> values = hm.values();
for(String value : values) {
System.out.println(value);
}
}
}
구 버전의 컬렉션인 Hashtable을 상속받은 클래스로 애플리케이션의 환경 설정 파일에 데이터를 읽고 쓰는 기능을 가지고 있다.
Map을 구현하고있음
읽어올 요소가 남아있는지 확인. 있으면 true, 없으면 false. Iterator의 hasNext()와 같음
다음 요소를 읽어 옴. Iterator의 next()와 같음
import java.util.Enumeration;
import java.util.Properties;
import java.util.Set;
public class PropertiesEx01 {
public static void main(String[] args) {
// HashMap 계열
// <String, String>
Properties prop = new Properties();
prop.setProperty("timeout", "30");
prop.setProperty("language", "kr");
prop.setProperty("size", "10");
System.out.println(prop);
System.out.println(prop.size());
// 프로퍼티 이름값 가져올 떄
Enumeration e = prop.propertyNames();
while(e.hasMoreElements()) {
System.out.println(e.nextElement());
}
// 이름값 출력
Set<String> names = prop.stringPropertyNames();
for(String name : names) {
System.out.println(name);
}
}
}
import java.util.Properties;
import java.util.Set;
public class PropertiesEx02 {
public static void main(String[] args) {
Properties prop = System.getProperties();
Set<String> names = prop.stringPropertyNames();
for(String name : names) {
System.out.println(name);
}
// 자바 버전 알려줌 / Eclipse JRE
System.out.println(System.getProperty("java.version"));
System.out.println(System.getProperty("java.home"));
}
}
stack - 뒤로가기같은 기능
queue -
LIFO ( Last In First Out )
import java.util.Stack;
public class StackEx01 {
public static void main(String[] args) {
Stack<String> stack = new Stack<>();
// 데이터 저장
stack.push("홍길동");
stack.push("박문수");
stack.push("이몽룡");
System.out.println(stack);
// 데이터 추출 pop
System.out.println(stack.pop());
System.out.println(stack);
System.out.println(stack.pop());
System.out.println(stack);
}
}
FIFO ( First In First Out )
LinkedList로 queue만듦
import java.util.LinkedList;
import java.util.Queue;
public class QueueEx01 {
public static void main(String[] args) {
Queue<String> queue = new LinkedList();
// 데이터 저장
queue.offer("홍길동");
queue.offer("박문수");
queue.offer("임꺽정");
System.out.println(queue);
// 데이터 추출
System.out.println(queue.poll());
System.out.println(queue);
System.out.println(queue.poll());
System.out.println(queue);
}
}