[STUDY] 231214 | Java | 오버라이딩(overriding), 다형성(polymorphism), Object, String, 인터페이스(Interface)

Nimgnos·2023년 12월 15일
0

👾 STUDY

목록 보기
20/40
post-thumbnail

💻 상속(Inheritance)

  • 관련없는 클래스들에게 하나의 공통된 성격을 부여하여 관련없던 다수의 클래스를 한 번에 관리할 수 있는 기능
  • 기존 클래스를 재활용해서 구현해야하는 코드의 양을 줄일 수 있음
  • 상속의 오버라이딩 + 다형성

📌 오버라이딩(Overriding)

  • 오버로딩(overloading) : 메소드명은 원래 중복 선언할 수 없지만 매개변수의 정보(개수, 자료형)가 다르면 중복 이름 사용 허용
  • 오버라이딩(overriding) : 상속 관계의 클래스에서 부모 클래스의 메소드를 자식 클래스에서 재정의 하는 것
  • 오버라이딩 된 메소드는 자식 클래스에서 재정의된 메소드만 실행함

    오버라이딩 예제

public class Student {
    public void tellName(){
        System.out.println("제 이름은 홍길동입니다.");
    }
}
class NewStudent extends Student{
    public void tellName(){
        //this();
        //super();
        System.out.println("제 이름은 이순신입니다.");
    }
}
public class StudentTest {
    public static void main(String[] args) {
        NewStudent ns = new NewStudent();
        //오버라이딩 된 메소드는 무조건 자식 클래스에서 재정의한 메소드가 실행
        //부모 클래스에게 정의한 tellName 메소드를 호출할 수 있는 방법은 전혀 없음
        ns.tellName();
    }
}

📌 다형성(Polymorphism)

  • 다형성(polymorphism) : 하나의 객체가 여러가지 다양한 타입을 가질 수 있는 것을 의미
  • 상속 관계의 클래스에서 부모클래스로 자식 클래스를 생성할 수 있음(부모 클래스 타입의 참조 변수로 자식 클래스 타입의 인스턴스를 참조할 수 있음)
  • 다형성을 통해 만들어진 객체는 자식 클래스의 메소드, 변수를 사용할 수 없다.
  • 다형성은 상속, 추상화와 더불어 객체 지향 프로그래밍을 구성하는 중요한 특징 중 하나

💻 Object 클래스

  • 모든 클래스의 부모 클래스
  • Object 클래스로 모든 클래스의 객체를 생성할 수 있음.
  • public void aaa(Object o){}
  • 우리가 만드는 클래스, 미리 만들어진 클래스 모두 Object 클래스에서 정의된 메소드를 사용할 수 있음.
  • equals(), toString(), String str = "aa"; str.

💻 String 클래스

  • String 클래스에는 문자열과 관련된 작업을 할 때 유용하게 사용할 수 있는 다양한 메소드가 포함되어 있음.
  • String 인스턴스는 한 번 생성되면 그 값을 읽기만 할 수 있고, 변경할 수는 없음. 이러한 객체를 자바에서는 불변 객체(immutable object)라고 함. ➡️ 자바에서 덧셈(+) 연산자를 이용하여 문자열 결합을 수행하면, 기존 문자열의 내용이 변경되는 것이 아니라 내용이 합쳐진 새로운 String 인스턴스가 생성됨.

String 클래스 예제

package string;
public class String01 {
    public static void main(String[] args) {
        //스트링은 immutable 변수(값이 한 번 저장되면 변경 불가)
        String str1 = "java";
        String str2 = "java";
        str1 = "c++";
        System.out.println(str1);
        System.out.println(str2);
        String str3 = new String("java");
        String str4 = new String("java");
        // == :  두 객체가 같은 주소에 저장된 데이터이다.
        if(str1 == str2){
            System.out.println("str1과 str2는 같음");
        }
        if(str2 == str3){
            System.out.println("str2과 str3는 같음");
        }
        if(str3 == str4){
            System.out.println("str3과 str4는 같음");
        }
    }
}
public class String02 {
    public static void main(String[] args) {
        String s1 = "java";
        String s2 = "hello";
        String s3 = s1.concat(s2);
        System.out.println(s3);
        //일부 문자열 추출
        String s4 = "abcdefg";
        String s5 = s4.substring(3);
        System.out.println(s5); //defg
        String s6 = s4.substring(1, 4);
        System.out.println(s6); //bcd
        System.out.println(s4.toLowerCase()); //소문자 변환
        System.out.println(s4.toUpperCase()); //대문자 변환
        //문자열을 숫자로 변환
        String s7 = String.valueOf(10);
        //문자열 짜르기(조각내기)
        String s8 = "a, b, c, d";
        String[] result = s8.split(",");
        System.out.println(result[0]);
    }
}

