enumeration 속기

Jung·2021년 2월 18일
0

수업

목록 보기
1/20

열거형
불연속적인 값. 상태가 아니라 값. 개수에 제한이 있어야 한다. 무한한 개수의 것들은 열거형으로 못쓴다. 돈, 통장잔고, 사람 이름은 열거형으로 못쓴다. 국가코드는 200개 내외이므로 열거형 가능하다.
type-safe: 메서드/오퍼레이션이 같은 타입에 대해서만 정의되어 있어, 다른 타입끼리 연산하면 컴파일 에러가 난다. ==, compare to 등이 가능하고, 메서드를 정의할 수 있다.
C의 enum은 아니지만 java는 type-safe하다.

C의 enum은 정수상수일뿐이라, (company.apple == fruit.apple)은 true이다.
java에선 (company.apple == fruit.apple)은 컴파일 에러가 난다.
JAVA enum은 Color, company, fruit 자체가 Type으로 간주된다.
내부적으로 enum Color { WHITE, BLACK } // WHITE =0; BLACK =1; 이 된다.

같은 줄에 public enum Animal{ CAT, DOG, HUMAN_2 }하면 ;안써도 되고
public enum Animal{
CAT, DOG, HUMAN_2 ;
}
줄바꿈 쓰려면 ; 써줘야한다.

Optional 공부해봐라.
junit말고 assertJ 써라.

junit5부터는 테스트 메서드에 private/ 등 접근제어자 쓰지 말아라.

테스트 클래스를 같은 패키지로 만들거나, import 하거나. 패키지 같이 하는걸 권장한다.
ex) package honux;
ex) import honux.Animal;

assertThat(dog == Animal.DOG).isTrue();
assertThat( dog.equals(Animal.DOG)).isTrue();

==와 equals의 차이: ==는 동등성을 비교하고, equals는 값이 같은지를 비교한다.
equals는 오버라이딩해서 비교할 수 있다. ==를 객체에 사용하면 똑같은 객체인지 아닌지를 (같은 주소인지를) 비교하므로 사용할수야있지만 우리가 원하는 것이 아닐 가능성이 있다.

public class Human{
	private String name;
    private int age;
    Human(String name, int age){
    	this.name = name;
        this.age = age;
    }
    
    @override
    public boolean equals(){
    //name만 같으면 같다고 오버라이드 하면? 
    }
   
    public static void main(String[] args){
    Human h = new Human("Kyu" , 25);
    Human j = new Human("Kyu" , 25);
    Human kyu = h ; 
    //h와  j는 다른 사람이다. 우연히 이름과 나이가 같을 뿐이다. 
    //heap에 객체 2개 생겨있다.
    h.equals(j); // true
    h==j; // false
    h == kyu; // true
    
    
    @override
    public boolean equals(){
    //name만 같으면 같다고 오버라이드 하면? 
    return Objects.equals(name, human.name)
    }
    
    Human h = new Human("Kyu" , 25);
    Human j = new Human("Kyu" , 30);
    h.equals(j); // true
    h==j; // false
    h == kyu; // true. key와 h는실제로 동일인물이기 때문에
    }
}

출처
출처2
==는 reference 비교(address비교)이고 .equals()는 내용물 content비교이다.
==는 메모리의 위치가 동일한지 비교하는 반면, equals()는 object내의 값을 비교하는 것이다. 만약 클래스에서 equals()를 override하지 않는다면 가장 가까운 조상에 정의된(override된) equals를 사용한다. (가장 가까운 조상이 Object이면 Object의 equals를 소환하는데, ==와 똑같아서, if and only if 그들의 참조가 하나이며 동일할때 true이다.)
equals를 오버라이드한다면, hashCode()역시 오버라이드해야된다. equals결과가 true라면 hashCode의 리턴 결과도 반드시 동일해야한다. 반대로 hashCode()가 동일하다고 equals()가 동일할 필요는 없다.

