오늘은 팀과제 발제, 팀회의(각자의 개인과제 코드 리뷰, 앞으로의 일정), 개인 공부(팀과제를 위한 초석을..!), 깃허브 특강 등이 있었다.
아주 알찬 하루였다고 할 수 있다.
공부하면서 정리한것을 올린다.
Git
매개변수
자바에서 "매개변수"는 메서드(함수)를 호출할 때 메서드에 전달되는 값 또는 데이터를 의미합니다. 메서드는 이러한 매개변수를 사용하여 입력 값을 받고, 해당 값을 처리하거나 연산을 수행한 다음 결과를 반환하거나 특정 작업을 수행할 수 있습니다. 매개변수는 메서드 정의에서 선언되며, 메서드가 호출될 때 매개변수에 전달된 값이 메서드 내에서 사용됩니다.
public int add(int a, int b) {
// 메서드 내에서 a와 b를 사용하여 두 정수를 더함
return a + b;
}
위의 코드에서 add 메서드는 int a와 int b라는 두 개의 매개변수를 가지고 있습니다. 이 메서드는 호출될 때 a와 b에 전달된 값들을 사용하여 두 정수를 더하고 결과를 반환합니다.
메서드는 실행할 때 return문을 만나면 그대로 종료하게 되는데 void 타입일 때 return;이렇게 return문을 사용하여 원하는 지점에서 메서드를 종료할 수도 있습니다.!
오버로딩
📌 오버로딩 은 함수가 하나의 기능만을 구현하는것이 아니라 하나의 메서드 이름으로 여러 기능을 구현하도록 하는 Java의 기능입니다.
즉, 한 클래스 내에 이미 사용하려는 이름과 같은 이름을 가진 메서드가 있더라도, 매개변수의 개수 또는 타입, 순서가 다르면 동일한 이름을 사용해서 메서드를 정의할 수 있습니다.
-->장점
1. 메서드 이름 하나로 상황에 따른 동작을 개별로 정의할 수 있습니다.
2. 메서드의 이름을 절약할 수 있습니다.
• 메서드의 이름이 같고, 매개변수의 개수, 타입, 순서가 달라야 합니다.
• '응답 값만' 다른 것은 오버로딩을 할 수 없습니다.
• 접근 제어자만 다른 것도 오버로딩을 할 수 없습니다.
• 결론, 오버로딩은 매개변수의 차이로만 구현할 수 있습니다.
접근제어자
📌 멤버 또는 클래스에 사용, 외부에서 접근하지 못하도록 제한합니다.
• 클래스, 멤버변수, 메서드, 생성자에 사용되고, 지정되어 있지 않다면 default 입니다.
○ public : 접근 제한이 전혀 없습니다.
○ protected : 같은 패키지 내에서, 다른 패키지의 자손클래스에서 접근이 가능합니다
○ default : 같은 패키지 내에서만 접근이 가능합니다.
○ private : 같은 클래스 내에서만 접근이 가능합니다.
Getter
외부에서 객체의 private 한 필드를 읽을 필요가 있을 때 Getter 메서드를 사용합니다.
• 메서드 이름의 규칙은 : get + 필드이름(첫 글자 대문자) 입니다.
• 사용하는 방법은 인스턴스 메서드 호출과 동일합니다.
public String getModel() {
return model;
}
Setter
외부에서 객체의 private 한 필드를 저장/수정할 필요가 있을 때 Setter 메서드를 사용합니다.
• 메서드 이름의 규칙은 : set + 필드이름(첫 글자 대문자) 입니다.
• 사용하는 방법은 인스턴스 메서드 호출과 동일합니다.
public void setModel(String model) {
this.model = model;
}
• 사용가능한 제어자
○ 클래스 : public, default, final, abstract
○ 메서드 : public, protected, default, private, final, abstract, static
○ 멤버변수 : public, protected, default, private, final, static
○ 지역변수 : final
클래스
📌 클래스는 Java의 클래스 로더에 의해 메서드 영역에 저장되고 사용됩니다.
• 이때 클래스 멤버란 메서드 영역의 클래스와 같은 위치에 고정적으로 위치하고 있는 멤버를 의미합니다.
• 따라서 클래스 멤버는 객체의 생성 필요없이 바로 사용이 가능합니다.
static String company = "GENESIS"; // 자동차 회사 : GENESIS
String getCompany() {
return "(주)" + company;
}
Car.company = "Audi";
String companyName = Car.setCompany("Benz");
참조형 변수를 사용하여 클래스 멤버에 접근은 가능하지만 추천하지 않습니다.
Object
말그대로 “객체”를 의미하는 단어이며 보통, Object 클래스를 의미합니다.
• Object 클래스는 Java 내 모든 클래스들의 최상위 부모 클래스 입니다.
• 따라서, 모든 클래스는 Object의 메서드를 사용할 수 있습니다.
• 또한 부모 클래스가 없는 자식 클래스는 컴파일러에 의해 자동으로 Object 클래스를 상속받게 됩니다.
몇가지 예시
• Object clone() : 해당 객체의 복제본을 생성하여 반환함.
• boolean equals(Object object) : 해당 객체와 전달받은 객체가 같은지 여부를 반환함.
• Class getClass() : 해당 객체의 클래스 타입을 반환함.
• int hashCode() : 자바에서 객체를 식별하는 정수값인 해시 코드를 반환함.
• String toString() : 해당 객체의 정보를 문자열 로 반환함. & Object 클래스에서는 클래스이름 @해쉬코드값 리턴함.
super는 부모 클래스의 멤버를 참조할 수 있는 키워드입니다.
• 객체 내부 생성자 및 메서드에서 부모 클래스의 멤버에 접근하기 위해 사용될 수 있습니다.
• 자식 클래스 내부에서 선언한 멤버와 부모 클래스에서 상속받은 멤버와 이름이 같을 경우 이를 구분하기 위해 사용됩니다.
// 부모 클래스 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
}
오버라이딩
부모 클래스로부터 상속받은 메서드의 내용을 재정의 하는 것을 오버라이딩이라고 합니다.
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();
}
}
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;
}
참조변수의 타입변환
자동 타입변환
부모타입 변수 = 자식타입객체;는 자동으로 부모타입으로 변환이 일어납니다.
-> 다만 주의할 점은 부모타입 변수로 자식객체의 멤버에 접근할 때는 부모 클래스에 선언된 즉, 상속받은 멤버만 접근할 수 있습니다.
강제 타입변환
자식타입 변수 = (자식타입) 부모타입객체;
• 부모타입객체는 자식타입 변수로 자동으로 타입변환되지 않습니다.
• 이럴때는 (자식타입) 즉, 타입변환 연산자를 사용하여 강제로 자식타입으로 변환할 수 있습니다.
// 자식타입객체가 자동 타입변환된 부모타입의 변수
Mammal mammal = new Whale();
mammal.feeding();
// 자식객체 고래의 수영 기능을 사용하고 싶다면
// 다시 자식타입으로 강제 타입변환을 하면된다.
Whale whale = (Whale) mammal;
whale.swimming();
• 다만 무조건 강제 타입변환을 할 수 있는 것은 아닙니다.
○ 자식타입객체가 부모타입으로 자동 타입변환된 후 다시 자식타입으로 변환될 때 만 강제 타입변환이 가능합니다.
○ 부모타입 변수로는 자식타입객체의 고유한 멤버를 사용할 수 없기 때문에 사용이 필요한 경우가 생겼을 때 강제 타입변환을 사용합니다.
Mammal newMammal = new Mammal();
Whale newWhale = (Whale) newMammal; // ClassCastException 발생
☆다형성
다형성이란 ‘여러 가지 형태를 가질 수 있는 능력’을 의미합니다.
Tire tire = new HankookTire("HANKOOK");
Tire tire = new KiaTire("KIA");
• 부모타이어 변수 = 자식타이어객체;를 선언하여 자동 타입변환된 변수를 사용하여 각각의 자식타이어 객체에 재정의 된 메서드를 통해 다양한 승차감을 가진 자동차를 생성할 수 있습니다.
public Car(Tire tire) {
this.tire = tire;
}
...
Car car1 = new Car(new KiaTire("KIA"));
Car car2 = new Car(new HankookTire("HANKOOK"));
• 매개변수에도 다형성이 적용될 수 있습니다.
• Car 생성자에서 매개변수의 타입이 부모 타이어 이기 때문에 자식 타이어 객체들을 매개값으로 전달할 수 있습니다.
Tire getHankookTire() {
return new HankookTire("HANKOOK");
}
Tire getKiaTire() {
return new KiaTire("KIA");
}
...
Tire hankookTire = car1.getHankookTire();
KiaTire kiaTire = (KiaTire) car2.getKiaTire();
• 반환타입에도 다형성이 적용될 수 있습니다.
• 반환타입이 부모 타이어 이기 때문에 자식 타이어 객체들을 반환값으로 지정할 수 있습니다.
• 또한 자동 타입변환이된 반환값인 자식 타이어 객체를 강제 타입변환할 수도 있습니다.
instanceof
📌 다형성 기능으로 인해 해당 클래스 객체의 원래 클래스명을 체크하는것이 필요한데 이때 사용할 수 있는 명령어가 instance of 입니다.
• 이 명령어를 통해서 해당 객체가 내가 의도하는 클래스의 객체인지 확인할 수 있습니다.
• {대상 객체} instance of {클래스 이름} 와 같은 형태로 사용하면 응답값은 boolean 입니다.
추상 클래스, 메서드
📌 클래스가 설계도라면 추상 클래스는 미완성된 설계도입니다.
• abstract 키워드를 사용하여 추상 클래스를 선언할 수 있습니다.
public abstract class 추상클래스명 {}
• 추상 클래스는 추상 메서드를 포함할 수 있습니다.
○ 추상 메서드가 없어도 추상 클래스로 선언할 수 있습니다.
• 추상 클래스는 자식 클래스에 상속되어 자식 클래스에 의해서만 완성될 수 있습니다.
• 추상 클래스는 여러개의 자식 클래스들에서 공통적인 필드나 메서드를 추출해서 만들 수 있습니다.
📌 추상 메서드는 아직 구현되지 않은 미완성된 메서드입니다.
• abstract 키워드를 사용하여 추상 메서드를 선언할 수 있습니다.
public abstract class 추상클래스명 {
abstract 리턴타입 메서드이름(매개변수, ...);
}
추상 메서드는 일반적인 메서드와는 다르게 블록{ }이 없습니다.
즉, 정의만 할 뿐, 실행 내용은 가지고 있지 않습니다.
📌 추상 메서드는 extends 키워드를 사용하여 클래스에서 상속됩니다.
public class 클래스명 extends 추상클래스명 {
@Override
public 리턴타입 메서드이름(매개변수, ...) {
// 실행문
}
}
상속받은 클래스에서 추상 클래스의 추상 메서드는 반드시 오버라이딩 되어야 합니다.
인터페이스
📌 인터페이스의 역할에 대해 학습해보겠습니다.
• 인터페이스는 두 객체를 연결해주는 다리 역할을 해줍니다.
• 상속 관계가 없는 다른 클래스들이 서로 동일한 행위 즉, 메서드를 구현해야할 때 인터페이스는 구현 클래스들의 동일한 사용 방법과 행위를 보장해 줄 수 있습니다.
○ 인터페이스는 스팩이 정의된 메서드들의 집합입니다.
○ 인터페이스의 구현 클래스들은 반드시 정의된 메서드들을 구현해야합니다.
○ 따라서 구현 클래스들의 동일한 사용 방법과 행위를 보장해 줄 수 있습니다.
○ 이러한 특징은 인터페이스에 다형성을 적용할 수 있게 만들어 줍니다.
• 모든 멤버변수는 public static final 이어야합니다.
○ 생략 가능합니다.
• 모든 메서드는 public abstract 이어야합니다.
○ 생략 가능합니다. (static 메서드와 default 메서드 예외)
• 생략되는 제어자는 컴파일러가 자동으로 추가 해줍니다.
public interface 인터페이스명 {
public static final char A = 'A';
static char B = 'B';
final char C = 'C';
char D = 'D';
void turnOn(); // public abstract void turnOn();
}
📌 인터페이스는 추상 클래스와 마찬가지로 직접 인스턴스를 생성할 수 없기 때문에 클래스에 구현되어 생성됩니다.
• implements 키워드를 사용하여 인터페이스를 구현할 수 있습니다.
public class 클래스명 implements 인터페이스명 {
// 추상 메서드 오버라이딩
@Override
public 리턴타입 메서드이름(매개변수, ...) {
// 실행문
}
}
• 인터페이스의 추상 메서드는 구현될 때 반드시 오버라이딩 되어야 합니다.
• 만약 인터페이스의 추상 메서드를 일부만 구현해야 한다면 해당 클래스를 추상 클래스로 변경해주면 됩니다.
📌 인터페이스간의 상속이 가능합니다.
• 인터페이스간의 상속은 implements 가 아니라 extends 키워드를 사용합니다.
• 인터페이스는 클래스와는 다르게 다중 상속이 가능합니다.
public class Main implements C {
@Override
public void a() {
System.out.println("A");
}
@Override
public void b() {
System.out.println("B");
}
}
interface A {
void a();
}
interface B {
void b();
}
interface C extends A, B { }
• 또한 인터페이스의 구현은 상속과 함께 사용될 수 있습니다.
디폴트 메서드와 static 메서드
📌 디폴트 메서드는 추상 메서드의 기본적인 구현을 제공하는 메서드입니다.
• 메서드 앞에 default 키워드를 붙이며 블럭{ }이 존재해야합니다.
• default 메서드 역시 접근 제어자가 public 이며 생략이 가능합니다.
• 추상 메서드가 아니기 때문에 인터페이스의 구현체들에서 필수로 재정의 할 필요는 없습니다.
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");
}
}
📌 인터페이스에서 static 메서드 선언이 가능합니다.
• static의 특성 그대로 인터페이스의 static 메서드 또한 객체 없이 호출이 가능합니다.
• 선언하는 방법과 호출하는 방법은 클래스의 static 메서드와 동일합니다.
○ 접근 제어자를 생략하면 컴파일러가 public을 추가해 줍니다.
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();
System.out.println();
// static 메서드 aaa() 호출
A.aaa();
}
}
interface A {
void a();
default void aa() {
System.out.println("AA");
}
static void aaa() {
System.out.println("static method");
}
}
☆☆다형성☆☆
자동 타입 변환
인터페이스 변수 = 구현객체;는 자동으로 타입 변환이 일어납니다.
public class Main {
public static void main(String[] args) {
// A 인터페이스에 구현체 B 대입
A a1 = new B();
// A 인터페이스에 구편체 B를 상속받은 C 대입
A a2 = new C();
}
}
interface A { }
class B implements A {}
class C extends B {}
강제 타입 변환
구현객체타입 변수 = (구현객체타입) 인터페이스변수;
public class Main {
public static void main(String[] args) {
// A 인터페이스에 구현체 B 대입
A a1 = new B();
a1.a();
// a1.b(); // 불가능
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()");
}
}
인터페이스의 다형성
// LG TV 구현체를 조작
MultiRemoteController mrc = new LgTv("LG");
mrc.turnOnOff();
mrc.volumeUp();
// 조작 대상을 Samsung TV로 교체
mrc = new SamsungTv("Samsung");
mrc.turnOnOff();
mrc.channelUp();
• 멀티리모컨인터페이스 변수 = TV구현객체; 를 선언하여 자동 타입변환된 인터페이스 변수를 사용하여 TV구현객체의 기능을 조작할 수 있습니다.
• TV구현객체를 교체해도 멀티리모컨인터페이스 변수는 전혀 수정작업 없이 그대로 기능을 호출할 수 있습니다.
• 다형성은 ‘여러 가지 형태를 가질 수 있는 능력’ 이라고 배웠습니다.
• 사용 방법은 동일하지만 다양한 특징과 결과를 가질 수 있는 것이 바로 다형성입니다.
○ 즉, 멀티리모컨으로 티비를 사용하는 방법은 동일하지만 어떤 TV구현객체가 대입되었느냐에 따라 실행 결과가 다르게 나옴을 통해 다형성이 적용되었음을 확인할 수 있었습니다.
// 매개변수와 반환타입 다형성 확인 메서드
default MultiRemoteController getTV(Tv tv) {
if(tv instanceof SamsungTv) {
return (SamsungTv) tv;
} else if(tv instanceof LgTv){
return (LgTv) tv;
} else {
throw new NullPointerException("일치하는 Tv 없음");
}
}
• 또한 인터페이스도 마찬가지로 매개변수와 반환타입에서 다형성이 적용될 수 있습니다.
• 위 예제는 반환타입에는 인터페이스, 매개변수에는 추상클래스로 다형성이 적용되어있습니다.
○ 인터페이스의 default 메서드입니다.