💻 인터페이스(interface)

🔎 인터페이스란?

  • 다른 클래스를 작성할 때 기본이 되는 틀을 제공하면서, 다른 클래스 사이의 중간 매개 역할까지 담당하는 일종의 추상 클래스 ➡️ 클래스의 '설계도'
    • 자바에서 추상 클래스는 추상 메소드 뿐만 아니라 생성자, 필드, 일반 메소드도 포함할 수 있으나, 인터페이스는 오로지 추상 메소드와 상수만을 포함할 수 있음.
  • 자바에서는 클래스를 통한 다중 상속은 지원하지 않음
    • 자식 클래스가 여러 부모 클래스를 상속받을 수 있다면, 다양한 동작을 수행할 수 있다는 장점이 있으나, 클래스를 이용하여 다중 상속을 할 경우 메소드 출처의 모호성 등 여러 가지 문제가 발생할 수 있음. ➡️ 인터페이스라는 것을 통해 다중 상속을 지원함.
  • 인터페이스는 클래스 구현 시 함께 사용하며, 단독 사용이 불가함.
  • 추상 클래스와 마찬가지로 자신이 직접 인스턴스를 생성할 수 없음. 인터페이스가 포함하고 있는 추상 메소드를 구현해 줄 클래스를 작성해야만 함.
  • 인터페이스 안의 메소드는 무조건 public으로 선언(접근제한자 생락하면 자동으로 public으로 설정)
  • 인터페이스의 문법 : class Car implements Aaa{}

🔎 인터페이스의 장점