assertJ의
assertThat(a).isEqualTo(b);라고 하면, a에는 actual, b엔 expected.
junit의
assertEquals와 달리 가독성이 좋다.

enum Color { WHITE, BLACK , GREEN ...} 에 0부터 값이 들어간다. 그렇다고 해서 WHITE BLACK을 01라고 쓰지말고 순서가 있다는 것이다. BLACK는 WHITE보다 크다는 것이다.
assertThat( Color.WHITE.compareTo(Color.WHITE)).isEqualTo(0); // test통과
assertThat( Color.WHITE.compareTo(Color.GREEN)).isEqualTo(-2); // 통과
assertThat( Color.BLACK.compareTo(Color.WHITE)).isEqualTo(1); // 통과
//compareTo는 둘의 차이값이 리턴되고, 내가 작으면 음수가 리턴된다.
assertThat( Color.WHITE.compareTo(Color.GREEN)).isLessThan(0);
assertThat( Color.BLACK.compareTo(Color.WHITE)).isGreaterThan(0);
와 같이 써도 된다. 정확한 -2 1이 궁금한 것이 아니라 음/양/0인지가 궁금한 것이므로.

Color color = Color.WHITE;
if(color == Color.WHITE)와 같이 사용.

public class Human{
	private String name;
    private int age;
    
    public enum EyeColor{ BLACK, BROWN, BLUE, YELLOW }
    
    Human(String name, int age){
    	this.name = name;
        this.age = age;
    }

클래스에 종속적일땐 내부, 아닐땐 외부에 enum쓰면 된다.
내부에 쓰면 지저분해지는 단점이 있다. 가독성이 떨어진다.
꼭 클래스 내부에 enum을 쓰는 것은 종속관계를 명확히해서 ,human외에는 eyeColor을 절대 안쓴다는것을 알리고 싶을 때.

enum을 남발하면 코드가 복잡해지므로 가독성을 위해 안쓰는 것이 좋다.
그래도 써야한다면, 자동완성과 type-safe로 실수를 막을수있다는 장점때문일 것이다.

미래를 예측하고 코딩하지말고 필요해지면 그때 리팩토링해라. static남발하면 메모리부족때문에 서버 죽일 수도 있다.

enum은 값이랑 연결해서 쓰는 것이 많이 쓰인다. WHITE가 내부적으로 스트링 값을 갖도록 생성자쓸수있다.

public class Chess {
    public enum Color {
        WHITE("white"), BLACK("black");	

        private String value;

        Color(String color) {	// enum생성자로 내부적인 값을 갖도록 할수있고,
        						//private 생략된 것임
            this.value = color;
        }

        public String getValue() {
            return this.value;
        }
    } //enum Color 끝

    private Color color;

