복습 / 예습
참조형의 메모리
String s= "자바"
- "자바"는 힙에 저장되고 s는 스택에서 그 주소를 저장하고있다
- 이 "자바"는 더이상 주소를 저장하고 있는 s를 사용할 수 없을때 가비지 콜렉터가 이 "자바"를 지워준다
int[] values1 = { 1, 2, 3 };
int result1 = com.sum1(values1); // sum1() 메소드 호출 , 주솟값을 가진 values1을 넘김
- 여기서 new를 쓴거나 다름없으므로 힙메모리상에 1,2,3의 공간이 생긴다
- 그리고 values1이 그 주소를 가지고 있음
- 메소드를 호출할 때 이 values1이 가진 주소를 sum1메소드에 전달함
- 같은 int형 배열의 주소를 전달함
- 이 values1은 재사용 가능함
- 이 주소를 참조해서 공간에 접근이 가능하기때문에 아직 이 힙메모리의 1,2,3을 지우지 않음
int result2 = com.sum1(new int[] { 1, 2, 3, 4, 5 }); // sum1() 메소드 호출 , 배열을 만들어서 그 주소를 넘김
System.out.println("result2 : " + result2);
- 힙메모리상에 5개의 공간을 생성하라 -> 1,2,3,4,5
- 이 주솟값을 한번 메소드를 호출할때 전달했다. 사용되고 나면 이제 지워짐
- 더이상 참조가 불가능 -> 가비지 콜렉터가 지움
정적 멤버변수
- static 붙은 변수
1. 공유를 목적으로 누구나 쉽게 변수에 접근할수있도록 만드는경우
- 객체생성 없이도 접근 가능하다
2. 클래스명.변수 또는 클래스명.메소드(정적메소드) 로 사용함
- 메모리영역 : static 영역 (공유영역, 메소드영역) 에 할당
- 클래스가 로딩되지마자 메소드 영역에 할당받음!!
- 일반 필드들처럼 기본자료형은 자동으로 초기값이 설정됨
- 프로그램이 종료될때까지 값을 유지한다
- 모든 필드가 정적필드면 나중에 메모리 부족함
- 싱글톤을 만들경우엔 static을 붙여 정적필드로 만들어야한다.
변수와 메모리 영역
- 지역변수(스택)
- 멤버변수(힙)
- 정적변수(메소드,공유,static영역)
클래스
- 클래스는 자료형이다.
- 객체생성시 필드들을 위한 공간이 힙에 마련되고 기본자료형은 초기화된다
- 배열, 클래스,인터페이스 -> new 를 써서 힙메모리상에 새로 공간 마련
메소드
1. 필드값 출력
2. set 메소드로 필드값 수정
3. get메소드로 필드값 돌려주기 return
클래스의 구성
- 멤버변수 (필드)
- 멤버함수 (생성자 + 메소드)
+구조체
- 클래스가 나오기 전엔 C언어의 구조체가 있었다
- C++에서 구조체를 확장한게 클래스다
- 구조체를 구성하는 건 필드밖에 없다 멤버변수뿐
- 클래스로 확장되면서 멤버변수뿐아니라 멤버함수도 추가된것임
정적필드를 쓰는 경우
- static이 붙은 정적필드/정적메소드
- 직접 정적필드 만드는 경우는 아주 제한적 -> 싱글톤 만들때 static 변수를 만듬
- jsp같은 웹프로그래밍다를때 싱글톤많이씀
- 객체생성을 한번만 해서 그걸 공유를 하도록 하는게 싱글톤
필드의 접근제어자가 private일때 값 설정
1. 생성자로 초기화
2. set메소드로 값을 초기화
과제풀이(MemberInput.java)
https://laker99.tistory.com/18
객체 배열
- 여러명 저장하려면 객체 배열 또는 리스트 를써야함
- 객체의 주소를 저장하는 객체 배열, 배열은 크기가 한계, 정해져있다, 나중엔 리스트 쓸것
- do~while문으로 일단 실행을 시키고 i++시키면서 객체배열에 입력값을 저장함
- getter 로 main에서 값을 돌려주는 형태로 만들어서 값을 돌려받은 뒤 출력함
+ 객체배열이 아니라 그냥 객체 m이었다면 여러명의 정보 입력해도 가장 마지막으로 입력된 정보만 가지게 됨그래서 객체배열 쓰면서 m[i] 해서 i++해서 객체 배열 안에 다 주소 저장하는것
그림
제어문
System.out.print("계속할려면 y, 멈출려면 n을 입력?");
yn = sc.nextLine();
if (yn.equals("y") || yn.equals("Y")) {
continue;
} else if (yn.equals("n") || yn.equals("N")) {
break;
}
- 중간에 그만 입력할 수 있는 코드
- 무한루프를 나올때는 break 로 빠져나오고, y 를 입력하면 continue해서 다시 반복문으로 돌아가서 다음 사람 정보를 받음
- continue를 만나면 아래의 반복문인 while(true)로 돌아가는것
System.out.print("계속할려면 y, 멈출려면 n을 입력?");
yn = sc.nextLine();
if (yn.equals("y") || yn.equals("Y")) {
continue;
} else if (yn.equals("n") || yn.equals("N")) {
break;
}
} while (true); //여기로 돌아가서 조건검사하고 완전 위로 올라감
- break는 반복문을 나가는거이므로 이 do while문을 나감
- continue는 다시 반복문으로 돌아가는 것이므로 while(true)로 돌아가서 조건을 검사하고 또 반복문을 돌림
- .equlas("") 는 리턴값이 true false
Scanner의 next()와 nextLine()
Scanner sc = new Scanner(System.in);
String name, email, address;
int age;
- scanner객체는 한번만 생성하면 됨
- next() 와 nextLine()은 둘 다 문자 받지만
- next()는 중간에 띄어쓰기가 있으면 뒤쪽이 짤림, 앞만 저장함
- nextLine()은 엔터키 눌렀던 전 그 통째로 한문장을 입력받음, 띄어쓰기 된것도 다 저장함
Scanner의 nextInt()와 nextLine()
System.out.print("성명을 입력하세요? ");
name = sc.nextLine();
System.out.print("나이를 입력하세요? ");
age = sc.nextInt(); // 숫자를 입력받은후에 enter키를
sc.nextLine(); // 누르면 null값을 return하게 됨
System.out.print("E-Mail을 입력하세요? ");
email = sc.nextLine();
System.out.print("주소를 입력하세요? ");
address = sc.nextLine();
m[i] = new MemberInfo(name, age, email, address);
// m[i].name="홍길동";
- 문제사항 : 나이를 입력하면 이메일 주소 입력 부분은 넘어가버림
- nextInt(); 다음 nextLine() 일때 생기는 문제
- nextInt()로 나이 받고 엔터키누르면 엔터키도 하나의 문자로서 이걸 email = sc.nextLine(); 에서 받아버림
- 즉, 엔터키 자체가 문자로서 email에 그게 들어감
- 그래서 엔터키를 받기 위해서 중간에 sc.nextLine()을 넣어서 엔터키로 입력을 받음 그 후에 이메일 받으면 됨.
* 엔터키를 누르면 null 값을 sc.nextLine()을 통해서 리턴하게 됨
값 초기화/수정
- MemberInfo의 필드들이 모두 private이므로 객체배열 m에서는 m[i].name 처럼 접근이 불가능함
-> 값을 설정하는 법 1. 생성자의 매개변수 통해서 2. 메소드의 set메소드 통해서
배열에 들어있는만큼 출력
for (int j = 0; j < i; j++) {
System.out.println("성명:" + m[j].getName());
System.out.println("나이:" + m[j].getAge());
System.out.println("E-Mail:" + m[j].getEmail());
System.out.println("주소:" + m[j].getAddress());
}
- 출력시킬땐 for문을 돌려서 j<i해서 입력된 만큼의 정보를 출력함 i는 자료의 개수임
- 1명이 입력됐을땐 i는 1이고 2명은 i는 2이고...
Scanner 클래스
- java.util 안이다
- 우리는 Scanner(InputStream source) 생성자를 쓰고있는 것
- in은 정적필드이고 자료형이 InputStream, 그래서 이 안에 System.in을 넣는다
Scanner 클래스 메소드
- nextInt() : 정수값 입력 , 리턴형 int
- nextLine() : 사용자가 입력한 한줄을 통째로 받음, 리턴형 String
- next(): 단어단위로 입력받기 떄문에 띄워쓰면 짤림, 리턴형 String
Scanner로 받은 값 메모리
- Scanner로 받은 String값은 힙메모리 상에 저장된다(String이라서)
과제의 DTO 클래스
https://laker99.tistory.com/18
- 이 MemberInfo 클래스를 DTO 클래스라고 부름
DTO (Data Transfer Object)
- Data 이동, 전환, 메모리 상의 값을 저장하고 돌려주는 역할을 하는 클래스
- 웹프로그래밍할때 들을 수 있다
- 이 클래스 안엔 필드, getter, setter메소드 가 들어감
- 나중엔 생성자를 쓰지 않고 setter메소드로 초기화를 시킴
객체배열
- 여기서 쓴 객체배열은 배열이다보니 크기가 정해져있다
- 자바에서는 주로 List 같은 자료구조로 다 처리함-> 크기가 계속 동적으로 늘어난다
- 나중엔 List나 ArrayList 로 주로 처리
싱글톤
- 하나의 애플리케이션 내에서 단 하나만 생성되는 객체
- 한개의 클래스가있으면 그 클래스로 객체 생성을 1번만 하는게 싱글톤임
- 클래스로 객체를 new써서 무한으로 만들 수 있지만 1번만 만드는거
- 계속 new써서 객체 생성하면 힙메모리상에 계속 새로운 공간 만들게되고, 공간을 생성하는데도 시간이 소요됨 (시간+ 힙메모리공간소요)
- 정적변수로 만들어야하는 경우 : 싱글톤만들때
싱글톤을 쓰는 경우 : db
- db연동하는 경우 이 싱글톤을 자주 사용함 (db연동하는 클래스로 객체 생성할때 싱글톤을 씀)
- 어떤 사이트 게시판을 보면 글들이 다 연동 / 공유 됨. 수십명이 같은 게시판 을 보게됨
- 서버측에서는 db연동을 하기 위한 클래스 내부에서 돌아감
- 원래는 사용자가 db접속할떄마다 db연동하는 클래스의 객체를 계속 만들게됨(메소드나 필드를 쓰려면 객체를 만들어야하므로)
- 그거의 단점(시간+공간) 막기위해 객체1번만 만드는 방법 싱글톤 사용
- 즉, 서버측에서는 db연동을 하기 위한 클래스로 객체를 1개만 만들고 그걸 공유하겠다는게 싱글톤
- 한번만 생성해서 정적으로 해서 공유를 하겠다는 개념
Q. 참조형 && 멤버변수 와 메모리(질문)
- String이 멤버변수로 있다면 그 주소값은 힙이 아니라 스택에 저장됨
- 택에서 null이란 값이 있는상태임
- 만약 그게 뭘 할당받으면 그건 힙메모리에 있는 뭔가를 스택에서 가리키는거임
- 즉 멤버변수 && 참조형 -> 주소값을저장할 공간은 스택에, 나중에 그게 할당되면 그건 힙에 있다
싱글톤과 db 객체생성
- 싱글톤 : db연동 처리해주는 클래스(jsp부분) 가지고 객체 생성을 1번만 수행함
- 이 클래스 안 메소드(DAO 안 update, delete등의 메소드) 를 호출하기 위해서 해당 클래스로 객체를 1개 생성함
- 이 DAO 클래스 안에 들어있는 건 메소드 뿐이다, 그 메소드를 사용하기 위해서는 클래스로 객체를 만든다음 메소드를 사용
- 그 sql문이 각 메소드이다. 그 메소드를 호출하기 위해선 객체.메소드() 해야함
- 게시판의 사이트 들어갈때마다 목록 뽑아옴 = select란 sql문으로 db연결해서 그걸 뿌려주는 것임. 그런 작업이 내부적 서버 측에서 계속 일어남
- 그 메소드를 호출하기 위해 클래스의 객체를 매번 생성해야한다. 100명 접속하면 100개 생성해야함. 그래야 객체1.check(), 객체2.check(), 객체3.check() 로 가능
- 매번 객체 생성에 시간 소요 + 서버 측의 힙메모리 자원을 계속 쓰게 됨 = 서버측 부하
- 이 부하를 줄이기 위해 객체 생성을 1번만 하고 이 객체를 정적메소드로 공유를 하겠다는 거임
Q. 정적메소드해서 그냥 클래스명.메소드 하면 되지 않나요? 왜 객체를 생성해야하는지?
Q. 물론 객체명.메소드로도 정적메소드 호출 할 수 있지만 굳이?
싱글톤 구현 방법
package p2022_06_30;
// p244
class Singleton {
// 싱글톤(Singleton) : 객체 생성을 1번만 수행하는 것을 의미함
// 이 클래스로 객체를 1번만 생성할 것임, 외부에선 접근 못하도록 접근제어자 private을 보통 붙임
// 같은 클래스 내에서만 접근가능하도록
// 정적필드
private static Singleton s = new Singleton();
// 모순발생 private(보호) + static(공유) -> 모순발생하기떄문에 이 필드로 다이렉트로 접근 불가
// 이거 필드임! static이 붙은 정적필드, 메모리영역에 로딩되며 공유되지만 private이므로 안됨, 아래 정적메소드 만들어서 그걸로
// 주고받고
// 정적메소드 public + static + 리턴자료형은 Singleton(자기의 클래스 자료형) + 메소드이름getInstance
public static Singleton getInstance() {
return s; // 위에서 만든 이 객체를 리턴
}
public void check() {
System.out.println("메소드 호출 성공1");
}
public void check1() {
System.out.println("메소드 호출 성공2");
}
// 이 메소드 쓰려면 매번 new해서 객체 생성해야함. 계속 메소드를 통해서 db연동할때 매번 객체를 생성해야한다
// 서버는 몇천명이 동시에 접속함, 그래서 매번 객체 생성하면 서버측에 큰 부하가 걸림
// 효율적으로 하기 위해 객체를 메소드 영역(정적필드) 에 만들어놓고 이걸로 계속 사용
}
public class SingletonEx {
public static void main(String[] args) {
Singleton obj1 = Singleton.getInstance();// 객체를 new로 생성하는게 아니라 이미 만들어진 s를 가져옴
// 정적메소드라 클래스명.메소드() 로 호출
Singleton obj2 = Singleton.getInstance();
System.out.println(obj1);
System.out.println(obj2);
if (obj1 == obj2) {
System.out.println("같은 주소"); // 같은 주소
} else {
System.out.println("다른 주소");
}
obj1.check();
obj1.check1();
obj2.check();
obj2.check1();
}
}
- 객체를 "클래스 내부" 에서 생성한다.
- static 인 정적필드는 메소드 영역(공유 영역) 에 저장됨, 하지만 private으로 외부 클래스 접근을 막아둔다
- 모순발생 private(보호) + static(공유) -> 모순발생하기떄문에 이 필드로 직접 접근 불가
- 그걸 getInstance() 라는 정적 메소드를 통해서 공유를 한다.
- getInstance() 를 통해 그 객체를 이 Singleton 클래스 쓰는곳에(main에) 돌려줌
- main에서 돌려받은 객체 s로 check()와 check1()을 호출할 수 있다
getInstance() (위 예제 부분1)
// 정적메소드 public + static + 리턴자료형은 Singleton(자기의 클래스 자료형) + 메소드이름 getInstance
public static Singleton getInstance() {
return s; // 위에서 만든 이 객체를 리턴
}
//#main
Singleton obj1 = Singleton.getInstance()
- 이 getInstance는 정적메소드이기때문에 클래스명.메소드 해서 사용하면됨 Singleton.getInstance() 하면됨
- 물론 이름은 Singleton 이어야만하는건아님
돌려받은 객체의 주솟값 (위 예제 부분2)
public static void main(String[] args) {
Singleton obj1 = Singleton.getInstance();//객체를 new로 생성하는게 아니라 이미 만들어진 s를 가져옴
//정적메소드라 클래스명.메소드() 로 호출
Singleton obj2 = Singleton.getInstance();
System.out.println(obj1);
System.out.println(obj2);
}
- obj1,obj2 출력하면 주솟값나옴
- 스택에서 주소를 저장하고 그 값은 s가 가진 주솟값과 같고 s와 이 obj1, obj2는 위에서 만든 객체를 가리킴 그 값은 힙에 있다
- 메소드 영역에 저장된 객체 s를 , 즉 그 주솟값을 받았으므로 같은 주솟값을 출력함
- 그래서 println() 출력값이 같은 주소가 나온다.
DB에서 사용하는 싱글톤 정리1(맛보기)
- 원래는 계속 main 쪽에서 new로 클래스를 생성해왔지만 부하막기위해서 메소드를 호출해서 sql문 수행할때, 하나의 객체로 하기 위해 정적메소드를 활용해서 Singleton s를 공유하는것
= private + static = 모순발생, 비공개+공개 , 결과적으론 접근안됨
- 그래서 정정메소드로 이 객체를 돌려줌. 리턴값이 Singleton 자료형
- 내부적 동작 : 게시판 클릭하면 sql select문을 수행함
+ main에서 Singleton.getInstance() 했을때 그 결과는 Singleton 클래스 객체로 받아줘야함
DB애서 사용하는 싱글톤 정리2(맛보기)
+Db연동하는 클래스인 DAO(Data Access Object) 클래스 만들것 이 클래스는 메소드만으로 구성되어있음.
+ 이 객체를 1개 만들어서 나중에 BoardDBBean이란 DAO쪽의 메소드에 전달해서 계속 글 작성 ,업데이트 등 하는것
- 원래는 이 DAO 클래스 를 new해서 10번 목록을 클릭하면 목록을 10개뽑아야함 (메소드)
-> 내가 목록 버튼 누를떄마다 실행됨
- 이때 메소드를 호출하려면 DAO 클래스 를 new해서 많이 객체 만들고 객체.메소드 로 접근해야함
- new마다 서버측 부담 + 시간 -> BoardDBBean 클래스 : 싱글톤으로 만들어져있음
private static BoardDBBean instance = new BoardDBBean();
public static BoardDBBean getInstance()
{
return instance;
}
- 해서 DAO를 싱글톤으로 구현하면 나중에 게시판 출력하는 클래스에서 BoardDBBean dao = BoardDBBean.getInstance(); 로 그 객체 불러옴
- 그리고 list = dao.getList 나 count = da.getCount() 해서 메소드 사용.이걸 반복문으로 계속 돌림
- 그래서 class안에 1번생성후 getInstance를 여러번 할수있는 구조로 만드는것
- DAO 클래스 안에서만 이 싱글톤이 사용됨
- 이 DAO 클래스의 메소드 호출(sql문)은 이 싱글톤 한개의 객체로 부터 호출한다
- DTO 가 계속해서 매개변수나 리턴자료형에 쓰임
- 목록 검색하는경우 그 검사결과를 돌려줘야하므로 그런 자료가 있는 자료형인 DTO를 리턴으로 돌려줌
final
- 사전적의미는 마지막, 이때 final이 어디에 붙냐에 따라서 의미가 달라짐
- 클래스, 필드, 메소드 앞에 붙을 수 있고, 어디 앞에 붙냐에 따라 의미가 달라짐
final 이 사용되는 경우
1. final이 멤버변수에 사용될 경우
- 마지막으로 저장되는 값이란 의미
- static final 이라 해도 되고 final 이라 해도 됨
- final붙은 값은 수정할 수 없는 상수이다.
2. final이 메소드에 사용될 경우
- 메소드 오버라이딩을 허용하지 않는다는 의
* 메소드 오버라이딩 : 부모클래스로부터 메소드 상속받아서 이름은 그대로 쓰지만 메소드 안의 내용을 다르게 쓰는것
3. final이 클래스에 사용될 경우
- 마지막 클래스라는 의미
- 상속을 허용하지 않는다는 의미
final 이 멤버변수에 사용될 경우 예제
- FinalTest01.java
package p2022_06_30;
class FinalMember {
final int a = 10; // 상수
public void setA(int a) {
this.a = a; // a는 상수이기 때문에 값을 수정할 수 없다.
}
}
public class FinalTest01 {
public static void main(String[] args) {
FinalMember ft = new FinalMember();
final int a = 1000;
ft.setA(100);
System.out.println(a);
}
}
- final이 멤버변수에 사용될 경우 : 상수가 됨 Constant (상수)
- setA메소드 호출하면서 매개변수에 전달된 값을 필드를 초기화하는데 쓰려했는데 필드가 final필드이므로 수정안됨. 오류발생
final 이 메소드에 사용될 경우
+ 상속 간단히 정리
- API에서 제공되는 클래스들은 상속관계가 형성되어있다
- 1개의 클래스 구성하는 멤버는 3개 = 필드, 생성자, 메소드
- 필드, 메소드 가 상속되고 생성자는 상속되지 않음
- 이때 상속을 해주는 클래스를 부모 클래서 상속을 받는 클래스를 자식 클래스라고 한다
- 자식클래스는 부모클래스로부터 상속받는것도 자기꺼고 자기꺼도 자기꺼임
- 상속받는법 : 자식 클래스 뒤에 extends 부모클래스 쓰기
그래픽프로그램 쓰기 위해 상속 많이 씀
+ 메소드 오버라이딩 간단히 정리
- 상속이 된 상태에서 부모클래스로부터 상속받은 메소드들을 이름과 형식은 그대로 따르지만 안의 내용은 바꿔쓰는 것
- "부모클래스안에 있는 메소드"에 final이 적혀있다? -> 그럼 그 메소드 오버라이딩 허용하지 않겠다는 의미
final 이 메소드에 사용될 경우 예제
- FinalTest02.java
- 메소드 앞에 final이 붙은 경우
- 파일안에 클래스 3개
package p2022_06_30;
class FinalMethod { //부모 클래스
String str = "Java ";
// public void setStr(String s) {
// final 붙이면 서브(자식) 클래스에서 오버라이딩이 불가.
public final void setStr(String s) {
str = s;
System.out.println(str);
}
}
class FinalEx extends FinalMethod { //자식 클래스
int a = 10; // final 붙이면 밑에서 a값 대입 불가.
public void setA(int a) {
this.a = a;
}
public void setStr(String s) { // 메소드 오버라이딩, 여기 오류생김!
str += s;
System.out.println(str);
}
}
public class FinalTest02 {
public static void main(String[] args) {
FinalEx ft = new FinalEx();
ft.setA(100);
ft.setStr("hi");// 슈퍼 클래스의 setStr을 실행.
FinalMethod ft1 = new FinalMethod();
ft1.setStr("hi");// 자신의 클래스의 setStr을 실행.
}
}
1. FinalMethod 클래스 : 부모클래스
2. FinalEx 클래스 : FinalMethod클래스를 상속받는 FinalEx자식클래스
3. FinalTest02 클래스 : main 메소드가 있는 클래스
- FinalClass엔 str이란 필드랑 setStr이란 메소드가 있다
- 이 setStr이 public final void setStr(String s){}
- final이 붙었으므로 상속은 되지만 메소드 오버라이딩은 안됨!
- 메소드 오버라이딩을 시도하는 자식클래스 쪽에 오류를 발생시킴
final 이 클래스에 사용될 경우 예제
- FinalTest03.java
package p2022_06_30;
// 상속을 허용하지 않는다.
final class FinalClass { // 부모 클래스
String str = "Java ";
public final void setStr(String s) {
str = s;
System.out.println(str);
}
}
class FinalEx extends FinalClass { // 자식 클래스, 여기서 오류 발생
int a = 10;
public void setA(int a) {
this.a = a;
}
public void setStr(String s) {
str += s;
System.out.println(str);
}
}
public class FinalTest03 {
public static void main(String[] args) {
FinalEx fe = new FinalEx();
}
}
- final class FinalClass란 부모클래스를 상속받는 곳에서 오류를 발생시킴 이거 실행 안됨
- final이 붙은 클래스라서 상속을 안해주는 클래스임
상수 만들떄
- final만 붙여도 상수 되고
- static final만 붙여도 상수 됨
- 보통은 static final 붙이는 경우가 더 많음
패키지
- 쉽게 말하면 폴더
- 비슷한 기능 가진 클래스끼리 모아둔 게 패키지
- api에서 제공되는 클래스들은 이미 패키지가 다 분류되어있다
- 사용자 정의로 만들어지는 클래스들도 같은 패키지 안에 들어가있으면 같은 폴더안에 들어가있는거임
- 폴더가 다르면 서로 다른 패키지 안에 들어가있는것
import문
- java.lang 패키지 안 클래스 사용할때는 import생략 가능
- 그 외 다른 api 제공 클래스 사용할때는 import를 써야한다.
* api에서 제공되는 클래스들은 비슷한 기능하는 클래스끼리 패키지로 이미 묶여져 있음
* 가장 사용빈도 높은 클래스 묶어둔게 java.lang 패키지, 기본패키지 라고도 한다.
* java.lang.Integer, java.lang.System, java.lang.String
+ 난수 발생 방법
1. Math.random()
2. Random 이란 클래스 사용
- Random클래스는 java.util 패키지 사용해야하므로 이 클래스 import해야함
자바에서 import하는 방법
1. 자동 import = ctrl + shift + O
- 또는 Random을 쓰면서 ctrl + space 하면 이것저것 목록 나타나는데 그 중 선택하면 import됨
2. import 안쓰고 쓰는법
- java.util.Random r = new java.util.Random();
Random클래스
- java.util 안에 있다
- 필드
- 생성자 : 우리는 기본생성자 형태를 쓰고 있다
- 메소드 : 정수형태 난수발생시킬떄는 random클래스의 메소드 중 nextInt()라는 메소드를 쓴다
- nextInt()가 메소드 오버로딩 되어있음 매개변수없는것도 있고 매개변수가 int 형 1개인것도 있다
- nextInt(int bound) : 0포함 , 0부터 시작해서 bound까지인데 , 0은 포함, bound는 미포함(즉, 미만)
import 예제 (난수발생 예제)
- RandomTest.java
package p2022_06_30;
import java.util.Random;
public class RandomTest {
public static void main(String[] args) {
// 난수 발생 방법 : 1. Math.random()
// 2. Random 클래스
// 자동 import 단축키 : Ctrl + Shift + O
Random r = new Random();
// java.util.Random r = new java.util.Random(); 도 가능
int n1 = r.nextInt(10); // 0 ~ 9
System.out.println("n1 = " + n1);
// 1 ~ 45 사이의 난수 발생
int n2 = r.nextInt(45) + 1;
System.out.println("n2 = " + n2);
// 0.0 <= Math.random() < 1.0 난수 발생 (추가)
int n3 = (int) (Math.random() * 45 + 1);
System.out.println("n3 = " + n3);
}
}
- int n2 = r.nextInt(45) 하면 0부터 44까지가 랜덤임 그래서 +1 해줘야하는 것임.
Date 클래스
- 날짜 시간 클래스
- Date클래스는 크게 2개의 패키지 안에 들어가있다, import해야함
- Date d = new Date(); 한상태로 ctrl + shift + O 하면 두개의 패키지 java.util, java.sql 뜬다
- 두개의 패키지 안에 들어가있어서 자동이 아니라 선택해야함
- 일반적으로 java.util 패키지의 date를 써야한다
- java.sql 안의 date는 기능이 좀 다름
import 예제 (날짜시간 예제)
import java.util.Date;
Date d = new Date();
System.out.println(d);
- 영미권에서 사용하는 날짜, 시간 포맷으로 출력됨
ex) Thu Jun 30 12:44:35 KST 2022
- api에서 제공되는 클래스는 java.lang뺴고 다 모두 import해야함
- 패키지 import아니라 클래스를 import하는거임
- import문 뒤에 ; 를 붙여야한다
import 할때 클래스명있는 쪽에 *
ex) import java.util.*;
- java.util. 안의 모든 클래스를 다 불러오겠다는 의미 한꺼번에 불러온다
- 이러면 Date,Random등 다 쓸 수 있다
import 정리
1. api에서 제공되는 클래스일때
- java.lang 을 빼고 모두 import해야한다.
2. 사용자 정의 클래스일때
- 패키지가 다를떄만 import한다!
- 같은 패키지안의 class끼리는 import하지 않아도 그 클래스 사용가능(객체 생성가능)
- 접근제어자와 관련있음(이제 공부할 것)
- 같은폴더 = 같은패키지, 다른폴더 = 다른패키지
접근 제어자
- 4가지가 있다, 이걸로 접근 허용할지 말지를 제어함
- public : 가장 넓은 접근 허용
- private : 가장 좁은 접근, 같은 클래스 내에서만 접근 가능, 다른 클래스/다른 패키지의 접근허용안함
- default : 중간정도 접근허용, 생략된 경우임, 같은 클래스, 같은 패키지(같은 폴더) 안에선 접근 가능
- protected : 상속에서만 사용, default 보다 접근범위 넓음, 하위클래스에서 접근가능
- 클래스, 필드, 생성자, 메소드 앞에 접근제어자 붙일 수 있다
- 클래스로 접근할때는 접근제어자가 접근 허용해야만 접근 가능
- 필드로 접근할때도 접근제어자가 접근 허용해야만 접근 가능
* 자바의 접근 제어자
접근제어자 자신의클래스 같은패키지 하위클래스 다른패키지
private O X X X
생략(default) O O X X
protected O O O X
public O O O O
- 같은 클래스내에서는 접근제어자 쓰는게 의미가 없다
- 같은 클래스내에선 다 접근 가능하기때문에 (private을 쓰더라도)
접근제어자 예시
- 사용자 정의로 클래스 2개 만들었을때
- 같은 패키지 안의 두개의 다른 클래스끼리는 접근할때는 import 안해도된다
- 같은 패키지 안의 두개의 다른 클래스끼리는 접근할때는 public이나 default면 됨
- 서로 다른 패키지 안의 두개의 다른 클래스는 접근할때는 import 해야한다.
- 서로 다른 패키지 안의 두개의 다른 클래스는 접근할때는 pulbic 이어야 한다.
1. 같은 패키지 안에 들어 있는 클래스
- src - p2022_06_30 - Called.java : check()메소드
- src - p2022_06_30 - Calling.java : main() 메소드
- 두 클래스가 같은 패키지 안에 있을때 접근제한자와 import 여부를 알아보자
package p2022_06_30;
public class Calling {
public static void main(String[] args) {
Called c = new Called(); //클래스 접근
c.check(); //메소드 접근
}
}
package p2022_06_30;
public class Called {
public void check() {
System.out.println("메소드 호출 성공");
}
}
클래스 접근
- Calling 클래스에서 Called 클래스로 객체만들어서 check()메소드 호출하자
- Calling 클래스에서 Called 클래스로 객체 만들기 = 그 클래스에 접근하는 거임
- 하지만 두 클래스는 같은 패키지 안에 있으므로 import가 필요없다,
- 그리고 Called 의 클래스의 접근제어자가 public이므로 접근해서 객체 생성이 가능했던것
- private class Called 로 바꾸면 Calling에서 Called 클래스로 객체 생성 불가 (접근 불가)
- 같은 패키지에 있는 class로 접근할때는 import안써도 되고 접근제어자는 private만 아니면 된다
- public default protected 는 다 접근가능하다
메소드 접근
- 그리고 생성된 객체를 통해 메소드를 호출하는 c.check()가 가능한 이유는 check() 메소드의 접근제어자가 public이라서이다.
- default도 접근 가능하다, private이면 접근안됨, 즉 private이면 메소드 호출안될것
필드 접근
+ 필드의 접근제어자도 같은 패키지 안 다른 클래스일때, default나 public으로 되어있어야 접근가능함
같은 패키지일때, 접근제어자와 import여부 정리
1) 같은 패키지 안에 들어 있는 클래스에 접근 하기 위해서는 접근 제어제가
public이나 default 접근 제어자로 되어 있어야 한다.
2) 같은 패키지 안에 들어 있는 클래스에 접근 하기 위해서는 import 를 하지
않아도 된다.
2. 다른 패키지 안에 들어 있는 클래스
- src - a - b - Called.java : check()메소드
- src - Calling.java : main() 메소드
- 두 클래스가 다른 패키지 안에 있을때 접근제한자와 import 여부를 알아보자
+ 패키지 생성
- scr 아래 a 패키지 내 , b패키지 내 Called 클래스 만드는법
- 패키지명을 : a.b 라고 하면 됨 -> a폴더하위에 b폴더 하위에 Called.java생기게됨
- Called.java 는 a패키지 안에 b패키지 안에 Called.java 파일이 있는것
- scr 바로 아래 Calling 클래스 만들것
-> 즉 서로 다른 패키지 안에 있다.
package a.b;
public class Called { //이게 default나 private이면 아래 객체생성코드에서 오류발생
public void check() { //이게 default나 private이면 아래의 c.check();에서 오류남. 접근불가
System.out.println("다른 패키지에서 호출");
}
}
import a.b.Called;
public class Calling {
public static void main(String[] args) {
Called c = new Called(); //클래스가 public이면 접근된다
c.check(); //메소드가 public이면 접근된다
}
}
- Calling 클래스에서 Called 클래스로 객체 만들기 = Called 클래스 접근
- import하지 않아서 만들면 빨간줄 뜬다, import해준다
- public이어도 import 안되어있으면 접근안됨
- 접근제어자는 무조건 public이어야만 접근된다
- 서로 다른 패키지 안의 클래스로 접근하고싶으면 접근제어자가 public이어야만함 import도 필수임
- 패키지가 다를때는 클래스,필드,생성자,메소드 전부 public으로 만들어야 접근해서 쓸 수 있음
다른 패키지일때, 접근제어자와 import여부 정리
1) 다른 패키지 안에 들어 있는 클래스에 접근 하기 위해서는 접근 제어제가
public 접근 제어자로 되어 있어야 한다.
2) 다른 패키지 안에 들어 있는 클래스에 접근 하기 위해서는 해당 클래스를 import 를
해야된다.
import와 접근제어자 정리
1. api 제공 클래스인경우
- 모두 import, 예외) java.lang
2. 사용자 정의 클래스 인 경우
2-1 ) 같은 패키지내 : public, protected, default 인 경우 접근 가능 / import 불필요
2-2 ) 다른 패키지내 : public 인 경우만 접근 가능 / import 필요
패키지와 접근제어자 예시
- PackageHelloWorld.java 파일 열어보면 패키지가 Hello 라 되어있음
-> 패키지 Hello 만든뒤 그 안에 넣자
- UsePackageHelloWorld.java는 열어보면 패키지 안적혀있다 (패키지 없는것)
-> 그냥 src에 파일 넣으면 디폴트 패키지속으로 들어감
import 여부
- 패키지가 다르므로 UsePackageHelloWorld.java에서 hello.PackageHelloWorld 클래스 를 import 해야한다
접근제한자
- PackageHelloWorld 클래스와 그 안의 printHello 메소드는 public이다.
- 그럼 PackageHelloWorld 로 객체를 만들 수 있고 그 객체를 통해 printHello 메소드가 잘실행됨
+ 같은 클래스 내에서는 접근제어자가 의미가 없다 4가지가 모두 접근이 가능하기 때문에
캡슐화 (과제에서의 접근제어자 설명)
https://laker99.tistory.com/18?category=1065834
- DTO 클래스 = MemberInfo 클래스
- MemberInfo 클래스의 필드들 접근제어자가 private이었다
-> 클래스가 달라지면 이 필드값을 객체로 접근해서 입력/수정/출력 등이 안됨, 접근이 안됨
- m[i].name = "홍길동" 으로 값을 셋팅할 수 없다.
- 두가지 방법
1. 생성자의 매개변수로 필드값 초기화
2. setter메소드 를 통해서 접근해서 입력/수정/출력함
캡슐화
- 이런개념이 "캡슐화" 이다.
- 정보를 캡슐씌우듯 보호함. 접근제어자 로 외부 다이렉트 접근 못하도록 private으로 막는 것 = 보호
날짜, 시간 관련 클래스
- Date, Timestamp, Calendar 라는 3개의 클래스
- 클래스마다 날짜시간 형식에 차이가 있다
- java.util.Date : 간단날짜
- java.sql.Timestamp : 정교한 날짜 작업할때 사용
- java.util.Calendar : 날짜시간, 캘린더 만들떄도 사용
Date 클래스
- Date는 java.util과 java.sql둘다 들어있다
- 지금 필요한건 java.util.Date 임 import해주자
Date d = new Date();
System.out.println(d);
출력 : Thu Jun 30 15:37:02 KST 2022
- 날짜 시간 간단히 출력시 Date 클래스
- 하지만 날짜시간 포맷이 불편함, 영미권에서 많이 쓰는 날짜 포맷임
- Date 클래스 자체적인 기능으로 다른 포맷으로 바꾸는 기능은 없지만 다른 클래스의 도움을 받으면 원하는 날짜 포맷으로 설정하면 원하는 날짜 포맷으로 출력 가능
SimpleDateFormat 클래스
- 날짜 시간 포맷 바꿔주는 클래스
- import java.text.SimpleDateFormat;
SimpleDateFormat 클래스 사용
java.lang.Object (최상위클래스, 슈퍼클래스)
java.text.Format
java.text.DateFormat
java.text.SimpleDateFormat
- 패턴을 지정하는 방법을 나타낸 표들이 있다
- ex) yyyy.MM.dd G 'at' HH:mm:ss z
- 필드 : 위로부터 상속됨
- 생성자 : 두번째 생성자 보면 SimpleDataFormat(String pattern) 임
- 여기에 String형으로 Date and Time Pattern 에 적힌대로 패턴을 써주면 된다 .
ex) yyyy는 4자리 연도 나타냄
SimpleDateFormat sd = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
- 연월일시분초로 패턴을 지정하겠다는 의미임
+ "yyyy년 MM월 dd일" 이렇게 해도 됨
- Date 클래스 자체 기능은 없지만 SimpleDataFormat 클래스의 도움을 받아서 원하는 포맷으로 날짜시간 출력가능
SimpleDateFormat 으로 포맷 적용하기
- 메소드 : format() 메소드로 지정
+ API 문서 보면 SimpleDateFormatt 클래스 내엔 format() 메소드 없다. -> 부모나 조상으로부터 상속받았을것!
+ format(Object obj) 이 Format 클래스에 보면 있다(조상)
+ format(Date date) 이 DateFormat 클래스에 있다(부모)
날짜시간 원하는 포맷으로 출력 예시
Date d = new Date();
System.out.println(d);
SimpleDateFormat sd = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss EEE요일");
System.out.println(sd.format(d));
출력
Thu Jun 30 15:52:24 KST
2022 2022-06-30 15:52:24 목요일
+ 운영체제가 한글이라서 영향을 받아서 Thu 대신 목 이라고 출력하는거임
SimpleDateFormat sd1 = new SimpleDateFormat("yyyy-MM-dd a hh:mm:ss EEE요일");
SimpleDateFormat sd2 = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss EEE요일");
System.out.println(sd1.format(d));
System.out.println(sd2.format(d));
출력
2022-06-30 오후 04:07:51 목요일
2022-06-30 16:07:51 목요일
- HH포멧은 24시간 시간제
- hh포멧은 12시간 시간제
- a 는 오전 오후
- 나중에 게시판에 작성시간 출력 포맷 지정할 때 쓴다
Timestamp 클래스
- 자바에서 가장 많이 사용되는 날짜 클래스
- 정교하고 자세한 날짜시간을 알려줌
- java.security , java.sql 두개의 패키지에 있는데 우리는 java.sql 쓸것 security 패키지의 것은 기능이 좀 다름
- 기본생성자 지원안함
- 3개의 생성자 있는데 일반적으로는 매개변수가 long형으로 되어있는 Timestamp(long time)생성자를 쓴다
Timestamp 클래스 사용
java.lang.Object
java.util.Date
java.sql.Timestamp
- 아까의 Date 클래스가 Timestamp의 부모 클래스이다.(상속)
- 필드 : 없다
- 생성자 : Timestamp(long time), Timestamp(int year,int month, int date ...)
Timestamp(long time)
- Timestamp 생성자
- 천분의 일초 ms를 구해줌
- 시스템에 대한 날짜 시간 을 ms단위로 가져옴
- 매개변수에는 System 클래스에서 제공되는 정적메소드 System.currentTimeMillis() 를 써야함
- 이 메소드는 정적메소드이므로 .으로 접근해서 호출함, 리턴자료형이 long형
Timestamp ts = new Timestamp(System.currentTimeMillis());
System.out.println(ts);
출력 : 2022-06-30 16:16:52.966
- 1000분의 1초 단위인 ms 단위까지 구해줌
- 일반인들이 이 정도 자세하게는 볼 필요가 없음
-> Timestamp도 SimpleDateFormat으로 형식 지정해서 쓰면 된다
Timestamp ts = new Timestamp(System.currentTimeMillis());
System.out.println(ts);
SimpleDateFormat sd3 = new SimpleDateFormat("yyyy년 MM월 dd일 HH:mm:ss");
System.out.println(sd3.format(ts));
출력
2022-06-30 16:20:37.122
2022년 06월 30일 16:20:37
- 즉 형식 포맷을 지정할 수 있으므로 Date 든 Timestamp든 뭘 써도 상관없다
Calendar 클래스
- java.util 안에 있는 클래스
- 앞의 Date, Timestamp 와는 기능이 좀 다르다
- 날짜시간 불러올떄도 쓰지만 캘린더를 만들떄도 씀
Calendar 클래스 객체 생성시 주의
Calendar c1 = new Calendar(); // 오류발생
- Calendar 클래스는 지금까지 다룬것처럼 new연산자로 객체 생성을 하면 안됨!
- 거의 대부분의 객체는 생성할떄 new 써야한다.
- new는 새로운 공간을 만든다는 의미인데 Calendar클래스는 새로운 날짜를 하는게 아니라 그냥 시스템의 날짜를 구해오는 것이기 때문이다.
Calendar클래스 객체 생성하는법 2가지 방법
1. 자식클래스인 GregorianCalendar 클래스로 객체를 생성해서 전달
- Calendar 클래스의 자식 클래스는 그레고리안 캘린더 클래스임
- 이걸 활용해서 Calendar 객체를 만드는법이 첫번째 방법
Calendar c2 = new GregorianCalendar(); // 업캐스팅
- 왼쪽 클래스명과 오른쪽 생성자 호출 생성자 명이 보통은 동일하지만 지금처럼 다른 경우에는 형변환이 된 것이다.(세번째 자료형변환 : 레퍼런스 형변환)
- 오른쪽의 자식 클래스인 GregorianCalendar 클래스로 객체를 생성해서 왼쪽 부모에게 전달하는것
= 레퍼런스 형 변환의 업캐스팅(반대의 경우는 다운캐스팅)
- 업캐스팅하면 기능이 좀 달라지는게 있다 (나중에 공부)
2. Calendar 클래스의 정적메소드인 getInstance() 로 객체 돌려받기
Calendar c = Calendar.getInstance();
* 객체 = instance
Calendar 클래스 구조 (API 문서)
필드 : static 붙은 정적필드 들이 대부분
생성자 : 기본생성자있지만 기본생성자 쓰면 오류생김, 이런 방식으로 객체 생성 불가
메소드 : 메소드 중 getInstance() 를 보면 리턴자료형이 static Calendar 이다, 이 메소드로 객체를 구해옴
* 값을 구해오는 메소드는 getX 정해주는건 setX
Calendar 사용해서 출력
Calendar c = Calendar.getInstance();
System.out.println(c);
출력
java.util.GregorianCalendar[time=1656574659906,areFieldsSet=true,areAllFieldsSet=true,lenient=true...
- 이제 Calendar 객체가 만들어졌다
- 근데 이 객체는 년,월,일,시 등이 한번에 출력되지 않음
- 이 time은 1970년 1월 1일 00:00 부터 지난 초(sec)같은거임
진짜 출력하는 방법 : Calendar 클래스의 정적필드를 활용
ex) YEAR 이란 정적필드가 있다 -> Calendar.YEAR 로 쓰고 리턴형은 int 이다.
System.out.println(Calendar.YEAR); //1
- Calendar.YEAR 필드값은 1
- Calendar.MONTH 필드값은 2
- 이렇게 get(Calendar.YEAR) 하면 Calendar 객체인 c중에서 인덱스에 맞는걸 꺼내온다.
- 우리는 필드명만 알고있으면 됨.
출력
1
- 이걸 활용해서 년 (YEAR)을 구할 수 있다
Calendar로 년 구하기
Calendar c = Calendar.getInstance();
int y = c.get(Calendar.YEAR);
System.out.println(y);
출력 : 2022
Calendar로 월 구하기
Calendar c = Calendar.getInstance();
int y = c.get(Calendar.YEAR); // 연(년) 정보
System.out.println(y);
int m = c.get(Calendar.MONTH) + 1; //월(0~11) -> 실제 사용하는 월과 맞추려면 +1해줘야함
System.out.println(y+ "-" + m);
출력
2022
2022-5
- Calendar.MONTH 필드 이용하면 0~11로 나온다. 실제 사용하는 월과 맞추려면 +1 해줘야함
Calendar로 시간구하기
int h1 = c.get(Calendar.HOUR); // 12시간제
int h2 = c.get(Calendar.HOUR_OF_DAY); // 24시간제
System.out.println(h1); //
System.out.println(h2);
출력
4
16
Calendar로 오전, 오후 구하기
int ap = c.get(Calendar.AM_PM); //오전시간은 0, 오후시간은 1 을 리턴해줌
if(ap==0) {
System.out.print("오전");
}else {
System.out.print("오후");
}
- ap는 숫자로 값을 돌려줌
- 오전시간은 0, 오후시간은 1로 리턴해줌
Calendar로 분, 초 구하기
int mm = c.get(Calendar.MINUTE); //분
int s = c.get(Calendar.SECOND); //초
System.out.println(h1 + ":" + mm + ":" + s);
System.out.println(h2 + ":" + mm + ":" + s);
- Calendar 클래스로 연월일시분초 구할땐 따로 구해야하고 제공하는 필드를 사용해야만 함
Calendar로 요일 구하기(과제)
https://laker99.tistory.com/20?category=1065834
int w = c.get(Calendar.DAY_OF_WEEK);// 1~7
System.out.println("w=" + w);
// 1:일, 2:월, 3:화, 4:수, 5:목, 6:금, 7:토
String[] week = { "일", "월", "화", "수", "목", "금", "토" };
System.out.println(week[w - 1] + "요일");
- DAY_OF_WEEK 필드를 사용한다
- 그럼 요일값을 숫자로 리턴해준다
- 1:일, 2:월, 3:화, 4:수, 5:목, 6:금, 7:토
- 그것을 String 객체배열에 넣어서 문자로 출력을 하고 있다.
'국비지원 과정 > JAVA' 카테고리의 다른 글
코딩 10일 / 2022.07.04 / JAVA의 Wrapper 클래스, 박싱, 언박싱, 업캐스팅, 다운캐스팅, 상속1 (0) | 2022.07.12 |
---|---|
코딩 9일 / 2022.07.01 / JAVA의 문자열 처리 클래스(String, StringBuffer, StringTokenizer) (0) | 2022.07.11 |
코딩 7일 / 2022.06.29 / JAVA의 접근제어자,메소드 오버로딩,정적 변수,정적 메소드 (0) | 2022.07.05 |
코딩 6일 / 2022.06.28 / JAVA의 클래스,객체,필드,생성자 (0) | 2022.07.01 |
코딩 5일 / 2022.06.27 / JAVA의 배열2,참조형,클래스,객체 (0) | 2022.06.28 |