dev-course day6

2rlokr·2025년 3월 11일

dev-course

목록 보기
6/43

오늘 배운 것

실습

static 내부 클래스

  • 외부 클래스 일부
public class StaticOuterClass {

    private final String instanceName = "StaticOuterClassInstanceName";
    private static final String staticName = "StaticOuterClassStaticName";

    public final Integer sharedInstanceValue = 10;
    public static final Integer sharedStaticValue = 90;
  • 내부 클래스
static class InnerClass {
	private String innerName = "StaticInnerClassInstanceName";
    private static String innerPrivateStaticName = "StaticInnerClassStaticName";

    public final Integer innerValue = 10;
    public static final Integer innerPublicStaticValue = 90;

    public static int a = 10;
    public int b = 20;

    public void test() {

        // 인스턴스 변수는 직접 참조할 수 없다.
        //System.out.println("instanceName = " + instanceName); 
        //static인 곳에서 non-static을 부를 수 없다
        System.out.println("staticName = " + staticName); 
        // 정적 영역에 있기 때문에 가능하다.
        System.out.println("sharedStaticValue = " + sharedStaticValue);

        // 인스턴스 변수 사용하는 법
        StaticOuterClass outerCls = new StaticOuterClass(); 
        // 인스턴스를 생성하면 접근이 가능하다.
        Integer privateValue = outerCls.sharedInstanceValue;
        System.out.println("privateValue = " + privateValue);
    }
}
  • 정적 내부 클래스는 외부 클래스와 독립적으로 존재할 수 있다.
  • static이라고 해서 외부 클래스의 다른 정적변수와 완전히 동일하게 동작하지는 않는다.
    - 만약 완전히 같다면, 내부 클래스에서 static 변수만 가능해야 한다.
    • 하지만, public int a = 10; 처럼 인스턴스 변수도 생성이 가능하다.

내부 클래스에서 외부 클래스의 변수를 사용할 수 있을까?

  • Outer Classstatic 변수는 가능하다.
  • Outer Classinstance변수는 직접 참조할 수 없다.
    -> static인 곳에서 non-static를 부를 수 없다.

그렇다면 외부 클래스의 instance 변수는 어떻게 사용할 수 있을까?

  • 외부 클래스의 instance 를 생성해야 한다.

public void accessToInnerClass() {

	Integer innerPublicStaticValue = InnerClass.innerPublicStaticValue;
    // static 변수이기 때문에 직접 참조가 가능하다.
    String innerPrivateStaticName = InnerClass.innerPrivateStaticName;
    // 접근 제어자가 private이더라도 가능하다.

    // 인스턴스 변수는 new로 인스턴스를 만들어준 후 사용가능함.
    String innerName = new InnerClass().innerName; 
    // private이지만 사용 가능하다.
    }

외부 클래스에서 정적 내부 클래스에게 접근할 수 있을까?

  • InnerClassstatic 변수들은 정적 변수이기 때문에 직접 참조가 가능하다.
    - 접근 제어자가 private이더라도 가능하다.
  • InnerClassinstance 변수들은 new 로 인스턴스를 만들어준 후 사용 가능하다.
    - private 이지만 사용 가능하다.

test

  • InnerClass가 static이기 때문에
    StaticOuterClass.InnerClass innerclass = new StaticOuterClass.InnerClass(); 와 같이 사용할 수 있다.
    외부 클래스에 있는 static 내부 클래스의 생성자를 호출하고 new 붙여주기

test2

private static void test3() {
	StaticOuterClass.InnerClass innerClass1 = new StaticOuterClass.InnerClass();
    innerClass1.a = 50;

    StaticOuterClass.InnerClass innerClass2 = new StaticOuterClass.InnerClass();
    innerClass2.a = 0;

    System.out.println("innerClass1 = " + innerClass1.a);
}
  • a는 정적변수이기 때문에 다른 instance에서a를 값을 바꿔주어도 다른 정적변수처럼 값이 같아진다.

동등성 (Equality) 와 동일성 (Identity)

동등성 Equality : 객체 안에 있는 내용 즉, 값들이 같은지 비교 (equals를 사용한다)