    public Chess(Color color) {
        this.color = color;
        System.out.println(color.getValue());
    }
}

enum생성자가 private인 이유는, 일종의 싱글턴singleton이라 우리가 만드느 것이 아니라 JVM이 만들어주는 것이다. 외부생성막기 위해 enum생성자는 내부적으로 private. 접근제어자 써주지 않아도 private인데, 컨벤션상 private 적지 않는다.
(*싱글턴이란? 인스턴스가 오직 1개만 생성되어야할때)

enum을 DB에 저장할 떄, DB에도 enum 타입이 있지만 enum타입을 사용하지 말아야한다.
varchar, char, 로 저장/사용할수있다.
DB에 상수로 저장할수없는 이유는 enum 목록에 중간삽입하면
public enum Size{ SMALL, NORMAL, BIG} 값이 각각 0 1 2이기 때문에
public enum Size{ SMALL, NORMAL, LITTLE_BIG, BIG} 했을때
BIG이 전부 LITTLE_BIG으로 바뀐다.
enum이 내부적으로 int이다.

pulic enum Size{
	SMALL('s', 44), MEDIUM('m', 55), BIG('l', 66), LITTLE_BIG('b', 77);
    public char v;
    public int value; //public이라면 final 써줘야한다. 아니면 꼭 private으로해서 외부에서 변경 불가하게 해줘야.
    
    Size(char v, int size){
    this.v = v;
    this.value = size;
    }
}

assertThat(Size.LITTLE_BIG.compareTo(Size.SMALL)).isGreaterThan(0); // pass
assertTHat(Size.LITTLE_BIG.ordinal()).isEqualTo(2); //그렇지만 ordinal은 절대 쓰지 말아라!

enum은 대부분 value Object이기 때문에 중간에 바꿀일ㄹ없어서, final로 바꾸어도된다.
enum으로 ==가 된다는 이야기는 참조주소가 같다는 뜻이다.

SMALL('s', 44) 이렇게 쓰면 DB 1번엔 s로 저장하고 DB 2번엔 44로 저장할수있다.

Size.name()은 값으로 이름을 갖고오고, Size.valueOf(이름)은 이름으로 값을 갖고 온다.
Size.values()는 이름들을 전부 갖고 옴.
Size안의 것 전부 가져와 for(String name: Size.values())식으로 사용.

일반적인 클래스와 value Object의 차이? value Object는 값으로만 이뤄진 클래스다.
Size와 Human클래스의 차이는, Size는 valu Object이라 value를 담는 것이 주목적이란 것이다. value는 상태가 변하지 않는다. 비교를 할때 value Object는 ==로 비교할 수있고, 값이 같으면 같은 객체라고 한다. HUman 객체는 값이 같더라도 다른 객체일수있기 때문에, value Object가 아니다. 유니크한 식별자가 없는 것이 value Object이다. 아무것도 안만들어도 객체는 자기 자신을 해시코드로 식별할수있다. 해시코드는 주소값, 포인터값이다. 일반적인 객체는 고유식별값이 있는데 value Object는 객체를 식별하는 것이 무의미하다. 예를들어 천원이면 다 천원이지 이 천원과 저 천원이 다르다고 생각하지 않고 이것이 value Object이다.

(DTO란 것도 있는데 DB할 때 배우자.)

List l = new ArrayList<>();
ArrayList al = new ArrayList<>();
일단 LIst에 담고 ArrayList 쓰고 싶으면 그 부분만 다운캐스팅하면 됨.
Li


C언어

void swap(int a, int b){
int temp =a;
a=b;
b=temp;
}

해도 스왑 안된다. swap(a, b)해봤자 swap(3, 5)가 된다. call by value이기 때문이다.
Argument = actual Parameter : 35
Parameter : ab

대신에 c에서는
void swap( int a, int b){
int temp = a;
a = b;
b = temp;
}하면 스왑 된다.
int a = 3; int b = 5;
swap(&a, &b);
하면 a=5; b =3;이 된다.
주소값을 호출해서 ...

c에서는 포인터를 사용해서 함수 안에서 매개변수를 바꿀 수 있게 된다.

bar(struct human h)하고 bar(pyro)하면 callby value로 struct human 의 크기가 전부 스택에 올라가지만
bar(struct human *h)하고 bar(&pyro)하면 call by address함. 자바는 이 이유로 primitivie는 call by value고 객체는 call by reference한다. 객체는 함수 내부에서 바꿀일이 많이 생긴다. 객체를 복사하면서 값을 복사하면 메모리가 아주 무거워지고 난리나고 성능도 느려진다.

struct human k; 하면 구조체 전체가 스택에 할당된다. 그래서 하면 안됨.
struct human *pyro = malloc(sizeof(human));하면
Human pyro =new human();한 것과 똑같아서 heap에 생긴다.

C언어는 call by value/reference 인지를 내가 결정하는 장점이 있고, 이것이 단점이기도 하다.

자바 클래스 내부에서 변수 직접접근해서 바꾸는 것이 좋지 않고, getter setter 메서드로 해야함. 내부에서 변경 적게 해야한다.

0개의 댓글