'공부/Spring'에 해당되는 글 7건

반응형

회원관리 예제


  • 회원 객체
package hello.hellospring.domain;

public class Member {
    //id식별자와 이름이 요구됨
    private Long id;
    private String name;

    //getter, setter생성
    public Long getId() {
        return id;
    }

    public void setId(Long id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }
}

 

  • 회원 리포지토리 인터페이스
package hello.hellospring.repository;

import hello.hellospring.domain.Member;

import java.util.List;
import java.util.Optional;

//회원 객체 저장소
public interface MemberRepository {
    Member save(Member member);//저장소에 회원 저장
    Optional<Member> findById(Long id);
    Optional<Member> findByName(String name);
    //optional 가져오는 값이 없으면 null일 수 잇음(NPE 방지)
    List<Member> findAll();//저장된 모든 회원 리스트 반환
}

 

  • 회원 리포지토리 메모리 구현체
package hello.hellospring.repository;

import hello.hellospring.domain.Member;

import java.util.*;

public class MemoryMemberRepository implements MemberRepository{

    //key는 long 값은 Memeber로
    private  static Map<Long, Member> store = new HashMap<>();//hashmap객체 map 생성(key는 long, value는 member
    private static long sequence = 0L;//0부터 키값 생성해줌

    @Override
    public Member save(Member member) {
        //id값 세팅후 store에 저장
        member.setId(++sequence);//save시 시퀀스값 올려줌
        store.put(member.getId(),member);

        return member;
    }

    @Override
    //store에서 꺼내서 찾으면됨
    public Optional<Member> findById(Long id) {
        //return store.get(id); => null이 반환될수도 있음
        return Optional.ofNullable(store.get(id));//NPE가 발생되지 않게 Optional로 감싸줌
    }

    @Override
    //store에서
    public Optional<Member> findByName(String name) {
        return store.values().stream()
                //stream은 iterator와 유사 => 요소를 순차적 처리, stream()은 stream객체로 반환
                .filter(memeber -> memeber.getName().equals(name))//member 객체를 받아서 equal하면 리턴
                .findAny();//filter로 찾은 값 중 아무값이나 하나 선택
        //루프를 돌면서 찾아지면 반환함, 끝까지 돌려서 없으면 Optional에 null이 포함되어 반환
    }

    @Override
    public List<Member> findAll() {
        //리스트로 반환
        //매개변수로 넘어온 컬렉션 객체가 저장되어 있는 ArrayList를 만듦
        //values는 값의 목록을 Collection 타입으로 리턴함
        return new ArrayList<>(store.values());
    }

    public void clearStore(){
        store.clear();
    }
}

 

 

  • 회원 리포지토리 메모리 구현체 테스트
package hello.hellospring.repository;

import hello.hellospring.domain.Member;
import org.junit.jupiter.api.Test;

//굳이 public하지 않아도됨 어디서 가져다 쓰지 않기 때문에
class MemoryMemberRepositoryTest {
    MemoryMemberRepository repository= new MemoryMemberRepository();

    @Test// 테스트를 수행하는 메소드가 된다.
    public void save(){
        Member member = new Member();
        member.setName("spring");

        repository.save(member);

        //반환타입이 Optional이므로 값을 꺼낼때 get으로 꺼냄냄
        //get() 메소드를 사용하면 Optional 객체에 저장된 값에 접근할 수 있습니다.
        //Optional<Member>이므로
        Member result = repository.findById(member.getId()).get();
        System.out.println("result = "+(result == member));

    }
}

 

 

출력하여서 확인하여도 된다.

 

출력하지 않고서 확인하는 법은

Assertion을 사용하는 것이다.

 

Assertions.assertThat(member).isEqualTo(result);