  • equalsObjects에 있는 함수이기 때문에, 사용할 때 우리가 오버라이딩 할 수 있다.
  • 하지만, 직접 오버라이딩 하지 않으면, == 비교랑 똑같이 리턴할 것이다. (Object에서 동일성을 비교하고 있기 때문에)

동일성 Identity : 객체가 메모리 주소(참조) 값이 같은지를 비교, 두 객체가 물리적으로 같은 객체인지 비교하는 것 (==를 사용한다)

  • == 연산자는 int, boolean과 같은 primitive type에 대해서는 값을 비교한다. reference type에 대해서는 주소값을 비교한다.
  • 엄밀히 따지면 primitive type 역시 Constant Pool에 있는 특정 상수를 참조하는 것이기 때문에 결국 주소값을 비교하는 것으로 볼 수 있다. 같은 상수를 참조하면 주소값이 같으니 결국 같은 값이면 동일하다고 판단할 수 있기 때문이다.

MemberV1 member1 = new MemberV1(1, "John", "admin@example.com");
MemberV1 member2 = new MemberV1(1, "John", "admin@example.com");

String name1 = member1.getName();
String name2 = new String("John"); // 이건 객체를 또 만들게 되는 것임. 그럼 다른 곳에
String name3 = "John";

MemberV1 member3 = member1;

boolean result1 = name1 == name3; // true
boolean result2 = name1 == name2; // false
boolean result3 = member3 == member1; // true
  • 중복을 최소화하기 위해 문자열 상수 풀이 존재한다. 거기서 꺼내서 비교하기 때문에 result1true가 나온다.
  • name2new라는 키워드로 새로운 객체를 만들었다. 그렇게 되면 다른 곳에 저장되기 때문에, result2false가 나온다.
  • member3member1을 참조하고 있다. 포인터로 가리키고 있다는 의미. 그래서 result3의 결과는 true 가 나온다.

equals 의 규칙

equalsnon-null object reference에 동등성 체크를 하는 것

  1. reflexive (반사성) : 자기 자신과 비교했을 땐 반드시 true가 반환된다.
  2. symmetric (대칭성) : 두 객체가 같다고 판단되면, 순서를 바꿔도 true가 반환되어야 한다.
  3. transitive (추이성) : 삼단 논법 느낌 a=b, b=c => a=c
  4. consistent (일관성) : 비교대상이 안 바뀌었을 때, 비교 결과가 항상 같게 나와야 한다.
  5. 비교 대상이 null 일 땐, 무조건 false를 반환한다.

equals 오버라이딩

@Override
public boolean equals(Object o) {
	if (this == o) { // reflexive 규칙 : 자기 자신이랑 같으면 true
		return true;
	}
    // null이거나 클래스가 다르다면 false
	if (o == null || getClass() != o.getClass()) {
        return false;
	}
	MemberV2 memberV2 = (MemberV2) o;
	
    // 멤버들 하나 하나 동등성 비교까지
	return memberId == memberV2.memberId
                && Objects.equals(name, memberV2.name)
                && Objects.equals(email, memberV2.email);
	// return Objects.equals(email, memberV2.email);
    }
  • 오버라이딩하면서 비교할 멤버를 마음대로 지정해줘도 가능하다. emailunique해야 한다면 email만 비교하는 것도 가능하다는 이야기

toString()

Object 에 있는 함수이며, 원하는 방식으로 출력하기 위해 클래스에 오버라이딩 해주는 함수이다.

@Override
public String toString() {
	return "Team{" +
           "teamName='" + teamName + '\'' +
           ", rank=" + rank +
           '}';
}

Comparable

  • Comparable<T>interface이다.
  • 사용하기 위해서는 implements 사용 ->compareTo 를 반드시 구현해야 한다.
  • <T>에는 비교하고 싶은 대상을 넣는다.
  • 자기 자신과 매개변수 객체를 비교
  • lang 패키지에 있기 때문에 import를 해줄 필요가 없다.
@Override
public int compareTo(CharacterCompare o) {
	return Integer.compare(this.level, o.level);
}

compare 함수

