상속이라는 것은 부모가 자식에게 물려주는 행위를 말합니다.
public class Car {
static final String company = "GENESIS"; // 자동차 회사
String model; // 자동차 모델
String color; // 자동차 색상
double price; // 자동차 가격
double speed; // 자동차 속도 , km/h
char gear = 'P'; // 기어의 상태, P,R,N,D
boolean lights; // 자동차 조명의 상태
Tire[] tire;
Door[] door;
Handle handle;
public Car(String model, String color, double price) {
this.model = model;
this.color = color;
this.price = price;
}
// 가변 길이의 배열을 받기 위함입니다.
public void setTire(Tire ... tire) {
this.tire = tire;
}
public void setDoor(Door ... door) {
this.door = door;
}
public void setHandle(Handle handle) {
this.handle = handle;
}
public double gasPedal(double kmh, char type) {
changeGear(type);
speed = kmh;
return speed;
}
public double brakePedal() {
speed = 0;
return speed;
}
public char changeGear(char type) {
gear = type;
return gear;
}
public boolean onOffLights() {
lights = !lights;
return lights;
}
public void horn() {
System.out.println("빵빵");
}
}
다중상속
Java 는 기본적으로 다중상속을 허용하지 않습니다.
Why?
final
final 은 수정할 수 없는 값으로 선언을 하는 것이다. 하지만, 여기서 의문을 가질 수 있다. 상속 받은 클래스에서 변형을 하지 않으면 사용할 수 있지 않을까?
정답은, 아닙니다! 상속은 무조건 Overriding 이라는 개념이 같이 따라 다닙니다. 그래서 final 은 상속 자체가 불가 합니다.
Overriding
@Overriding 이라는 것은 부모 클래스로 부터 상속 받은 것을 재정의 하는 과정을 말합니다.
super
super 는 생성자와 관련이 있는 녀석입니다. 즉, 부모 클래스의 멤버를 참조할 수 있는 키워드 입니다.
객체 내부 생성자 및 메서드에서 부모 클래스의 멤버에 접근하기 위해서 사용할 수 있습니다.
자식 클래스 내부에서 선언한 멤버와 부모 클래스에서 상속받은 멤버와 이름이 같은 경우 이를 구분하기 위해서 사용됩니다.
public class SportsCar extends Car{
String engine;
String model = "Ferrari"; // 자동차 모델
String color = "Red"; // 자동차 색상
double price = 300000000; // 자동차 가격
public SportsCar(String engine) {
this.engine = engine;
}
public void booster() {
System.out.println("엔진 " + engine + " 부앙~\n");
}
public void setCarInfo(String model, String color, double price) {
super.model = model; // model은 부모 필드에 set
super.color = color; // color는 부모 필드에 set
this.price = price; // price는 자식 필드에 set
}
@Override
public double brakePedal() {
speed = 100;
System.out.println("스포츠카에 브레이크란 없다");
return speed;
}
@Override
public void horn() {
booster();
}
}

