Java 프로그래밍 5~12

kdew0308·2022년 10월 21일
0

자바

목록 보기
2/8

5) 클래스와 객체

5-1) 클래스

  • 객체를 정의하는 설계도
  • 붕어빵 틀
  • 레시피

5-2) 객체, 인스턴스

  • 객체 (Object)
    • 실체
  • 인스턴스 (Instance)
    • 클래스와 객체의 관계
    • 클래스로부터 객체를 선언 (인스턴스 화)
    • 어떤 객체는 어떤 클래스의 인스턴스

5-3) 클래스 사용

  • 클래스: 객체를 만들기 위한 설계도
    • 객체 변수, 메소드로 이루어짐
public class 클래스명 {
// 객체 변수
// 메소드
// + 접근제어자
// + static
}

클래스명 객체명 = new 클래스명();

5-4) 생성자 (Constructor)

  • 객체가 생성될 때 자동으로 호출됨
  • 생략가능
  • 생성자 규칙
    • 클래스명과 이름 맞추기
    • 리턴 타입 없음
public class 클래스명 {
클래스명() {}
}

5-5) this, this()

  • this : 객체 자신을 의미
  • this() : 생성자

5-6) 오버로딩 (Overloading)

  • 한 클래스 내에서 같은 이름의 메소드를 여러 개 정의
  • 오버로딩 조건
    • 메소드의 이름이 같아야 함
    • 매개변수의 개수 또는 타입이 달라야 함
      (리턴타입의 차이로는 오버로딩이 되지 않음)
public class 클래스명 {
	클래스명() {}
	클래스명(String name, String type) {
		구현 내용;
	}
}

5-7) 접근제어자

  • 클래스의 변수나 메소드의 접근에 제한을 두는 키워드
  • 접근제어자 종류
    • private : 해당 클래스에서만 접근 가능
    • public : 어디서든 접근 가능
    • default : 해당 패키지 내에서만 접근 가능
    • protected : 해당 패키지 및 상속받은 클래스에서 접근 가능

5-8) Static

  • 변수나 메소드의 특성을 바꾸는 키워드
  • Static 특징
    • 메모리에 한번만 할당됨
    • 즉, Static 변수나 메소드는 공유되는 특성을 가짐
  • Static 클래스 변수
    • 해당 클래스의 각 객체들이 값을 공유
  • Static 클래스 메소드
    • 객체를 생성하지 않아도 호출 가능

6. 상속

  • 기존 클래스에 기능 추가 및 재정의하여 새로운 클래스를 정의
    • 부모 클래스: 상속 대상이 되는 기존 클래스 = 상위 클래스, 기초클래스
    • 자식 클래스: 기존 클래스를 상속하는 클래스 = 하위 클래스, 파생 클래스
  • 부모 클래스의 필드와 메소드가 상속됨 생성자, 초기화 블록은 상속되지 않음
  • 다중 상속은 불가능
  • private, default 멤버는 자식 클래스에서 접근 불가 default의 경우, 내부 패키지의 자식 클래스는 가능

6-1) super, super()

  • super
    • 부모 클래스와 자식 클래스의 멤버 이름이 같을 때 구분하는 키워드
  • super()
    • 부모 클래스의 생성자 호출

6-2) 오버라이딩 (Overriding)

  • 부모 클래스의 메소드를 자식 클래스에서 재정의
  • 오버라이딩 조건
    • 메소드의 선언부는 부모 클래스의 메소드와 동일해야 함
    • 반환 타입에 한해, 부모 클래스의 반환 타입으로 변환할 수 있는 타입으로 변경 가능
    • 부모 클래스의 메소드보다 접근제어자를 더 좁은 범위로 변경 불가
    • 부모 클래스의 메소드보다 더 큰 범위의 예외 선언 불가

7) 다형성

정의

  • 한 객체가 여러 가지 타입을 가질 수 있는 것
  • 부모클래스 타입의 참조 변수로 자식클래스 인스턴스
  • 자식클래스가 부모의 객체를 받아서 사용할 수 없음
  • 자식 객체는 오버라이딩된 부분만 접근 가능