  • Integer.java에 있는 함수이다. 두 값을 비교해준다.
  • 왼쪽이 더 크다면 -> 1
    오른쪽이 더 크다면 -> -1,
    두 수가 같다면 -> 0 이 반환된다.

compareTo 함수

  • int를 반환한다.
  • '값'을 비교하여 정수를 반환해야 한다.
  • o1.compareTo(o2)
    -> 양수 => 왼쪽이 더 큰 것
    -> 음수 => 오른쪽이 더 큰 것
    -> 0 => 같다

Comparable을 이용한 sort

int isUser1HigherThanUser2 = user1.compareTo(user2);
// user1이 더 크다면 1, 
// user2가 더 크다면 -1,
// 같다면 0
List<CharacterCompare> raidParty = makeParty(PARTY_SIZE);
raidParty.sort(null); // 오름차순으로 정렬
  • 원래 저 null 자리에 Comparator이 들어가야 한다.
  • sort 즉, 정렬을 하기 위해서는 객체를 비교할 수 있어야 한다.
    CharacterCompare 클래스에 compareTo라는 함수를 정의해놨기 때문에 이제 객체를 비교할 수 있게 된다.

Comparator

  • Comparable<T>interface이다.
  • 사용하기 위해서는 implements 사용 ->compare 를 반드시 구현해야 한다.
  • <T>에는 비교하고 싶은 대상을 넣는다.
  • 두 매개변수 객체를 비교
  • util 패키지에 있다.
@Override
public int compare(Character o1, Character o2) {
	return Integer.compare(o1.gold, o2.gold); // 오름차순
	// return Integer.compare(o2.gold, o1.gold); // 내림차순
}
  • 마찬가지로, o1이 o2보다 더 크다면 1,
    o1이 o2보다 더 작다면 -1,
    o1이 o2와 같다면 0

  • 양수면 +니까 쭉쭉 올라간다고 생각하자 -> 오름차순
    => 앞이 더 클 때 양수가 나온다.

  • 음수면 -니까 쭉쭉 내려간다고 생각하자. -> 내림차순
    => 앞이 더 작을 때 음수가 나온다.

Comparator를 이용한 sort

List<Character> userGuild = makeGuild(3);

CharacterGoldComparator comparator = new CharacterGoldComparator();
userGuild.sort(comparator);
  • 이번엔 Comparator를 구현한 CharacterGoldComparator의 인스턴스를 sort의 매개변수에 넣어준 것이다.
  • 그럼 userGuild를 정렬하기 위해 객체를 비교할 기준이 CharacterGoldComparator에 저장된 compare함수가 된 것이다.
  • compare에서 설정해둔 정렬 방식으로 정렬된다.

람다로 sort 구현

example 1


List<Character> userGuild = makeGuild(10);
userGuild.sort((o1, o2) -> {
	int result = Integer.compare(o1.getGold(), o2.getGold());

	if(result == 0){
	result = Integer.compare(o1.getLevel(), o2.getLevel());
	}
	return result;
});

example 2

userGuild.sort(
	Comparator.comparing(
	(Character c)  -> c.getGold(), Comparator.reverseOrder()
	).thenComparing(
	(Character c) -> c.getLevel()
	)
);

example 3

userGuild.sort(
	Comparator.comparing(Character::getGold, Comparator.reverseOrder()).thenComparing(Character::getLevel)
);

어노테이션 (Annotation)

어노테이션(Annotation)은 컴퓨터가 이해할 수 있는 (읽을 수 있는) 특별한 주석

표준 어노테이션