super()
super() 자신이 상속받은 부모의 생성자를 호출하는 메서드입니다.
super() 를 사용하여 부모 생성자를 호출해주는 메서드를 추가해줍니다.다형성이란, 여러 가지 형태를 가질 수 있는 능력을 말합니다.
b num = new a(); 가 가능하다는 의미입니다.B num = new a(); → A num = new a()다형성의 기능으로 인해 해당 클래스 객체의 원래 클래스 명을 체크하는 것이 필요한데 이때 사용할 수 있는 명령어가 instanceOf() 입니다.
// 다형성
class Parent { }
class Child extends Parent { }
class Brother extends Parent { }
public class Main {
public static void main(String[] args) {
Parent pc = new Child(); // 다형성 허용 (자식 -> 부모)
Parent p = new Parent();
System.out.println(p instanceof Object); // true 출력
System.out.println(p instanceof Parent); // true 출력
System.out.println(p instanceof Child); // false 출력
Parent c = new Child();
System.out.println(c instanceof Object); // true 출력
System.out.println(c instanceof Parent); // true 출력
System.out.println(c instanceof Child); // true 출력
}
}
미완성된 설계도라고 표현할 수 있다. 즉, 형식만 정의하고 자식 클래스에서 구현해서 사용하는 방식입니다.
public abstract class ClassName{
}
두 객체의 다리 역할을 해주는 형식입니다.
상속 관계가 없는 다른 클래스들이 서로 동일한 행위 즉, 메서드를 구현해야할 때 인터페이스는 구현 클래스들의 동인한 사용 방법과 행위를 보장해 줄 수 있습니다.
public interface InterfaceName{
}
public static final 이어야 합니다. 다만, 없어도 알아서 추가 해줍니다.implemens 라는 키워드로 받아서 구현합니다.extends 키워드를 사용합니다. 이것은 기존 클래스와 다르게 다중 상속이 가능합니다!
우선 요구사항은 다음과 같습니다.
간단한 계산기 구현으었으나, 연산자는 따로 빼서 Operator 라는 Interface의 operate(int a, int b)라는 메서드를 정의하여 각각의 클래스를 생성하여 구현했습니다.
AddOperator<class>
package weekOne.calculatorTwo.operator;
public class AddOperator implements Operator{
@Override
public double operate(int a, int b) {
return a+b;
}
}
위 같은 구현체를 Operator라는 Interface로 Overriding을 했기 때문에 위의 연산자를 사용하는 OperateCalculator 클래스에 Operator 객체를 생성했습니다.
OperateCalculator<class>public class OperateCalculator{
// 생성자로 받아온 변수를 저장하기 위한 용도
private int a;
private int b;
private char oper;
// 연산자를 받아와 쓰기 위한 Operator 객체 생성
private Operator operator;
// 계속 누적되지 않고 호출마다 db를 비워주기 위해 여기서 선언 및 정의
private List<Double> data = new ArrayList<>();
// 생성자
public OperateCalculator(int a, int b, char oper) {
this.a = a;
this.b = b;
this.oper = oper;
}
// 입력되는 연산자에 따라 Operator 객체를 그 안에 구현되어 있는 내부 연산 객체와 연결
public List<Double> calculate(char oper) {
switch (oper) {
case '+':
operator = new AddOperator();
break;
case '-':
operator = new SubtractOperator();
break;
case '*':
operator = new MultiplyOperator();
break;
case '/':
operator = new DivideOperator();
break;
}
// 해당 클래스 내의 List에 데이터를 저장 후 return
data.add(operator.operate(a, b));
return data;
}
}
Calculator<class>package weekOne.calculatorTwo;
import java.util.List;
public class Calculator implements Service{
// 기본적인 exit, removeFirst, inquiry 동작을 따로 Service로 구현해 상속받아
// 해당 클래스에 Overriding 한다.
// mode의 Interface
private List<Double> data;
// 어떤 모드를 실행할지를 결정 받고, 그에 따른 계산 결과를 생성자를 두개를 만들어 설계
public Calculator(int a) {
this.data = new CircleCalculator(a).calculate();
}
public Calculator(int a, int b, char oper) {
this.data = new OperateCalculator(a, b, oper).calculate(oper);
}
// 얻은 data에 방금 들어간 요소를 main에서 출력하기 위한 것
public double getAns() {
return data.getLast();
}
@Override
public void exited() {
System.out.println("This system will be shutdown.");
System.exit(0);
}
@Override
public void removeFirst() {
System.out.println("Remove " + data.getFirst() + ".");
data.removeFirst();
}
@Override
public void inquiry() {
System.out.print("DataBase : ");
for (Double ele : data) {
System.out.print(ele + " ");
}
System.out.println("\n");
}
}
main.java
public class App {
static Calculator calc;
static Scanner scanner = new Scanner(System.in);
static int swit;
public static void main(String[] args) throws CustomException {
// 원 넓이 / 사칙연산 선택 및 나머지 조건 입력
while(swit != 0){
swit = 0;
System.out.print("Which mode do you want to play? (Circle/Operators) : ");
String mode = upper(scanner.nextLine());
label:
while (true){
if(mode.equals("circle")){
System.out.print("반지름을 입력하세요 : ");
int num1 = Integer.parseInt(scanner.nextLine());
calc = new Calculator(num1);
}else if(mode.equals("rect")){
System.out.print("첫번째 정수를 입력하세요 : ");
int num1 = Integer.parseInt(scanner.nextLine());
System.out.print("두번째 정수를 입력하세요 : ");
int num2 = Integer.parseInt(scanner.nextLine());
System.out.print("연산자를 입력하세요 : ");
char operator = scanner.nextLine().charAt(0);
calc = new Calculator(num1, num2, operator);
}
System.out.println("Answer : " + calc.getAns());
System.out.print("How do you want to play? (change/exit/remove/inquiry) ");
String query = upper(scanner.nextLine());
switch (query) {
case "exit":
calc.exited();
swit++;
break;
case "remove":
calc.removeFirst();
break;
case "inquiry":
calc.inquiry();
break;
case "change":
break label;
}
}
}
}
public static String upper(String mode){
return mode.toLowerCase();
}
}
IoC(제어 역전)은 프로그램의 개체나 부분에 대한 제어를 컨테이너나 프레임워크로 전송하는 소프트웨어 엔지니어링의 원칙입니다. 이러한 원칙은 OOP(객체지향 프로그래밍) 기법에서 자주 사용되는 개념입니다.
기존의 라이브러리에 요청을 하여 코딩하는 방법들과는 상반되게 IoC는 Framework를 우리의 프로그램의 흐름에 맞게 그리고 우리 코드에 맞게 요청을 하여 컨트롤 할 수 있습니다. 이러한 기능은 구현하기 위해서, Frameworks는 추가 동작이 내장된 추상화를 사용합니다. 만약 우리가 특정 동작(기능)을 추가하고 싶으면, 우리는 프레임워크 혹은 플러그인 클래스들을 우리 확장해서 사용해야 합니다.
이렇게 IoC 구조의 장점을 아래와 같습니다.
즉, 다른 객체를 직접 생성하거나 제어하는 것이 아니라 외부에서 관리하는 객체를 가져와 사용하는 것을 말하며 아래 코드의 예시를 들겠습니다.
public class A{
b = new B();
}
public class A{
private B b;
}
이렇게 스프링은 직접 생성하는 것이 아니라, 어딘가에서 받아와서 사용합니다. 여기서 위 같은 객체를 가져오는 곳은 Spring Container입니다.
Dependency Injection은 우리가 IoC를 제어가 역전된, 즉 불러와서 사용하는 객체의 의존성들을 설정하는 패턴 중 하나입니다. 그러면 어떻게 Dependencies 를 주입하는지에 대해서 알아봅시다.
public class Store{
private Item item;
public Store(){
item = new ItmeImpl();
}
}
위의 예시를 보면 구현체의 상위에 있는 Interface를 Container에서 불러와서 주입하여 주는 방식입니다. 하지만, DI를 사용하면 아래와 같이 다시 작성해볼 수 있습니다.
public class Store{
private Item item;
public Store(Item item){
this.item = item;
}
}
위의 내용도 간단하게 정리를 하면, DI는 어떤 클래스가 다른 클래스에 의존한다는 의미입니다.
public class A{
@Autowired
B b;
}
바로 위의 예시에서 사용하는 @Autowired는 애너테이션 중에 하나로, 스프링 컨테이너에 있는 빈이라는 것을 주입하는 역할을 합니다. 여기서 빈은 스프링 컨테이너에서 관리하는 객체를 말합니다.

빈은 스프링 컨테이너가 생성하고 관리하는 객체를 말합니다. 위에서 @Autowired로 주입받은 B객체가 바로 빈입니다. 스프링 빈은 스프링 컨테이너에 등록하기 위해 XML 파일에 설정하거나, 애너테이션으로 등록하는 등의 방법을 제공합니다. 예시를 들어 보겠습니다.
public class A{
@Autowired
B b;
}
@Bean
public class B{
}
@Configuration
@ComponentScan("com.baeldung.constructordi")
public class Config {
@Bean
public Engine engine() {
return new Engine("v8", 5);
}
@Bean
public Transmission transmission() {
return new Transmission("sliding");
}
}
@Component
public class Car {
@Autowired
public Car(Engine engine, Transmission transmission) {
this.engine = engine;
this.transmission = transmission;
}
}
이 부분은 조금 더 공부를 합시다....
Reference
1. https://velog.io/@rhdmstj17/java.-super와-super-완벽하게-이해하기
2. IoC / DI
3. IoC / DI