2019. 7. 13. 14:09ㆍ카테고리 없음
STEP 01 . 상속 [오버로딩 , 오버라이딩] ( inheritance [ Overloading , Overriding ] )
상속의 정의 및 특징
- 말그대로 자식이 부모로부터 물려받는 다는 의미이다.
- 상속은 ( IS - A 관계 ) 이다.
- 부모 클래스( ParentClass ) 와 자식 클래스( ChildClass )는 자바의 예약어인 extends에 의하여 정해진다.
- 하나의 부모 클래스 ( ParentClass )는 여러개의 자식 클래스( ChildClasss ) 를 가질 수 있지만 반대로 자식 클래스(Child Class)는 여러개의 부모 클래스(ParentClass)를 가질 수 없다.
- 자식 클래스 ( ChildClass ) 는 부모 클래스 ( ParentClass ) 의 자원 (resource) 를 사용 할 수 있다. 반대로 부모 클래스는 자식 클래스의 자원을 가져다 쓸 수 없다 .
- 자식 클래스는 부모 클래스로부터 물려받은 자원들을 Override 하여 수정해서 사용할 수 있다.
- 부모 클래스가 상속받은 자원도 자식 클래스가 사용 가능하다.
- 생성자와 초기화 블럭은 상속되지 않는다 . 멤버만 상속된다.
- 자손 클래스의 멤버 개수는 조상 클래스보다 항상 같거나 많다.
// 다음과 같은 방식으로 상속을 구현한다
class Child extends Parent{}
다음과 같은 용어를 사용해서 표현하기도 한다.
조상클래스자손 클래스
- 부모(Parent)클래스 , 상위(super)클래스 , 기반(base)클래스
- 자식(child)클래스 , 하위(sub)클래스 , 파생된(derived)클래스
[출처] 자바의정석 남궁성
간단한 동물 예제를 통해서 알아보겠습니다.
package com.juniordev.firstweek;
public class Animal {
String name;
protected void setName(String name) {
this.name = name;
} // end of setName method
protected void printName() {
System.out.println("이름 : " + this.name);
} // end of printName method
protected void sleep() {
System.out.println("Animal.java sleep() 메소드");
} // end of sleep method
} // end of Animal class
package com.juniordev.firstweek;
public class Dog extends Animal{
public static void main(String[] args) {
Dog dog = new Dog();
dog.setName("말티즈");
dog.printName();
dog.sleep();
} // end of main method
@Override
public void sleep() {
System.out.println("Dog.java sleep() 메소드");
} // end of sleep method
}// end of Dog class
/**
출력 결과
이름 : 말티즈
Dog.java sleep() 메소드
*/
package com.juniordev.firstweek;
public class Cat extends Animal{
public static void main(String[] args) {
Cat cat = new Cat();
cat.setName("페르시안 친칠라");
cat.printName();
cat.sleep();
}// end of main method
@Override
public void sleep() {
System.out.println("Cat.java sleep() 메소드");
}// end of sleep method
}// end of Cat class
/**
출력 결과
이름 : 페르시안 친칠라
Cat.java sleep() 메소드
*/
위의 3개의 Class를 추가해준다. 부모 클래스로 사용할 Animal class 파일과 자식 클래스로 사용할 Dog , Cat class 파일입니다.
출력 결과는 위의 코드블럭에 포함시켰습니다.
다만 Animal , Cat , Dog 클래스에 sleep()이라는 공통된 메소드가 있습니다.
Dog 와 Cat에서 sleep메소드를 실행시켰을때 각각 클래스가 가지고 있는 결과가 나온다.
하지만 sleep()메소드를 주석처리하고 실행하게 된다면 에러없이 실행은된다. 다만 결과는 Animal class가 가지고 있는 sleep()이 실행되게 된다. ( 밑에서 나올 오버라이딩 정의 )
그이유는 자신이 해당 메소드를 가지고 있지 않다면 부모클래스들이 가지고 있는지 확인하고 그래도 없다면( 최상위 클래스인 Object Class 까지 검색) Error를 발생하게 된다.
메소드 오버라이딩 (Method Overriding)
[출처 : 자바의 정석 P.327]
오버라이딩의 정의
조상 클래스로부터 상속받은 메서드의 내용을 변경하는 것을 오버라이딩이라고한다. 상속받은 메서드를 그대로 사용하기도 하지만 자손 클래스에 맞게 변경해서 사용해야할 경우 조상의 메서드를 오버라이딩한다고 말한다.
오버라이딩(Overriding)의 조건
- 자손 클래스에서 오버라이딩하는 메서드는 부모 클래스의 메서드와 이름이 같아야한다.
- 자손 클래스에서 오버라이딩하는 메서드는 부모 클래스의 메서드와 매개변수가 같아야한다.
- 자손 클래스에서 오버라이딩하는 메서드는 부모 클래스의 메서드와 반환타입이 같아야한다.
Overriding 조건에 해당되는 경우
부모클래스의 overiding(int) 메소드와 A클래스를 상속받은 B,C클래스에서 반환타입 , 매개변수 , 메소드 이름까지 다 같게하였을 경우 에러가 발생하지 않는다. class A { |
Overriding 조건에 해당되지 않는 경우
B클래스의 경우 A클래스의 overriding메소드와 다르게 반환타입이 void 이고 , C클래스는 매개변수가 한개 더 많다는것을 볼 수 있다. class A { public int overriding(int b) { return b; }// end of overriding(int) method }// end of A class
class B extends A { //The return type is incompatible with A.overriding(int) // 반환 타입이 A.overriding(int) 와 같지 않습니다.
@Override public void overriding(int b) { return b; }// end of overriding(int) method }// end of B class
class C extends A { // The method overriding(int, int) of type C must override or implement a supertype method // superType의 메소드를 재구현하거나 새로운 메소드를 만들어야한다. // 이경우 @Overriding이 없다면 에러가 나는경우는 아닙니다. 어노테이션은 뒤에서 살펴보겠습니다. @Override public int overriding(int a , int b) { return a; }// end of overriding(int , int) method }// end of C class |
오버로딩 vs 오버라이딩 ( 면접질문에 자주나옴 명확히 구분 가능해야함 )
오버로딩 (overloading) - 기존에 없는 새로운 메서드를 정의하는 것 , 같은 클래스 내에서 같은 이름의 메서드를 매개변수의 타입 , 갯수에 따라 다른 호출을 하게하는것
오버라이딩 (overriding) - 상속받은 메서드의 내용을 변경하는 것 ( 가능한 조건이 있음 )
class ParentClass{
public void parent() {}
}
class ChildClass extends ParentClass{
@Override
public void parent() { super.parent(); }
// Overloading
public String parent(String name) {return name;}
public int parent(int number) {return number;}
}
STEP 02 . Interface
Interface 의 정의 및 특징
- 인터페이스는 표준 , 약속 , 규칙이다.
- 인터페이스는 몸통이 없는 추상 메소드와 상수로 이루어진다.
- Interface로는 인스턴스를 생성할 수 없다.
- Interface를 일종의 설계도이다.
- 서로 조건이 없는 클래스 사이에 관계를 맺어줄 수 있다.
- interface의 구현은 implements keyword로 작성한다.
- class exnteds상속과는 다르게 implements를 통한 다중 상속 가능. ( extends는 확장의 의미 , implements는 구현의 의미 )
제약 사항
- 모든 멤버 변수는 public static final이여야 한다 . (default 생략 가능)
- 모든 멤버 메서드는 public abstract 이여야 한다 . (default 생략 가능)
// 인터페이스의 작성 방법
interface interfaceName {
public static final constantName = value;
public abstract methodName(argu);
}
abstract를 사용했을떄와 interface를 사용했을때이 차이점은 무엇일까?
- abstract와 interfacesms 스스로 인스턴스를 생성하지 못하고 , 상속관계에서만 존재할수 있다는 공통점이 있다.
- abstract는 extends로 다중상속이 되지 않는 반면 interface 는 implements를 통한 다중상속이 가능하다.
- abstract는 필요한 부분만 구현하거나 몸통만 구현하도록 할 수 있지만 , interface는 모든 메서드를 구현해야한다.
STEP 03 . 다형성
다형성이란 같은 자료형에 여러 가지 객체를 대입하여 다양한 결과를 얻어내는 성질을 의미한다.
package com.juniordev.firstweek;
import java.text.DecimalFormat;
import java.util.Scanner;
/**
* @author YunJin Choi <zzdd1558@gmail.com>
*/
public class Polymorphism {
public static void main(String[] args) {
Scanner scan = new Scanner(System.in);
Buyer buyer = new Buyer();
Product product = null;
System.out.print(" 구입할 물건 ( 1. TV , 2. Radio ) : " );
switch (scan.nextInt()) {
case 1:
product = new TV("LG 40인치 TV", 2000000);
break;
case 2:
product = new Radio("삼성 라디오", 500000);
break;
}
buyer.buy(product);
product.on();
}
}
abstract class Product {
private String className;
private String name;
private int price;
public static double pointPercent = 0.10;
public String getClassName() { return className;}
public void setClassName(String className) { this.className = className;}
public String getName() { return name;}
public void setName(String name) { this.name = name;}
public int getPrice() { return price;}
public void setPrice(int price) { this.price = price;}
public abstract void on();
public String getDecimalPrice(int price) {
DecimalFormat form = new DecimalFormat("#,###");
form.setDecimalSeparatorAlwaysShown(false);
return form.format(price);
}
public void getProductInfo() {
// TODO Auto-generated method stub
System.out.println("---구매 제품 정보---");
System.out.println(getClassName() + " 클래스");
System.out.println("가전제품 종류 : " + getName() );
System.out.println("가전제품 가격 : " + getDecimalPrice(getPrice()) + "원");
System.out.println("---------------");
}
}
class Radio extends Product{
// Constructor
public Radio() {
String[] array = this.getClass().getName().toString().split("\\.");
setClassName(array[array.length - 1]);
}
public Radio(String name , int price ) {
this();
setName(name);
setPrice(price);
}
@Override
public void on() { System.out.println("Radio 스위치 ON!!");}
}
class TV extends Product{
// Constructor
public TV() {
String[] array = this.getClass().getName().toString().split("\\.");
setClassName(array[array.length - 1]);
}
public TV(String name , int price ) {
this();
setName(name);
setPrice(price);
}
@Override
public void on() { System.out.println("TV 스위치 ON!");}
}
class Buyer{
private String name ;
private int money;
public Buyer() {
this.name = "최 윤진";
this.money = 50000000;
}
public Buyer (String name , int money) {
this.name = name;
this.money = money;
}
public String getName() { return name;}
public void setName(String name) { this.name = name;}
public int getMoney() { return money;}
public void setMoney(int money) { this.money = money;}
public void buy(Product product) {
product.getProductInfo();
money -= product.getPrice();
System.out.println("잔금 : " + getDecimalPrice(money) + "원");
}
public String getDecimalPrice(int price) {
DecimalFormat form = new DecimalFormat("#,###");
form.setDecimalSeparatorAlwaysShown(false);
return form.format(price);
}
}
STEP 04 . String , StringBuffer , StringBuilder
[참조 : http://jeong-pro.tistory.com/85]
다양한 코드를 보거나 프로그래밍을 하다보면 String도 문자열이고 StringBuffer , StringBuilder도 문자열을 저장하고 관리하는 클래스라는것을 확인할 수 있다.
하지만, 그 차이를 모르고 쓴다면 안쓰니만못하다.
각각의 차이가 무엇인지 알아보기 앞서 정의를 알아보겠습니다.
String- 짧은 문자열을 더할 경우 사용.
StringBuffer- Thread에 안전한 프로그램이 필요하거나 , 개발 중인 시스템의 부분이 Thread에 안전한지 모를경우 사용하면 좋다.
StringBuilder- Thread 안전한지 여부가 전혀 관계 없는 프로그램을 개발할때 사용하면 좋다.
STEP 05 . == 와 equals의 차이
String 관련 문자열을 비교하면서 항상 equals만 사용했을 것이다.
또한 ==도 비교 연산이고 equals도 비교연산인데 왜 ==을 안쓰고 equals를 사용하는지 궁금하지만 모르는사람이 있을수도 있다.
== 는 무엇이고 equals는 무엇인가 코드를 먼저 보고 출력결과를 예측해보고 알아보도록 하겠습니다.
package com.juniordev.firstweek;
public class StringEquals {
public static void main(String[] args) {
String first = "ABC";
String second = "ABC";
String equalsFirst = new String("ABC");
String equalsSecond = new String("ABC");
// 출력결과를 예상해봅시다.
System.out.println(first == second);
System.out.println(first == equalsFirst);
System.out.println(equalsFirst == equalsSecond);
System.out.println(first.equals(equalsFirst));
System.out.println(equalsFirst.equals(equalsSecond));
}
}
equals -객체가 가지고 있는 값을 비교.
==- 객체가 가지고 있는 값의 비교
그렇다면 일반 리터럴 변수로 생성한 String과 new를 이용하여 객체형식으로 생성된 String 에는 어떠한 차이가 있는지 알아보도록 하겠습니다 .
Java 7 미만에서는 String Constant Pool 영역이 Perm 영역에 저장되었으나 Java 7 이상부터는 String Constant Pool 영역이 Heap 영역에 저장된다.
리터럴과 객체로 생성하는것이 Heap 영역에 어떻게 저장되는지 사진으로 알아보곘습니다.
[이미지 참조 : https://brunch.co.kr/@kd4/1 ]
사진을 보면 알 수 있듯이 String 리터럴로 생성된 문자열은 Heap영역의 String Constant Pool 에 저장이 되어 다른 String 리터럴로 같은 Cat을 지정해도 같은 참조변수로 String Constant Pool 에 있는 Cat을 참조하게 되므로 ==와 equals로 비교했을때 True가 나온다.
하지만 String 클래스로 객체로 생성하였을경우 객체가 저장되는 Healp영역에 저장되어 실제 값은 같을수 있지만 그 객체를 참조하는 참조변수값이 달라 참조값으로 비교하는 == 연산자를 사용했을때는 참조변수 값이 달라 False가 출력된다.
따라서 위의 그림을 보면 s1 == s3를 하였을때 일반 리터럴 변수와 객체를 비교하였기 때문에 False가 출력된것을 확인 할 수 있다.
이제 다시 위의 작성된 예제를 돌려보고 한번더 이해하는 시간을 가져보는것을 추천한다.