일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | |||||
3 | 4 | 5 | 6 | 7 | 8 | 9 |
10 | 11 | 12 | 13 | 14 | 15 | 16 |
17 | 18 | 19 | 20 | 21 | 22 | 23 |
24 | 25 | 26 | 27 | 28 | 29 | 30 |
- ineer join
- 베주계수
- 모던자바
- 동일성과 동등성
- toLowerCase()
- 최대공약수
- 자바 유클리드
- addDoc
- 프로그래머스 레벨1
- 스프링뼈대
- 유클리드호제법
- 자바 스트링
- while과 two-pointer
- islowercase()
- sql 데이터형 변환
- 자바 최소공배수
- stringbuilder의 reverse()
- 래퍼타입
- string
- replaceAll()
- 스프링
- 스프링환경설정
- git 컨벤션
- 최대공약수와 최소공배수
- string과 stringbuilder
- Git사용법
- 최소공배수
- StringBuilder
- isuppercase()
- 자바 최대공약수
- Today
- Total
주노 님의 블로그
20240723 본캠프 7일차 TIL 본문
본캠프 7일차 내용 간단요약
- 09:00 ~ 12:00 : 강의
3주차 예습 - 12:00 ~ 13:00 : 점심시간
- 13:00 ~ 14:00 : 코드카타
알고리즘 - 44 SQL-58 - 14:00 ~ 18:00 : 강의
3주차 1강 ~ 13강 - 18:00 ~ 19:00 : 저녁시간
- 19:00 ~ 21:00 : 강의
3주차 14강~18강 - 21:00 ~ 22:00 : TIL정리
오늘 해야할 일✔️ 🔺 ❌
✔️ 코드카타
✔️ 자바문법종합반3주차
강의 - 자바문법종합반 3주차
객체지향
- 객체
식별이 가능한 하나의 실체이다,
객체는 필드와 메서드로 이루어져 있다. - 객체의 상호작용
메서드의 호출을 통해 상호작용이 이루어진다.
person이라는 객체는 car와 상호작용을 하기위해 gasPedal(50) 메서드를 호출한다, 이때 필요한 값인 50을 매개변수로 전달한다. 입력을 받은 car 객체는 return값인 speed값을 반환해준다. - 매개변수
메서드에 값을 사용하기 위한 변수로 위 내용에서는 gasPedal의 괄호안에 들어가는 50 부분이다.
car은 이 50값을 받아서, 자동차의 속도를 50만큼 증가시킨후, 새로운 속도를 리턴해준다.
쉽게 요약해서 메서드가 필요로 하는 값을 외부로 받게 해주는 변수이다. - 객체 간의 관계
사용관계
한 객체가 다른 객체의 메서드를 호출하여 사용한다.
포함 관계 (HAS-A)
각각의 개체는 자동차 객체에 포함되어 있다(속한다)
상속 관계(IS-A)
한 클래스가 다른 클래스를 상속받는다. - 객체지향의 특징
캡슐화(은닉화) : 속성(필드) 행위(메서드)를 접근 제어자를 통해 외부에서는 알 수 없게 감추는 것
다형성 : 동일한 인터페이스나 메서드를 다양한 방식으로 구현 가능하다
상속 : 부모 클래스의 속성과 메서드를 자식 클래스가 물려받아, 코드 재사용성을 높인다
추상화 : 복잡한 시스템을 단순화하여 상위 개념으로 새롭게 선언하는것 - 객체와 클래스
클래스를 토대로 만들어진 객체를 해당 클래스의 인스턴스라고 부르며, 동일한 클래스에 여러개의 인스턴스를 만들 수 있다.
클래스는 new 키워드를 통해 객체를 만들고 그것을 인스턴스화 라고한다. - 클래스 만들어보기
아래 클래스 다이어그램을 보자..
위에서부터 클래스이름, 필드, 생성자, 메서드이다.
1. 클래스 선언 : public class Car{}
2. 필드 정의 : 데이터를 저장하는 역할을 한다.
String company; // 자동차 회사 String model; // 자동차 모델 String color; // 자동차 색상 double price; // 자동차 가격 double speed; // 자동차 속도 , km/h char gear; // 기어의 상태, P,R,N,D boolean lights; // 자동차 조명의 상태
3. 생성자 정의 : public Car() {} 빈 생성자는 생략가능하다.
4. 메서드 정의
gasPedal 설명 : 반환 타입이 더블인 메서드를 선언한다.double gasPedal(double kmh) { speed = kmh; return speed; } double brakePedal() { speed = 0; return speed; } char changeGear(char type) { gear = type; return gear; } boolean onOffLights() { lights = !lights; return lights; } void horn() { System.out.println("빵빵"); }
매개변수인 kmh를 전달받아 speed필드에 해당값을 저장한다.
onofflights는 매개변수(입력값)을 받지 않아도 반전으로 구현 가능하다 - 객체 생성
Car car1 = new Car(); 객체기때문에 생성하기 위해 new 키워드를 사용해야한다.
car 클래스의 접근제어자가 public이기 때문에 다른 클래스에서도 객체를 받아 올 수 있다!
객체는 배열 또는 컬렉션에도 저장이 가능하다.public class Main { public static void main(String[] args) { Car[] carArray = new Car[3]; Car car1 = new Car(); car1.changeGear('P'); carArray[0] = car1; Car car2 = new Car(); car2.changeGear('N'); carArray[1] = car2; Car car3 = new Car(); car3.changeGear('D'); carArray[2] = car3; for (Car car : carArray) { System.out.println("car.gear = " + car.gear); } } } // 출력 //car.gear = P //car.gear = N //car.gear = D
- 객체의 속성 : 필드
객체의 데이터를 저장하는 역할
외부접근 : .(도트연산자)를 사용하면 된다 car.color = "blue"
내부 접근 : 그냥 직접 접근하면된다 - 객체의 행위 : 메서드
서로 다른 객체의 조작을 위해서 메서드라는걸 쓰게된다.
반환할 값이 없다면 리턴 타입은 void리턴 타입 메서드명 (매개변수) { 실행할 코드 작성 리턴 값 }
리턴타입이 있다면 반환값은 리턴타입과 일치시켜야한다
매개변수의 순서에 맞게 작성을 해줘야한다.
매개변수는 입력. return은 출력이라고 생각하면 편하다
가변길이의 매개변수를 사용할수 있다 void carSpeeds(double ... speeds) 이렇게 - 메서드의 접근
외부접근 : 도트연산자로 접근한다 car.changeGear(geers);
내부접근 : 그냥 접근하면된다 changeGear(gears);
매개변수의 형, 값, 수를 일치시켜야한다. - 메서드 오버로딩
하나의 메서드 이름으로 여러가지 기능을 구현할 수 있는것
매개변수의 타입이 다를경우, 매개변수의 수가 다를경우, 매개변수의 순서가 다를경우는 오버로딩이 가능하다.
기본형 & 참조형 매개변수 모두 받을 수 있다.
다만, 매개변수의 타입이 기본형일 때 값 자체가 넘어가기때문에 원본값이 변경되지 않지만
참조형일때는 주소가 전달되기때문에 원본이 같이 변할수 있다.
장점 : 다양한 인수를 처리할수 있으므로, 코드의 중복을 제거할 수 있고, 코드의 가속성과 유지보수성을 올릴수 있다.
char type = 'D'; car.brakePedal(type); double brakePedal(char type) { speed = 0; type = 'P'; // 정지 후 매개변수 type을 어떤 타입으로 전달 받았는지 상관없이 'P'로 고정시키기 changeGear(type); return speed; }
위 코드에서는 type을 기본형인 char에 넣어서 전달을 했다, 기본형이기때문에 값만 전달해준것이며, brakepedal문에서 값을 변경하여도 원본 char type는 바뀌지않는다
Tire tire = new Tire(); tire.company = "금호"; // 금호 타이어 객체 생성 // 차 객체의 타이어를 등록하는 메서드 호출한 후 반환값으로 차 객체의 타이어 객체 반환 Tire carInstanceTire = car.setTire(tire); Tire setTire(Tire tireCompany) { tireCompany.company = "KIA"; // 금호 타이어를 전달 받았지만 강제로 KIA 타이어로 교체 tire = tireCompany; return tire; }
하지만 위 코드에서는 객체를 생성하고 객체를 전달하였기때문에 전달되는건 실제 객체의 값이 담겨있는 주소값만 전달되었고 setTire 메서드에서 실제 주소를 참조하여 변경하였기 때문에
원본 tire.company또한 변경되게 된다. - 멤버
클래스 내부에 선언된 필드와 메서드를 의미한다
인스턴스 멤버 : 인스턴스 필드 + 인스턴스 메서드 - 객체를 생성해야지만 사용가능 (new를 이용해서 생성)
클래스 멤버 : 클래스 필드 + 클래스 메서드 - 객체를 생성하지 않고도 사용가능 (static을 사용해야함)
클래스 멤버는 인스턴스 멤버를 사용할 수 없지만
인스턴스 멤버는 클래스 멤버를 클래스명.변수 로 사용 가능하다.
참조형 변수를 통해 클래스 접근은 할 수 있지만 추천하지는 않는다
이유는? 인스턴스에 속한것 처럼 보이기 떄문에. - 전역변수 지역변수
전역 변수 : 클래스 내에 선언된 변수로 모든 메서드에서 접근 할 수 있다, 프로그램이 종료되면 소멸된다.
지역 변수 : 해당 메서드 내에서만 사용되며, 메서드가 종료되면 소멸된다. - final
필드 타입 앞에 final 키워드를 주면 선언한다.
수정이 불가능하다 ->반드시 초기값을 지정해야한다.
변수명은 카멜케이스지만 상수는 전체문자를 대문자로 선언한다. - 상수
값이 고정되어 변경되지 않는 변수이며, 프로그램 종료까지 값이 변하지 않도록 보장함. - 생성자
객체가 생성될때 호출되며 객체를 초기화하는 역할 수행
클래스 이름과 동일하며, 반환 타입도 없다
위가 기본 생성자이며 객체가 생성될때 위 생성자가 호출된다.public class Car{ public Car() {}//생성자 }
public class Car { // 기본 생성자 public Car() { System.out.println("Car 객체가 생성되었습니다."); } public static void main(String[] args) { // 기본 생성자를 사용하여 Car 객체를 생성 Car myCar = new Car(); // 출력: Car 객체가 생성되었습니다. } }
위 처럼 객체가 생성될 시 기본생성자가 호출되는것을 볼 수 있다.
또는 기본 생성자는 만들지 않아도 자동으로 호출된다
하지만 위와 같은 경우에는 이미 만들어진 생성자가 있기때문에
기본생성자는 자동으로 생성되지않으며 오류를 뱉는다
생성자 또한 오버로딩을 적용 할 수 있다. - this와 this()
this는 현재 객체 자신을 표현
여기서 this.model은 인스턴스 변수 즉 private String model 을 참조하는것이고
model은 매개변수를 가리킨다.
생성자를 선언하는데 매개변수명과, 객체의 필드명이 동일할경우, 오류는 생기지 않지만, 가장 가까운 매개변수명을 가르켜 둘다 자신에게 값을 대입하는것을 방지하기 위해서이다.
this()는 자신의 생성자를 호출하는 키워드이다.
위의 this는 자신의 객체인 car을 가르키는것이다.
this를 사용하면 코드의 중복을 제거할 수 있다.
this위에 아무것도 있으면 안된다
위는 오류가 발생한다 - 접근 제어자
멤버 또는 클래스에 사용이나, 외부에서 접근하지 못하도록 제한하는것
접근제어자 클래스명 (매개변수명){로직}
으로 구성되며, 접근제어자가 생략된 경우 default이다.
클래스에서 사용 가능한 접근제어자
public : 어디서나 접근 가능하다
default : 같은 패키지 내에서만 접근 가능하다.
메서드 & 멤버변수 에서 사용 가능한 접근제어자
public , default
protected : 같은 패키지 내에서 접근 가능하며, 다른 패키지의 하위클래스에서 접근가능
private : 같은 클래스 내에서만 접근 가능
접근 제어자의 목적은 객체지향의 4가지 특징중의, 캡슐화(은닉성)이다
생성자에서 접근제어자를 사용함으로 인스턴스의 무분별한 생성을 방지 할 수 있다 - 접근제어자의 조합
클래스 : public, default, final, abstract
메서드 : public, protected, default, private, final, abstract, static
멤버변수 : public, protected, default, private, final, static
지역변수 : final
메서드에 static과 abstract를 함께 사용할 수 없다. - static은 클래스 레벨에서 호출되며, 하위 클래스에서 오버라이딩 불가능, abstract는 다른 클래스에서 상속받아와야함.
클래스에 abstract와 final을 동시에 사용할 수 없다. - abstract는 다른 클래스에서 상속받아와야 하지만, final 클래스는 상속할수 없게 함
abstract메서드의 접근 제어자가 private일 수 없다. - abstract은 자식 클래스에서 반드시 구현해야한다, private는 해당 클래스 내부에서만 접근 가능하면, 상위 클래스가 접근할 수 없음
메서드에 private와 final을 같이 사용할 필요는 없다. - private와 final은 오버리이딩을 방지하기때문에 서로 사용할 필요는 없다.
public abstract void myMethod();
이렇게 사용하면 된다 - Getter와 Setter
getter와 setter는 외부에서 객체의 필드에 직접 접근하지 못하도록 하고, 대신 메서드를 통해 접근하도록 한다.
필드는 프라이빗으로 정의되어있다 이 필드를 정의할때 getter setter메서드를 사용하며 네이밍은 get필드이름이다. 필드이름의 첫번째 글자는 카멜 표기법에 다라 대문자로 표현한다.
필드
Getter
외부에서 객체의 private 필드를 조회해야할때 getter을 사용한다.
Setter
외부에서 객체의 private 필드를 수정해야할때 setter을 사용한다
- package와 import
package
책 두권이 있고 두권에 조나단이 있을때 조나단을 짚으면 a책의 조나단인지, b책의 조나단인지 알 수가없음
그것을 식별하기 위한 용도임
즉, 패키지는 클래스를 식별해주는 용도다.
package 상위패키지.하위패키지; 로 선언 할 수 있다>
import
다른 패키지에 있는 클래스를 사용하기 위해서 명시하는 키워드
import 상위패키지.하위패키지.클래스;이다
우리가 자주 사용하는 import java.util.Scanner; 또한 자바 패키지 하위의 유틸패키지의 스캐너 클래스를 사용하기위해 불러오는것이다
패키지 내의 모든 클래스를 가져오기 위해서는
import java.util.*;을 사용하면 된다. - 상속
부모 클래스의 필드와 메서드를 자식 클래스에 물려 줄 수 있다
적은 양의 코드로 새로운 코드를 만들수 있으며, 중복이 제거되고, 재사용성이 증가한다.
클래스 간의 상속은 extends 키워드를 사용하며
public class 자식클래스명 extends 부모클래스 {} 처럼 사용된다.
- 단일 상속과 다중 상속
자바는 다중 상속을 허용하지 않는다 - Object(클래스 명)
Object 클래스는 자바에서 최상위 부모 클래스이다.
모든 클래스는 Object클래스를 이용 가능하고, 부모클래스가 없는 자식클래스는 자동으로 Object클래스를 상속받게 된다. - 오버라이딩
부모 클래스로부터 상속받은 메서드의 내용을 재정의 하는것을 오버라이딩 이라고 한다
선언부가 부모 클래스의 메서드와 일치해야 한다.
접근 제어자를 부모 클래스의 메서드 보다 좁은 범위로 변경할 수 없다.
예외는 부모 클래스의 메서드 보다 많이 선언할 수 없다.
부모클래스 car
public class Car { String company; // 자동차 회사 private String model; // 자동차 모델 private String color; // 자동차 색상 private double price; // 자동차 가격 double speed; // 자동차 속도 , km/h char gear = 'P'; // 기어의 상태, P,R,N,D boolean lights; // 자동차 조명의 상태 public String getModel() { return model; } public void setModel(String model) { this.model = model; } 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("빵빵"); } }
자식클래스 sportscar
public class SportsCar extends Car{ String engine; public void booster() { System.out.println("엔진 " + engine + " 부앙~\n"); } public SportsCar(String engine) { this.engine = engine; } @Override public double brakePedal() { speed = 100; System.out.println("스포츠카에 브레이크란 없다"); return speed; } @Override public void horn() { booster(); } }
1. 선언부가 부모 클래스와 일치하는가? : 네.//부모클래스 public double brakePedal() { speed = 0; return speed; } //자식클래스 @Override public double brakePedal() { speed = 100; System.out.println("스포츠카에 브레이크란 없다"); return speed; }
2. 접근제어자를 부모보다 넓은 범위인가? : 같음
3. 예외는 부모 클래스의 메서드보다 많이 선언했는가? : 아니요 같음.
부모 클래스의 브레이크 페달 메서드를 재정의 하여 print문을 추가하였고, 기본 속도를 수정하였다. 물론 부모클래스에는 영향을 주지 않는다. - super와 super()
super
부모 클래스의 멤버에 접근하기 위해 사용된다.
위의 super.model은 부모클래스의 model을, this.price는 자식클래스의 price를 가져온다.// 부모 클래스 Car String model; // 자동차 모델 String color; // 자동차 색상 double price; // 자동차 가격 // 자식 클래스 SportsCar String model = "Ferrari"; // 자동차 모델 String color = "Red"; // 자동차 색상 double price = 300000000; // 자동차 가격. //자식 클래스의 메서드 public void setCarInfo(String model, String color, double price) { super.model = model; // model은 부모 필드에 set super.color = color; // color는 부모 필드에 set this.price = price; // price는 자식 필드에 set }
super()
부모 클래스의 생성자를 호출한다
// 부모 클래스 Car 생성자 public Car(String model, String color, double price) { this.model = model; this.color = color; this.price = price; } // 자식 클래스 SportsCar 생성자 public SportsCar(String model, String color, double price, String engine) { // this.engine = engine; // 오류 발생 super(model, color, price); this.engine = engine; }
자식 클래스의 생성자는 부모 클래스의 생성자를 먼저 호출해야한다. - 다형성
같은 이름의 메서드라도 메서드의 매개변수나 반환값에 따라 다양하게 구현 할 수 있는것 - 참조 변수의 타입변환
자동타입변환
부모타입변수 = 자식타입객체; 는 자동으로 부모 타입으로 반환이 일어난다(업캐스팅)
자식클래스 객체는 부모 클래스타입으로 자동 변환해준다.
강제타입변환
자식타입변수 = (자식 타입) 부모 타입 객체;
부모 클래스의 변수를 자식 객체로 변환하여 자식클래스의 메서드를 사용할 수 있게 한다.
class Mammal { // 포유류는 새끼를 낳고 모유수유를 한다. public void feeding() { System.out.println("모유수유를 합니다."); } } class Whale extends Mammal { // 고래는 포유류 이면서 바다에 살며 수영이 가능하다. public void swimming() { System.out.println("수영하다."); } @Override public void feeding() { System.out.println("고래는 모유수유를 합니다."); } } public class Main { public static void main(String[] args) { Mammal mammal = new Whale(); // 자동 타입 변환 mammal.feeding(); // "고래는 모유수유를 합니다." 출력 // mammal.swimming(); // 컴파일 오류: Mammal 타입에서는 swimming() 메서드를 사용할 수 없음 Whale whale = (Whale) mammal; // 강제 타입 변환 whale.swimming(); // "수영하다." 출력 } }
whale은 부모 타입변수인 mammal로 자동타입변환이 되었다, whale객체가 mammal타입의 변수에 할당된것이다.
mammal은 Mammal타입이지만, 객체는 whale이기 때문에 고래는 모유수유를 합니다를 출력한다.
mammal타입은 Mammal타입이기 때문에 정의되지 않은 swim은 호출할수가 없다 비록 객체는 whale객체지만 타입 자체는 mammal이기때문이다.
(Whale)타입으로 부모를 강제 형변환을 하게되면, swimming도 출력가능하다.근데 고래도 모유수유해?>
- 추상 클래스 추상메서드
추상클래스는 abstract를 사용하여 추상클래스를 선언할 수 있습니다. 추상클래스는 완성되지 않은 클래스로, 추상메서드를 포함할 수 있으며, 자식클래스는 그것을 상속받아 추상 메서드를 구현하여 클래스를 완성시킨다. 원래 클래스는 자식 클래스가 부모 클래스를 이용하는거라면, 추상클래스는 다른 클래스들이 공통적으로 들어갈 필드를 정의만 하고, 자식클래스에서는 그 내용을 오버라이딩하여 완성시킨다.
추상클래스의 용도: 여러개의 자식 클래스에서 공통적인 필드나 메서드를 추출해서 코드의 중복을 제거하고 유지보수를 용이하게 만들기 위해서 사용합니다.
자식 클래스에서 알아서 정의하라는 뜻으로 추상 메서드를 빈칸으로 놓고, 자식클래스에서 스스로 정의한다. - 추상 클래스 만들기.
1. 각각의 클래스들에서 공통된 내용을 뽑는다
public class BenzCar { String company; // 자동차 회사 : GENESIS String color; // 자동차 색상 double speed; // 자동차 속도 , km/h public double gasPedal(double kmh) { speed = kmh; return speed; } public double brakePedal() { speed = 0; return speed; } public void horn() { System.out.println("Benz 빵빵"); } } public class AudiCar { String company; // 자동차 회사 : GENESIS String color; // 자동차 색상 double speed; // 자동차 속도 , km/h public double gasPedal(double kmh) { speed = kmh; return speed; } public double brakePedal() { speed = 0; return speed; } public void horn() { System.out.println("Audi 빵빵"); } } public class ZenesisCar { String company; // 자동차 회사 : GENESIS String color; // 자동차 색상 double speed; // 자동차 속도 , km/h public double gasPedal(double kmh) { speed = kmh; return speed; } public double brakePedal() { speed = 0; return speed; } public void horn() { System.out.println("Zenesis 빵빵"); } }
위 코드를 보면 공통된 horn, brake, gaspedal이 있다.
위 세 메서드를 묶어서 추상클래스를 구현해 거기다가 공통된 메서드를 묶어보자
위 코드가 수정된 코드이다public class W15AudiCar extends W15Car{ @Override public void horn() { System.out.println("Audi 빵빵"); } } public class W15BenzCar extends W15Car { @Override public void horn() { System.out.println("Benz 빵빵"); } } public class W15GenesisCar extends W15Car { @Override public void horn() { System.out.println("Zenesis 빵빵"); } } public abstract class W15Car { String company; // 자동차 회사 String color; // 자동차 색상 double speed; // 자동차 속도 , km/h public double gasPedal(double kmh) { speed = kmh; return speed; } public double brakePedal() { speed = 0; return speed; } public abstract void horn(); }
W15car를 abstrac으로 선언하면서 추상클래스임을 명시하고, 공통된 부분인 gaspedal과, brakepedal은 추상클래스에서 명시해주고
서로 다른 horn메서드는 또한 추상메서드로 정의해 각자 구현할수있게 바꾸었다.
추상 클래스로인해, 코드 가독성부분이 크게 향상된것을 볼 수 있다. - 인터페이스
상속 관계가 없는 다른 클래스에서 동일한 메서드를 구현하도록 강제한다.
interface Vehicle { void start(); void stop(); }
인터페이스는 추상메서드(public abstrac또는 생략)와 상수(public static final 또는 생략)만을 포함하며.
다중 상속을 지원하지 않는 자바에서도, 다중상속처럼 느껴지게 구현 할 수 있다.
인터페이스는 직접 인스턴스를 생성 할 수 없기때문에 클래스에 구현된다 그때는 implements를 사용한다.
인터페이스간의 상속도 가능하며, 그때는 extends를 사용한다.public class 클래스명 implements 인터페이스명 { // 추상 메서드 오버라이딩 @Override public 리턴타입 메서드이름(매개변수, ...) { // 실행문 } }
public class Main extends D implements C { @Override public void a() { System.out.println("A"); } @Override public void b() { System.out.println("B"); } @Override void d() { super.d(); } public static void main(String[] args) { Main main = new Main(); main.a(); main.b(); main.d(); } } interface A { void a(); } interface B { void b(); } interface C extends A, B { } class D { void d() { System.out.println("D"); } }
메인클래스는 d 클래스를 상속받아 c인터페이스를 구현한다. c는 void a와 void b를 가지고 있는것과 같다. - 디폴트 메서드와 static 메서드
디폴트 메서드
인터페이스에 기본 구현을 제공하는 메서드이다, 인터페이스의 기능을 확장하면서 기존 구현 클래스와의 호환성을 유지할 수 있다
default void myDefaultMethod() { // 기본 구현 }
재정의 할 수 있으며, 추상클래스처럼 재정의가 필수사항이 있는게 아니다.
디폴트 메서드에서 기본 구현한 내용을 받아쓸수도, 재정의할수도 있는것이다.
default키워드로 메서드를 만들면 오버라이드를 하지 않아도 사용이 가능하다public class Main implements A { @Override public void a() { System.out.println("A"); } public static void main(String[] args) { Main main = new Main(); main.a(); // 디폴트 메서드 재정의 없이 바로 사용가능합니다. main.aa(); } } interface A { void a(); default void aa() { System.out.println("AA"); } }
- 인터페이스의 다형성
자동 타입 변환
인터페이스 변수 = 구현객체; 는 자동으로 타입변환이 일어난다
A a1 = new B
A인터페이스지만 B객체를 가지고 있다
강제 타입 변환
구현 객체 타입 변수 = (구현 객체 타입) 인터페이스 변수;
public class Main { public static void main(String[] args) { // A 인터페이스에 구현체 B 대입 A a1 = new B(); a1.a(); // a1.b(); // B객체를 불러오긴 하지만 A인터페이스기때문에 불가능 System.out.println("\nB 강제 타입변환"); B b = (B) a1; b.a(); b.b(); // 강제 타입변환으로 사용 가능 System.out.println(); // A 인터페이스에 구편체 B를 상속받은 C 대입 A a2 = new C(); a2.a(); //a2.b(); // 불가능 //a2.c(); // 불가능 System.out.println("\nC 강제 타입변환"); C c = (C) a2; c.a(); c.b(); // 강제 타입변환으로 사용 가능 c.c(); // 강제 타입변환으로 사용 가능 } } interface A { void a(); } class B implements A { @Override public void a() { System.out.println("B.a()"); } public void b() { System.out.println("B.b()"); } } class C extends B { public void c() { System.out.println("C.c()"); } }
// A 인터페이스에 구현체 B 대입
A a1 = new B();
a1.a();
// a1.b();
a1이 .b메서드를 호출 하지 못하는 이유는 B객체를 참조하긴 하지만, A인터페이스로 선언했기때문에 공통으로 있는 B.a()는 출력하지만,
A인터페이스에는 b메서드가 없기떄문에 불러오지 못한다
이럴때는 강제 형변환을 통해 받아와야하는데
B b = (B) a1;으로 명시적으로 형변환을 해줄때 불러올수 있게된다.
코드카타 - 최소직사각형
명함 지갑을 만드는 회사에서 지갑의 크기를 정하려고 합니다. 다양한 모양과 크기의 명함들을 모두 수납할 수 있으면서, 작아서 들고 다니기 편한 지갑을 만들어야 합니다. 이러한 요건을 만족하는 지갑을 만들기 위해 디자인팀은 모든 명함의 가로 길이와 세로 길이를 조사했습니다.
아래 표는 4가지 명함의 가로 길이와 세로 길이를 나타냅니다.
명함 번호 가로 길이 세로 길이
1 60 50
2 30 70
3 60 30
4 80 40
가장 긴 가로 길이와 세로 길이가 각각 80, 70이기 때문에 80(가로) x 70(세로) 크기의 지갑을 만들면 모든 명함들을 수납할 수 있습니다. 하지만 2번 명함을 가로로 눕혀 수납한다면 80(가로) x 50(세로) 크기의 지갑으로 모든 명함들을 수납할 수 있습니다. 이때의 지갑 크기는 4000(=80 x 50)입니다.
모든 명함의 가로 길이와 세로 길이를 나타내는 2차원 배열 sizes가 매개변수로 주어집니다. 모든 명함을 수납할 수 있는 가장 작은 지갑을 만들 때, 지갑의 크기를 return 하도록 solution 함수를 완성해주세요.
문제가 너무 귀찮아서 대충 솔루션을 적고 풀었다
제일 큰 max값은 어딜가도 크니까 고정을 한 후, 나머지 카드의 가로 세로길이중 가장 큰것을 max값에 있는곳에 넣고, 반대쪽에서 max값을 찾으면 된다.
즉, max값이 있는곳은 배열의 가로 세로중 긴것을 넣어서 정리하고, 짧은쪽끼리중에서 긴것을 추려낸다.
1. 최대값을 찾아서 한곳에 고정한다
> 카드의 가로 세로중 가장 긴 길이를 가진 카드를 찾는다
2. 최대값이있는 index를 제외하고 나머지 배열의 가로값과 세로값중 비교해서 낮은값을 찾는다
> 제일 긴 카드를 제외한 나머지중 각각의 카드에 대해 짧은 길이를 가지게 정렬한다.
3. 그 낮은값중에서 큰 값을 찾으면 가로x세로중 가장 작은값이 나오게된다.
> 각각의 카드 중 짧은길이중 가장 큰 값까지 들어가는 지갑이 최종 지갑의 크기이다.
class Solution {
public int solution(int[][] sizes) {
int answer = 0;
int max1=0, index=0;
for(int i = 0 ; i<sizes.length; i++)
{
for(int j = 0; j<sizes[i].length; j++)
{
if(sizes[i][j]>max1)
{
max1=sizes[i][j];
index=i;
}
}
}
int max2=0;
for(int i = 0 ; i<sizes.length; i++)
{
if(i!=index && max2<Math.min(sizes[i][0],sizes[i][1]))
{
max2=Math.min(sizes[i][0],sizes[i][1]);
}
}
if(max2<Math.min(sizes[index][0],sizes[index][1]))
max2=Math.min(sizes[index][0],sizes[index][1]);
answer=max1*max2;
return answer;
}
}
가로 세로중 가장 긴 길이인 맥스값을 찾고(첫번째 반복문),
또 그 맥스값의 위치를 뺀후, 나머지중에서 가로 세로길이중 짧은값을 찾는다(두번째 반복문).
마지막은 맥스값이 있는 인덱스의 반대쪽길이가 최대일 가능성을 고려해봐야한다.
위 코드를 보니 뭔가 되게 더럽게 짜졌다는게 느껴졌다, 좋은방법이 없을까 고민했다
위는 시간복잡도가 o(n^2)이다 이중for문이 있어서
생각해보니 내 전체 배열을 순회하지않고, 반복문을 하나 줄이고 세로값을 증가시킨후, 그중 맥스값을 찾으면 된다고 생각됐다.
class Solution {
public int solution(int[][] sizes) {
int answer = 0;
int max1 = 0, index = 0;
for (int i = 0; i < sizes.length; i++) {
if (Math.max(sizes[i][0], sizes[i][1]) > max1) {
max1 = Math.max(sizes[i][0], sizes[i][1]);
index = i;
}
}
int max2 = 0;
for (int i = 0; i < sizes.length; i++) {
if (i != index && max2 < Math.min(sizes[i][0], sizes[i][1])) {
max2 = Math.min(sizes[i][0], sizes[i][1]);
}
}
if (max2 < Math.min(sizes[index][0], sizes[index][1])) {
max2 = Math.min(sizes[index][0], sizes[index][1]);
}
answer = max1 * max2;
return answer;
}
}
위 처럼 수정을 하면 o(n)이 되는거시다
대충 휴먼을 갖고노는 ai
챗지피티한테 더 효율적인 방법을 물어봤다
class Solution {
public int solution(int[][] sizes) {
int maxWidth = 0;
int maxHeight = 0;
for (int[] size : sizes) {
int w = Math.max(size[0], size[1]); // 가로 길이는 두 수 중 큰 값
int h = Math.min(size[0], size[1]); // 세로 길이는 두 수 중 작은 값
maxWidth = Math.max(maxWidth, w);
maxHeight = Math.max(maxHeight, h);
}
return maxWidth * maxHeight; // 계산된 최대 가로 및 세로 길이의 곱
}
}
코드라인이 확실히 사라졌다
그냥 카드 한장에서 큰값과 작은값을 나누고, 그 값들을 다시 maxwidth랑 maxheight에 넣으면 되는거시다
레벨1인데 코테테 너무어려워용 ㅠ
오늘의 회고
뭔가 이론부분에서 남들에게 말하기 어려운느낌이 강한 3주차였다
그래서 예습도 따로 들어가고 챗지피티한테 엄청 많이 물어서 내가 이해할수 있는 수준으로 풀어쓴거같아서 괜찮은거같다
주말에 이내용으로 복습 좀 하면될거같다..
찾아볼 내용
내가 옛날에 들은 강의에서 Setter를 남발하지말랬는데 맞는지 찾아보자..
내일 해야할 일
4주차 예습 및 강의듣기
젯브레인 얼티메이트 가입
12시간 몰입했는가?
노농 중간에 흐름이 끊겨서 2~3시간 정도는 집중을못한거같다...
'TIL' 카테고리의 다른 글
20240725 본캠프 9일차 TIL (0) | 2024.07.25 |
---|---|
20240724 본캠프 8일차 TIL (0) | 2024.07.24 |
20240722 본캠프 6일차 TIL (0) | 2024.07.22 |
20240719 본캠프 5일차 TIL (0) | 2024.07.19 |
20240718 본캠프 4일차 TIL (0) | 2024.07.18 |