class Person {}
class Student extends Person {}
Person p1 = new Student();
// Student s1 = new Person();

instanceof

  • 실제 참조하고 있는 인스턴스의 타입 확인
class Person {}
class Student extends Person {}
Person p1 = new Student();
// Student s1 = new Person();
System.out.println(p1 instanceof Person); // 이렇게 하면 p1이 Person의 객체인지 아닌지 확인 가능

코드1

class Person {
    public void print() {
        System.out.println("Person.print");
    }
}

// Person을 상속
class Student extends Person {
    public void print() { //print()오버라이딩
        System.out.println("Student.print");
    }

    public void print2() {
        System.out.println("Student.print2");
    }
}
// Person을 상속
class CollegeStudent extends Person {
    public void print() {
        System.out.println("CollegeStudent.print");
    }
}


public class Main {

    public static void main(String[] args) {

//      1. 다형성
        System.out.println("== 다형성 ==");
        Person p1 = new Person();
        Student s1 = new Student();

        Person p2 = new Student(); // 자식 객체인데 부모 타입의 클래스로 만들어줌
//        Student s2 = new Person(); 이렇게 사용 못함

        p1.print(); // 결과 : Person.print
        s1.print(); // 결과 : Student.print
        s1.print2(); // 결과 : Student.print2
        p2.print(); // 결과 : Student.print
//        p2.print2(); 이거는 오류남 왜냐하면 오버라이딩된 부분이 print()이기 때문에 print()까지만 접근 가능

        Person p3 = new CollegeStudent();
//        CollegeStudent c1 = new Student(); 이렇게 다형성은 안됨
        p3.print();


//      2. 타입 변환
        System.out.println("== 타입 변환 ==");
        Person pp1 = null;
        Student ss1 = null;

        Person pp2 = new Person();
        Student ss2 = new Student();
        Person pp3 = new Student();     // 업캐스팅(그래서 실객체는 Student임)

        pp1 = pp2;
        pp1 = ss2;

        ss1 = ss2;
//        ss1 = (Student)pp2; 거꾸로는 안됨
        ss1 = (Student)pp3; // 다운캐스팅 

//        CollegeStudent cc1;
//        CollegeStudent cc2 = new CollegeStudent();
//        ss1 = (Student) cc2;
//        cc1 = (CollegeStudent) ss2;


//      3. instanceof
        System.out.println("== instanceof ==");
        Person pe1 = new Person();
        Student st1 = new Student();
        Person pe2 = new Student();
        Person pe3 = new CollegeStudent();

        System.out.println("== instance of ==");
        System.out.println(pe1 instanceof Person); // 결과 : true
        System.out.println(pe1 instanceof Student); // 결과 : flase

        System.out.println(st1 instanceof Student); // 결과 : true
        System.out.println(st1 instanceof Person); // 결과 : true

        System.out.println(pe2 instanceof Person); // 결과 : true
        System.out.println(pe2 instanceof Student); // 결과 : true

        System.out.println(pe3 instanceof Person); // 결과 : true
        System.out.println(pe3 instanceof CollegeStudent); // 결과 : true

        if (pe1 instanceof Student) {
            Student stu1 = (Student) pe1;
        }

        if (st1 instanceof Person) {
            Person per1 = (Person)st1;
        }

    }
}

업캐스팅 : 자식클래스의 객체가 부모 클래스의 타입으로 형변환 되는 것
다운캐스팅 : ppr3의 객체는 Student였으니까 잠깐 업캐스팅돼서 타입만 Person이었으니까 이 타입을 다시 원래 자기 자신인 Student로 타입 변환을 해주면 사용 가능

코드2

class Car {
    Car(){}
    public void horn() {
        System.out.println("빵빵!");
    }
}

class FireTruck extends Car {
    public void horn() {
        System.out.println("위이잉!");
    }
}

class Ambulance extends Car {
    public void horn() {
        System.out.println("삐뽀삐뽀!");
    }
}

public class Practice {
    public static void main(String[] args) {
        // Test code
        Car car = new Car();
        car.horn();

        car = new FireTruck();
        car.horn();

        car = new Ambulance();
        car.horn();
// 2번째 방법
//        Car car[] = {new Car(), new FireTruck(), new Ambulance()};
//
//        for (Car item: car) {
//            item.horn();
//        }
    }
}