  1. @Retention() : 어노테이션 안의 정보를 어느 시점까지 살릴 건지 설정한다. 어노테이션이 유지되는 기간을 정하기 위해 사용한다.
  • RetentionPolicy.RUNTIME` : 런타임동안 사용한다는 것
  1. @Target() : 이 어노테이션을 어디에 적용시킬 건지 제한을 둘 수 있다.
  • ElementType.TYPE : 클래스, 인터페이스 등
  • ElementType.METHOD : 메소드
  1. @Documented : 어노테이션 정보를 javadoc으로 작성된 문서에 포함시킨다.

  2. @Deprecated : 앞으로 사용하지 않을 대상임을 알린다.

  3. @SuppressWarning() : 컴파일러가 경고 메세지를 나타내지 않는다.

  • "deprecation"을 두면 컴파일러에게 deprecation 관련 경고 메세지는 알려주지 말라고 하는 것이다.
  • "all" : 모든 경고 메세지를 나타내지 않는다.

등...이 있다.

사용자 정의 어노테이션

public @interface Apple {
    String value() default ""; // 꼭 안 받아도 될 때 default로 둔다
    int range();
}
  • 다음과 같이 꼭 필요한 멤버들을 정의 해둔다.
  • 꼭 안 받아도 될 때는 default 값을 지정해준다.
  • 어노테이션을 사용할 때는 @Apple(value = "yummy")와 같이 value값을 주어야 한다.

나중에 다시 볼 내용

람다... 어렵다 ! 람다 예시들은 이후 강의를 들은 후, 다시 한 번 더 봐야 할 것 같다.

오늘 어려웠던 내용

개념이 이제 익숙하지 않은 게 나오니까 어떤 게 뽀인트인지 초점을 못 잡으니까 조금 어려웠던 것 같다. TIL을 적으면서 Comparable, Comparator를 다시 보니까 이제는 이해가 확실히 되는 것 같다.
어노테이션도 Spring 들어가서는 활용만 하고 저런 식으로 작성할 일은 잘 없다고 하니 좀 안심이 되었다.

Request 예시도 다시 한 번 보니 이해가 된다. 하지만, 이 코드를 다시 혼자 짜봐라... 하면 못 짤 것 같긴 하다.

칭찬해요

오늘도 복습을 차근차근 잘 해서 오늘 배운 내용을 이해하고 넘어갈 수 있었다. 정말 할 건 많은데 시간은 너무 없다.. ㅎ 시간을 쪼개서 할 건 하고 넘어가야 한다는 걸 더 느낀다. 오늘 배운 내용을 이해 못 하면 점점 쌓이고~ 내 업보가 될 것이야 ~ TIL만큼은 하루하루 잘 써야겠다고 다짐한다. TIL을 쓰는 건 사실 부가적인 것이고, 오늘 배운 내용을 다 이해하고 넘어가자고 다짐한다 ! 오늘도 잘 살아남았다.

팀 활동 후기

아직 팀원들이랑 너무 어색하다. I들에게는 정적이 별로 불편하지 않다고 들었는데,, 난 너무 불편하다 !! 흑 ㅠㅠ 아직 2일차니 어색한 게 당연하긴 해? ㅎ
오늘 스크럼 남길 때 수업 때 들은 거 완전히 이해는 못 하겠다고 얘기했더니 팀원 분들이 다 도와주시고 격려(?)해주셔서 너무 감사했다.. ! 나도 팀원들에게 그럴 수 있는 사람이 되어야겠다.

느낀 점

오늘도 무사히 끝냈다. 오늘은 수업 중에 위기감을 느꼈다. 코드가 이해는 되는데 이걸 왜 하는거지? 뭘 보여주려고 그러는 거지? 하면서 뽀인트를 못 찾았다. 이게 개념이 익숙하지 않아서 그렇겠지.. 후.. 수업 들으면서도 '이따가 복습할 때 완전히 새로 공부해야 하고 너무 어려우면 어떡하지?' 하고 걱정했는데, 다행히 ! 복습하면서 다 이해할 수 있었다. 차근차근 .. 꼭 잘 따라가야지.
어제 오랜만에 러닝도 하고, 상체도 했더니 아침에 피곤했다. 그래도 6시 이후를 의미 없이 보내는 것보다 훨씬 보람되고 개운했다. 지금처럼 스트레스 받지 않고 열심히 노력하자 ! 빠이팅 :)

아 맞다! 오늘 소회의실에서 자율학습하고 있을 때 강사님이 들어오셨다. 블로그 보고 있다고 하셔서 어머 !!! 했다. 세상에... 너무 감사하잖아요.. 누군가 읽는다는 게 뭔가 뿌듯(?), 기분 좋았다! 뭔가 쑥스럽기도 했다 ㅎㅋㅎ 앞으로도 열심히 해야겠다 .. ! !

0개의 댓글