- 오버로딩(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) : 하나의 객체가 여러가지 다양한 타입을 가질 수 있는 것을 의미
- 상속 관계의 클래스에서 부모클래스로 자식 클래스를 생성할 수 있음(부모 클래스 타입의 참조 변수로 자식 클래스 타입의 인스턴스를 참조할 수 있음)
- 다형성을 통해 만들어진 객체는 자식 클래스의 메소드, 변수를 사용할 수 없다.
- 다형성은 상속, 추상화와 더불어 객체 지향 프로그래밍을 구성하는 중요한 특징 중 하나
public void aaa(Object o){}
equals()
, toString()
, String str = "aa"; str.
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]); } }
class Car implements Aaa{}
인터페이스를 사용하면 다중 상속이 가능할 뿐만 아니라 다음과 같은 장점을 가질 수 있음.
예제 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(); } } }
예제 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]); } }
예제 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]; } }
- 지난 시간에 이어 상속과 관련된 심화 개념들과 함께 중요한 개념인 인터페이스에 대해 배웠다. 다중 상속이 가능하여 보다 효율적인 개발을 도와주는 중요한 기능인 것을 알았으며, 인터페이스를 사용함으로써 실무 현장에서 일관성 있는 표준화된 개발이 가능하다는 것을 느꼈다.