8) 추상 클래스

추상 메소드 (Abstract Method)

  • 자식클래스에서 반드시 오버라이딩 해야하는 메소드
  • 선언만하고 구현 내용 없음
    abstract void print();

추상 클래스 (Abstract Class)

  • 하나 이상의 추상 메소드를 포함하는 클래스
  • 반드시 구현해야 하는 부분에 대해 명시적으로 표현
  • 추상 클래스 자체는 객체 생성 불가
abstract class 클래스명 {abstract void print();
}

코드1

// 추상 클래스 Person
abstract class Person {

    abstract void printInfo();
}

// 추상 클래스 상속
class Student extends Person {

    public void printInfo() {
        System.out.println("Student.printInfo");
    }
}


public class Main {

    public static void main(String[] args) {

//        추상 클래스의 사용
//        Person p1 = new Person(); 추상 클래스를 바로 객체로 만드는 것을 안됨
        Student s1 = new Student();
        s1.printInfo();

        Person p2 = new Person() {
            @Override
            void printInfo() {
                System.out.println("Main.printInfo");
            }
        };
        p2.printInfo();

    }

}

코드2

abstract class Device {
    int deviceId;

    abstract void deviceInfo();
    abstract void connect();
    abstract void disconnect();
    abstract void send();
    abstract void receive();
}

// UsbPort1 클래스
class UsbPort1 extends Device {
    UsbPort1(int id) {
        this.deviceId = id; // 생성자
    }
    
// 여기서부터는 오버라이딩이 필요한 추상 메소드들
    void deviceInfo() {
        System.out.println("id = " + this.deviceId);
    }
    void connect() {
        System.out.println("연결 하였습니다.");
    }
    void disconnect() {
        System.out.println("연결이 해제되었습니다.");
    }
    void send() {
        System.out.println("데이터를 전송합니다.");
    }
    void receive() {
        System.out.println("데이터를 수신합니다.");
    }
}

// WiFi 클래스
class WiFi extends Device {
    public WiFi(int id) {
        this.deviceId = id; // 생성자
    }

    void deviceInfo() {

    }

    void connect() {

    }

    void disconnect() {

    }

    void send() {

    }

    void receive() {

    }
}

public class Practice {

    public static void main(String[] args) {
        // Test code
        UsbPort1 usb1 = new UsbPort1(1);
        WiFi wifi = new WiFi(0);
    }

}
  • 오버라이딩 유용한 기능 : 우클릭 -> Generate -> implement

9) 인터페이스

9-1) 정의

  • 다중 상속처럼 사용할 수 있는 기능
  • 추상 메소드와 상수만으로 이루어짐
접근제어자 interface 인터페이스이름 {
	public static final 타입 상수이름 =;
	public abstract 반환타입 메소드이름(매개변수);}
class 클래스이름 implements 인터페이스이름 {}

9-2) 상속과 인터페이스 동시 사용

  • 동시 사용으로 다중 상속과 같은 효과
접근제어자 interface 인터페이스이름 {}
접근제어자 class 클래스이름 {}
class 클래스이름 extends 클래스이름 implements 인터페이스이름 {}

코드1

// School 인터페이스
interface School {
    public static final int MAX_CLASS = 20;
    public static final int MAX_PERSON_PER_CLASS = 40;
    public abstract void printSchool();
}

// Student 클래스 - School 인터페이스 이용
class Student implements School {

    public void printSchool() {
        System.out.println("00 University");
    }
}

// Person 클래스
class Person {
    public String name;

    public void printName() {
        System.out.println("Name: " + name);
    }
}


// Student2 클래스 - Person 상속, School 인터페이스 이용
class Student2 extends Person implements School {

    Student2(String name) {super.name = name;}
    public void printSchool() {
        System.out.println("11 University");
    }
}

public class Main {

