강의에서 객체지향에 대해 옛날 컴퓨터로 예를 들어 설명해주시는 부분이 인상 깊었다.
예전에는 컴퓨터의 본체, 모니터, 키보드가 하나로 단일화되어 있어 한 부분이 망가지면 새로 사야하거나 고치는데 돈이 많이 들었다.
현재는 모니터, 본체, 키보드를 분리하여 기능들을 부품화 시킨 덕분에 구성요소 중 하나가 고장났을시 교체가 용이해지게 되었다.
=> 객체지향을 사용하는 이유
하지만 기술이 경량화되며 컴퓨터는 작아지게 되었고 그 결과 부품화는 제거되고 있다. => 상황에 따라 부품화는 중요하지만 그보다 중요한 것은 적절한 사용
문제점1. 메소드 vs 객체지향 무엇이 다를까?
기능이 저장되어있는 메소드를 통해 코드의 양을 극적으로 줄일 수 있다.
BUT 프로그램이 커지면 많은 메소드들이 생기기 때문에 메소드와 변수를 관리하기 어려워짐 => 발전의 필요성
매소드의 집합 = 객체(프로그램 안의 작은 프로그램)메소드는 하나의 프로젝트에서 밖에 못쓰지만 객체는 호출하여 여러 프로그램에 쓸 수 있다.
class Calculator{
int left, right;
int void setOprands(int left, int right){
this.left = left;
this.right = right;
}
public void sum(){
System.out.println(this.left+this.right);
}
public void avg(){
System.out.println((this.left+this.right)/2);
}
}
//Calculator의 설계도, 즉 class
//Calculator 안에 있는 setOprands는 메소드임
this.left와 left의 차이점
this.left = Calculator class안에 있는 left 변수 전부
left = 우리가 left에 직접 입력한 값
*은닉화(캡슐화): 작동원리가 어떻게 되어있는지를 인지하지 못하더라도 사용방법만을 통해 쓸 수 있는 것.
은닉화가 잘 되어있을수록 좋은 객체이다.
클래스: 설계도
인스턴스: 만들어진 물건
클래스 속 변수는 모든 인스턴스에 영향을 미침
인스턴스의 변수는 각 인스턴스에서도 별개의 값을 가질 수 있음
모든 인스턴스가 공유하는 값
인스턴스에 따라 변하지 않는 값 클래스에 변수 지정
인스턴스를 생성할 필요가 없는 값
=> 클래스에 변수 지정
Calculator c1 = new Calculator();
//Calculator라는 객체 생성 후 c1이라는 변수에 담음
=> 이러한 과정을 통틀어 인스턴스라고 함
c1.setOprands(10,20);
c1.sum();
c1.avg();
객체는 상태와 행위의 집합이라고 할 수 있다.
Calculator 객체에서 left=10, right=20이라고 하자.
이 값이 상태이고 이 값을 통해 결과를 얻는 과정을 행위라고 한다.
인스턴스 메소드 -> 클래스 맴버 접근 O
클래스 메소드 -> 인스턴스 맴버 접근 X
클래스를 기반으로 인스턴스가 생성되는 것이기 때문에 선후관계로 인해 접근할 수 없다.
디렉토리로 설명한 부분이 인상깊었다.
파일을 저장할 때 이름이 겹치면 저장이 안된다.
숫자, 기호, 띄어쓰기 등을 동원하여 안겹치도록 하지만 불편함
=> 디렉토리 도입을 통해 같은 디렉토리 안에서는 이름이 중복되면 안되지만 다른 디렉토리 안에 있으면 중복이 허용된다.
=> 스코프 지정의 중요성
class Calculator{
int left, right;
int void setOprands(int left, int right){
this.left = left;
this.right = right;
}
public void sum(){
System.out.println(this.left+this.right);
}
public void avg(){
System.out.println((this.left+this.right)/2);
}
}
인스턴스를 만들고 클래스를 실행할 때 setOprands를 통해 값을 지정해줘야 한다는 불편함이 있음
class Calculator{
int left, right;
**public Calculator(int left, int right){
this.left = left;
this.right = right;
}**
public void sum(){
System.out.println(this.left+this.right);
}
public void avg(){
System.out.println((this.left+this.right)/2);
}
}
위에 코드처럼 수정해주면 따로 setOprands를 호출하여 변수를 지정할 필요가 사라진다. 이를 생성자라고 한다.
생성자는 클래스가 생성될때 클래스와 똑같은 이름을 가진 메소드(생성자)를 제일 우선으로 실행되도록 한다. 이를 초기화 작업이라고 한다.
객체지향을 통해 달성하고자 하는 제 1목표는 재활용성을 높이는 것이다.
상속은 객체지향의 재활용성을 극대화시키는 기법임.
상속은 왜 필요할까?
- 객체를 내가 만들지 않아서 소스를 변경할 수 없을 때 사용
- 잘 사용되지 않는 기능을 추가할 때
- 여러 상황에서 사용되는 객체에 기능을 추가할 때(인스턴스의 기능과 충돌할 수 있으므로)
기존의 객체는 기능을 물려준다는 의미에서 부모객체(상위클래스)가 되고,
새로운 객체는 기능을 물려받으므로 자식객체(하위클래스)가 된다.
class SubstractionableCalculator extends Calculator{
public void substruct(){
System.out.println(this.left - this.right)
}
}
위 코드에서 SubstractionableCalculator는 extends를 통해 Calculator를 부모객체로 하는 자식객체가 된다.
class Calculator{
int left, right;
public Calculator(int left, int right){
this.left = left;
this.right = right;
}
public void sum(){
System.out.println(this.left+this.right);
}
public void avg(){
System.out.println((this.left+this.right)/2);
}
}
class SubstractionableCalculator extends Calculator{
public void substruct(){
System.out.println(this.left - this.right)
}
}
위 코드에선 컴파일 오류가 뜰 것이다.
why? Calculator 기본 생성자가 없기 때문
위 코드를 오류없이 실행시키고 싶다면 클래스에 public Calculator(){}, 즉 기본 생성자를 추가하여 초기화를 시켜야 한다.
문제점 3. super에 대한 이해
강의를 들을 때 super에 대한 이해가 잘 되지 않아 추가적으로 찾아보았다.
super: 부모 생성자를 호출해주는 문법class Parent { Parent(int x) { System.out.println("부모"); } } class Child extends Parent { Child() { super(10); // 부모 생성자 호출 System.out.println("자식"); } }이때 super();를 통해 부모 생성자를 호출하지 않았다면 컴파일에러가 뜬다.
super를 사용하고 싶지 않다면 클래스에 기본 생성자를 추가해야 한다.
기존에는 부모 클래스의 기능에 자식 클래스를 이용하여 기능을 새롭게 추가하는 것에 대한 이야기를 했다.
이번 overriding은 자식 클래스가 부모 클래스의 기본적인 동작방법을 변경하는 기능을 수행한다.
class Calculator{
int left, right;
public Calculator(int left, int right){
this.left = left;
this.right = right;
}
public void sum(){
System.out.println(this.left+this.right);
}
public void avg(){
System.out.println((this.left+this.right)/2);
}
}
class SubstractionableCalculator extends Calculator{
public void sum(){
System.out.println("실행 결과는 " + (this.left + this.right) + "입니다");
}
public void substract(){
System.out.println(this.left - this.right);
}
위 아래 모두 sum이라는 메소드가 저장되어 있다.
이 코드를 실행해보면 자바는 부모클래스의 sum이 아닌 자식 클래스의 sum을 실행시킨다는 것을 알 수 있다.
부모 클래스와 자식 클래스 모두 가지고 있는 메소드를 실행시킴
=> 자식 클래스의 메소드를 더 우선 순위에 둔다.
BUT. 부모와 자식 메소드의 리턴 데이터 타입과 이름, 매개변수의 개수, 데이터 타입, 순서가 일치해야 한다.
같은 메서드 이름을 가지고 있더라도 매개변수의 데이터 개수와 타입, 순서가 바뀌면 충돌 X
다음은 예시이다.
class Calculator{
int left, right;
int third = 0;
public void setOprands(int left, int right){
System.out.println("setOprands(int left, int right)");
this.left = left;
this.right = right;
}
**public void setOprands(int left, int right, int third){
System.out.println("setOprands(int left, int right, int third)");
this.left = left;
this.right = right;
this.third = third;
** }
public void sum(){
System.out.println(this.left+this.right+this.third);
}
public void avg(){
System.out.println((this.left+this.right)/2);
}
}
매소드 오버로딩은 매개변수를 기준으로 사용된다.
=> 매개변수가 같지만 리턴타입이 다르면 오류가 발생한다.
문제점 3. overriding과 overloading의 헷갈림
overriding과 overloading이 헷갈린다.
하지만 당장 이 이름을 외우는 것보다 코드를 써보며 기능을 익히는 것이 더 중요하다고 하셔서 간단하게만 정리해 보겠다.
Overriding: 부모 클래스의 메서드를 자식 클래스에서 다시 정의하는 것
Overloading: 같은 이름의 메서드를 여러 개 만드는 것
컴퓨터의 저장장치 어딘가에 존재하는 클래스 파일을 사용하기 위한 수단
하나의 클래스 안에서 같은 이름의 클래스들을 사용하기 위한 수단
intellij에서 패키지를 사용해보았기 때문에 익숙한 느낌이 든다.
어떻게 객체지향을 활용해서 부품화를 하고 복잡성을 줄일 수 있는 건가, 메소드와 뭐가 다른거지 하는 의문이 남아있었는데 경로와 패키지를 활용하여 클래스를 불러오는 것이구나를 깨달았다.
더불어 intellij가 정말 편리한 것임을 알게되었다.
API
System.out.println(1);위 코드에서 print(1)은 메소드, System.은 클래스, out은 변수이다.
우리는 어떻게 불러오지도 않은 클래스 System을 쓸 수 있는 것일까?
=> System은 java lang에 있는 클래스, 이 패키지에 있는 클래스들은 자바 코딩을 할 때 매우 필수적이고 자주 사용하고 중요하기 때문에 자동으로 import되어 사용할 수 있게 되어있다.
package control;
class A{
public String y(){
return "public void y()";
}
private String z(){
return "public void z()";
}
public String x(){
return z();
}
}
public class Access {
static void main(String[] args) {
A a = new A();
System.out.println(a.y());
//아래 코드는 오류를 발생시킨다.
//System.out.println(a.z());
System.out.println(a.x());
}
}
위 코드에서 private로 묶인 z는 호출할 수 없다.
=> 접근이 클래스 내부로 제한되어있기 때문
BUT. public인 x를 통해 우회하여 z를 쓸 수 있다.

왜 접근제어자를 사용하는가?
- 데이터를 보호하기 위해
모든 변수나 메서드를 아무데서나 접근할 수 있게 하면
값이 마음대로 바뀌어서 프로그램이 망가질 수 있음- 역할을 나누기 위해
외부에서 사용하는 기능과 내부 기능을 구분하기 위함- 코드 유지보수를 쉽게 하기 위해
접근 범위를 제한하면 코드 구조가 깔끔해지고 수정이 쉬워짐
위는 클래스 맴버에 관한 접근제어자였다. 이번엔 클래스의 접근제어자를 알아보자. 클래스의 접근제어자는 public과 default로 나뉜다.

=> 메소드의 핵심만 정의해놓고 그 메소드의 실제 동작은 하위 클래스에 위임하고 있음
왜 abstract를 사용하는가?
공통적인 부분만 정의하고 상황에 따라 가변적이 될 수 있는 부분은 사용자에게 위임함. 주로 큰 프로젝트에서 사용되는 경우가 많음.
일회성 클래스를 여러개 만들기보다 공통된 부분만 클래스를 만들어 두는 것
final
abstract와 반대되는 개념
field: 변경을 금지시킴
메소드, 클래스: 상속을 금지시킴
abstract와 interface
공통점: 자식클래스가 메소드를 추가해야함
차이점: 인터페이스는 클래스가 아닌 고유한 형태를 가지지만 abstract는 추상 클래스로 존재함, 인터페이스는 구체적인 로직이나 상태를 가지지 못하는 반면 추상 클래스로서 구체적인 메소드를 가질 수 있음.
abstract는 기능을 만들어놓고 추가하는 느낌이라면
interface는 기능의 규칙만 정해놓고 나머지 전부를 만드는 느낌
결과
package lion.Week2;
import java.util.Scanner;
public class step1 {
static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
System.out.println("아기사자의 이름을 입력해주세요!");
String name = scanner.nextLine();
System.out.println("전공을 입력해주세요!");
String major = scanner.nextLine();
System.out.println("기수를 입력해주세요!");
int grade = scanner.nextInt();
System.out.println("입력값 검증을 진행합니다.");
if (name == null){
System.out.println("이름은 비어있을 수 없습니다.");
return;
}
else if (major == null){
System.out.println("전공은 비어있을 수 없습니다.");
return;
}
else if (grade < 1){
System.out.println("올바르지 않은 기수입니다.");
}
else
System.out.println("입력값 검증에 성공하여 아기사자 객체 생성을 진행합니다.");
System.out.println("아기사자 객체정보를 성공적으로 저장하였습니다!");
System.out.println("아기사자 정보를 출력합니다.");
System.out.println("이름: " + name + " / 전공: " + major+ " / 기수: " + grade);
}
}
문제를 제대로 안읽어서 오류가 떴다...
문제점4.
int형으로 받으면 빈값을 체크할 수 없음 => String으로 받고 나중에 변환

다시 문제 제대로 읽고 1보다 작으면 경고문구 뜨는 걸로 바꾸었다.
결과
package lion.Week2;
import java.util.Scanner;
public class step4 {
static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
System.out.println("아기사자 이름을 입력하세요: ");
String name = scanner.nextLine();
System.out.println("아기사자 전공을 입력하세요: ");
String major = scanner.nextLine();
System.out.println("아기사자 기수를 입력하세요: ");
int grade = scanner.nextInt();
System.out.println("입력이 완료되었습니다. 아기사자 객체 상태를 확인합니다.");
String result = Validation.validate(name, major, grade);
if (result == "success"){
Lion lion = new Lion(name, major, grade);
lion.printInfo();
}
else{
System.out.println(result);
}
}
}
문제점5.
점점 헷갈리기 시작하면서 앞내용이 기억 안나기 시작했다...(세미콜론도 안쓰고 대소문자도 안맞고 기수도 String으로 받음)
한개씩 입력받을 거라 저런식으로 썼었는데
모든 매개변수의 개수, 타입이 같아서 오류가 생긴 거였다.
=> 한번에 매개변수를 다 받는 생성자로 수정

결과
// 실행코드
package lion.Week3;
import java.util.Scanner;
public class step3 {
public static void main(String[] args){
Scanner scanner = new Scanner(System.in);
System.out.println("============아기사자 정보입력============");
System.out.println("이름: ");
String newName = scanner.nextLine();
System.out.println("전공: ");
String newMajor = scanner.nextLine();
System.out.println("기수: ");
int newGrade = scanner.nextInt();
scanner.nextLine();
System.out.println("파트(백엔드 / 프론트엔드 / 디자인 / 기획): ");
String newPart = scanner.nextLine();
System.out.println("학번: ");
int newYear = scanner.nextInt();
scanner.nextLine();
System.out.println("============운영진 정보입력============");
System.out.println("이름: ");
String name = scanner.nextLine();
System.out.println("전공: ");
String major = scanner.nextLine();
System.out.println("기수: ");
int grade = scanner.nextInt();
scanner.nextLine(); //엔터지우기!!!!!!!!!!!
System.out.println("파트(백엔드 / 프론트엔드 / 디자인 / 기획): ");
String part = scanner.nextLine();
System.out.println("직책(대표 / 부대표 / 파트장 / 멘토): ");
String role = scanner.nextLine();
Lion lion = new Lion(newName, newMajor, newGrade, newPart, newYear);
Staff staff = new Staff(name, major, grade, part, role);
System.out.println();
System.out.println("============아기사자 정보============");
lion.printInfo();
System.out.println();
System.out.println("============운영진 정보============");
staff.printInfo();
}
}
//부모 클래스
package lion.Week3;
abstract class Member {
String name;
String major;
int grade;
String part;
public Member(String name, String major, int grade, String part) {
this.name = name;
this.major = major;
this.grade = grade;
this.part = part;
}
}
//자식클래스(스태프)
package lion.Week3;
class Lion extends Member implements SubmitPolicy{
int year;
public Lion(String name, String major, int grade, String part, int year){
super(name, major, grade, part);
this.year = year;
}
public boolean canSubmit() {
return true;
}
public void printInfo(){
System.out.println("==========결과 출력===========");
System.out.println("이름: " + name);
System.out.println("전공: " + major);
System.out.println("기수: " + grade);
System.out.println("파트: " + part);
System.out.println("학번: " + year);
System.out.println("과제제출 가능여부: " + canSubmit());
}
}
//자식 클래스(아기사자)
package lion.Week3;
class Staff extends Member implements SubmitPolicy{
String role;
public Staff(String name, String major, int grade, String part, String role){
super(name, major, grade, part);
this.role = role;
}
public boolean canSubmit() {
return false;
}
public void printInfo(){
System.out.println("==========결과 출력===========");
System.out.println("이름: " + name);
System.out.println("전공: " + major);
System.out.println("기수: " + grade);
System.out.println("파트: " + part);
System.out.println("역할: " + role);
System.out.println("과제제출 가능여부: " + canSubmit());
}
}
//인터페이스
package lion.Week3;
public interface SubmitPolicy {
boolean canSubmit();
}
문제점6.
1. 변수이름을 똑같이 설정해서 오류가 발생함
2. 인터페이스를 적용하는 방법이 익숙하지 않음(쳇GPT의 도움을 많이 받음...🥲)
3. nextInt() 뒤에 nextLine으로 엔터 없애야 하는 거 또 까먹음
이번주 과제를 하며 제일 크게 느낀 것은 벨로그 보기 좋게 만드는게 제일 어려운 것 같다는 점이다.
내용이 많아지니 체계적으로 보기 좋게 정리하는 것이 어렵고 쓰다보니 나조차도 점점 이걸 어디다 적어야 하는지 헷갈리기 시작했다.
그래도 미래의 내가 볼 거라고 생각하고 열심히 정리했다.
또한 overriding과 overloading, protected와 default처럼 이름과 기능이 헷갈리는 것들이 조금 있었는데 기가 막히게 그런 부분에서 강사님이 걱정할 필요가 없다고 해주셔서 마음이 놓였다.
나는 의외로 클래스 패스와 패키지 부분이 제일 힘들다고 느꼈는데 intellij를 쓸때에는 신경도 안썼던 부분에서 시간을 들여 공부를 한다고 느껴지니 더 집중을 못했던 것 같다.
그건 인텔리제이가 친절한 부분이지 나중에 자바 쓰게되면 다 필요한 것들인데....
인텔리제이에서는 간단하게 패키지를 만들고 경로를 설정할 수 있어서 이렇게 공부해야 하는 부분인지 몰랐다. 나중에 공동작업을 하게되거나 할때 경로에 대해 다시 더 공부해야 할 것 같다고 느꼈다.
이 집 트러블슈팅 맛집이군요. 마주친 문제와 해결과정을 기록하는 모습이 정말 대단합니다... 이 기록이 현재 마주치는 문제만이 아니라 나중에 마주칠 문제를 해결하는 근육이 될 것 같습니다! 수고하셨습니다~!
수빈님 글은 항상 일목요연하게 정리가 되어있으면서도, 내용이 정말 알차다고 느껴집니다. 문제를 풀때도 그냥 푸는게 아니라 같이 문제를 풀어가는 분위기로 술술 읽힌다는 것이 정말 놀라울정도.. 수고많으셨습니다~!!
저도 오버라이딩과 오버로딩의 차이에 대해서 많이 헷갈렸었어요…. 과제도 뭔가 혈투???가 많으셨는데 결국 잘 해내셔서 다행입니다 !! 과제 하시느냐고 수고 많으셨습니다!!