를 사용하여도 된다.(org.assertj.core.api)

 

 

    @Test
    public void findByName(){
        Member member1 = new Member();
        member1.setName("spring1");
        repository.save(member1);

        Member member2 = new Member();
        member2.setName("spring2");
        repository.save(member2);

        Member result = repository.findByName("spring1").get();

        Assertions.assertThat(result).isEqualTo(member1);

 

정리하면

package hello.hellospring.repository;

import hello.hellospring.domain.Member;
import org.assertj.core.api.Assertions;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.Test;

import java.util.List;

//굳이 public하지 않아도됨 어디서 가져다 쓰지 않기 때문에
class MemoryMemberRepositoryTest {
    MemoryMemberRepository repository = new MemoryMemberRepository();

    @AfterEach//메소드가 끝날때 마다 동작
    //test시 member객체를 계속 만들어서 중복이 되버리므로
    public void afterEach(){
        repository.clearStore();
    }

    @Test// 테스트를 수행하는 메소드가 된다.
    public void save() {
        Member member = new Member();
        member.setName("spring");

        repository.save(member);

        //반환타입이 Optional이므로 값을 꺼낼때 get으로 꺼냄냄
        //get() 메소드를 사용하면 Optional 객체에 저장된 값에 접근할 수 있습니다.
        //Optional<Member>이므로
        Member result = repository.findById(member.getId()).get();
        //System.out.println("result = "+(result == member));
        //Assertions.assertEquals(member, null);
        Assertions.assertThat(member).isEqualTo(result);

    }

    @Test
    public void findByName() {
        Member member1 = new Member();
        member1.setName("spring1");
        repository.save(member1);

        Member member2 = new Member();
        member2.setName("spring2");
        repository.save(member2);

        Member result = repository.findByName("spring1").get();

        Assertions.assertThat(result).isEqualTo(member1);
    }

    @Test
    public void findAll() {
        Member member1= new Member();
        member1.setName("Spring1");
        repository.save(member1);

        Member member2 = new Member();
        member2.setName("spring2");
        repository.save(member2);

        List<Member> result = repository.findAll();
		//크기가 2인지 확인한다.
        Assertions.assertThat(result.size()).isEqualTo(2);
    }

}

=> 자바는 Junit이라는 프레임워크로 테스트를 실행한다.

(main메소드나 웹 애플리케이션의 컨프롤러를 통하여 테스트할 경우 오래걸리고 반복실행, 여러테스트를 한번에 실행하기 어렵다.)

  • JUnit

    자바에서 독립단위 테스트(Unit Test)를 지원해주는 프레임워크

    assert메소드로 테스트케이스의 수행결과를 판별한다.

    @Test : 테스트를 수생하는 메소드 (각각 테스트가 서로 영향을 주지 않고 독립적으로 실행, @Test마다 객체를 생성)

    @AfterEach, BeforeEach : Test메소드가 실행될때 호출됨(각각 메소드 실행 후, 실행전 호출)

    @AfterAll, BeforeAll : 클래스에 존재하는 모든 메소드를 실행한다고 할때, 메소드 시작전, 끝난후에 실행됨

    메소드설명
    assertEquals(x, y)· 객체 x와 y가 일치함을 확인합니다.· x(예상 값)와 y(실제 값)가 같으면 테스트 통과
    assertArrayEquals(a, b);· 배열 A와 B가 일치함을 확인합니다.
    assertFalse(x)· x가 false 인지 확인합니다.
    assertTrue(x)· x가 true 인지 확인합니다.
    assertTrue(message, condition)· condition이 true이면 message표시
    assertNull(o)· 객체o가 null인지 확인합니다.
    assertNotNull(o)· 객체o가 null이 아닌지 확인합니다.
    assertSame(ox, oy)· 객체 ox와 oy가 같은 객체임을 확인합니다.· ox와 oy가 같은 객체를 참조하고 있으면 테스트 통과· assertEquals()메서드는 두 객체의 이 같은지 확인하고, assertSame()메서드는 두 객체의 레퍼런스가 동일한가를 확인합니다. (== 연산자)
    assertNotSame(ox, oy)· ox와 oy가 같은 객체를 참조하고 있지 않으면 통과
    assertfail()· 테스트를 바로 실패처리

 

728x90
반응형

'공부 > Spring' 카테고리의 다른 글

스프링 웹개발 기초  (0) 2021.10.20
자바 - Map  (0) 2021.10.19
자바 - Set  (0) 2021.10.18
자바 - 컬렉션(List)  (0) 2021.10.15
자바 - 제네릭  (0) 2021.10.14
블로그 이미지

아상관없어

,
반응형

스프링


스프링은 자바의 웹 프레임워크이다.

자바로 다양한 앱을 만들기 위한 프로그래밍 툴

 

thymeleaf : html 템플릿 엔진

 

.idea : intellij가 사용하는 설정파일

 

gradle : gradle관련 폴더

 

src : main, test가 있음 main이랑 test가 나뉘어져있음

main밑에 가면 자바랑 리소스(실제 자바코드파일을 제외한 어떤 xml, properties, 설정파일, html등)가 있음, 자바 밑에 실제 소스파일

test는 테스트코드들과 관련된 소스들이 있음

테스트코드가 중요하단 소리 요즘 개발 트렌드

 

build.gradle 이 중요

버전설정, 라이브러리 땡겨옴

plugins {
   id 'org.springframework.boot' version '2.5.4'
   id 'io.spring.dependency-management' version '1.0.11.RELEASE'
   id 'java'
}

group = 'hello'
version = '0.0.1-SNAPSHOT'
sourceCompatibility = '11' //자바 11버전

repositories {
   mavenCentral() //mavencentral싸이트에서 라이브러리를 다운받음
}

//라이브러리들
dependencies {
   implementation 'org.springframework.boot:spring-boot-starter-thymeleaf'//thymeleaf
   implementation 'org.springframework.boot:spring-boot-starter-web'//web
   testImplementation 'org.springframework.boot:spring-boot-starter-test'
   //테스트라이브러리가 자동으로 들어감 
}

test {
   useJUnitPlatform()
}

 

.gitignore

깃에는 필요한 소스코드만 올라감, start.spring.io에서 관리해줌

 

gradlew

gradlew.bat

 

settings.gradle

 

 

 

콘솔로 빌드 하기

해당 디렉토리로 이동후 "gradlew.bat build" 입력

image-20210928173216290

cd build

cd libs

java -jar hello-spring-0.0.1-SNAPSHOT.jar

image-20210928173505805image-20210928173523377

 

서버배포시 "hello-spring-0.0.1-SNAPSHOT.jar" 파일만 복사해서 옮기고 실행하면 된다.

그러면 서버에서 스프링이 동작하게 된다.

 

"gradle clean" or "gradle clean build" 명령어 입력시 build폴더가 없어진다.

 

 

스프링 웹 개발 기초


정적 컨텐츠 : 파일을 그대로 웹브라우저에 내려줌. 그냥 파일을 그대로 전달해줌

MVC와 템플릿 엔진 : 가장많이 하는 방식, (jsp, php 등 템플릿 엔진), 서버에서 프로그래밍해서 동적으로 웹브라우저에 내림, 서버에서 변형을 해서 전달해줌

API : json데이터 포맷으로 클라이언트에게 데이터를 전달해줌, 뷰나 리액트에서 사용(데이터만 주면 화면은 클라이언트가 알아서 그림), 서버끼리 통신할때(데이터만 왓다갓다)

 

 

- 정적컨텐츠

image-20210928174256185

resources/static 폴더 안 아무 html파일 하나 생성후 작성

image-20210928174427627

정적파일이 그대로 반환이 됨.

따로 프로그래밍을 할 수는 없다.

 

thymeleaf엔진은 서버없이 html파일을 열어볼 수 있음

image-20210930220333376image-20210930220344251

 

 

image-20210930220846830

동작하지 않음

 

2021-09-30 22:08:36.038 WARN 3676 --- [nio-8080-exec-4] .w.s.m.s.DefaultHandlerExceptionResolver : Resolved [org.springframework.web.bind.MissingServletRequestParameterException: Required request parameter 'name' for method parameter type String is not present]

"Required request parameter 'name' for method parameter type String is not present" 임

 

image-20210930221110958image-20210930221354214

변환된 html이 넘어간다.

템플릿 방식은 뷰가 있고 거기서 화면을 조작함

 

 

api사용법

@GetMapping("hello-string")
    @ResponseBody //http에서 body부분의 데이터를 직접 넣어주겟다 라는 뜻
    public String helloString(@RequestParam("name") String name){
        return "hello" + name;//문자가 그대로 내려감,
        // 템플릿 엔진과의 차이점은 뷰 엔진이 없고 문자가 그대로 내려감

    }

 

http://localhost:8080/hello-string?name=string!!!

image-20210930221801049image-20210930221809163

문자만 그대로 내려감

728x90
반응형

'공부 > Spring' 카테고리의 다른 글

회원관리 예제 - 회원도메인, 리포지토리, 테스트케이스  (0) 2021.10.20
자바 - Map  (0) 2021.10.19
자바 - Set  (0) 2021.10.18
자바 - 컬렉션(List)  (0) 2021.10.15
자바 - 제네릭  (0) 2021.10.14
블로그 이미지

아상관없어

,

자바 - Map

공부/Spring 2021. 10. 19. 15:49
반응형

Map

key와 value로 이루어져있다.

키는 해당 map에서 중복되지않고 키와 값이 1:1로 저장된다.

(키가 다르고 값이 같은 경우 서로 다른 것으로 간주한다.)

 

모든 데이터는 키와 값이 존재

키없이 값만 저장 불가

값 없이 키만 저장 불가

키는 해당 맵에서만 고유함

값은 중복되어도 상관없음

 

java.util.Map 인터페이스로 선언되어 있다.

 

주요 메소드는

V put(K key, V value) : 키와 값을 데이터에 저장한다.

void putAll(Map<? extends K, ? extends V> m) : 매개변수로 넘어온 Map의 모든 데이터를 저장

V get(Object key) : key에 해당하는 값을 넘겨줌

V remove(Object key) : key에 해당되는 값을 넘기고, 해당 키와 값을 삭제한다.

Set keySet() : 키의 목록을 Set타입으로 리턴함

Collection values() : 값의 목록을 Collection 타입으로 리턴함

Set<Map.Entry<K,V>> entrySet() : Map안에 Entry라는 타입의 Set을 리턴함

int size() : Map 크기 리턴

void clear() : Map내용 지움

 

Map을 구현한 주요 클래스들은 HashpMap, TreeMap, LinkedHashMap, Hashtable 등이 있다.

 

Hashtable 클래스는 Map 인터페이스를 구현하였지만, 다른 Map을 구현한 클래스와는 조금 다르다.

Map은 키,값, 키-값 쌍으로 데이터를 순환하여 처리 가능 // Hashtable은 키-값 쌍으로 데이터를 순환하여 처리 불가

Map은 iteratrion을 처리하는 도중에 데이터를 삭제하는 안전한 방법 제공 // Hashtable은 제공 X

Map은 Collection view 사용 // Hashtable은 Enumeration 객체를 통하여 데이터 처리

 

HashMap과의 차이는

Hashtable은 키나 값에 null을 저장할 수 없고

HashMap과 다르게 여러 쓰레드에서 동시 접근이 가능하다.

 

=> 중요한 것은 어떤 작업에 어떤 클래스가 어울리는지 알고 사용하는 것이다.

 

HashMap

Object - AbstractMap - HashMap

 

생성자

HashMap() : 16개의 저장곤간을 갖는 HashMap 객체 생성

HashMap(int initialCapacity) : 매개변수만큼의 저장공간을 갖는 HashMap객체 생성

HashMap(int initialCapactiy, float loadFactor) : 첫 매개변수의 저장공간을 갖고, 두번째 매개 변수의 로드 팩터를 가지는 객체 생성

HashMap(Map<? extends K, ? extends V> m) : 매개 변수로 넘어온 Map을 구현한 객체에 있는 데이터를 갖는 HashMap객체 생성

 

대부분 HashMap 객체 생성시에는 매개변수가 없는 생성자를 사용한다.

 

import java.util.HashMap;
import java.util.Set;
import java.util.Map.Entry;

public class MapSample {
	public static void main(String[] args){
		MapSample sample=new MapSample();
		sample.checkHashMap();
	}
	//HashMaP객체 생성 후 값 넣기
	public void checkHashMap(){
		HashMap<Strig, String> map = new HashMap<String, String>();
		map.put("A", "a"); //키-값 순서이다.
		
		System.out.println(map.get("A"));
		System.out.println(map.get("B")); // ->null을 리턴 없는값이므로\
		
		map.put("A", "1"); // A의 값이 1로 변경된다.(값 입력, 수정 모두 put을 이용)
		
		//키와 값 모두 확인하려면??
		map.put("C", "c");
		map.put("D", "d");
		Set<String> keySet=map.keySet();//keySet()메소드 사용
		//출력의 순서는 뒤죽박죽이다. List와 Queue외에는 저장순서가 중요하지 않다
		for(String tempKey:keySet){
			System.out.println(tempkey+"="+map.get(tempKey));//값은 get으로 가져옴
		}
		
		//객체에 담겨있는 값만 확인하려면?? => value()
		Collection<String> values=map.values();//HashMap 객체에 담긴 값을 Collection 타입의 목록으로 반환
		for(String tempValue:values){
			System.out.println(tempValue);
		}
		
		
		//Entry 객체를 사용하여 키와 값을 얻기 => getKey(), getValue()사용
		Set<Entry<String, String>> entries= map.entrySet();
		for(Entry<String, String> tempEntry:entries){
			System.out.println(tempEntry.getKey()+"="+tempEntry.getValue())
		}
		
		//키나 값이 존재하는지 확인 => containsKey(), containsValue() 리턴값은 참 거짓
		map.containsKey("A");
		map.containsValue("a");
		
		//데이터 삭제 => remove()
		map.remove("A"); //A를 키로 갖는 데이터가 삭제됨

 

728x90
반응형

'공부 > Spring' 카테고리의 다른 글

회원관리 예제 - 회원도메인, 리포지토리, 테스트케이스  (0) 2021.10.20
스프링 웹개발 기초  (0) 2021.10.20
자바 - Set  (0) 2021.10.18
자바 - 컬렉션(List)  (0) 2021.10.15
자바 - 제네릭  (0) 2021.10.14
블로그 이미지

아상관없어

,

자바 - Set

공부/Spring 2021. 10. 18. 18:15
반응형

Set

순서 상관없이 어떤 데이터가 조재하는지 확인하기 위한 용도로 사용

중복되는 것을 방지하고 원하는 값이 포함되어 있는지 확인하는 용도

 

Set 인터페이스를 구현한 주요 클래스는 HashSet, TreeSet, LinkedHashSet가 있다

 

  • HashSet

순서가 필요없는 데이터를 해시테이블에 저장함. 성능이 가장 좋음

Object - AbstractCollection - AbstarctSet - HashSet 구조로 상속받는다.

 

HashSet의 생성자에는

HashSet() : 데이터를 저장할 수 있는 16개의 공간과 0.75의 load factor를 갖는 객체를 생성한다.

HashSet(Collection<? extends E> c) : 매개 변수로 받은 컬랙션 객체의 데이터를 HashSet에 담는다.

HashSet(int initialCapacity) :매개 변수로 받은 개수만큼의 데이터 저장 공간과 0.75의 load factor를 갖는 객체를 생성

HashSet(int initialCapacity, float loadFactor) : 첫번째 매개변수로 받은 개수만큼의 데이터 저장공간과, 두번째 매개변수로 받은 만큼의 load factor를 갖는 객체를 생성한다.

 

load factor : 데이터 개수/ 저장공간

데이터 개수가 증가하여 load factor 보다 커지면 저장공간의 크기는 증가되고 해시 재정리 작업을 해야한다.

=> 자료구조를 다시 생성하므로 "성능에 영향"

load factor가 클수록 공간은 넉넉해지지만, 데이터를 찾는 "시간은 증가"하게 된다.

=> 초기 공간 개수와 load factor는 데이터의 크기를 고려하여 산정하는 것이 좋음

 

HashSet의 주요 메소드들

boolean add(E e) : 데이터 추가

void clear() : 모든 데이터 삭제

Object clone() : HashSet 객체를 복제, 담겨잇는 데이터는 복제X

boolean isEmpty() : 데이터가 있는지 확인함

boolean contains(Object o) : 해당 객체가 있는지 확인

Iterator iterator() : 데이터를 꺼내기 위한 Iterator 객체를 리턴함

boolean remove(Object o) : 매개 변수로 넘어온 객체를 삭제함

int size() : 데이터의 개수

 

import java.util.HashSet;
import java.util.Iterator;

...
... main ...
String[] cars = new String[]{"Hyundai", "Kia", "Samsung", "BMW", "Audi", "Kia", "Samsung"};

...

//차종의 개수를 알아내려는 메소드
public int getCarKinds(String[] cars){
	if(cars == null) return 0;
	if(cars.length==1) return 1;
	
	//HashSet을 생성하여 add해줌 => 중복된 값이 없어짐
	HashSet<String> carSet=new HashSet<String>();
	for(String car : cars){
		carSet.add(car);
	}
	//size를 반환하면 차종의 수를 알 수 있음
	return carSet.size();
}

//값을 꺼낼경우 1=> 데이터의 저장순서는 뒤죽박죽이다. Set은 데이터의 저장순서가 중요하지않은 경우 사용한다.
public void printCarSet(HashSet<String> carSet){
	for(String temp : carSet){
		System.out.print(temp + " ");
	}
	System.out.println();
}

//값을 꺼낼 경우 2 => Iterator의 hasNext, next이용
public void printCarSet2(HashSet<String> carSet){
	Iterator<String> iter=carSet.iterator();
	while(iter.hasNext()){
		System.out.print(iter.next()+" ");
	}
}

 

 

TreeSet

저장된 데이터의 값에 따라서 정렬됨

red-black(이진트리)이라는 트리 타입으로 저장되며 HashSet보다 약간 느리다.

 

LinkedHashSet

연결된 목록타입으로 구현된 해시 테이블에 데이터 저장

저장된 순서에 따라 값이 정렬됨. 성능이 가장 나쁘다.

728x90
반응형

'공부 > Spring' 카테고리의 다른 글

스프링 웹개발 기초  (0) 2021.10.20
자바 - Map  (0) 2021.10.19
자바 - 컬렉션(List)  (0) 2021.10.15
자바 - 제네릭  (0) 2021.10.14
자바 문법  (0) 2021.10.13
블로그 이미지

아상관없어

,
반응형

컬렉션

자바 컬렉션은 목록성 데이터를 처리하는 자료구조를 통칭함

 

만약 여러개의 String 객체를 하나의 객체에 담으려면? => 배열을 이용하면된다.

하지만 담으려는 데이터의 크기를 모르면?

 

자바에선 이러한 문제를 해결하는 클래스가 미리 만들어져있다.

 

순서가 있는 목록인 List형

순서가 중요하지 않은 목록인 Set형

먼저 들어온 것이 먼저 나가는 Queue형

키-값(key-value)로 저장되는 Map형

 

List, Set, Queue는 Collection이라는 인터페이스를 구현한다.

Collection 인터페이슨느 java.util 패키지에 선언되어있고,

여러 개의 객체를 하나의 객체에 담아 처리할때 공통적으로 사용되는 여러 메소드를 선언해두었다.

 

Map은 Collection과 관련없는 별도의 인터페이스로 선언되어있다.

 

public interface Collection<E> extends Iterable<E>

Collection인터페이스는 Iterable라는 인터페이스를 확장했다.

해당 인터페이스는 iterator()메소드만 선언되어있고 Interator라는 인터페이스를 리턴한다.

 

Iterator라는 인터페이스에는

hasNext() : 추가데이터가 잇는지 확인

next() : 현재 위치를 다음 요소로 넘기고 그 값을 리턴해줌

remove() : 데이터를 삭제

라는 메소드가 있다.

 

Collection인터페이스가 Iterable 인터페이스를 확장했으므로 Iterator 인터페이스로 데이터를 순차적으로 가져올 수 있다.


 

 

List

List 인터페이스는 Collection인터페이스를 확장한다.

Collection 인터페이스를 확장하는 다른 인터페이스와 다른점은 배열처럼 순서가 있다는 점이다.

 

List 인터페이스를 구현한 클래스들 중 많이 사용하는 것은

  • ArrayList
  • Vector
  • Stack
  • LinkedList

이다.


 

ArrayList

크기 확장이 가능한 배열이다.

 

상속관계를 보면

java.lang.Object

jaba.util.AbstractCollection

java.util.AbstractList

java.util.ArrayList

이다.

=> AbstractCollection,AbstractList는 각각 Collection, List 인터페이스 중 일부만 구현했다.

 

ArrayList가 구현한 inerface들은

Serializable, Cloneable, Iterable, Collection, List, RandomAccess

이다.

 

public class ListSample{
	public static void main(String[] args){
		ListSample sample = new ListSample();
		sample.checkArrayList1();
	}
	
	public void checkArrayList1(){
		//list1 객체 생성 => ArrayList객체인 list1에 객체들을 넣을 수 있음
		ArrayList list1=new ArrayList();
		
		//list1에 객체들을 넣음
		list1.add(new Object());
		list1.add("ArrayListSample");
		list1.add(new Double(1));
	}
}

컴파일 되지 않는다. => ArrayList는 java.lang에 속한 클래스가 아니기 때문이다.

따라서

import java.util.ArrayList //를 해주어야한다.

 

ArrayList 객체에 여러 객체들을 넣을 수 있지만, 한가지 종류의 객체만을 주로 저장한다.

여러 종류를 하나의 객체에 담을 때는 DTO라는 객체를 만들어서 담는것이 좋다.

따라서 컬렉션 관련 클래스의 객체를 선언할때는 제네릭을 사용하여 선언하는것이 좋다.

=> 한가지 종류의 객체만을 저장

ArrayList<String> list1=new ArrayList<String>();

위와 같이 선언하면 list1은 String 타입의 객체만 넣을 수 있다.

(제네릭을 사용하여, 컴파일 시점에 다른 타입이 잘못 지정되는 것을 막을 수 있다.)

 

ArrayList 객체를 선언할 때 매개변수를 넣지 않으면 기본 초기값은 10이다.

(10개 이상의 데이터가 들어가면 크기를 늘리는 작업은 ArrayList내부에서 자동으로 수행된다.)

ArrayList<String> list1 = new ArrayList<String>(100);

 

 

ArrayList에 데이터를 담기위해선 add와 addAll메소드를 사용하면된다.

 

boolean add(E e) : 매개 변수로 넘어온 데이터를 가장 끝에 담음(리턴값은 제대로 추가되었는지 확인)

void add(int index, E e) : 매개 변수로 넘어온 데이터를 지정된 index위치에 담는다.

boolean addAll(Collection<? extends E> c) : 매개 변수로 넘어온 컬렌션 데이터를 가장 끝에 담는다.

boolean addAll(int index, Collection<? extends E> c) : 매개 변수로 넘어온 컬렉션 데이터를 index에 지정된 위치부터 담는다.

 

만약 list1의 내용을 list2에 복사하고 싶으면

ArrayLsit<String> list2 = new ArrayList<String>(list);

와 같이 사용하면 된다.

ArrayList에는 Collecion 인터페이스를 구현한 어떠한 클래스도 포함시킬 수 있는 생성자가 있기 때문

 

list2=list1

을 해버리면 주소가 같으므로 위와같이 생성자를 이용하여 복사하거나

addAll()을 이용하여 복사하여야 한다.

 

데이터를 꺼내는 법

size() : ArrayList객체에 들어가 있는 데이터의 개수를 가져오는 메소드

=> ArrayList의 크기를 말하는 것이 아님

get(int index)메소드를 사용하여 데이터를 가져올 수 있다.

 

중복된 값이 잇을경우에는

int indexOf(Object o) : 매개 변수로 넘어온 객체와 동일한 데이터의 위치를 리턴한다.

=>앞에서부터 찾을 경우

int lastIndexOf(Object o) : 매개 변수로 넘어온 객체와 동일한 마지막 데이터의 위치를 리턴한다.

=> 뒤에서부터 찾을 경우

 

ArrayList 객체에 있는 데이터들을 배열로 뽑아낼 경우엔 toArray()메소드를 사용한다.

Object[] toArray() : 객체에 있는 값들을 Object[] 타입의 배열로 만듬

T[] toArray(T[] a) : 객체에 있는 값들을 매개변수로 넘어온 T타입의 배열로 만든다.

 

매개변수가 없는 toArray는 Object타입의 배열로만 리턴하므로, 제네릭을 사용하여 선언한 ArrayList 객체를 배열로 생성할 때는 매개변수가 있는 toArray를 사용하는것이 좋다.

String[] temp = new String[5];
String[] strList=list.toArray(temp);

만약 list의 size가 3이라면 (데이터는 1, 2, 3이라 가정)

strList를 출력하면 1, 2, 3, null, null로 출력될것이다.

 

ArrayList에 저장된 데이터 size > 매개변수로 넘어온 배열의 크기

즉, size(list)=3 > temp=0 크기이면

새로운 배열을 생성하여 넘겨주므로

String[] strList=list.toArray(new String[0]);

와 같이 크기가 0인 배열을 넘겨주는 것이 좋다.

 

데이터 삭제

void clear() : 모든 데이터 삭제

E remove(int index) : 매개 변수에서 지정한 위치에 있는 데이터를 삭제하고 리턴

boolean remove(Object o) : 매개변수에 넘어온 객체와 동일한 "첫번째" 데이터를 삭제한다.

boolean removeAll(Collection<?> c) : 매개 변수로 넘어온 "컬렉션 객체에 있는 데이터"와 "동일한 모든 데이터"를 삭제한다.

 

데이터 변경

E set(int index, E element) : 지정한 위치에 있는 데이터를 두번째 매개변수로 넘긴 값으로 변경, 해당위치에 있던 데이터를 리턴

=> 원래 값 반환하고 설정값으로 값 바꿈

=> remove, add 두 과정을 거칠필요 없음

 

trimToSize() : 객체 공간의 크기를 데이터의 개수만큼으로 변경함, 즉 앞뒤 공백을 없앰

 

728x90
반응형

'공부 > Spring' 카테고리의 다른 글

스프링 웹개발 기초  (0) 2021.10.20
자바 - Map  (0) 2021.10.19
자바 - Set  (0) 2021.10.18
자바 - 제네릭  (0) 2021.10.14
자바 문법  (0) 2021.10.13
블로그 이미지

아상관없어

,

자바 - 제네릭

공부/Spring 2021. 10. 14. 18:33
반응형

제네릭

import java.io.Serializable;

public class CastingDTO implements Serializable{
	//타입이 Object이므로 어떤 타입이든 사용할 수 있다.
	priavet Object object;
	public void setObject(Object object){
		this.object=object;
	}
	
	public Object getObject(){
		return object;
	}
}

위 경우 Object타입을 인자로 받으므로 생성시 String이나 StringBuffer등 여러타입으로 생성할 경우 각각 타입으로 형 변환을 해야한다. 또한 여러 타입으로 생성시 각 객체가 어떤 타입인지 혼동 될 수 있다.

 

따라서 

import java.io.Serializable;

public class CastingGenericDTO<T> implements Serializable{
	priavet T object;
	public void setObject(T object){
		this.object=object;
	}
	
	public T getObject(){
		return object;
	}
}

T는 아무런 이름을 지정하여도된다.

<>안에는 현재 존재하는 클래스를 사용해되 되고, 존재하지 않는 것을 사용해도 된다.

되도록이면 클래스 이름의 명명 규칙과 동일하게 지정하는 것이 좋다.

선언 후 클래스 안에서 하나의 타입 이름처럼 사용하면된다.

만약 <>안의 이름이 현재 존재하는 클래스여야한다면, 컴파일시 에러가 발생할 것이다.

따라서, 가상 타입의 이름이라고 생각하면 된다.

 

 

제네릭을 사용하지 않을 경우 예시를 보면,

public class GenericSample{
	public static void main(String[] args){
		GenericSample sample = enw GenericSample();
		sample.checkCastingDTO();
	}
	
	public void checkCastingDTO(){
		CastingDTO dto1=new CastingDTO();
		dto1.setObject(new String());
		
		CastingDTO dto2=new CastingDTO();
		dto2.setObejct(new StringBuffer());
		
		CastingDTO dto3=new CAstingDTO();
		dto3.setObject(new StringBuilder());
	}
}

 

String temp1 = (String)dto1.getObject();
StringBuffer temp2 = (StringBuffer)dto2.getObject();
StringBuilder temp3 = (StringBuilder)dto3.getObject();

리턴 값으로 넘어는 타입은 Object이므로 형변환을 해주어야한다.

dto2의 인스턴스 변수 타입이 StringBuilder인지 StringBuffer인지 혼동된다면??

instanceof를 사용하여서 점검해도 되지만,

 

CastingGenericDTO클래스를 이용하여

public void checkGenericDTO(){
	CastingGenericDTO<String> dto1 = new CastingGenericDTO<String>();
	dto1.setObject(new String());
	
	CastingGenericDTO<StringBuffer> dto2 = new CasintgGenericDTO<StringBuffer>();
	dto2.setObject(new StringBuffer());
	
	CastingGenericDTO<StringBuilder> dto3 = new CasintgGenericDTO<StringBuilder>();
	dto3.setObject(new StringBuilder());
 }
String temp1 = dto1.getObject();
StringBuffer temp2 = dto2.getObject();
StringBuilder temp3 = dto3.getObject();

로 사용할 수 있다.

<>안에 타입을 명시적으로 적어주게되어 헷갈리지 않는다.

실행시에 타른 타입으로 잘못 형변환되어 예외가 발생하는 일이 없어진다

또한 형변환을 해주지 않아도 된다.

결과적으로 실행시 다른 타입으로 잘 못 형변환한하여 예외가 발생하는 일이 없어진다.

 

제네릭한 클래스의 타입만 바꾼다고 Overriding이 불가능하다.

public class WildcardGeneric<W>{
	W wildcard;
	public void setWildcard(W wildcard){
		this.wildcard = wildcard;
	}
	pubilc W getWildcard(){
		return wildcard;
	}
}

set, get하는 간단한 class이다

 

public class WildcardSample{
	public static void main(String[] args){
		WhildcardSample sample = new WildcardSample();
		sample.callWildcardMethod();
	}
	
	public void callWildMethod(){
		//String을 사용하는 제네릭한 객체를 생성함
		WildcardGeneric<String> wildcard = new WildcardGeneric<String>();
		wildcard.setWildcard("A");
		wildcardMethod(wildcard);
	}
	
	public void wildcardMethod(wildcardGeneric<String> c){
		String value = c.getwildcard();
		System.out.println(value);
	}
}

 

 

만약 <String>이 아니라 WildcardGeneric<Integer>과 같이 선언된 객체를 받으려면??

불가능하다.

제네릭한 클래스의 타입만 바꾼다고 오버라이딩이 가능하진 않다.

public void wildcardMethod(WhildcardGeneric<?> c){ 
//<- ?로 적어주면 어떤 제너릭 타입이 되더라도 상관없다.
	Object value=c.getWildcard(); //정확한 타입을 모르므로, Object로 값을 받아야한다.
	System.out.println(value);
}

 

이렇게는 사용 불가하다.

	public void callWildMethod(){
		//알수 없는 타입에 String을 지정할 수 없다고 에러가 난다.
		WildcardGeneric<?> wildcard = new WildcardGeneric<String>();
		wildcard.setWildcard("A");
		wildcardMethod(wildcard);
	}

객체에 제너릭 타입으로 값을 지정하는 것은 불가능하다.

 

제네릭 선언에 사용하는 타입의 범위도 지정할 수 있다.

<? extends 타입>으로ㅓ 선택한다.

 

//Car

public class Car{
	protected String name;
	public Car(String name){
		this.name=name;
	}
	
	public String toString(){
		return "Car name="+name;
	}
}
//Bus

public class Bus extends Car{
	public Bus(String name){
		super(name);
	}
	public String toString(){
		return "Bus name="+name;
	}
}
//WildcardSample

public class WildcardSample{
	public static void main(String[] args){
		WhildcardSample sample = new WildcardSample();
		sample.callWildcardMethod();
	}
	
	public void callWildMethod(){
		//String을 사용하는 제네릭한 객체를 생성함
		WildcardGeneric<String> wildcard = new WildcardGeneric<String>();
		wildcard.setWildcard("A");
		wildcardMethod(wildcard);
	}
	
	public void wildcardMethod(wildcardGeneric<String> c){
		String value = c.getwildcard();
		System.out.println(value);
	}
	
	public void callBoundedWildcardMethod(){
		//Car을 사용하는 제네릭 객체 생성
		WildcardGeneric<Car> wildcard = new WildcardGeneric<Car>();
		wildcard.setWildcard(new Car("BMW"));
		wildcardMethod(wildcard);
	}
	
	//?는 어떠한 타입이 와도 상관이 없다. 
	//제네릭 타입으로 Car를 상속받은 모든 클래스를 사용할 수 있다는 의미가 된다.
	//즉 반드시 Car클래스를 확장한 클래스가 넘어와야한다.
	public void boundedWildcardMethod(WildcardGeneric <? extends Car> c){
		Car value=c.getWildcard();
		System.out.println(value);
	}
}
public void callBoundedWildcardMethod(){
		//Bus을 사용하는 제네릭 객체 생성
		WildcardGeneric<Bus> wildcard = new WildcardGeneric<Bus>();
		wildcard.setWildcard(new Bus("Bus"));
		wildcardMethod(wildcard);
	}

callBoundedWildcardMethod()를 호출하면, Bus를 사용하는 제네릭한 객체를 넘겨주어도 실행이 잘 된다.

Bus클래스는 Car클래스를 상속받기 때문이다.

 

public class WildcardGeneric<W>{
	W wildcard;
	public void setWildcard(W wildcard){
		this.wildcard = wildcard;
	}
	pubilc W getWildcard(){
		return wildcard;
	}
}
//wildcardSample
...
public <T> void genericMethod(WildcardGeneric<T> c, T addValue){
	c.setWildcard(addValue);//값을 할당함
	T value = c.getWildcard();
	System.out.println(value);
}

//genericMethod 사용
public void callGenericMethod(){
	WildcardGeneric<String> wildcard = new WildcardGeneric<String>();
	genericMethod(wildcard, "Data");//string을 사용하는 제네릭한 객체와 T타입의 변수
}

 

public <S, T extends Car > void genericMethod(WildcardGeneric<T> c, T addValue, S another){
	...
}
//도 가능하다.
//S와 T라는 제네릭 타입을 메소드에서 사용할 수 있다.

 

리턴타입 앞 로 제네릭 타입을 선언했다.

매개변수에는 제네릭타입이 포함된 객체를 받아서 처리했다.

메소드 선언시 리턴타입 앞에 제네릭한 타입을 선언해주고 그 타입을 매개 변수에서 사용하면 컴파일할 때 문제가 없다.

 

728x90
반응형

'공부 > Spring' 카테고리의 다른 글

스프링 웹개발 기초  (0) 2021.10.20
자바 - Map  (0) 2021.10.19
자바 - Set  (0) 2021.10.18
자바 - 컬렉션(List)  (0) 2021.10.15
자바 문법  (0) 2021.10.13
블로그 이미지

아상관없어

,

자바 문법

공부/Spring 2021. 10. 13. 21:10
반응형

배열

int [] nums;
int nums[];

int [] nums;
nums = new int[5];

int nums[] = {1, 2, 3}


 

생성자

생성자는 자바 클래스의 객체를 생성하기 위해 존재한다.

Test test = new Test();

생성자의 리턴타입은 클래스의 객체이다.

다른 생성자가 없을 경우 기본으로 컴파일할 때 만들어진다.

-> 다른 생성자가 있을 경우, 기본 생성자는 만들어지지 않음


 

메소드 overloading

이름은 같지만 매개변수가 다르다. 매개변수의 종류, 개수, 순서가 다르다.


 

static 메소드

객체를 생성하지 않아도 호출할 수 있다.

static => 클래스가 메모리에 올라갈때 할당된다.

 

자바에서는 하나의 클래스를 컴파일할 때, 관련된 클래스가 컴파일 되어있지않으면 알아서 컴파일해준다.


 

static 블록

static {
//딱 한번만 실행되는 코드
}

객체가 생성되기 전에 한번만 호출됨.

메소드 내에 선언 불가 => static 이므로

생성자가 호출되기 전에 static 블록들이 호출된다.

static한 변수, 메소드를 사용할 수 있다.


 

String

string은 참조형이지만

String b="b";//new를 쓰지않았지만 객체를 생성한것임
b="z";

String b=new String("b");
b=new String("z");

String b="b";
b=b+"z" //더하기 연산시 기존의 객체는 버리고 새로운 객체를 만든다.

 

매개변수 개수가 몇개일지, 호출될때마다 바뀔때 방법

public void calc(int... nums){
}

//호출시
calc(1, 2, 3, 4)
calc(1, 2)


OR

public void calc(String op, int... nums){
}

**여러 매개변수가 있을때, "타입... 변수명"은 항상 맨 뒤에 와야함.
**"타입... 변수명"다음엔 메소드의 선언을 닫는 소괄호가 와야한다.

 

패키지

클래스들을 구분짓는 폴더

어떤 클래스가 어떤 일을 하는지 혼동되는 것을 방지

  • 패키지 이름을 java로 시작하면 안된다.
  • 패키지 선언은 소스 하나에는 하나만 있어야한다.
  • 패키지 이름과 위치한 폴더이름이 같아야한다.
  • (자바 파일을 만든 폴더 이름과 선언된 패키지 이름이 다르면 파일을 찾지 못한다.)
  • 패키지 이름은 모두 소문자로 지정
  • 자바의 예약어를 사용하지 않는다.(com.int.util과 같이 int가 없어야함 )
package c.javapackage;//패키지 선언문

public class Package{
...
}

컴파일시 소스코드와 컴파일된 클래스가 같은 디렉토리에 존재하게 된다.

 

import를 이요하여 다른패키지에 접근할 수 있다.

import 패키지이름.클래스이름


 

import static

static한 변수와 메소드를 사용할때 용이

package c.sub;

public class Sub{
...

	public final static String CLASS_NAME="sub";
	public static void method(){
		System.out.println('sub method');
	}
}
//1. 그냥 import하여 사용
package c;

immport c.sub;

...
public static void main(Strings[] args){
	Sub.method();
	System.out.println(Sub.CLASS_NAME);
}
//2. import static 사용

package c;

import static c.sub.Sub.CLASS_NAME;
import static c.sub.Sub.method;

...
~~ main ~~ {
	method();
	System.out.println(CLASS_NAME);
}
...

static 변수나 메소드가 중복될때는 자신의 클래스에 있는 static 변수나 메소드가 import static으로 가져온 것보다 우선이다.


 

접근제어자

  • public : 누구나 접근
  • protected : 같은 패키지내에있거나 상속받은 경우 접근
  • package-private : 같은 패키지내에 잇을때 (접근제어자 없을경우 기본)
  • private : 해당 클래스내에서만 접근 가능

=> 말그대로 접근을 제어하기 위해 사용, 주로 직접 접근하지 않고 메소드를 통하여 변경이나 조회를 할 수 있도록 할 때 사용

static => 클래스 변수/ 메소드 밖, 클래스 안

자바에서는 하나의 클래스를 컴파일할 때 관련된 클래스가 컴파일 되어 있지 않다면, 알아서 컴파일 해줌

한번만 호출되어야 하는 코드가 있따면 static 블록 사용

public으로 선언된 클래스가 소스내에 있으면, 그 소스 파일의 이름은 public 인 클래스 이름과 동일해야함

하나의 클래스 소스에서 여러 클래스가 선언가능하다 (단, 같은 패키지 내에 있는 클래스만 이 클래스의 객체를 생성하고 사용할 수 있다.)

 

public으로 선언된 클래스가 소스내에 있으면, 소스파일의 이름은 public인 클래스 이름과 동일해야한다.


 

상속

부모 클래스에 선언된 public, protected로 선언된 모든 변수와 메소드를 내가 갖고 잇는 것처럼 사용

자바에서 아무런 상속을 받지 않으면, java.lang.Object 클래스를 확장한다.

자바는 이중상속을 받을 수 없지만, 여러 단계로 상속을 받을 수 있다.

ex) Object -> Parent -> Child

Object 클래스에 있는 메소드를 통해서 클래스의 기본적인 행동을 정의할 수 있음.

(기본적으로 갖추어야될 메소드들 ex) equals, toString, getClass ... )

자식 클래스의 생성자가 호출되면 자동으로 부모클래스의 매개변수 없는 생성자가 실행된다.

=>하나를 만들고 파생되는 것을 조금씩 바꾸면 편리함

 

parent 클래스에 매개변수를 받는 생성자만 있을경우(기본생성자는 자동으로 생성되지 않음) => 에러

child 클래스의 모든 생성자가 실행될때 parent의 기본 생성자를 찾기 때문이다.

따라서 super(매개변수)와 같이 부모 클래스의 생성자를 호출 시켜주면된다.

super은 반드시 생성자의 첫줄에 있어야한다.


 

메소드 오버라이딩(덮어씀)

접근제어자, 리턴타입, 메소드 이름, 매개변수 타입 및 개수 모두 동일

접근제어자는 확장되는것은 괜찮지만 축소되는것은 문제가 된다.

 

참조 자료형의 형변환

Parent parent = new Parent();
Child child = new Child();

//부모 클래스에선 자식 클래스의 메소드와 변수를 사용할 수 없다.
Child obj1 = new Parent();//parent로 생성시 child의 기능을 사용할 수 없다.

//자식클래스에선 부모 클래스의 메소드와 변수 사용가능
Parent obj = new Child();//child로 생성시 parent의 기능을 사용할 수잇다.


Child child = new Child();
Parent parent = child; //child는 paret의 기능을 사용할 수 있다, parent는 실제로 child 객체이다.
Child child2 =(Child)parent;//따라서 형변환이 가능하다.

부모 타입의 객체를 자식 타입으로 형 변환을 할 때에는 명시적으로 타입을 지저해 주어야 한다. 부모타입의 실제 객체는 자식 타입이어야만 한다.


 

다형성

Parent parent1 = new Parent();
Parent parent2 = new Child();
Parent parent3 = new Child2();

//printName메소드는 각 클래스별로 있으며 해당 타입의 이름을 출력
parent1.printName();
parent2.printName();
parent3.printName();

//출력: 각각 타입
parent1 - parent
parent2 - child
parent3 - child2

모두 parent 타입으로 선언되었는데 각 객체의 실제 타입은 다르다.

그리고 형변환을 하더라도 실제 호출되는 것은 원래 객체에 있는 메소드가 호출된다.

=> 원래 객체의 printName 메소드를 호출하여 각각 다른 결과가 나온다.


 

java.lang.Object

아무런 상속을 받지 않으면 java.lang.Object 클래스를 확장한다.

java.lang.Object는 모든 자바 클래스의 부모이다. => Object에 있는 클래스의 메소드를 통해서 클래스의 기본 행동을 정의할 수 있기 때문(이정도 메소드는 잇어야한다~)

다중 상속은 되지 않으나, 여러단계로 상속을 받을 수 있다.


 

인터페이스

자바에선 클래스 파일 이외에 interface, abstract 클래스가 있다.

존재이유 => 프로그램 설계단계에서 인터페이스를 정해놓으면 메소드 이름, 매개변수 등등을 고민하지 않아도 된다. 인터페이스형식에 맞추어 메소드를 구현하면 된다.

구현시 implements로

정의된 메소드를 모두 구현하여야 컴파일이 된다.

인터페이스의 변수는 public static final로 자동 선언된다.

메소드의 경우도 public abstract로 자동 선언된다.

선언시 class 대신 interface를 사용

public interface test {
	methods....
}
MemberManagerInterface manager = new MemberManagerInterface();
//아무것도 구현해놓지 않은 인터페이스로 초기화 하려고하여 에러가남

MemberManagerInterface manager = new MemberManager();
//실제 구현은 MemberManager에 되어있으므로 실제 타입은 MemberManager에

 

abstract 클래스

마음대로 초기화하고 실행할 수 없다.

abstarct 클래스를 구현해 놓은 클래스로 초기화 및 실행이 가능하다.

선언시 class앞에 abstract를 사용

public abstarct class test{
	public abstract boolean addMemeber(MemberDTO member);
	public void test(){
		System.out.println("test");
	}
	...
}

abstract는 추상 메소드가 하나라도 있으면 사용한다.

인터페이스와 달리 구현되어 있는 메소드가 있어도 상관없다.

구현이 아니라 상속을 하여 사용하면된다.

extends하여 abstract한 메소드를 사용하면된다.

사용하는 이유는 어떤 메소드는 미리 만들어 놓아도 문제가 없는 경우가 발생한다.

하지만 해당 클래스를 만들기는 애매할 때, 공통적인 기능을 미리 구현하면 도움이 된다.

 

abstract의 경우 abstract 메소드(구현안된 메소드)가 하나라도 있을경우 class 예약어 앞에 붙인다.

상속과 동일하게 extends를 사용하면 된다.

어떤 메소드는 미리 만들어도되지만 클래스를 만들기는 애매할때 공통적인 기능을 미리 구현해놓으면 도움이 된다.


 

 

final

final의 경우 상속해줄수 없다.

확장해서는 안되는 클래스, 상속받아서 내용을 변경해서는 안되는 클래스 선언시 사용

기본 속성이 변경되면 안되는 클래스에 사용한다.

메소드 또한 final로 선언시 overriding할 수 없게 된다.

인스턴스 변수나 static으로 선언된 클래스 변수의 경우 생성과 동시에 초기화를 해주어야한다. 생성자나 메소드에서 초기화시, 중복되어 변수값이 선언될 수 있다.

하지만, 매개변수의 경우 이미 초기화가 되어 값이 넘어오고

지역변수의 경우 메소드를 선언하는 중괄호 내에서만 참조되므로 다른곳에서 변경할 일이 없으므로 컴파일시 문제발생X

 

객체를 final로 선언시 객체안의 변수들은 제약이 없다. final로 선언되어 있지 않으면

=> 해당 클래스가 final이라고 그 안의 인스턴수 변수나 클래스 변수가 무조건 final로 선언된건 아니다.


 

enum

상수의 집합이다.

클래스의 일종

public enum Time{
	THREE,
	FIVE,
	EIGHT;
}
...
	public int timecheck(Time value){
		switch(value){
			case THREE:
				System.out.println("3")
			...
		}
	}

 

main

~~ ~~~ main(~~){
	Time test = new Time();
	test.timecheck(Time.THREE);
}

클래스이름.상수이름 을 넘겨준다.

생성자를 만들 수 있지만, 생성자를 통하여 객체를 생성할 수는 없다.

 

enum클래스 선언시 각 상수의 값을 지정할 수 있다.

public enum Time{
	THREE(1000),
	FIVE(3000),
	private final int amount;
	
	Time(int amount){
		this.amount= amount;
	}
}

enum클래스의 생성자는 아무것도 명시하지 않는 pacakge-private와 private만 접근 제어자로 사용할 수 있다.

=> 각 상수를 enum 클래스내에서 선언할 때에만 이 생성자를 사용할 수 있다.

 

  • enum 클래스는 다른 클래스와 같이 컴파일 할때 생성자를 자동을 만들어준다.

 

 

Nested 클래스

클래스 안의 클래스

코드를 간단하게 표현하기 위해서

주로 UI처리시 사용자의 입력이나 외부의 이벤트에 대한 처리를 하는 곳에서 많이 사용됨

 

static으로 선언시 static nested 클래스 => 한 곳에서만 사용되는 클래스를 논리적으로 묶어서 처리할 필요가 있을때

아닌경우 내부클래스이다. => 캡슐화가 필요할 때(A클래스의 private 변수접근을 위한 B클래스를 선언하고, B클래스를 외부에 노출시키고 싶지 않을 경우), 다른클래스에서 전혀 필요가 없을 경우

내부클래스는 로컬내부클래스와 익명내부클래스로 구분된다.


 

 

static nested class

내부 클래스는 감싸고 있는 외부 클래스의 어떤 변수도 접근할 수 있다. 심지어 private 변수까지

하지만 "Static"하기 때문에 그렇게 사용하는 것은 불가능하다.

public class Test{
	staic class StaticTest{
		public void setVal(int val){
			...
		}
		...
	}
}

내부 static 클래스 객체 생성?

public class InterClassTest{

	public static void main(String[] args){
		InterClassTest sample = new InterClassTest();
		sample.StaticObject();
	}
	
	public void StaticObject(){
		Test.StaticTest staticNested = new Test.StaticTest();
		staticNested.setVal(1230);
	}
}

감싸는 클래스.내부클래스 로 생성한다.

 

사용하는 이유

예로 학교를 관리하는 school 클래스를 만들고 대학을 관리하느 univ클래스를 만들면,

student는 어디 학생인지 모름

따라서 school안에 static nested 클래스 student를 만들면 용도가 명확해짐

또한 해당 클래스는 univ에서 사용 불가함.


 

 

내부 클래스와 익명클래스

public class Test{
	 class Inner{
		public void setVal(int val){
			...
		}
		...
	}
}

 

생성시 감싸는 클래스의 객체를 만들어야한다.

public class InterClassTest{

...
	public void InnerObject(){
		Test outer = new Test();//감싸는 클래스 객체 생성
		Test.Inner inner = outer.new Inner();//객체를 통해서 생성
	}
...

}

=>다른 클래스에서는 그 클래스가 전혀 필요 없을때 이러한 내부클래스 사용

 

예를 들어 gui에서 버튼 클릭 이벤트 처리시 내부 클래스를 만드는 것이 편이함(따로 클래스를 만드는것 보다)

하지만 익명클래스를 사용하면 더 편리함

 

  1. 내부 클래스 사용방법
package a.inner;

public interface EventListener{
	public void onClick();
}

 

package c.inner;

public class MagicButton{
	public MagainButton(){
	
	}
	//EventListener는 인터페이스이다.
	private EventListener listener;
	public void setListener(EventListener listener){
		this.listener=listener;
	}
	public void onClickProcess(){
		if(listener!=null){
			listener.onClick();
		}
	}
}
package c.inner;

public class NestedSample{
	...
	public void setButtonListner (){
		MagicButton button = new MagicButton();
		MagicButtonListener listener = new MagicButtonListener();
		button.setListener(listener); //<- 별도 클래스를 넘기지 않고 밑의 내부 클래스를 넘김
		button.onClickProcess();
	}
}
package c.inner;

public class NestedSample{
	...
	//내부 클래스
	class MagicButtonListener implements EventListener {
		public void onClick(){
			System.out.println("clicked")
		}
	}
}

 

  1. 익명 클래스 사용방법
package c.inner;

public class NestedSample{
	...
	public void setButtonListner (){
		MagicButton button = new MagicButton();
		//MagicButtonListener listener = new MagicButtonListener();
		//button.setListener(listener); //<- 별도 클래스를 넘기지 않고 밑의 내부 클래스를 넘김
		
		//익명 클래스 생성로 인자 넘김
		button.setListener(new EventListener(){
			public void onClick(){
				System.out.println("button clicked");
			}
		});
		
		button.onClickProcess();
	}
}

new EventListener로 생성자 호출 후 바로 중괄호를 열고 메소드 구현

클래스 이름도 없고 객체 이름도 없어서 다른곳에서 참조할 수는 없다.

 

사용이유

클래스를 많이 만들면 메모리가 많이 필요해짐. 따라서 내부, 익명클래스로 간단하게 객체를 생성할 수 잇다.

클래스 개수를 줄일 수 있으면 좋으니까

또한 다른 클래스에서 재사용할 일이 없을때 유용하다.


 

 

예외

예외적인 일이 발생한 경우

잘못을 컴파일할 때 점검해주지 않으므로 예외처리 해야한다.

try{
...
}
catch (Exception e){
...
}

예외가 발생하는 부분만 묶어주면 된다.

try 블록 안에서 예외가 발생되면 그 이하의 문장은 실행되지 않고 바로 catch로 넘어간다.

그리고 try-catch 구문 밖에 잇는 문장이 실행된다.

 

try에서 선언한 변수를 catch에서 사용할 수 없다.

따라서 일반적으로 catch 문장에서 사용할 변수는 try 앞에 선언한다.

 

모든 예외 객체의 부모 클래스는 java.lang.Exception 클래스이다.

따라서 만약 catch가 여러개인 경우,

부모 예외 클래스가 잡고 자식 클래스가 잡도록 되어있으면 자식 클래스가 예외를 처리할 수 없다.

즉, 위에서 먼저 catch해버리므로 그 다음에서 catch할 수 없다.


 

Throw

모든 예외는 java.lang.Throwable 클래스를 상속받는다.

이러한 이유는 모두 동일한 이름의 메소드를 사용하여 처리할 수 있게 하기 위함이다.

 

예외를 발생시키기 위해서 Throw를 사용한다.

 

try{
	throw new Exception("wrong input");
	...
}

catch (Exception e){
	e.printStrackTrace();
}

try블록 내에서 throw라고 명시한 수 개발자가 예외 클래스의 객체를 생성하면 된다.

throw한 문장 이후에 있는 모든 try 블록 내의 문장들은 수행되지 않고 catch로 이동한다.

 

또한 예외가 발생된 메소드를 호출한 메소드로 던질수도 있다.

public class TestException {
	public void throwException(int num) throws Exception{

			if(num<0){
				throw new Exception("wrong");
			}

	}
}

try-catch로 묶지 않았지만,

throws가 선언되어 있기 때문에 throwException 메소드를 호출한 메소드에선 try-catch블록으로 감싸어서 예외를 받아서 처리해야한다.

 

try{
	test.throwException(-1);
}
catch(Exception e){
  ....
}

 

여러가지 예외를 던질수도 있다.

public void multiThrow() throws NullPointerException, ArrayIndexOutOfBoundsExceptioin{
	...
} 

 

예외를 만들수도 잇다.

public class MyException extends Exception{
	...
}

 

finally

어떠한 경우에도 반드시 실행

try{

}
catch (Exception e){

}
finally{

}

예외가 발생하면 catch가 실행되고 finally 블록이 실행되고 try-catch 이후 문장이 실행된다.

finally는 예외와 상관없이 실행된다.

코드의 중복을 피하기 위해서 반드시 필요하다.


 

어노테이션

클래스나 메소드 선언시 @를 사용함

메타데이터라고도 함

  • 컴파일러에게 정보를 알려줌
  • 컴파일할 때와 설치시의 작업을 지정
  • 실행시 별도의 처리가 필요할때

 

미리정해진 어노테이션은 3개

  • @Override즉, 메소드가 override되엇으니 잘못코딩되면 컴파일ㄹ러에게 알려달라고 한다.
  • 해당 메소드가 부모 클래스에 잇는 메소드를 override 했다고 명시적으로 선언
  • @Deprecated
  • 미리 만들어진 클래스나 메소드가 더이상 쓰이지 않을때 알려줌
  • @SuppressWarnings
  • 컴파일러에서 경고를 주는 경우, 일부러 이렇게 코딩햇으니 괜찮다고 알려줌

 

메타 어노테이션

어노테이션을 선언할때 사용

  • @Target
  • 어노테이션을 어떤 것에 적용할지 선언할때 사용
  • @Retention
  • 얼마나 오래 어노테이션 정보가 유지되는지 선언
  • @Documneted
  • 해당 어노테이션에 대한 정보가 javadocs 문서에 포함된다는 것을 선언
  • @Inherited
  • 모든 자식 클래스에서 부모 클래스의 어노테이션을 사용할 수 있다는 것을 선언
  • @interface
  • 어노테이션을 선언할때 사용

 

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Target(ElementType.METHOD)
//이 어노테이션은 메소드에 사용할 수 있다고 지정

@Retention(RetentionPolicy.RUNTIME)
//실행시에 이 어노테이션을 참조하게 됨. 

//UserAnnotation이라는 어노테이션 선언
//@interface를 앞에 붙여서 사용시 @UserAnnotation으로 사용할 수 있다.
public @interface UserAnnotation {
	public int number();
	//메소드처럼 어노테이션 안에 선언해두면, 이 어노테이션을 사용할 때 해당항목에 대한 타입으로 값을 지정해야한다.
	public String text() default "This is first annotation";
	//default를 사용할 경우 뒤에 있는 값이 이 어노테이션을 사용할때 별도로 값을 지정해 주지 않을 때의 값이 된다.
}



 

사용시

만든 어노테이션의 target이 메소드였으므로 대상은 메소드 뿐이다.

public class Sample{
	@UserAnnotation(number=0)
	public static void main(String args[]){
		Sample sample = new Sample();
	}

	@UserAnnotation(number=3, text="Test")
	public void annotationexam(){
		
	}
}

 

 

 

 

728x90
반응형

'공부 > Spring' 카테고리의 다른 글

스프링 웹개발 기초  (0) 2021.10.20
자바 - Map  (0) 2021.10.19
자바 - Set  (0) 2021.10.18
자바 - 컬렉션(List)  (0) 2021.10.15
자바 - 제네릭  (0) 2021.10.14
블로그 이미지

아상관없어

,