    public static void main(String[] args) {
        
//      1. 인터페이스 기본 사용
        System.out.println("== 기본 인터페이스 ==");
        Student s1 = new Student();
        s1.printSchool(); // 결과 : 00 University
        System.out.println(s1.MAX_CLASS); // 결과 : 20
        System.out.println(s1.MAX_PERSON_PER_CLASS); // 결과 : 40

//      2. 다중 상속처럼 사용하기
        System.out.println("== Like 다중 상속 ==");
        Student2 s2 = new Student2("A");
        s2.printSchool(); // 결과 : 11 University
        s2.printName(); // 결과 : Name: A
    }
}

코드2

abstract class GreenOrc {
    public final String SKIN_COLOR = "녹색";
    public int health;
    public int attackDamage;
    public int defense;

    public abstract void setHealth();
    public abstract void setDamage();
    public abstract void setDefense();
}

interface NPCSystem {
    public abstract void conversationSystem();
    public abstract void questionSystem();
}

interface UserSystem {
    public abstract void partySystem();
    public abstract void tradeSystem();
}

// OrkNPC1 클래스
class OrkNPC1 extends GreenOrc implements NPCSystem {
    @Override
    public void setHealth() {
        this.health = 100;
    }

    @Override
    public void setDamage() {
        this.attackDamage = 10;
    }

    @Override
    public void setDefense() {
        this.defense = 5;
    }

    @Override
    public void conversationSystem() {
        System.out.println("안녕");
        System.out.println("요즘 새로운 소식 없나요?");
    }

    @Override
    public void questionSystem() {
        System.out.println("새로운 퀘스트");
        System.out.println("퀘스트 완료");
    }
}

// OrkUser1 클래스
class OrkUser1 extends GreenOrc implements UserSystem {
    @Override
    public void setHealth() {
        this.health = 200;
    }

    @Override
    public void setDamage() {
        this.attackDamage = 20;
    }

    @Override
    public void setDefense() {
        this.defense = 10;
    }

    @Override
    public void partySystem() {
        System.out.println("파티 초대");
        System.out.println("파티 수락");
    }

    @Override
    public void tradeSystem() {
        System.out.println("거래 신청");
        System.out.println("거래 완료");
    }
}


public class Practice {
    public static void main(String[] args) {
        // Test code
        // No test code
    }
}

10) 내부 클래스

10-1) 정의

  • 클래스 in 클래스 (클래스 안에 선언한 클래스)
class Outer {class Inner {}
}

10-2) 내부 클래스 특징

  • 내부 클래스에서 외부 클래스 멤버에 접근가능
  • 외부에서는 내부 클래스에 접근 불가

10-3) 내부 클래스 종류

  • 인스턴스 클래스 (instance class) : 바깥 클래스를 만들어야 사용 가능
  • 정적 클래스 (static class) : static사용, 바깥 클래스가 없어도 사용 가능
  • 지역 클래스 (local class) : 메소드 안에 클래스가 있음
  • 익명 클래스 (anonymous class)

10-4) 익명 클래스 (Anonymous Class)

  • 이름을 가지지 않는 클래스
  • 선언과 동시에 객체 생성
  • 일회용 클래스
클래스이름 참조변수이름 = new 클래스 이름 () {};

코드1

class Outer {

    public void print() {
        System.out.println("Outer.print");
    }

    class Inner {
        void innerPrint() {
            Outer.this.print();
        }
    }

    static class InnerStaticClass {
        void innerPrint() {
//            Outer.this.print();
        }
    }

    public void outerMethod() {
        class InnerLocal {

        }

        InnerLocal il1 = new InnerLocal();
    }
}

abstract class Person {
    public abstract void printInfo();
}

class Student extends Person {
    public void printInfo() {
        System.out.println("Student.printInfo");
    }
}

public class Main {

    public static void main(String[] args) {

//      외부 클래스
        Outer o1 = new Outer();

//      내부 클래스 - 인스턴스
        Outer.Inner i1 = new Outer().new Inner();

//      내부 클래스 - 정적
        Outer.InnerStaticClass is1 = new Outer.InnerStaticClass();
        
//      익명 클래스
        Person p1 = new Person() {
            @Override
            public void printInfo() {
                System.out.println("Main.printInfo");
            }
        };

    }

}

0개의 댓글