인터페이스를 사용하면 다중 상속이 가능할 뿐만 아니라 다음과 같은 장점을 가질 수 있음.

  • 대규모 프로젝트 개발 시 일관되고 정형화된 개발을 위한 표준화가 가능함.
  • 클래스의 작성과 인터페이스의 구현을 동시에 진행할 수 있으므로, 개발 시간을 단축할 수 있음.
  • 클래스와 클래스 간의 관계를 인터페이스로 연결하면, 클래스마다 독립적인 프로그래밍이 가능함.
    (참고 출처: https://tcpschool.com/java/java_polymorphism_interface)

📌 상속(Inheritance) 예제 풀이

예제 1.

public class Cake {
    public void eatCake(){
        System.out.println("맛있는 케익을 먹는다.");
    }
}
class CheeseCake extends Cake{
    public void eatCheeseCake(){
        System.out.println("맛있는 치즈 케익을 먹는다.");
    }
}
class StrawberryCheeseCake extends CheeseCake{
    public void eatStrawberryCheeseCake(){
        System.out.println("맛있는 딸기 치즈 케익을 먹는다.");
    }
}
public class CakeTest {
    public static void main(String[] args) {
        StrawberryCheeseCake c1 = new StrawberryCheeseCake();
        Cake c2 = new CheeseCake();
        c2.eatCake();
        Cake c3 = new StrawberryCheeseCake();
        c3.eatCake();
        StrawberryCheeseCake c9 = (StrawberryCheeseCake)c3;
        c9.eatStrawberryCheeseCake();
        c9.eatCheeseCake();
        c9.eatCake();
        CheeseCake c4 = new StrawberryCheeseCake();
        c4.eatCake();
        c4.eatCheeseCake();
        //CheeseCake c5 = new Cake(); -오류 //부모클래스만 자식클래스를 받을 수 있음
        //StrawberryCheeseCake c5 = new Cake(); -오류
        //StrawberryCheeseCake c5 = new CheeseCake(); -오류
    }
}

예제 2.

public class MobilePhone {
    private String phoneNumber;
    private String modelName;
    public void sendMsg(){
        System.out.println("메세지를 보냅니다.");
    }
}
//스마트폰은 모바일폰이다 o
//모바일폰은 스마트폰이다 x
public class SmartPhone extends MobilePhone{
    private String os;
    public void playApp(){
        System.out.println("앱을 실행합니다.");
    }
}
public class PhoneTest1 {
    public static void main(String[] args) {
        MobilePhone p1 = new MobilePhone();
        SmartPhone p2 = new SmartPhone();
        //상속 관계의 클래스에서 부모 클래스로
        //자식 클래스를 생성할 수 있다.
        //다형성 - 객체가 다양한 형태를 지닌다.
        //다형성을 통해 만들어진 객체는 자식 클래스의 메소드, 변수를 사용할 수 없다.
        MobilePhone p3 = new SmartPhone();
        //SmartPhone p4 = new MobilePhone();
        //p3.playApp(); -> 오류
        //형변환(정수 -> 실수, 실수 -> 정수)
        int a = (int)10.5;
        SmartPhone p5 = (SmartPhone) p3;
    }
}

예제 3.

//모든 클래스는 object를 상속한다.
public class Car extends Object {
    public void a(int a){
    }
    public void a(String a){
    }
    public void a(Object a){
    }
}
class SuperCar extends Car{
}
import phone.Cake;
public class CarTest {
    public static void main(String[] args) {
        Car c = new Car();
        Object o1 = new Car();
        Object o2 = new Cake();
    }
}

예제 4.

public class Person {
    String name;
    int age;
    //어노테이션 : 개발자의 실수를 줄이기 위해 사용
    @Override
    public boolean equals(Object obj){
        Person person = (Person)obj;
        if(name.equals(person.name) && age == person.age){
            return true;
        }
        else{
            return false;
        }
    }
    @Override
    public String toString() {
        return "Person{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }
}
public class PersonTest {
    public static void main(String[] args) {
        Person p1 = new Person();
        p1.name = "java";
        p1.age = 29;
        Person p2 = new Person();
        p2.name = "java";
        p2.age = 20;
        System.out.println(p1.equals(p2));
        //객체를 문자열로 표현
        //객체를 출력하면 자동으로 toString() 메소드를 실행
        System.out.println(p1.toString());
        System.out.println(p1);
        int[] arr = new int[3];
        System.out.println(arr);
        System.out.println(arr.toString());
    }
}

예제 5.

package zoo;
//동물병원에 케이지가 5개 있다.
//강아지, 고양이, 소
//케이지에 동물들을 저장할 수 있는 프로그램 생성
class Animal{
    public void Sound(){
        System.out.println("동물이 웁니다.");
    }
}
public class Dog extends Animal{
    public void Sound(){
        System.out.println("강아지가 웁니다.");
    }
}
class Cat extends Animal{
    public void Sound(){
        System.out.println("고양이가 웁니다.");
    }
}
class Cow extends Animal{
    public void Sound(){
        System.out.println("소가 웁니다.");
    }
}
package zoo;
public class ZooTest {
    public static void main(String[] args) {
        //강아지 케이지3
        Dog[] dogs = new Dog[3];
        Cat[] cats = new Cat[3];
        Cow[] cows = new Cow[3];
        int dogCnt = 0;
        dogs[dogCnt++] = new Dog();
        dogs[dogCnt++] = new Dog();
        int catCnt = 0;
        cats[catCnt++] = new Cat();
        cats[catCnt++] = new Cat();
        int cowCnt = 0;
        cows[cowCnt++] = new Cow();
        cows[cowCnt++] = new Cow();
        for(int i = 0; i < dogCnt; i++){
            //dogs[i].dogSound();
        }
        for (int i = 0; i < catCnt; i++){
            //cats[i].catSound();
        }
        for (int i = 0; i < cowCnt; i++){
            //cows[i].cowSound();
        }
    }
}
public class ZooTest2 {
    public static void main(String[] args) {
        Animal[] animals = new Animal[5];
        //다형성 활용
        int cnt = 0;
        animals[cnt++] = new Dog();
        animals[cnt++] = new Cat();
        animals[cnt++] = new Cow();
        //오버라이딩
        for(int i = 0; i < cnt; i++){
            animals[i].Sound();
        }
    }
}

📌 String 예제 풀이

예제 1.

package string;
public class String01 {
    public static void main(String[] args) {
        //스트링은 immutable 변수(값이 한 번 저장되면 변경 불가)
        String str1 = "java";
        String str2 = "java";
        str1 = "c++";
        System.out.println(str1);
        System.out.println(str2);
        String str3 = new String("java");
        String str4 = new String("java");
        // == :  두 객체가 같은 주소에 저장된 데이터이다.
        if(str1 == str2){
            System.out.println("str1과 str2는 같음");
        }
        if(str2 == str3){
            System.out.println("str2과 str3는 같음");
        }
        if(str3 == str4){
            System.out.println("str3과 str4는 같음");
        }
    }
}
public class String02 {
    public static void main(String[] args) {
        String s1 = "java";
        String s2 = "hello";
        String s3 = s1.concat(s2);
        System.out.println(s3);
        //일부 문자열 추출
        String s4 = "abcdefg";
        String s5 = s4.substring(3);
        System.out.println(s5); //defg
        String s6 = s4.substring(1, 4);
        System.out.println(s6); //bcd
        System.out.println(s4.toLowerCase()); //소문자 변환
        System.out.println(s4.toUpperCase()); //대문자 변환
        //문자열을 숫자로 변환
        String s7 = String.valueOf(10);
        //문자열 짜르기(조각내기)
        String s8 = "a, b, c, d";
        String[] result = s8.split(",");
        System.out.println(result[0]);
    }
}

📌 인터페이스(interface) 예제

예제 1

package basic;
//implements: 구현
//CoffeeTest 클래스는 CoffeeMachin 인터페이스의 모든 메소드를 반드시 구현해야 함.
public class CoffeeTest implements CoffeeMachin{
    @Override
    public void getCoffee() {
    }
    @Override
    public void getCoffee1() {
    }
    @Override
    public void getCoffee13() {
    }
}
package basic;
//인터페이스 안의 메소드는 무조건 public으로 선언!
//접근제한자 생락하면 자동으로 public으로 설정
//인터페이스 안에는 오직 메소드의 정의만 존재
//변수x, 생성자x
//인터페이스는 단독 사용 불가!
//인터페이스는 클래스 구현 시 함께 사용!
//인터페이스: 클래스의 설계도
public interface CoffeeMachin {
    //int a;
    //public CoffeeMachin(){}
    void getCoffee();
    void getCoffee1();
    void getCoffee13(); 
}

예제 2.

package math;
//아래 제시된 인터페이스를 구현하는 클래스 MyMath를 만들고
//해당 클래스 안에 요구사항에 맞는 메소드를 구현하시오.
public interface MathUtil {
    //매개변수로 받은 두 수 중 작은 수를 리턴
    int getMin(int a, int b);
    //매개변수로 받은 반지름을 가진 원의 둘레를 리턴
    //단, 반지름이 0 이하라면 둘레는 0이 되어야 함.
    //2*3.14*반지름
    double getCircleArea(int radius);
    //첫번째 매개변수로 받은 수의 n제곱 값을 리턴
    //ex) 첫번째 매개변수: 2
    //    두번째 매개변수: 4
    //결과 : 2*2*2*2
    int getMultipul(int num1, int num2);
}
package math;
public class MyMath implements MathUtil{
    @Override
    public int getMin(int a, int b) {
        return a > b ? b : a;
    }
    @Override
    public double getCircleArea(int radius) {
        return radius < 0 ? 0 : 2 * radius * Math.PI;
//        return radius < 0 ? 0 : 2 * radius * 3.14;
//        if(radius < 0){
//        return 0;
//        }
//        else{
//            return radius * 2 * 3.14;
//        }
    }
    @Override
    public int getMultipul(int num1, int num2) {
        int result = 1; //*0으로 초기화하면 안됨
        for (int i = 0; i < num2; i++) {
            result = result * num1;
        }
        return result;
    }
}

예제 3.

  • MyArray 클래스 구현, 메소드 구현
  • 매개변수로 들어온 배열의 모든 요소의 값이 짝수일 때만 true를 리턴, 나머지는 false 리턴
package arrayutil;
//MyArray 클래스 구현, 메소드 구현
public interface ArrayUtil {
    //매개변수로 들어온 두 배열의 모든 요소의 평균을 리턴
    double getTwoArrayAvg(int[] arr1, int[] arr2);
    //매개변수로 들어온 배열의 모든 요소의 값이 짝수일 때만
    //true를 리턴, 나머지는 false 리턴
    boolean isEvenArray(int[] arr);
}
package arrayutil;
public class Arraytest implements ArrayUtil {
    @Override
    public double getTwoArrayAvg(int[] arr1, int[] arr2) {
        int sum1 = 0;
        int avg = 0;
        for(int i = 0; i < arr1.length; i++){
            sum1 = sum1 + arr1[i];
        }
        int sum2 = 0;
//        for(int e : arr2){
//            sum2 = sum2 + e;
//        }
        for(int i = 0; i < arr2.length; i++){
            sum2 = sum2 + arr2[i];
        }
        return (double)(sum1 + sum2) / (arr1.length + arr2.length);
    }
    @Override
    public boolean isEvenArray(int[] arr) {
        for (int i = 0; i < arr.length; i++){
            if(arr[i] % 2 == 1){
                return false;
            }
        }
        return true;
    }
}

예제 4.

  • 아래 요구사항에 만족하는 추상 메소드를 정의
  • StudentTest 클래스에서 만든 메소드를 구현
  • 매개변수로 들어온 학생의 총점을 리턴
  • 매개변수로 들어온 두 학생 중 총점이 높은 학생 리턴(총점이 같은 경우는 없음)
  • 학생 여러명을 매개변수로 받아, 또 다른 매개변수로 받은 학생의 이름과 일치하는 학생의 점수 등급을 문자열로 리턴. 만약, 매개변수로 받은 이름과 일치하는 학생이 없다면 "학생 정보 없음"이라는 문자열을 리턴.
  • 90 <= 평균 <= 100 -> A 문자열 리턴, 80 <= 평균 <= 89 -> B 문자열 리턴, 70 <= 평균 <= 79 -> C 문자열 리턴, 평균 < 70 -> D 문자열 리턴
  • 매개변수로 학생 여러명을 받아, 해당 학생들의 총점을 배열로 리턴. 각각의 학생 총점이 270점, 280, 250이라고 하면 270, 280, 250 값을 갖는 배열을 리턴
package stu;
public interface StudentUtil {
    //매개변수로 들어온 학생의 총점을 리턴
    int getTotalScore(Student student);
    //매개변수로 들어온 두 학생 중 총점이 높은 학생 리턴
    //총점이 같은 경우는 없다고 생각
    Student getHighScoreStudent(Student stu1, Student stu2);
    //매소드명: getGradeByStudentName
    //학생 여러명을 매개변수로 받아, 또 다른 매개변수로 받은
    //학생의 이름과 일치하는 학생의 점수 등급을 문자열로 리턴
    //만약, 매개변수로 받은 이름과 일치하는 학생이 없다면
    //"학생 정보 없음"이라는 문자열을 리턴.
    //90 <= 평균 <= 100 -> A 문자열 리턴
    //80 <= 평균 <= 89 -> B 문자열 리턴
    //70 <= 평균 <= 79 -> C 문자열 리턴
    // 평균 < 70 -> D 문자열 리턴
    String getGradeByStudentName(Student[] students, String name);
    //메소드명: getTotalScoresToArray
    //매개변수로 학생 여러명을 받아, 해당 학생들의 총점을 배열로 리턴
    //각각의 학생 총점이 270점,  280, 250이라고 하면
    //270, 280, 250 값을 갖는 배열을 리턴
    int[] getTotalScoresToArray(Student[] students);
}
package stu;
public class StudentTest implements StudentUtil {
    //매개변수로 들어온 학생의 총점을 리턴
    @Override
    public int getTotalScore(Student student) {
        return student.getKorScore() + student.getEngScore() + student.getMathScore();
    }
    //매개변수로 들어온 두 학생 중 총점이 높은 학생 리턴
    //총점이 같은 경우는 없다고 생각
    @Override
    public Student getHighScoreStudent(Student stu1, Student stu2) {
        if (getTotalScore(stu1) > getTotalScore(stu2)) {
            return stu1;
        } else {
            return stu2;
        }
    }
    //매소드명: getGradeByStudentName
    //학생 여러명을 매개변수로 받아, 또 다른 매개변수로 받은
    //학생의 이름과 일치하는 학생의 점수 등급을 문자열로 리턴
    //만약, 매개변수로 받은 이름과 일치하는 학생이 없다면
    //"학생 정보 없음"이라는 문자열을 리턴.
    //90 <= 평균 <= 100 -> A 문자열 리턴
    //80 <= 평균 <= 89 -> B 문자열 리턴
    //70 <= 평균 <= 79 -> C 문자열 리턴
    // 평균 < 70 -> D 문자열 리턴
    @Override
    public String getGradeByStudentName(Student[] students, String name) {
        String grade = "학생 정보 없음";
        for (int i = 0; i < students.length; i++) {
            if (students[i].getName().equals(name)) {
                double avg = getTotalScore(students[i]) / 3.0; //평균
                grade = getGrade(avg);
            }
        }
        return grade;
    }
    public String getGrade(double avg) {
        if (avg >= 90 && avg <= 100) {
            return "A";
        } else if (avg >= 80) {
            return "B";
        } else if (avg >= 70) {
            return "C";
        } else {
            return "D";
        }
    }
    @Override
    public int[] getTotalScoresToArray(Student[] students) {
        return new int[0];
    }
}

🍀 회고

  • 지난 시간에 이어 상속과 관련된 심화 개념들과 함께 중요한 개념인 인터페이스에 대해 배웠다. 다중 상속이 가능하여 보다 효율적인 개발을 도와주는 중요한 기능인 것을 알았으며, 인터페이스를 사용함으로써 실무 현장에서 일관성 있는 표준화된 개발이 가능하다는 것을 느꼈다.
profile
먹고 기도하고 코딩하라

0개의 댓글