Git
🔴 VS Code 작업 환경 구성
VS Code 창 2개 열기
1. 학원 : git_test\test12
2. 집 : 다른Com\git_repo\test12
🔴 GitHub에서 README.md 파일 생성
GitHub 해당 저장소에서 README.md 파일 생성
Add a README ➜ "#test 예시 Git 테스트중" 제목 추가
commit changes click : 저장소에 README.md 파일 생성 완료
🔴 원격 저장소의 변경사항 로컬로 반영 (학원에서)
git fetch origin main : 최신 커밋을 받아왔지만 워킹 트리에 표시되지 않은 상태
Graph 확인
origin/main 브랜치 Create README.md 커밋 확인 가능
🔺README.md 파일을 워킹 트리에 반영하려면?
git checkout origin/main : README.md 파일이 워킹트리에 표시
git checkout main : main 브랜치로 이동 ➜ README.md 파일이 워킹트리에서 사라짐
🔺main 브랜치에 반영하려면?
git merge origin/main : 병합
➜ README.md 파일이 워킹트리에 표시되고 main 브랜치가 최신 상태로 업데이트
🔴 집에서 변경사항 반영
git pull origin main : fetch + merge 동시에 수행
➜ README.md 파일을 로컬 워킹트리에 반영
🔴 학원과 집에서 각각 commit
🔺학원
acorn.html 파일 추가
"acorn.html 추가함" 이라는 commit 메세지 작성 후 ✔Commit click
🔺집
home.html 파일 추가
"home.html 추가함" 이라는 commit 메세지 작성 후 ✔Commit click
🔺GitHub
현재 README.md 파일이 있는 상태
🔴 학원에서 push
git push origin main : origin에 main 브랜치 이력 내려받기
➜ Graph에서 원격 저장소 이력이 한 칸 내려온 걸 확인 가능
➜ 에러 없이 원격 저장소에 반영 완료
⚠️ 집에서 push ➜ error 발생
git push origin main ➜ rejected error 발생
🔺원인
원격 저장소 이력이 더 앞 선다 (학원에서 먼저 push)
🔺해결 방법
git pull origin main : 충돌없이 자동 merge
➜ 작업 내용이 겹치지 않기에 충돌이 없다
:wq 입력하여 종료하면 push 성공
🔗 학원, 집, GitHub 커밋 이력 동기화
git pull origin main ➜ 모두 동기화 완료
⚠️ 협업 시 주의사항
1. 항상 push 전 pull 먼저 하기
2. 충돌 발생 시 파일 내용 정리 후 add commit
3. 워킹트리가 clean 상태인지 확인하고 작업 진행
🔴 충돌 발생
🔺학원
index.html 파일에 p 요소 추가
"p3 추가함" 이라는 commit 메세지 작성 후 ✔Commit click
🔺집
index.html 파일에 div 요소 추가
"div1 추가함" 이라는 commit 메세지 작성 후 ✔Commit click
Sync Changes click : push 완료
🔺다시 학원
git pull origin main ➜ 충돌 발생‼️
🔴 충돌 해결
해결 순서 : fetch ➜ merge ➜ push
🔺학원
git fetch origin main
git merge origin/main ➜ 충돌 발생
index.html 열기 ➜ <<<<<, =====, >>>>> 기호로 구분된 충돌 지점 정리 ➜ 정리 완료
git add .
git commit -m "merged"
Graph 확인 : 병합 완료된 상태
Sync Changes click ➜ push 성공
🔴 집에서 다시 pull
git pull origin main ➜ 학원, 집, GitHub 모두 커밋 이력 동기화 완료
Eclipes
객체 생성 방식 비교
↱ 생성한 객체의 참조값을 변수에 담고
int ran = new Random();
int a = ran.nextInt()
↳ 변수에 담긴 값을 이용해서 여러 번 사용 가능
vs
↱ 객체를 생성해서 얻어낸 참조값을
int a = new Random().nextInt();
↳ 한번만 사용 (1회용 객체)
익명 클래스 사용
new Weapon(){
@Override
pulic void attack(){ }
} ➜ 익명의 클래스로 생성한 Weapon type의 참조값
new Weapon(){
@Override
pulic void attack(){ }
}. attack();
⤷ 참조값을 변수에 담지 않고 바로 사용 가능
// main 클래스
import test.mypac.Weapon;
public class MainClass07 {
public static void main(String[] args) {
Weapon w1 = new Weapon() {
@Override
public void attack() {
System.out.println("공격중!");
}
};
useWeapon(w1);
useWeapon(new Weapon() {
@Override
public void attack() {
System.out.println("공격중!");
}
});
}
public static void useWeapon(Weapon w) {
w.attack();
}
}
only static filed : 필드는 오직 static 필드만 가능
➜ 수정이 불가능해 readonly = 항상 같은 값 = 상수
➜ static 예약어를 안 써도 static이 자동으로 붙는다
only abstract method : 메소드는 오직 추상 메소드만 가능
➜ 메소드 선언만 존재, 실제 구현X
// Remocon 인터페이스
public interface Remocon {
public void up();
public void down();
}
Remocon r1 = null;
r1.up();
r1.down();
➜ r1에 참조값이 없기에 NullPointerException error 발생
implements 키워드를 통해 구현 필요// MyRemocon 클래스
public class MyRemocon implements Remocon {
@Override
public void up() {
System.out.println("볼륨을 올려요!");
}
@Override
public void down() {
System.out.println("볼륨을 내려요!");
}
}
import test.mypac.MyRemocon;
import test.mypac.Remocon;
public class MainClass01 {
public static void main(String[] args) {
// 인터페이스는 data type의 역할도 할 수 있다
Remocon r1 = null;
// 인터페이스 단독으로 객체 생성 불가 (아예 생성자 조차도 존재하지 않는다)
// Remocon r2 = new Remocon();
// 인터페이스 type 의 참조값이 필요하면 해당 인터페이스를 implements 한 하위 클래스를 이용해서 얻어낸다
Remocon r2 = new MyRemocon();
r2.up();
r2.down();
}
}
// Remocon 인터페이스
public interface Remocon {
public String COMPANY = "LG"; // static final 상수는 관례상 필드명을 모두 대문자로
public void up();
public void down();
}
// main 클래스
String a = Remocon.COMPANY; // LG
// main 클래스
import test.mypac.MyRemocon;
import test.mypac.Remocon;
public class MainClass02 {
public static void main(String[] args) {
// 다형성 확인
Object r1 = new MyRemocon();
Remocon r2 = new MyRemocon();
MyRemocon r3 = new MyRemocon();
useRemocon(r3);
useRemocon(r2);
useRemocon((Remocon)r1);
}
public static void useRemocon(Remocon r) {
r.up();
r.down();
}
}
import test.mypac.Remocon;
public class MainClass04 {
public static void main(String[] args) {
// 인터페이스도 익명의 InnerClass 를 이용해서 구현 객체를 만들 수 있다
Remocon r1 = new Remocon() {
@Override
public void up() {
System.out.println("채널을 올려요!");
}
@Override
public void down() {
System.out.println("채널을 내려요!");
}
};
// 지역변수 r1 에 있는 참조값을 전달하면서 메소드 호출
useRemocon(r1);
// 메소드 호출하면서 즉석에서 객체 들어서 호출
useRemocon(new Remocon() {
@Override
public void up() {
System.out.println("머리를 올려요!");
}
@Override
public void down() {
System.out.println("머리를 내려요!");
}
});
}
public static void useRemocon(Remocon r) {
r.up();
r.down();
}
}
// Drill 인터페이스
public interface Drill {
// 구멍을 뚫는 추상 메소드 1개만 정의해 보자
public void hole();
}
// main 클래스
Drill d1 = new Drill() {
@Override
public void hole() {
System.out.println("바닥에 구멍을 뚫어요!");
}
};
useDrill(d1);
🟥 람다 표현식으로 간소화
( )->{ }Drill d2 = () -> {
System.out.println("천장에 구멍을 뚫어요!");
};
useDrill(() -> {
System.out.println("변기 구멍을 뚫어요!");
});
// Warmer 인터페이스
@FunctionalInterface
public interface Warmer {
public void warm(String target);
}
// main 클래스
import test.mypac.Warmer;
public class MainClass06 {
public static void main(String[] args) {
Warmer w1 = new Warmer() {
@Override
public void warm(String target) {
System.out.println(target+"을 따뜻하게 해요");
}
};
useWarm(w1);
Warmer w2 = (String target)->{
System.out.println(target+"을 뜨겁게 해요");
};
useWarm(w2);
// 매개변수 type 생략 가능
Warmer w3 = (e)->{
System.out.println(e+"에 불을 붙여요");
};
useWarm(w3);
useWarm((e)->{
System.out.println(e+"이 불타고 있어요");
});
}
public static void useWarm(Warmer w) {
w.warm("손");
}
}
// Operator 인터페이스
@FunctionalInterface
public interface Operator {
public double execute(double num1, double num2);
}
// main 클래스
import test.mypac.Operator;
public class MainClass07 {
public static void main(String[] args) {
Operator plus = (double num1, double num2)->{
return num1+num2;
};
Operator minums = (num1, num2)->{
return num1-num2;
};
Operator multiply = (a, b)-> a*b;
double result1 = plus.execute(10, 10); // 20
double result2 = minums.execute(10, 10); // 0
double result3 = multiply.execute(10, 10); // 100
}
}
// Singer 인터페이스
public interface Singer {
public void sing();
}
// Programmer 인터페이스
public interface Programmer {
public void develope();
}
// work 클래스
public class Person implements Singer, Programmer{
public void work() {
System.out.println("일을 해요!");
}
@Override
public void develope() {
System.out.println("노래를 불러요!");
}
@Override
public void sing() {
System.out.println("App을 개발해요!");
}
}
// main 클래스
import test.mypac.Person;
import test.mypac.Programmer;
import test.mypac.Singer;
public class MainClass08 {
public static void main(String[] args) {
// Person 객체를 생성ㅎ해서 Person type 으로 받으면
Person p1 = new Person();
p1.work();
p1.sing();
p1.develope();
System.out.println("-----------");
// Person 객체를 생성해서 Singer type 으로 받으면 sing() 메소드만 사용 가능
Singer p2 = new Person();
p2.sing();
System.out.println("-----------");
// Person 객체를 생성해서 Programmer type 으로 받으면 develope() 메소드만 사용 가능
Programmer p3 = new Person();
p3.develope();
}
}
< > : 포괄적인 클래스// Apple 클래스
public class Apple {}
// Banana 클래스
public class Banana {}
FruitBox<T> 를 통해 타입 안정성과 재사용성 확보// FruitBox 클래스
public class FruitBox <T> {
// T 를 필드의 type 으로 활용
private T item;
// T 를 매개변수의 type 으로 활용
public void pack(T item) {
this.item = item;
}
// T 를 메소드의 return type 으로 활용
public T unPack() {
return item;
}
}
// main 클래스
import test.box.FruitBox;
import test.fruit.Apple;
import test.fruit.Banana;
public class MainClass02 {
public static void main(String[] args) {
// Apple 을 담은 용도로 사용할 FruitBox 객체 생성하기
FruitBox<Apple> box1 = new FruitBox<Apple>();
box1.pack(new Apple());
// Banana 을 담은 용도로 사용할 FruitBox 객체 생성하기
FruitBox<Banana> box2 = new FruitBox<Banana>();
box2.pack(new Banana());
}
}