과제 풀이
https://laker99.tistory.com/23?category=1065834

 

		System.out.printf("%.2f", l);

- 소숫점 둘째자리까지(%.2) 출력하고 실수형태(%f) 로 출력

 

		DecimalFormat df = new DecimalFormat("0.00"); //내 코드
		DecimalFormat df = new DecimalFormat("###.00"); //강사님 코드

- 0과 #은 의미가 다르다. 
- ###을 넣으면 두자리여도 두자리만 표시하고 세자리면 세자리로 표시한다.
- 000을 넣으면 0은 무조건 자리를 채워넣는 형식, 31.42인 값이 031.42 로 표시된다.


상속을 쓰는 이유
- 중복코드를 줄이기 위해서
- 통일성있는 클래스를 설계하기 위해서
- 그래픽프로그램에서 상속을 많이 사용한다
- 나중에 JSP model2 = MVC 패턴개발 를 할때 클래스가 많을때 사용한다

자바에서 그래픽 프로그램
- CUI(Console User Interface)
- GUI(Graphic User Interface)

그래픽 프로그램 관련 패키지
- java.awt.*
- javax.swing.*
- javafx.*
- 여기 그래픽 프로그램 만들기 위한 클래스들이 모여있다
- 그래픽 프로그램에서 상속을 많이 사용함
- 캔버스, 체크박스, 프레임, 스크롤바, 메뉴, 텍스트필드 등 만들 수 있다

상속관련 용어 정리
- 부모클래스 = 상위클래스 = 슈퍼클래스
- 자식클래스 = 하위클래스 = 서브클래스 = 파생클래스

단일상속
- 자바는 단일상속만 가능
- 두개이상의 클래스로부터 상속받을수없다(C++, Python은 가능)

+ 부모클래스로 객체를 만드는게 의미없다(상속)
+ 자식클래스로 객체를 만드는게 의미있다(부모클래스의 필드와 메소드도 받았으므로)

패키지와 파일
- 한개 파일에 클래스 여러개 들어가도된다
- 나중에 컴파일될때 바이트코드는 클래스별로 따로따로 만들어짐
- 패키지는 폴더를 의미한다

 

상속 예제1
- SuperSub01.java 
- 자식클래스명 옆에 extends 옆에 부모클래스명을 쓰자

package p2022_07_05;

class Parent {
	public void parentPrn() {	//부모 클래스
		System.out.println("슈퍼 클래스 메서드는 상속된다.");
	}
}

//Parent를 슈퍼 클래스로 하는 서브 클래스 Child 정의 
class Child extends Parent {	//자식 클래스
	public void childPrn() {
		System.out.println("서브 클래스 메서드는 슈퍼가 사용 못한다.");
	}
}

//Parent를 슈퍼 클래스로 하는 서브 클래스 Child 정의
//Parent클래스의 parentPrn() 메소드는 자식 클래스에 상속된다.
class SuperSub01 {
	public static void main(String[] args) {
		Child c = new Child(); // 서브 클래스로 객체를 생성
		c.parentPrn(); // 슈퍼 클래스에서 상속 받은 메서드 호출
		c.childPrn(); // 서브 클래스 자기 자신의 메서드 호출
		System.out.println("-------------------------------------->> ");
		Parent p = new Parent(); // 슈퍼 클래스로 객체 생성
		p.parentPrn(); // 슈퍼 클래스 자기 자신의 메서드 호출
		// p.childPrn( ); //서브 클래스 메서드는 가져다 사용 못함
	}
}

- 상속은 부모가 자식에게 일방적으로 주는것만 가능하다
- 부모클래스는 자식클래스의 멤버(필드나 메소드) 사용불가!

 

상속 예제2
- SuperSub04.java

package p2022_07_05;

class Point2D { // 부모 클래스
	protected int x = 10; // private int x=10;
	protected int y = 20; // private int y=20;
}

// 부모 클래스의 필드의 접근제어자가 private이면 자식이 접근할 수 없다.(상속 불가), 여기선 오류 발생
class Point3D extends Point2D { // 자식 클래스
	protected int z = 30;

	public void print() {
		System.out.println(x + ", " + y + ", " + z);
	}
}

class SuperSub04 {
	public static void main(String[] args) {
		Point3D pt = new Point3D();
		pt.print();
	}
}

- Point2D클래스가 부모클래스, 안의 필드 x, y 의 접근제한자가 protected
- Point3D클래스가 Point2D 클래스를 상속받음
- Point3D의 필드 protected int z, 메소드 print();
- 메인메소드가 있는 클래스 SuperSub04
- 메인메소드에서 Point3D 클래스로 객체를 생성하고 pt.print()로 메소드 호출
- 그럼 이 print()에서 x,y는 자기 클래스의 멤버는 아니지만 부모 클래스의 멤버이므로
자기거인것처럼 출력하는 것임

 

- 이때 접근 제어자, Point2D의 접근제어자를 private으로 두면? 오류발생, 자식 클래스에 상속 안된다!
- 부모클래스의 필드/메소드가 private이면 자식클래스라도 외부클래스이므로 접근불가, 상속을 못함
- private만 아니면 다 됨, default, public, protected는 다 상속 된다

 

접근제어자 protected
- 상속에선 나중에 접근제어자를 protected를 많이 씀
- 심지어 패키지가 달라져도 상속관계에 있을때는 자식이 접근 가능하다

패키지가 달라져도 접근가능한 경우
1. public인 경우
2. protected이고 상속관계인 경우 자식이 부모클래스 필드/메소드 접근

* 자바의 접근 제어자


1. 상속 관계가 있는 경우에 2개의 클래스(부모,자식 클래스)가 같은 패키지 안에 들어 있을때는 부모의 접근제어자가 default, protected, public 접근제어자인 경우에 자식클래스에서 접근 할수 있다. (단, private접근 제어자만 자식 클래스에서 접근 할 수 없음)

2. 상속 관계가 있는 경우에 2개의 클래스(부모,자식 클래스)가 다른 패키지 안에 들어 있을때는부모의 접근제어자가 protected, public 접근제어자인 경우에 자식클래스에서 접근 할수 있다. 

3. 상속 관계가 없는 경우에 2개의 클래스가 서로 다른 패키지 않에 들어 있을때는 public 접근제어자로 되어 있어야만 다른 클래스에서 접근 할 수 있다.

+ 메소드 오버라이딩
- 상속에서 가장 중요한 개념
- 반드시 상속이 전제되어야만 쓸 수 있다.
- 메소드는 상속이 되지만, 부모로 부터 상속받은 메소드를 이름과 형식은 같게 하지만 안의 내용을 다르게 하는것
- 나중에 자세히 공부할것

 

상속 예제 3-1 (필드)
- SuperTest02.java

package p2022_07_05;

//부모 클래스 안에 있는 필드는 자식 클래스에게 상속된다.
class Point2D2 {	//부모 클래스
	protected int x = 10;
	protected int y = 20;
}

class Point3D2 extends Point2D2 {	//자식 클래스
	protected int z = 30;

	public void print() {
		System.out.println(x + ", " + y + ", " + z); // x와 y는 상속 받아 사용하는 멤버변수
	}
}

class SuperTest02 {
	public static void main(String[] args) {
		Point3D2 pt = new Point3D2();
		pt.print();
	}
}

+ protected이므로 상속 가능
- 이 예제는 필드 중복 그거 아니고 다음 예제이다
- 위 예제는 그냥 부모 클래스 안에 있는 필드는 자식 클래스에게 상속된다는걸 보여주는 예제

- 그럼 부모클래스에 있는 필드 x, y 를 상속받은 자식 클래스에서 똑같은 이름 x, y으로 필드를 정의해보자
- 자식클래스로 객체 만들어서 필드값출력할떄 어느값을 출력하는가?
-> 새로정의한 x, y값만 출력됨.
- 다음 예제에서 설명

 

상속 예제 3-2 (필드의 상속)
- SuperTest03.java

package p2022_07_05;
//부모 클래스에 있는 필드를 자식 클래스에서 재정의(동일한 이름의 변수)하면,
//자식 클래스에서 재 정의한 필드만 사용 가능하다.
class Point2D3 {	//부모 클래스
	protected int x = 10; // Point3D에서 다시 한번 정의되므로 은닉 변수가 됨
	protected int y = 20; // 은닉 변수는 쉐도우 변수라고도 함
}

class Point3D3 extends Point2D3 {	//자식 클래스
	protected int x = 40; // 슈퍼 클래스에 존재하는 멤버변수를
	protected int y = 50; // 서브 클래스에 다시 한 번 정의함

	protected int z = 30;

	public void print() {
		System.out.println(x + ", " + y + ", " + z); // x와 y는 재 정의된 Point3D 클래스 소속
	}
}

class SuperTest03 {
	public static void main(String[] args) {
		Point3D3 pt = new Point3D3();
		pt.print();
	}
}
40, 50, 30

- x, y가 중첩되고 있다
- 결론은 새로정의한 x, y값만 출력됨, 즉 10, 20 대신 40, 50 이 출력됨
- 기존에 상속해준 부모 클래스의 x, y 필드는 더이상 사용이 되지않음, 은닉이된다
-> 이 변수를 은닉 변수 = 쉐도우 변수 라고 함
- 이 은닉 변수들에 굳이 접근하고 싶으면 super. 을 사용해서 접근한다!

필드의 상속 정리
- 부모 클래스에 있는 필드를 자식 클래스에서 재정의(동일한 이름의 변수)하면, 자식 클래스에서 재정의한 필드만 사용 가능하다.

은닉 변수에 접근
- super.x, super.y 하면 은닉변수에 접근가능하다
- 쓸 일이 많지 않다

은닉 변수에 접근 예시
- 은닉변수에 굳이 접근하려면 super. 해서 접근
- 부모 클래스에 접근해서 값을 구해오라는 의미
- SuperTest04.java

package p2022_07_05;

//super : 부모 클래스를 의미함
//super.x 는 부모 클래스의 은닉된 필드를 호출할 때 사용된다.
//super.x 는 "자식클래스"의 "메소드 안"에서만 사용할 수 있다. (주의)
//그 외의 장소에서 System.out.println(super.x); //오류 발생

class Point2D4 { // 부모 클래스
	protected int x = 10; // 은닉 변수
	protected int y = 20; // 혹은 쉐도우 변수
}

class Point3D4 extends Point2D4 { // 자식 클래스
	protected int x = 40; // 슈퍼 클래스에 존재하는 멤버변수를
	protected int y = 50; // 서브 클래스에 다시 한 번 정의함

	protected int z = 30;
	// System.out.println(super.x); 메소드 내부가 아니므로 오류

	public void print() {
		System.out.println(x + ", " + y + ", " + z); // x와 y는 재 정의된 Point3D 클래스 소속
	}

	public void print02() {
		System.out.println(super.x + ", " + super.y + ", " + z); // Point2D 클래스 소속 멤버변수로 접근
	}
}

class SuperTest04 {
	public static void main(String[] args) {
		Point3D4 pt = new Point3D4();
		pt.print(); // 40, 50, 30 // Point3D의 x, y
		pt.print02(); // 10, 20, 30 // Point2D의 x, y

		System.out.println(pt.x); // 40
	}
}
40, 50, 30
10, 20, 30
40

 

은닉 변수에 접근 정리
- super : 부모 클래스를 의미함
- super.x 는 부모 클래스의 은닉된 필드를 호출할 때 사용된다.
- super.x 는 "자식클래스"의 "메소드 안"에서만 사용할 수 있다. (주의)
- 그 외의 장소에서 System.out.println(super.x); //오류 발생

super 와 this
- super : 부모 클래스를 의미하는 일종의 레퍼런스 변수
- this : 자기 클래스를 의미하는 일종의 레퍼런스 변수

* this와 super
this. : 생성자와 메소드에서 매개변수와 멤버변수 이름이 동일한 경우에 사용

this() : 같은 클래스내에 있는 다른 생성자를 호출(다른 클래스 내의 생성자는 이걸로 호출하지않음)
super. : 부모 클래스에 있는 은닉된 멤버변수와  메소드를 호출  할때 사용, 반드시 자식 클래스의 메소드 내에 써야만 사용가능하다. 자식 클래스의 메소드 밖이나 다른 클래스 내에서 사용불가
super() : 부모 클래스의 매개변수를 가진 생성자를 호출 할 때 사용

메소드로의 적용 (메소드 오버라이딩)
- 필드에서 재정의된 필드가 사용되는 것 처럼 메소드도 마찬가지이다.
- 메소드는 메소드 오버라이딩이라고 하지만 필드는 이런거 따로 부르는 이름이 없다
- 결론적으론 메소드도 새로 정의된 메소드 오버라이딩된 메소드만 호출됨

- 부모 클래스의 메소드는 은닉 메소드가 됨, 굳이 호출하고 싶으면 super.메소드() 로 호출하면된다
- 필드때처럼 부모의 메소드와 똑같은 이름 + 똑같은 형식 으로 메소드를 만들어야함
- 메소드 오버라이딩(Method Overriding), 동일이름 동일형식 다른내용 상속전제 필수

메소드 오버라이딩 예제

- SuperSub05.java 

package p2022_07_05;

// 메소드 오버라이딩(Method Overriding)
// : 부모 클래스로부터 상속받은 메소드를 자식 클래스에서 재정의 해서 사용하는 것.
// 1. 부모 클래스로부터 상속받은 메소드를 자식 클래스에서 메소드 오버라이딩을 하면
//  메소드 오버라이딩 된 메소드만 호출되고, 부모 클래스의 메소드는 은닉이 되어서
//  자식클래스에 상속되지 않는다.
// 2. 부모 클래스에 은닉된 메소드를 호출할 때는 자식클래스의 메소드 안에서
//  super.parentPrn() 형식으로 호출해야 된다.

class Parent05 {	//부모 클래스
	public void parentPrn() {	//은닉 메소드가 된다
		System.out.println("슈퍼 클래스 : ParentPrn 메서드");
	}
}

//Parent05를 슈퍼 클래스로 하는 서브 클래스 Child05 정의 
class Child05 extends Parent05 {	//자식 클래스
//	super.parentPrn(); //오류 발생, 자식클래스의 메소드 내부여야함
	
	// 슈퍼 클래스에 있는 ParentPrn 메서드를 오버라이딩하면
	// Child05로 선언된 객체는 슈퍼 클래스의 메서드가 은닉되어 상속 받지 못하게 된다.
	public void parentPrn() {	// 메소드 오버라이딩(Method Overriding), 동일이름 동일형식 다른내용 상속전제 필수
		System.out.println("서브 클래스 : ParentPrn 메서드");
	}

	public void childPrn() {	// 자식 클래스만 있는 메소드
		super.parentPrn();	//부모 클래스의 은닉 메소드 호출
		System.out.println("서브 클래스 : ChildPrn 메서드");
	}
}

class SuperSub05 {
	public static void main(String[] args) {
		Child05 c = new Child05(); // 서브 클래스로 객체를 생성
		c.parentPrn(); // 오버라이딩된 서브 클래스의 메서드 호출(새로 정의된, 오버라이딩된 메소드만 호출됨)
		c.childPrn(); // 서브 클래스 자기 자신의 메서드 호출
		System.out.println("-------------------------------------------->> ");
		Parent05 p = new Parent05(); // 슈퍼 클래스로 객체를 생성
		p.parentPrn(); // 슈퍼 클래스(자기 자신)의 메서드 호출
	}
}
서브 클래스 : ParentPrn 메서드
슈퍼 클래스 : ParentPrn 메서드
서브 클래스 : ChildPrn 메서드
-------------------------------------------->>
슈퍼 클래스 : ParentPrn 메서드

- 은닉된 메소드도 호출할때는 super.메소드() 로 호출하면 호출된다!
- super.메소드() 를 쓰는 위치는 필드랑 동일하게 자식 클래스의 메소드 안에서 사용해야함 (주의)
ex) super.parentPrn();을 자식 클래스의 메소드 밖에서 쓰면 오류 발생함

 

- 메소드 오버라이딩을 하면 오버라이딩된 메소드만 호출된다.
- 부모클래스로부터 상속된 메소드는 사용이 더이상되지않고 은닉메소드가 된다
- 은닉메소드를 굳이 호출될때는 자식 클래스의 메소드 내에서 super.메소드() 로 호출

 

메소드 오버라이딩(Method Overriding) 정리
- 부모 클래스로부터 상속받은 메소드를 자식 클래스에서 재정의 해서 사용하는 것.
- 부모 클래스로부터 상속받은 메소드를 자식 클래스에서 메소드 오버라이딩을 하면 메소드 오버라이딩 된 메소드만 호출되고, 부모 클래스의 메소드는 은닉이 되어서 자식클래스에 상속되지 않는다.
- 부모 클래스에 은닉된 메소드를 호출할 때는 자식클래스의 메소드 안에서 super.parentPrn() 형식으로 호출해야 된다.

* 메소드 오버라이딩(Method Overriding)
- 부모 클래스로 부터 상속받은 메소드를 자식 클래스에서 재정의 해서 사용하는것

- Spring , JSP 할 때도 계속 따라가는 개념이므로 잘 익혀둬야 한다.

 

은닉 정리
- 결과적으로 자식 클래스에서 재정의 시 부모클래스안의 상속이 되는 필드, 메소드는 상속이 되지 않는다
- 은닉이 됨. 사용하려면 자식클래스의 메소드 안에서 super.필드명, super.메소드명() 으로 호출가능하다

+ 메소드 오버라이딩을 해도 되고 안해도 되지만 곧 배울 추상클래스, 인터페이스의 경우에는 반드시 메소드 오버라이딩을 해야하는 경우가 있다, 하지 않으면 오류 발생
+ 상속에서는 메소드와, 메소드 오버라이딩이 제일 중요하다

생성자와 상속
- 기본적으로 생성자는 상속되지 않는다, 어떻게 쓸까?
- 자식 클래스의 객체를 생성할때, 자식 클래스의 생성자가 호출되면 부모 클래스의 기본 생성자를 연쇄적으로 호출해줌
- 자식 클래스의 생성자는 기본생성자 여도 되고 매개변수를 가진 생성자여도 상관없음
- 이때 부모 클래스의 생성자는 "기본 생성자"만 호출되어 실행이됨

 

생성자와 상속 예제
- SuperTest05.java

package p2022_07_05;

class Point2D05 {	//부모 클래스
	protected int x = 10;	//필드
	protected int y = 20;

	public Point2D05() {	//부모클래스의 기본 생성자
		System.out.println("슈퍼 클래스인 Point2D 생성자 호출");
	}
}

class Point3D05 extends Point2D05 {	//자식 클래스
	protected int z = 30;

	public void print() {
		System.out.println(x + ", " + y + ", " + z);
	}

	public Point3D05() {	//자식클래스의 기본 생성자
		System.out.println("서브 클래스인 Point3D 생성자 호출");
	}
}

class SuperTest05 {
	public static void main(String[] args) {
		Point3D05 pt = new Point3D05();	//자식클래스의 기본생성자 호출
		pt.print();
슈퍼 클래스인 Point2D 생성자 호출
서브 클래스인 Point3D 생성자 호출
10, 20, 30

- 즉, main메소드에서 자식클래스의 생성자가 먼저 호출되었지만 실행 결과는 부모클래스의 기본 생성자의 출력문이 먼저 출력됨
- Point3D05 클래스의 기본 생성자가 호출되면 부모 클래스인 Point2D05 클래스의 기본 생성자를 호출함
- 그러므로 "슈퍼 클래스인 Point2D 생성자 호출" 출력 다음 "서브 클래스인 Point3D 생성자 호출" 메세지를 출력한다
- 부모 클래스의 기본생성자 만들어놓지 않으면 컴파일러가 자동으로 만듬
- 지금처럼 기본생성자 만들어뒀을때는 객체 생성할때 부모 클래스의 기본 생성자를 호출함

생성자와 상속 정리
* 상속에서의 생성자
1. 생성자는 기본적으로 상속이 되지 않는다
2. 자식클래스를 이용해서 객체를 생성할때 자식클래스의 생성자(기본생성자,매개변수 있는 생성자 모두 가능)가 호출되면, 부모클래스의 기본생성자가 자동으로 호출된다.
3. 매개변수가 있는 생성자가 있는 경우에는 더이상 컴파일러가 기본 생성자를 자동으로 생성해 주지 않는다.
4. 부모 클래스의 매개변수가 있는 생성자를 자식 클래스에서 호출 할때는 super()를 이용해서 호출할 수 있다. 단, super()는 자식 클래스의 생성자 안에서만 사용 가능함.

부모클래스의 기본생성자 호출
- 심지어 부모 클래스 쪽에 기본생성자가 없어도 된다.
- 자식생성자가 부모 클래스의 기본생성자를 만들어서 호출해줌
- 또한 자식 클래스 쪽에 기본생성자가 없어도 된다, 컴파일러가 자동으로 기본클래스를 생성 후 부모 클래스의 기본 생성자 호출
- 만약 부모 클래스의 기본생성자가 아닌 매개변수가 있는 생성자를 호출하고 싶다면, super()로 명시적으로 호출해줘야지만 부모클래스의 매개변수가 있는 생성자를 호출 할 수 있다

 

- 자식클래스는 매개변수 있는 상속자여도 된다

	public Point3D05(int a) {	//자식클래스의 기본 생성자
		System.out.println("서브 클래스인 Point3D 생성자 호출");
	}
// main
	Point3D05 pt = new Point3D05(30);	//자식클래스의 기본생성자 호출

- 이어도 문제 없고 부모클래스의 기본생성자를 호출함 또한

	public Point3D05() {	//자식클래스의 기본 생성자
		System.out.println("서브 클래스인 Point3D 생성자 호출");
	}

- 이 코드(자식클래스의 기본생성자) 를 주석으로 막아도 컴파일러가 자동으로 기본클래스를 생성
- 또한 연쇄적으로 부모클래스의 기본 생성자도 호출됨

 

부모클래스의 기본생성자 호출 정리
- 자식클래스는 기본생성자여도 되고 매개변수가 있는 생성자여도 됨
- 부모클래스는 기본생성자만 연쇄적으로 자동적으로 호출해주게 되고, 매개변수가 있는 생성자는 우리가 super()로 명시해서 직접 호출해 줘야함

 

부모클래스에 기본생성자가 없다면
- 부모클래스에서 이미 매개변수가 있는 생성자가 있는경우 기본생성자가 자동으로 만들어지지 않는다
- 그래서 기본생성자를 내가 명시해서 만들어주지 않으면 자식클래스의 생성자에도 오류가 생김

부모클래스에 기본생성자가 없다면 예제/super() 통해서 호출하는 예제
- SuperTest06.java
- 이 예제에선 부모클래스에서 이미 매개변수가 있는 생성자가 있으므로 기본생성자가 만들어지지 않는다
-> 그래서 기본생성자를 내가 명시해서 만들어주지 않으면 자식클래스의 생성자에도 오류가 생김

	public Point2D06( ){ System.out.println("슈퍼 클래스인 Point2D 생성자 호출"); }

- 부모 클래스의 기본 생성자 주석을 풀어야만 자식클래스에서 오류가 생기지 않음
- 부모의 기본생성자를 자식 객체 생성될때 연쇄호출됨
- 부모 클래스에서 매개변수가 있는 생성자는 자식 클래스의 생성자에서 호출해주지 않는다, super() 로 호출해야함
- 그리고 부모 클래스에서 매개변수가 있는 생성자가 있고 기본 생성자가 적혀져있지 않으면 기본생성자는 자동으로 만들어지지 않는다
- 이런 경우에는 기본생성자를 명시해주지 않으면 자식 생성자쪽에서 오류가 남.

+ 매개변수가 있는 생성자가 있을때는 예외적으로 컴파일러가 기본생성자를 생성해주지 않는다.

- 물론 자식 클래스에서 호출하지 않을때는 안만들어도 되지만 자식 클래스 쪽에서 호출을 할떄는 부모클래스의 기본생성자가 필요하고, 부모 클래스의 기본생성자 없으면 오류남
- 지금은 자식 클래스의 생성자가 호출되므로 부모 클래스의 기본 생성자도 호출되기때문에 부모클래스의 기본 생성자가 필요하다

 

부모클래스의 매개변수가 있는 생성자 호출하는 방법
- 자식클래스에서 super() 형태로 호출해야함
- super()는 자식클래스의 생성자 내부 첫번째 라인에 써야함! 위치가 정해져있다

package p2022_07_05;

//super()
//1. super()는 부모 클래스의 매개변수를 가진 생성자를 호출할 때 사용한다.
//2. super()는 자식 클래스의 생성자 안에서 첫번째 라인에 사용해야 한다.
//3. super()를 이용해서 부모 클래스의 매개변수를 가진 생성자를 호출하면,
//더이상 부모클래스의 기본생성자를 호출해주지 않는다.


class Point2D06 { // 부모 클래스
	protected int x = 10; // 필드
	protected int y = 20;
	
	// 매개변수가 있는 생성자가 있을때는 예외적으로 컴파일러가 기본생성자를 생성해주지 않는다.
	public Point2D06() { //기본 생성자
		System.out.println("슈퍼 클래스인 Point2D 생성자 호출"); 
	}

	public Point2D06(int xx, int yy) {
		x = xx;
		y = yy;
	}
}

class Point3D06 extends Point2D06 {	//자식 클래스
	protected int z = 30;

	public void print() {
		System.out.println(x + ", " + y + ", " + z);	//상속받은 필드 x, y
	}

	public Point3D06() {	//자식 클래스의 기본 생성자
		super(50,60);	// 부모 클래스의 매개변수가 있는 생성자 호출
		System.out.println("서브 클래스인 Point3D 생성자 호출");
	}
}

class SuperTest06 {
	public static void main(String[] args) {
		Point3D06 pt = new Point3D06();	//자식 클래스의 생성자 호출
		pt.print();
	}
}
서브 클래스인 Point3D 생성자 호출
50, 60, 30

- 부모클래스의 매개변수 2개인 생성자가 호출되면서 x값이 50, y값이 60이 되는 것이다.

 

위 예제 처리과정
1. 메인메소드에서 먼저 Point3D06이란 자식클래스의 생성자를 호출한다
2. 자식클래스의 생성자가 호출됨, 내부 코드를 실행함
3. 원래는 자식클래스의 생성자가 호출되면 연쇄적으로 부모클래스의 기본 생성자를 호출함
4. 근데 여기선 super()를 썼으므로 super()가 우선이 됨 
- super()를 통해 호출된 부모클래스의 매개변수있는 생성자가 호출되면 부모클래스의 기본생성자는 호출되지 않음
5. 그래서 "슈퍼 클래스인 Point2D 생성자 호출" 은 출력되지 않았고 값은 50, 60으로 변경됨
- 즉 매개변수를 가진생성자만 호출되었다는 의미


Point2D06 (부모)클래스의 매개변수 2개인 생성자를 호출하고 싶다면? (위 예제 부분1)

	public Point2D06(int xx, int yy) {
		x = xx;
		y = yy;
	}

- 이걸 호출하고 싶으면 자식클래스의 생성자 내부

	public Point3D06() {	//자식 클래스의 기본 생성자
		super(50,60);
		System.out.println("서브 클래스인 Point3D 생성자 호출");
	}

- 에서 super()를 통해서 부모 클래스의 매개변수가 2개인 생성자를 호출한다
- 부모 클래스의 기본생성자 주석으로 막아도 오류 안생김

 

super() 유의사항
- super()는 자식클래스의 생성자 안에서만 사용가능하다
- 생성자 내부의 첫번째 라인만 가능하다! 다른 장소에 들어가면 오류 발생한다
- 자식 생성자가 호출되면 부모의 기본생성자가 호출되지만 자식 생성자 내에서 super()를 써서 매개변수 있는 생성자 호출할떄는
부모의 기본생성자는 호출되지 않는다.
- super()가 우선순위 높다, super()쓰면 기본생성자 호출안해줌 
- 동시에 2개(기본 생성자, 매개변수가 있는 생성자) 호출해주지 않는다
- super()는 메소드 안에 못쓴다.
- super()가 우선순위 높다, super()쓰면 기본생성자 호출안해줌 

super() 정리
1. super()는 부모 클래스의 매개변수를 가진 생성자를 호출할 때 사용한다.
2. super()는 자식 클래스의 생성자 안에서 첫번째 라인에 사용해야 한다.
3. super()를 이용해서 부모 클래스의 매개변수를 가진 생성자를 호출하면, 더이상 부모클래스의 기본생성자를 호출해주지 않는다.

super. 와 super()의 차이
- super. : 메소드 오버라이딩 되었을때 부모클래스 안의 필드, 메소드를 호출할 때 사용, 잘 안 쓴다
- super() : 자식클래스에서 부모 클래스의 매개변수를 가진 생성자를 호출할 때 사용, 잘 쓴다

+ super() 는 그래픽 프로그램 예제 다룰 때 썼었다
- FrameTestEx extends Frame 클래스의 생성자  첫번째 라인에서 super("Frame Test"); 라고 썼다. 
- 자기 부모의 매개변수가 있는 생성자를 호출하라는 의미로서 부모인 Frame클래스의 매개변수가 String인 생성자를 호출하고 있다

 

this. 예제
- DMBCellPhone.java

package p2022_07_05;
// p290 ~ 292

class CellPhone{							// 부모 클래스
	String model;							// 필드
	String color;
	
	void powerOn() {						// 메소드
		System.out.println("전원을 켭니다.");
	}
	void powerOff() {
		System.out.println("전원을 끕니다.");
	}
	void bell() {
		System.out.println("벨이 울립니다.");
	}
	void sendVoice(String message) {
		System.out.println("자기:"+message);
	}
	void receiveVoice(String message) {
		System.out.println("상대방:"+message);
	}
	void hangUp() {
		System.out.println("전화를 끊습니다.");
	}	
}

// 부모 클래스의 필드와 메소드는 상속된다.
class DMBCellPhone extends CellPhone{	// 자식 클래스
	int channel;

	public DMBCellPhone(String model, String color, int channel) {
		this.model = model;				// 자바폰
		this.color = color;				// 검정
		this.channel = channel;			// 10
	}
	
	void turnOnDmb() {
		System.out.println("채널:"+channel+"전 DMB방송 수신을 시작 합니다.");
	}
	void changeChannelDmb(int channel) {
		this.channel = channel;
		System.out.println("채널"+channel+"번으로 바꿉니다.");
	}
	void turnOffDmb() {
		System.out.println("DMB방송 수신을 멈춥니다.");
	}	
}

public class DMBCellPhoneEx {

	public static void main(String[] args) {
		// TODO Auto-generated method stub
		
		DMBCellPhone dmb = new DMBCellPhone("자바폰", "검정", 10);
		
		// model, color 필드는 부모 클래스로 부터 상속 받아서 사용
		System.out.println("모델:"+dmb.model);
		System.out.println("색상:"+dmb.color);
		System.out.println("채널:"+dmb.channel);

		// 부모 클래스로 부터 상속 받아서 사용되는 메소드
		dmb.powerOn();
		dmb.bell();
		dmb.sendVoice("여보세요");		
		dmb.receiveVoice("안녕 하세요! 저는 홍길동 입니다.");		
		dmb.sendVoice("아~ 예 반갑습니다.");		

		dmb.turnOnDmb();
		dmb.changeChannelDmb(12);
		dmb.turnOffDmb();		
	}

}

 

위 예제 부분 1

		DMBCellPhone dmb = new DMBCellPhone("자바폰", "검정", 10);

위 예제 부분 2

	public DMBCellPhone(String model, String color, int channel) {
		this.model = model;				// 자바폰
		this.color = color;				// 검정
		this.channel = channel;			// 10
	}

- DmbCellPhone 클래스의 생성자에서 초기화할때 상속받은 필드들도 다 초기화하고 있다
- this. 써서 가능 model과 color는 상속을 받아 쓰는것

 

위 예제 부분 3

	void changeChannelDmb(int channel) {
		this.channel = channel;
		System.out.println("채널"+channel+"번으로 바꿉니다.");
	}

- DmbCellPhone 클래스의 메소드인 changeChannelDmb()에서 매개변수와 필드가 이름이 같기때문에 여기서도 this. 를 쓴다

 

위 예제 부분 4

		// 부모 클래스로 부터 상속 받아서 사용되는 메소드
		dmb.powerOn();
		dmb.bell();
		dmb.sendVoice("여보세요");		
		dmb.receiveVoice("안녕 하세요! 저는 홍길동 입니다.");		
		dmb.sendVoice("아~ 예 반갑습니다.");

- 상속받은 메소드를 자기것처럼 씀

+ Ctrl키 누르고 메소드명 클릭하면 그게 정의되어있는 곳으로 감! 파일 달라도 거기로 찾아감

 

메소드 오버라라이딩 예제
- ComputerEx.java

package p2022_07_05;
// p296 ~ 297
// 메소드 오버라이딩(Method Overriding)
// : 부모 클래스로 상속받은 메소드를 자식 클래스에서 재정의 해서 사용하는 것

class Calculator{						// 부모 클래스
	double areaCircle(double r) {
		System.out.println("Calculator 객체의 areaCircle() 실행");
		return 3.14159 * r * r;
	}
}

class Computer extends Calculator{		// 자식 클래스	

	@Override
	double areaCircle(double r) {		// 메소드 오버라이딩
//		super.areaCircle(r);
		System.out.println("Computer 객체의 areaCircle() 실행");
		// TODO Auto-generated method stub
		return Math.PI * r * r;
	}		
	
}

public class ComputerEx {

	public static void main(String[] args) {
		// TODO Auto-generated method stub
		
		int r = 10;
		Calculator cal = new Calculator();
		System.out.println("원의 면적:"+ cal.areaCircle(r));
		
		// 자식클래스에서 메소드 오버라이딩 된 메소드만 호출된다.
		Computer comp = new Computer();
		System.out.println("원의 면적:"+ comp.areaCircle(r));
	}

}

- 부모클래스로부터 상속받은 Computer 클래스는 메소드 오버라이딩을 수행한다.
- 이때, 부모클래스의 이름과 형식 (매개변수, 리턴형) 그대로 해야한다
- 만약 부모클래스의 메소드를 호출하고 싶다면 return super.areCircle(r)로 super. 를 쓰면 된다.

- 클래스를 상속받을땐 메소드 오버라이딩을 해도 되고 안해도 됨.
- 상속을 하더라도 메소드 오버라이딩 안해도 됨
- 이게 끝나면 추상클래스라는걸공부하는데 추상클래스가 extends뒤에 오게되면 반드시 메소드 오버라이딩을 해야함 

+ 인터페이스는 클래스처럼 extends로 상속받는게 아니라 implements 키워드로 상속을 받음
+ 직접 내가 클래스를 만들때 상속을 하려면 ex까지 쓰고 ctrl+ space하면 자동으로 입력됨

 

이클립스 메소드 오버라이딩 생성
- 이때 이클립스를 이용하면 메소드 오버라이딩 자동으로 만들어주는 기능 있다
- 주석으로 막고 이클립스로 메소드 오버라이딩 해보자

오른쪽 마우스 -> Source -> Override/Implement Methods
- 부모클래스, 조상클래스(Object등)가 보이고 그 안의 오버라이딩 할 메소드 선택 가능
- 원하는 메소드만 클릭해서 오버라이딩 하면 된다

- 그럼 이게 생성된다

	@Override
	double areaCircle(double r) {
		// TODO Auto-generated method stub
		return super.areaCircle(r);
	}

 

오버라이드 어노테이션

@Override

- 컴파일러가 이 어노테이션 만나면 아래쪽에 메서드가 오버라이딩 잘 되었는지 체크한다
- 이런역할을 어노테이션이 해줌
- 없어도 실행에 지장은 없다.

 

메소드 오버라이딩 정리
- 오버라이딩 하면 부모클래스의 메소드가 아닌 자식클래스에서 메소드 오버라이딩 된 메소드만 호출된다.
- 은닉된 메소드를 굳이 호출할떄는 자식 클래스의 메소드에서 super. 으로 호출한다
- 이 내용이 그 다음의 추상클래스, 인터페이스와 연결됨 거기선 반드시 메소드 오버라이딩을 해야함 

final 키워드
- 상속을 배우기 전 간단히 설명 했었다
- final 필드 : 수정 불가 필드 = 상수
- final 메소드 : 자식 클래스에서의 이 메소드 오버라이딩을 허용하지 않음 (마지막 메소드)
- final 클래스 : 상속을 허용하지 않는 클래스 (마지막 클래스)
- 여기서 final 메소드와 final 클래스를 볼 것

final 메소드
- 상속이 되더라도 메소드 오버라이딩 불가능 메소드 오버라이딩 하려하면 오류 발생시킴

final 클래스
- 해당 클래스를 상속 하려고 하면 오류 발생시킴

상속에서의 접근제어자
* 자바의 접근 제어자


1. 상속 관계가 있는 경우
1-1. 2개의 클래스(부모,자식 클래스)가 같은 패키지 안에 들어 있을때
- 부모의 접근제어자가 default, protected, public 접근제어자인 경우에 자식클래스에서 접근 할수 있다. 
- (단, private 접근제어자만 자식 클래스에서 접근 할 수 없음)

1-2. 2개의 클래스(부모,자식 클래스)가 다른 패키지 안에 들어 있을때
- 부모의 접근제어자가  protected, public 접근제어자인 경우에 자식클래스에서 접근 할수 있다. 

2. 상속 관계가 없는 경우
- 2개의 클래스가 서로 다른 패키지 안에 들어 있을때는 public 접근제어자로 되어 있어야만 다른 클래스에서 접근 할 수 있다.

import 기준
- 패키지가 달라질때 -> 반드시 import

패키지가 다를때 접근하는법
1. 접근제어자가 public 이면 다 됨
2. 두 클래스 상속관계 && 접근제어자 protected

+ 그래서 이 protected 접근제어자는 상속에서 많이 씀

상속과 접근제어자
1. 같은 패키지 안의 클래스 2개가 부모-자식 상속관계 -> private 빼고 다 접근가능하다
- public은 다 되고, default 는 원래부터 같은 패키지면 접근가능하고
- protected는 원래부터 같은 패키지면 접근 가능했고 또 상속관계면 다 접근 가능하기떄문에 접근 가능

2. 다른 패키지 안의 부모-자식 상속관계 -> protected, public 둘 중 하나여야만 함
- default 는 다른패키지는 접근 불가
- protected는 패키지가 달라져도 상속관계면 접근 가능함
- private은 자식 클래스라도 외부클래스이므로 접근 불가
+ private은 딱 자기 클래스만 접근 가능
- 다른 패키지더라도 상속관계이고 protected면 접근 가능하다

상속과 접근제어자 예제
- 예제 중에서 부모클래스는 src - packTest - packOne -  AccessTest.java(부모클래스)
- 자식클래스 패키지 없기때문에 복사를 해서 바로 scr에 집어넣기, SubOne.java
- 제3의 클래스 SuperSubA.java

- 부모클래스 AccessTest.java는 scr의 packTest.packOne 패키지를 만들어서 넣기
- 자식 클래스는 default package안에 들어가게됨
- 부모클래스에는 4개의 변수가 있는데 접근제어자가 다 다르다
- 원래는 public 일떄만 다른 패키지 접근 가능하지만
- 상속관계에 있고 protected 면 접근 가능하다
- 즉 부모와 자식이 서로 다른 패키지 안에 들어가있을때 4가지 접근제어자 중 어떤 접근제어자가 접근가능하게하는지 알아보는 예제임

정리
- 부모클래스 (AccessTest) -> 여기 필드값에 다양한 접근제어자가 있다
- 자식 클래스(SubOne)는 다른 패키지 안에 있을떄 protected, public이 가능함
- 제3의 클래스(SuperSubA)는 public 클래스만 접근 가능

 

// 부모 클래스
package packTest.packOne;

public class  AccessTest {  //다른 패키지에서 가져다 사용할 것임으로 pubic으로 
  private int    a=10;   //[1] private           
  int            b=20;  //[2] 기본 접근 지정자
  protected  int c=30;  //[3] protected        
  public     int d=40;  //[4] public       

  public void print( ){
    System.out.println("AccessTest의 print");
    System.out.println(a);
    System.out.println(b);
    System.out.println(c);
    System.out.println(d);
  }
}
// 자식 클래스
import  packTest.packOne.AccessTest;

//AccessTest의 서브 클래스로 SubOne을 설계
class SubOne extends AccessTest {
  void subPrn( ){
    System.out.println(a); //[1. Sub] private -X 에러
    System.out.println(b); //[2. Sub] 기본 접근 지정자-X 에러
    System.out.println(c); //[3. Sub] protected -O
    System.out.println(d); //[4. Sub] public -0
  }
}
// 제 3의 클래스
//AccessTest랑 상속관계가 없는 클래스 
class SuperSubA{
  public static void main(String[] args){
    AccessTest at=new AccessTest( );
    at.print( );
    System.out.println("main");
    System.out.println(at.a); //[1. main] private -X 에러
    System.out.println(at.b); //[2. main] 기본 접근 지정자-X 에러
    System.out.println(at.c); //[3. main] protected -X 에러
    System.out.println(at.d); //[4. main] public -O
  }
}

 

1. 상속 관계 있는 자식클래스 SubOne 에선 부모 클래스와 자식 클래스가 서로 다른 패키지에 있을때
- 이때 private 접근제어자로 되어있는 a는 자식이더라도 상속이 안됨(접근이 안됨)
- 이때 default 접근제어자로 되어있는 b는 자식이더라도 상속이 안됨(접근이 안됨)
- 이때 protected 접근제어자로 되어있는 c는 자식이라서 상속이 됨(접근 가능)
- 이때 public 접근제어자로 되어있는 d는 public이니까 상속이 됨(접근 가능)

2. 상속 관계 없는 제3의 클래스 SuperSubA 에선 제3의 클래스인데 서로 다른 패키지에 있을때
- 기존 내용처럼 public 접근제어자로 되어있는 필드만 접근 가능\

강사님 정리
src - packTest - packOne -  AccessTest.java(부모클래스)

SubOne.java(자식클래스) : protected, public만 접근가능
SuperSubA.java(제3의 클래스) : public만 접근가능    

- 필드의 접근제어자를 주로 protected를 많이 씀
- 두 패키지가 상속관계 && 서로다른 패키지 -> public, protected 접근 가능
- public > protected > default > private

레퍼런스 형변환
- 추상클래스, 인터페이스까지 공부 후 공부

자바 3가지 자료형변환
1. 기본자료형 변환
2. Wrapper클래스로 주로 String <-> int 형 변환
3. 레퍼런스 형변환(반드시 두 클래스 사이 상속관계 있어야만 가능함)

추상클래스 개념 1 (개념과 특징)
- 이름만 있고 내용이 없는 클래스
- 자체적으로 객체를 생성할 수 없는 클래스
- 여태껏 한개의 클래스로 무한개 객체만들어냈지만 추상클래스는 객체 생성 불가

추상클래스 개념 2 (형식과 구성)
- 추상클래스는 일반 클래스와 구분하기 위해서 클래스 앞에 abstract를 붙임
- 추상메소드 앞에도 반드시 abstract 붙이고 맨뒤 세미콜론 ex) abstract void Method01();
- 추상클래스에 들어가는 멤버 : 일반 멤버변수, 추상 메소드, 일반 메소드 등 있다. 
- 일반 클래스와 가장 큰 차이는 추상메소드를 가질 수 있다는 점
- 추상메소드를 가질 수 있다는게 가장 큰 특징
+ 추상메소드는 이름만있고 내용이 없는 메소드

추상클래스 개념 3 (생성과 사용)
- 추상클래스 상속 받을때는 클래스기떄문에 자식들은 일반 클래스 상속처럼 extends로 상속
- 그리고 부모 추상 클래스 나머지 안에 있는 추상메소드들을 반드시 메소드 오버라이딩 해야함
- 자체적으로 new연산자로 객체 생성 불가능한게 추상클래스 특징
- 부모 추상 메소드 : 공통적인 내용들을 넣어야함
ex) 새 클래스, 곤충 클래스, 물고기 클래스 -> 공통특징 추출해서 부모클래스 만듬 -> 부모클래스는 동물클래스
+ 나중에는 부모클래스 만들때 일반클래스보다 추상클래스를 부모클래스로 많이 만듬

추상클래스 개념 4 (상속)
- 자체적으로 객체 생성 안되므로 추상 클래스를 일반 클래스가 상속받아서 쓰는거다.
- 추상클래스를 상속받은 일반 클래스는 추상클래스 안에 들어있는 추상 클래스를 반드시 Method Overriding을해야한다
- 부모클래스의 이름, 형식 그대로 따라서 내용을 다르게 써내려가면 된다
- 메소드 오버라이딩 안하면 오류발생
- 추상클래스도 단일상속만 가능하다,2개이상의 추상클래스 상속 불가
- 자바는 일반클래스든 추상클래스든 다중상속 허용안하기 때문임

인터페이스
+ 추상클래스의 기능 있음 (추상메소드 가질수있음)
+ 인터페이스는 다중상속까지 허용함

+ 나중엔 추상클래스는 거의 안쓰고 인터페이스를 쓴다
+ 인터페이스 쓰기위해서 추상클래스 이해하는것임
+ 보통 추상클래스를 부모로 만드는게 아니라 인터페이스를 부모로 만듬

복습

String : 가장 많이 사용, 메소드에 많은 기능
StringBuffer : 메서드에서 값의 변화 일어나더라도 시작 주소값 변하지 않음
StringTokenizer : 문자열을 구분기호로 파싱할때 사용

 

과제 풀이
https://laker99.tistory.com/22?category=1065834

 

- 문자로 받아서 연산하기위해 정수형으로 바꿔야함
- Wrapper 클래스를 사용해서 String -> Int 형변환해야 함
- 정적 메소드로 만들어야 객체 생성안하고 편하게 호출 가능, 특히 같은 클래스내에선 클래스명. 제외하고 그냥 메소드명만 쓰면됨
- 정적 메소드를 쓰지 않을거라면 같은 클래스 내에서 객체 만들어서 메소드를 호출해야한다.
ex) JuminCheck01 jc = new JuminCheck01();

 

Scanner 클래스의 메소드 next()와 nextLine()
- 공통점 : 둘다 문자열을 입력받는다
- 차이점
- next()는 개행문자를 무시하고 입력을 받는다.
- nextLine() 은 한줄 단위로 입력을 받기 때문에 개행문자도 포함한다.

 

Scanner 클래스의 메소드 next()와 nextLine() 예시1
ex) 5를 입력하고 Enter를 쳤다면 버퍼에 5\n이 존재한다.
- nextInt()가 버퍼의 내용을 가져오면 분리자를 제외하고 가져오기 때문에 5만 가져온다. 
- 그럼 버퍼에 \n이 그대로 남아있다 그 다음 이 버퍼에서 nextLine()가 버퍼의 내용을 가져온다면
- 공백문자, 개행문자인 분리자를 포함시키기 때문에 \n만 가져오고 프로그램이 종료된다.

Scanner 클래스의 메소드 next()와 nextLine() 예시2
ex) 1234를 입력하고 Enter를 쳤다면 버퍼에 1234\n이 존재한다.
- nextInt()가 버퍼의 내용을 가져올 때 분리자를 제외하고 가져오기 때문에 1234만 가져온다.
- 그럼 버퍼에 \n이 그대로 남아있다 그 다음 이 버퍼에서 nextLine()가 버퍼의 내용을 가져온다면
- 공백문자, 개행문자인 분리자를 포함시키기 때문에 \n만 가져오고 프로그램이 종료된다.

 

Scanner 클래스의 메소드 next()와 nextLine() 정리
next() : 개행문자(Enter)를 무시하고 입력을 받음
nextLine() : 한줄 단위로 입력을 받기 때문에 개행문자(Enter)도 포함한다.

자료형 변환 3가지
1. 기본자료형 변환(자동형변환, 강제형변환) ex) double -> int
2. Wrapper클래스 이용한 자료형 변환(박싱과 언박싱) ex) String -> int , int n = Integer.parseInt("20")
3. 레퍼런스 형변환(상속 공부 이후 공부)
- 두 클래스 사이 상속관계 있을때 레퍼런스 자료형끼리 변환

Wrapper(포장) 클래스
- 기본자료형과 참조형 사이에 자료형 변환할 때 사용됨
- 여러 종류 있다, 가장 많이 쓰는건 Ingeter

Wrapper 클래스 종류
- 기본 자료형 값을 내부에 두고 포장하는 객체
- 기본 자료형 마다 Wrapper 클래스가 기본으로 제공된다

- Integer, Double 정도만 배우고 나머지는 규칙성이 비슷하므로 익힐 수 있음
- 90%이상은 Integer만 사용함

 

Wrapper 클래스 필요성
- 기본자료형과 참조형 사이의 자료형 변환을 해야할 경우
- 기본자료형 -> 참조형 , 참조형 -> 기본자료형

 

String과 int사이의 변환
1. 참조형 -> 기본자료형 으로 변환시킬때, 즉 String->int ex) "20" -> 20

방법1.

		int num = Integer.parseInt("20");

- Integer클래스의 parseInt() 정적메소드를 호출해서 int형으로 리턴함

 

방법2.

		Integer in01 = new Integer("20");		
		int num01 = in01.intValue();		//언박싱

- Integer 클래스의 생성자에 "20" 매개변수로 주고 그걸 그 객체 메소드인 intValue() 사용해서 int형으로 바꿈

 

- 문자를 숫자로 변환할땐 두 방법중 뭘 쓰더라도 Wrapper 클래스 반드시 써야함
- String -> int 변환시 반드시 Integer 클래스(Wrapper 클래스) 써야함

 

2. 기본자료형 -> 참조형 으로 변환시킬때,  즉, int->String ex) 20 ->"20"

 

방법1.

	String s = String.valueOf(20);

- String클래스에서 지원되는 정적메소드 valueOf() 써서 int형에서 String형으로 리턴
- Wrapper 클래스 안쓰는 방법임

 

방법2.

	Integer in = new Integer(20);
	String s = in.toString();

- Integer 객체 생성해서 toString() 메소드 사용
- Wrapper 클래스 쓰는 방법

 

방법3.

20 --> 20 + ""

- 이렇게 해도 String 형이 된다.
- Wrapper 클래스 안쓰는 방법임

 

- 숫자를 문자로 변환할땐 Wrapper 클래스 꼭 써야하는건 아님

 

Wrapper 클래스 (API 문서)
- Wrapper 클래스들은 java.lang 패키지안에 있다.

Integer 클래스 상속관계
java.lang.Object
java.lang.Number
java.lang.Integer

+ Object는 슈퍼클래스
+ 모든 패키지는 최상위클래스가 Object

Integer 클래스의 필드
- static이 붙은 정적 필드만 5개 있다
- MAX_VALUE : int의 저장가능한 최대 값, 약 +21억
- MIN_VALUE : int의 저장가능한 최소 값, 약 -21억

Integer 클래스의 생성자
- 기본생성자 없다
- 매개변수가 int형인 생성자 와 매개변수가 String형인 생성자만 있다
- Integer(int value)
- Integer(String s)

Integer 클래스의 메소드


pasreInt(String s)
- 이 String형 변수 s를 int형으로 바꿔줌
- int형 변수로 받아야한다. 
- 매개변수엔 숫자로 변환가능한 문자만 올 수 있다. ex) "ABCD" "가나다라" 는 안됨 (예외발생), "123" 가능

parseInt(String s, int radix)
- 메소드 오버로딩 되어있다.

toBinaryString()
- 10진수 -> 2진수 변환해주는 메소드
toHexString() 
- 10진수->16진수 변환해주는 메소드
toOctalString() 
- 10진수 -> 8진수 변환 메소드

Wrapper 클래스 예제1

package p2022_07_04;

public class WrapperEx {

	public static void main(String[] args) {

	// int형 변수의 최대값과 최소값
		System.out.println("max = " + Integer.MAX_VALUE);
		System.out.println("min = " + Integer.MIN_VALUE);
		
	// String형을 int형으로 형변환 ex) "20" -> 20 : parseInt() 정적메소드
		int n = Integer.parseInt("20"); //정적메소드 호출, 숫자로 변환가능한 문자 들어가야함
		System.out.println(n);
		System.out.println(n+10); // 산술연산 가능 -> 정수형이다.
		
	// 10진수 -> 2진수로 변환해주는 메소드 : toBinaryString() 정적메소드, 매개변수에 10진수 정수값 넣으면 2진수 변환해줌
		System.out.println("2진수 : " + Integer.toBinaryString(10));//1010
	// 10진수 -> 8진수로 변환
		System.out.println("8진수 : " + Integer.toOctalString(10));//12
	// 10진수 -> 16진수로 변환
		System.out.println("16진수 : " + Integer.toHexString(10));//a
		
	}

}

 

Wrapper 클래스 예제2

package p2022_07_04;

public class WrapperEx1 {

	public static void main(String[] args) {

	//Integer 클래스는 기본생성자가 지원되지 않는다.
//		Integer num = new Integer() //오류 발생
		
// 생성자 Integer(int value)로 객체 생성하는 경우 -> 자료형 변환 안일어남
		
	// 박싱(boxing) : heap메모리를 박스로 생각하고, stack메모리에 저장된 10을 힙메모리에 복사하는 것. (박스에 집어넣는다)
		int n = 10; //지역변수 -> stack 영역에 저장, 이 main메소드 안에서만 사용가능
		Integer num01 = new Integer(n); // 박싱(boxing) , new연산자로 객체 생성 -> 힙메모리 상에 복사를 함. 
	// 언박싱(unboxing) : heap메모리에 있는 데이터를 stack메모리로 가져오는 것을 의미한다.
		int n01 = num01.intValue(); //언박싱(unboxing)
		
// 생성자 Integer(String s)로 객체 생성하는 경우 -> 자료형 변환 일어남 "20" -> 20
		Integer num02 = new Integer("20"); //박싱(boxing)
		int n02 = num01.intValue(); //언박싱(unboxing)
	}

}



위 예제 부분1
- 생성자로 객체 생성시 메모리 상에서 어떤게 일어나는지 보자

	//Integer 클래스는 기본생성자가 지원되지 않는다.
//		Integer num = new Integer() //오류 발생
		
	// 생성자 Integer(int value)로 객체 생성
	// 박싱(boxing) : heap메모리를 박스로 생각하고, stack메모리에 저장된 10을 힙메모리에 복사하는 것. (박스에 집어넣는다)
		int n = 10; //지역변수 -> stack 영역에 저장, 이 main메소드 안에서만 사용가능
		Integer num01 = new Integer(n); // new연산자로 객체 생성 -> 힙메모리 상에 복사를 함.

- n의 값 10이 스택영역에 저장되어있었는데, 이 n을 가지고 객체 생성을 하면 이게 힙메모리상으로 이 n의값 10이 복사가 일어나는것 = 박싱
- 힙메모리 영역을 box로 생각하고 박스에 집어넣는게 "박싱"
- 힙메모리에서 끄집어내서 스택영역으로 가져오는게 "언박싱"

 

 

박싱(boxing)

- heap메모리를 박스로 생각하고, stack메모리에 저장된 10을 힙메모리에 복사하는 것. (박스에 집어넣는다)
- 박싱된걸 가리키는게 Integer 객체 num01이다

 

위 예제 부분2

		int n = 10; //지역변수 -> stack 영역에 저장, 이 main메소드 안에서만 사용가능
		Integer num01 = new Integer(n); // new연산자로 객체 생성 -> 힙메모리 상에 복사를 함. (박싱 boxing)
	// 언박싱(unboxing) : heap메모리에 있는 데이터를 stack메모리로 가져오는 것을 의미한다.
		int n01 = num01.intValue(); //언박싱(unboxing)

- 이게 언박싱이다
- 힙메모리의 데이터를 스택 메모리에 가져오는 것을 의미함
- 객체 num01의 값이 힙메모리에 있었는데 이걸 지역변수인 n01로 가져옴 = 힙 -> 스택

 

박싱 언박싱 정리1
- 힙메모리 = 박스
- 박싱 : 스택 -> 힙
- 언박싱 : 힙 -> 스택

 

Integer 생성자 2개 차이


1. Integer 생성자중 매개변수가 int형인 생성자를 사용시
- int받아서 intValue()로 int 돌려주므로 언박싱시 자료형 변환이 일어나지 않음

2. Integer 생성자중 매개변수가 String형인 생성자를 사용시 

// 생성자 Integer(String s)로 객체 생성 -> 자료형 변환 일어남 "20" -> 20
		Integer num02 = new Integer("20"); //박싱(boxing)
		int n02 = num01.intValue(); //언박싱(unboxing)

- 이렇게하면 바로 힙메모리상에 "20"이 저장, 하지만 원래 String 형 자료형이므로 원래부터 힙메모리(box)에 있다, 그래도 박싱
- 그걸 스택영역으로 가져오는게 언박싱, n02로 가져옴
- 스택영역으로 가져오는 과정에서 자료형변환이 일어남
- intValue()메소드로 자료형 변환이 일어남.
- 즉 언박싱하는 과정에서 자료형변환이 일어나고 이걸 우리는 활용하는 것

 

+ 하지만 "20" -> 20 할때 주로 Integer.pasreInt("20") 씀
+ 박싱은 힙으로 값을 복사하는 것이기 때문에 Wrapper 객체 생성할 때 일어난다
+ 언박싱은 스택으로 값을 가져오는 것이기 때문에 Wrapper 객체에서 지역변수로 값을 받을때 일어난다.

 

* 박싱과 언박싱

+ 자동 박싱, 자동 언박싱 (auto boxing / auto unboxing) 
- jdk 1.6 부터 지원하는 기능

 

+ 자동 박싱
- integer 객체 생성시 new 연산자 써서 boxing 했었는데, 자동 boxing은 new없이 바로 할당
- 오른쪽에 그냥 숫자를 쓰는것

+ 자동 언박싱

		int n01 = num01.intValue(); //언박싱(unboxing)

- 에서 intValue()없어도 언박싱 일어나는거

 

박싱 언박싱 정리2

- 박싱 : 기본타입의 값을 Wrapper 객체로 만는 과정
- 언박싱 : Wrapper 객체에서 기본 타입의 값을 얻어내는 과정

 

박싱 일어나는 경우
- 해당 Wrapper 클래스로 new써서 객체 생성할떄 박싱이 일어남
= 기본자료형의 값이 객체가 되어서 힙메모리상으로 복사됨

 

언박싱 일어나는 경우
- 박스(힙) 에 있는 데이터를 스택으로 가져올 때,
- 객체명.intValue() 나 객체명.doubleValue() 메소드로 가져옴

 

박싱 언박싱 예제1
- WrapperEx2.java

package p2022_07_04;

public class WrapperEx2 {

	public static void main(String[] args) {
//p529
		
	// 박싱
		Integer obj01 = new Integer(10);
		Integer obj02 = new Integer("200");
		Integer obj03 = Integer.valueOf("300");
		
	// 언박싱
		int value1 = obj01.intValue();
		int value2 = obj02.intValue(); //자료형 변환 : "200" -> 200
		int value3 = obj03.intValue(); //자료형 변환 : "300" -> 300
		
		System.out.println(value1);
		System.out.println(value2);
		System.out.println(value3);
		
	}

}

 

박싱
- 스택메모리의 10을 객체생성하면서 힙메모리로 = 박싱, 그 값을 obj01이 가리키고 있다
- "200"을 객체생성하면 힙메모리에 "200" 저장됨 = 박싱, 그 값을 obj02이 가리키고 있다
- Integer 객체 생성안하고 정적메소드인 valueOf를 써서 300을 힙메모리 상에 저장 = 박싱, 그 값을 obj03이 가리키고 있다
+ 생성자 어떤걸 쓰느냐에 따라 자료형 변환 일어날수도 안일어날수도

 

언박싱
- obj01 객체에 intValue()메소드를 활용해서 힙메모리의 값 10 을 언박싱해서 스택의 value1에 저장
- 이때는 int형 받았다가 int형 돌려주는거므로 자료형변환 안일어남
- obj02 객체에 intValue()메소드를 활용해서 힙메모리의 값 "200" 을 언박싱해서 스택의 value2에 저장
- 그 과정에서 자동형변환이 일어남, obj03도 마찬가지 
+ 모두 기본자료형인 int로 바뀌었다. (double로 바꾸고싶으면 doubleValue() )

 

박싱 언박싱 정리3
- 박싱은 new연산자(힙메모리상에 새로운 공간 생성하라는 뜻) 써서 Intege 객체 생성할때 박싱이 일어남, 힙메모리에 데이터 집어넣는게 박싱
- 자동 박싱은 new 연산자 안쓰고 이 오른쪽에 바로 10, "200","300" 등을 쓰는것
ex) Integer obj02 = "200";
- 언박싱 원래는 .intValue() 써서 하는데 자동언박싱은 .intValue()안쓰고 언박싱하는거

자동박싱과 자동언박싱
- 자동박싱 : 왼쪽은 Wrapper 클래스로 되어있는데 오른쪽은 기본자료형 이 쓰인 형태
ex) Integer obj = 100;
- 자동언박싱 : 
Integer obj = new Integer(200);
int value1 = obj; //자동 언박싱 (.intValue가 없다)
int value2 - obj + 100; //자동 언박싱

Q. 스택 -> 힙으로 가는것만 박싱이 아니라 String처럼 원래부터 힙에 만들어지는 것도 박싱인가요?
A. 이 교재에선 원래부터 힙 만들어지는것도 박싱이라고 한다

 

자동박싱과 자동언박싱 예제1
- WrapperEx3.java

		// 자동 박싱
		Integer oj = new Integer(10); //박싱
		Integer obj = 10; //자동 박싱
//		Integer obj1 = "10"; //오류생김





		// 자동 언박싱
		System.out.println("언박싱 : "  + obj.intValue()); //언박싱
		System.out.println("자동 언박싱 : "  + obj); //자동 언박싱


		// 자동 언박싱 (변수형태로 저장)
		int value1 = obj.intValue(); //언박싱
		
		int value2 = obj; //자동 언박싱
		System.out.println("value2 : " + value2); // value2 : 10

- Integer 객체 만들때 오른쪽에 new 연산자 안하고 그냥 바로 데이터가 온다 (데이터가 힙으로 들어감)
-> 이러면 내부적으로 자동으로 박싱이 일어남 , 그걸 obj가 가리키고 있다 = 자동박싱
- 자동언박싱은 객체.intValue() 같은 메소드 없는거, 그냥 객체명만 써서 왼쪽을 기본자료형으로 받으면됨
ex) int value2 = obj; //자동 언박싱

 

자동박싱과 자동언박싱 예제2

		Integer obj = 10; //자동 박싱
		
		// 자동 언박싱
		int result = obj + 100;
		System.out.println("result : " + result); // result : 110

- obj자체가 내부적으로 자동 언박싱 된거임, 즉 이미 기본자료형임 그래서 연산이 가능하다

+ 연산과 string의 붙이기 + 혼돈 막기위해 괄호()를 잘 쓰기

		System.out.println("언박싱 : "  + obj.intValue()); //언박싱
		System.out.println("언박싱 : "  + (obj.intValue() + 10)); //연산시 괄호를 잘 해야 계산이 됨(string과 착각)

 

Integer 클래스 외의 다른 Wrapper 클래스
- 90% Integer 만 사용, 나머지 10% 중 Double 클래스 사용빈도가 가장 높다 

Double 클래스(API 문서)
java.lang.Object
java.lang.Number
java.lang.Double

Double 클래스 필드(멤버변수)
- MAX_VALUE
- MIN_VALUE 등

Double 클래스 생성자
- 기본 생성자 지원안함
- Double(double value)
- Double(String s)

Double 클래스 메소드
- Double.pasreDouble(String s)로 형변환 가능
- 정적메소드이고 매개변수는 String, 리턴형은 double 이다
- 이 문자 s를 실수형태로 형변환시켜서 반환함

Double 클래스 문자->숫자(double) 형변환 예시1
- WrapperEx4.java

package p2022_07_04;

public class WrapperEx4 {

	public static void main(String[] args) {

	// Double 클래스는 기본 생성자를 지원하지 않는다.
//		Double d = new Double() // 오류 발생
		
		Double d1 = new Double(3.14); //매개변수 double인 생성자, 3.14는 힙으로 복사됨 = 박싱(boxing)
		Double d11 = 3.14; //자동 박싱
				
		double n1 = d1.doubleValue(); //언박싱(unboxing)
		double n11 = d11; //자동 언박싱
		
	}

}

- 이렇게 생략해서 자동박싱, 자동언박싱 많이 씀
- 언박싱 할때 자료형Value() 라는 이름으로 언박싱할때 쓰는 메소드가 정해져있다
ex) intValue(), doubleValue() 

 

Double 클래스 문자->숫자(double) 형변환 예시2

		Double d2 = new Double("42.195");

- 매개변수 String인 생성자, 이때 자료형 변환 일어남.
- "42.195"는 42.195와 달리 스택 -> 힙이 아니라 원래부터 힙에 저장되어있음 = 그래도 박싱(boxing) 이라고 함

 

Double 클래스 문자->숫자(double) 형변환 예시3
- 매개변수가 문자형일때는 자동박싱이 지원 안된다

		Integer n1 = 11 //자동 박싱 가능
		Integer n11 = "11"; // 오류 발생
		Double d2 = 42.195 //자동박싱 가능
		Double d22 = "42.195"; // 오류 발생
        

	//매개변수 String인 생성자
		Double d2 = new Double("42.195"); //이때 자료형 변환 일어남, 
		// "42.195"는 스택-> 힙이 아니라 원래부터 힙에 저장되어있음(String형이니까) = 박싱(boxing)
//		Double d22 = "42.195"; // 오류 발생
		
		double n2 = d2.doubleValue(); //언박싱(unboxing) , 이 과정에서 자료형이 일어남 String -> double
		double n22 = d2; //자동 언박싱, 이건 가능함

- 문자형 가지고 자동 박싱을 못한다!

 

Double 클래스 문자->숫자(double) 형변환 예시4

	//자료형 변환 : "42.195" -> 42.195
		double num = Double.parseDouble("42.185");
		System.out.println("num = " + (num + 10));

- int num = Integer.parseInt("20") 처럼 double num = Double.pasreDouble("42.185"); 를 하고 있다.
- Integer 클래스처럼 박싱-> 언박싱 하면서 자료형변환도 가능하고
- 메소드 pasreInt() pasreDouble() 해서 자료형변환도 한줄에 가능하다
- 문자-> 숫자 할땐 2가지 방법 있는데 둘다 반드시 Wrapper 클래스 써야함!
- 숫자 -> 문자 는 3가지 방법이 있다 ex) valueOf()메소드로 자료형 변환은 Wrapper 클래스 쓰지 않음

 

숫자 -> 문자 형변환 방법 3가지

방법1 .
     String s = String.valueOf(20);
방법2 . 
     Integer in = new Integer(20);
     String s = in.toString();
방법3
     숫자 + ""

 

valueOf() 메소드

- String클래스의 valueOf() 메소드로 기본자료형을 문자열로 변환 ex) 20 -> "20"
- valueOf() 메소드로 자료형 변환 가능하다
- 오버로딩되어있는 메소드, 정적메소드

 

숫자 -> 문자 형변환 예제1 (valueOf() 메소드 예제)
- ValueOfEx.java

package p2022_07_04;

public class ValueOfEx {

	public static void main(String[] args) {

// p511
// valueOf() : 기본자료형을 문자열로 변환
// ex) 20 -> "20"
		
		String str1 = String.valueOf(10); // 10 -> "10"
		String str2 = String.valueOf(10.5); // 10.5 -> "10.5"
		String str3 = String.valueOf(true); // true -> "true"
		
		System.out.println(str1);
		System.out.println(str2);
		System.out.println(str3);
	}

}

- valueOf() 메소드(String의) 는 오버로딩되어있다.
- 매개변수의 자료형이 다 다르게 되어있다
- 그래서 위에서 저렇게 매개변수 안에 여러 자료형의 값을 넣어도 된다 그걸 다 String 문자형으로 바꿔줌
- valueOf() 메소드는 기본자료형을 String으로 바꿔준다 (int,float,long .. -> String)
- valueOf()는 정적메소드다
- true 라는 boolean 값을 넣으면 문자 "true"로 변환됨
- 이건 Wrapper클래스 안쓰는 방법이다. (String은 Wrapper클래스 아님 주의)

 

Wrapper 형변환 예제
- WrapperTestA.java (이미설명헀던 내용)

package p2022_07_04;

class WrapperTestA {
  public static void main(String[] args) {
    int n01=10;
	int n02;
	Integer num01 ;  //Integer 객체 생성
    Integer num02= new Integer(20) ; //박싱
    
    num01 = n01;    //오토 박싱, 왼쪽은 Integer객체, 오른쪽은 기본자료형 -> 오토박싱
//	num01 = new Integer(n01); //오토 말고 그냥 박싱

    n02   = num02; //오토 언박싱
//	n02   = num02.intValue(); //그냥 언박싱

	System.out.println(n01 + ", " + num01); //num01도 n01을 받았기 떄문에 10이 출력
	System.out.println(n02 + ", " + num02); //n02는 num01를 받았기 때문에 20이 출력

  }    
}

 

숫자 -> 문자 형변환 예제2
- ChangeString.java

package p2022_07_04;

public class ChangeString {
    public static void main( String[] args ) {
    
	// 기본 데이터 형 선언
	int a = 10;
	System.out.println( a + 10 ); //20

	// String 형으로 변환 : 10 -> "10"
	String sa1 = String.valueOf( a );
	System.out.println( sa1 + 10 ); //문자 + 숫자 이므로 1010

	// Wrapper Class 객체 생성 
	Integer oint = new Integer( 10 ); //박싱 : 스택->힙 으로 값 복사
	
	// String 형으로 변환 : 10 -> "10"
	String sa2 = oint.toString(); // int-> String 변환
	System.out.println( sa2 + 10 ); // 1010

//  String형을 int형으로 변환 : "10" -> 10
 	int k =  Integer.parseInt(sa2);
    }
}

- valueOf() 말고도 Integer 객체에 .toString() 메소드를 써서 String으로 형변환 가능 (int-> String)
- 이게 숫자-> 문자 의 두번째 방법임

 

업캐스팅과 다운캐스팅
- 지금은 그냥 개념을 간단히 보고 나중에 자세히 설명함
- GenericTest01.java

package p2022_07_04;

class TestClass {
  private int member;
  public void setValue(int value){
    member = value;
  }
   public int getValue( ){  
    return member;    
  }                
}
class GenericTest01{  
  public static void main(String[] args) { 
     TestClass obj01=new TestClass();
     obj01.setValue(3);
     System.out.println("되돌리는 값은->" + obj01.getValue( ));
     obj01.setValue(3.4);
     System.out.println("되돌리는 값은->" + obj01.getValue( ));
     obj01.setValue("이해할 수 있다.");
     System.out.println("되돌리는 값은->" + obj01.getValue( ));
  }
}

- GeneticTest01 클래스와 TestClass 클래스 이렇게 두개의 클래스있다
- TestClass보면 필드 1개(private) , set(초기화), get 1개씩 있다
- GenericTest01 클래스에서 TestClass의 객체를 만들어서 힙 메모리에 새로운 공간을 생성했다
- 기본자료형이 된 멤버변수 member 는 자동으로 0으로 초기화된다
- 이때, setValue() 메소드 통해서 필드값 3으로 수정한다 -> getValue() 로 출력시 3출력 (문제 없다)

 

- 만약, setValue()에 3.4를 전달하면? 매개변수는 int형인데 이건 double형이므로 오류 생김
-> 메소드 오버라이딩하여 setValue() 매개변수 double 형인걸 만들어야한다

- 또 setValue에 "이해할 수 있다." 라는 문자열을 전달해도 안된다.
-> 메소드 오버라이딩하여 매개변수가 String인 메소드 있어야함

이 문제들을 해결하기 위한 방법
1. setValue를 메소드 오버로딩 시켜야함
2. 메소드 오버로딩 없이 이걸 처리할 수 있는 방법이 있다! -> 업캐스팅, 다운캐스팅 개념

이 문제들을 해결하기 위한 방법 예제1 (업캐스팅, 다운캐스팅)
- GenericTest02.java

package p2022_07_04;

class TestClass2 {
	private Object member;

	public void setValue(Object value) {
		member = value;
	}

	public Object getValue() {
		return member;
	}
}

class GenericTest02 {
	public static void main(String[] args) {
		TestClass2 obj01 = new TestClass2();

		// Object value = new Integer(3); // 업캐스팅 + 박싱
		// Object value = 3; 과 같은것 // 업캐스팅 + 자동박싱
		obj01.setValue(3);
		System.out.println("되돌리는 값은->" + obj01.getValue());

		int n1 = ((Integer) (obj01.getValue())).intValue(); // 다운캐스팅 + 언박싱
		int n2 = ((Integer) (obj01.getValue())); // 다운캐스팅 + 자동언박싱

//   ------------------------------------------------------------
		// Object value = new Double(3.4); 와 마찬가지 // 업캐스팅 + 박싱
		// Object value = 3.4; 와 마찬가지. //업캐스팅 + 자동박싱
		obj01.setValue(3.4);
		System.out.println("되돌리는 값은->" + obj01.getValue());

		double d1 = ((Double) obj01.getValue()).doubleValue(); // 다운캐스팅 + 언박싱
		double d2 = ((Double) obj01.getValue()); // 다운캐스팅 + 자동언박싱
// ------------------------------------------------------------

		// Object value = new String("이해할 수 있다.");//업캐스팅 + 박싱
		// Object value = "이해할 수 있다"; //업캐스팅 + 자동박싱
		obj01.setValue("이해할 수 있다.");
		System.out.println("되돌리는 값은->" + obj01.getValue());

		String str = (String) obj01.getValue(); //다운캐스팅
		// String형은 원래부터 힙메모리에 있던거므로 언박싱은 안됨, 다운캐스팅만 됨

	}
}

- setValue메소드의 매개변수가 Object 자료형으로, getValue메소드의 리턴자료형이 Object 형으로 바뀐것뿐임
- int를 전달하든 double 을 전달하든 다 됨.
-> Object 클래스는 모든 클래스의 최상위 클래스이기 때문에 가능
- Object의 자식들 String, Integer, Double등등
- 이 Object는 자식들을 모두 받을 수 있다

 

자동 박싱
- int, double등의 기본자료형을 넣을때도 메소드가 잘 작동함, int, double은 클래스가 아니다, Object의 자식도 아님
- 2가지 일이 일어나서 가능함, 3은 int이고 자동박싱이 일어난다

 

위 예제 부분1

  private Object member;
  public void setValue(Object value){
    member = value;
  }
//main
   TestClass2 obj01=new TestClass2();
   obj01.setValue(3); //*
   System.out.println("되돌리는 값은->"+obj01.getValue( ));

- obj01.setValue(3); 코드 는 Object value = 3; 이나 마찬가지임.
- 즉 자동 박싱(스택 -> 힙) 이 되어서 가능함
- new Integer 를 안썼으므로 자동 박싱

 

업캐스팅
- 오른쪽에 부모, 왼쪽에 자식 있으면 업캐스팅
- 자식객체 생성해서 왼쪽 부모쪽에 넘겨주는것
ex) 왼쪽이 Object 오른쪽엔 Integer

 

레퍼런스 변수끼리 즉 참조형끼리 변환 (세번째 자료형 변환)
- 반드시 그 사이에 상속관계 있어야함
- 이때 자식 객체 생성해서 부모쪽에 전달하는게 업캐스팅
- 특히 부모쪽이 Object이면 모든 자료형이 업캐스팅 가능 (Object는 모든 클래스의 부모,조상이므로)

 

업캐스팅 예제

		// Object value = new Integer(3); // 업캐스팅 + 박싱
		// Object value = 3; 과 같은것 // 업캐스팅 + 자동박싱
		obj01.setValue(3);
		System.out.println("되돌리는 값은->" + obj01.getValue());

 

다운캐스팅 예제(위 예제 부분2)

   TestClass2 obj01=new TestClass2();
   obj01.setValue(3);

   System.out.println("되돌리는 값은->"+obj01.getValue( ));

   // 다운캐스팅 + 언박싱
   int n = ((Integer)(obj01.getValue())).intValue();

- getValue()하면 Object형을 반환함, 즉 지금 Object형을 출력하고 있는거임
- 맨 마지막 줄에서 obj01.getValue()는 Object인데 (Integer)를 앞에 붙여서 형변환시킴 = 다운캐스팅
- 이때 반드시 (Integer) 를 붙여야만 형변환 가능함
- 즉 다운캐스팅할때는 업캐스팅할떄와는 다르게 반드시 형변환 시킬 자료형을 명시해야함
- Object에서 뭐로 형변환시킬지 안써져있으면 모름

- 그리고 Integer로 형 변환 된 상태에서 .intValue()를 썼으므로 언박싱이다. 
- 만약 intValue()를 뺐다면 자동 언박싱이다.

   int n1 = ((Integer)(obj01.getValue())).intValue();    // 다운캐스팅 + 언박싱
   int n2 = ((Integer)(obj01.getValue())); // 다운캐스팅 + 자동언박싱

 

위 예제 부분3 (double형과 박싱)

   TestClass2 obj01=new TestClass2();

   // Object value = new Double(3.4); // 업캐스팅 + 박싱
   // Object value = 3.4; 와 마찬가지.  //업캐스팅 + 자동박싱
   obj01.setValue(3.4); //업캐스팅 + 자동박싱
   System.out.println("되돌리는 값은->"+obj01.getValue( ));

 

위 예제 부분4 (String형과 박싱)

  TestClass2 obj01=new TestClass2();

   // Object value = new String("이해할 수 있다.");//업캐스팅 + 박싱
   // Object value = "이해할 수 있다"; //업캐스팅 + 자동박싱
   obj01.setValue("이해할 수 있다.");
   System.out.println("되돌리는 값은->"+obj01.getValue( ));
   
   String str = (String)obj01.getValue(); //다운캐스팅
   //String형은 원래부터 힙메모리에 있던거므로 언박싱은 안됨, 다운캐스팅만 됨

- Object형을 String으로 바꾸었지만 그대로 힙에 있다, 이 경우는 언박싱은 아님

 

equals() 메소드와 업캐스팅 (업캐스팅의 활용)
- String을 Object와 업캐스팅, 다운캐스팅 많이 시킨다
- String클래스의 equals()메소드, 리턴형 boolean, equals(Object anObject)
- 매개변수가 Object이므로 값을 비교 할 떄, 문자열 뿐만 아니라, Object의 자식들은 모두 이 자리에 전달 가능하다 
ex) Integer, Double, String
- 이 저 Object 자리 안에 String, Double등을 쓸때 즉, 메소드 쓸때 업캐스팅을 쓰게 되는 것임, 
- 자동박싱이 되기때문에 .equals(3)을 써도 됨. = .equals(new Integer(3)) 와 같다

 

equals() 메소드와 업캐스팅 예시1

if ("java".equals("자바")) {
	System.out.println("같은 값");
}else {
	System.out.println("다른 값");
}

- equals() 메소드에 String형을 넣었다

 

equals() 메소드와 업캐스팅 예시2

if (new Integer(30).equals(30)) { //오토박싱됨
	System.out.println("같은 값");
} else{
	System.out.println("다른 값");
}

 

if (new Double(3.14).equals(3.14)) { //오토박싱됨
	System.out.println("같은 값");
} else{
	System.out.println("다른 값");
}

- equals() 메소드에 Integer(int), Double(double)형을 넣었다
- Object의 자식들은 다 매개변수 자리에 올수 있게됨
- 만약 기본자료형이 바로 오면 자동박싱됨 ex) 30, 3.14

 

equals() 메소드와 업캐스팅 예시3
- 자동박싱이 아니라 박싱을 쓴다면?

if (new Integer(30).equals(new Integer(30))) { //그냥 박싱됨
	System.out.println("같은 값");
} else{
	System.out.println("다른 값");
}

- 매개변수가 Object인 메소드 -> 자식 자료형 다 올수 있다

 

상속
- 객체지향 언어의 중요 특징
- 지금까진 클래스 1개만 다뤘지만 상속해주는 부모클래스, 상속받는 자식클래스 해서 기본적으로 2개의 클래스 사용
- 상속받을때 extends 사용
- 상속과 관련된 여러 개념들을 학습할것

객체지향 프로그램에서의 상속
- 자식(하위,파생,서브) 클래스가 부모(상위,슈퍼) 클래스의 멤버를 물려받는것
- 자식이 부모를 선택해 물려받음
- 한개의 클래스의 구성인 필드,생성자,메소드 중에서 상속되는건 2가지 멤버인 필드, 메소드와 뿐이다
- 생성자는 상속이 되지 않음. (나중에 호출이라는 방법 통해서 사용을 하게됨)
- API 제공 클래스와 사용자 정의 클래스에서의 상속을 나눠서 생각해야함

1. API에서 제공되는 클래스와 상속관계
- 모두 상속관계 이미 형성되어있다
- 상속관련 내용 많이 쓰는 프로그램 : 그래픽 프로그램 ex) 관련 패키지 : java.awt, javax.swing, java.fx 등
- 상속 활용 : API의 클래스를 쓰다보면 어떤 필드나 메소드들이 그 클래스 안에 없어도 그 부모, 조상의 필드와 메소드를 상속받기 떄문에 그 클래스에서 쓸수 있다.

2. 사용자 정의 클래스와 상속관계
- 클래스를 조금 만들땐 상속 잘 쓰지 않지만 JSP를 공부하며 클래스를 많이 만들때 내가 원하는 형태로 클래스 설계시 상속을 설계한다
- 공통적인 내용을 부모클래스에서 만들고 공통적인걸 상속으로 하고, 나중에 세부내용은 자식클래스들에서 쓰는 식으로 함

상속의 장점
- 중복적인 코드를 줄일 수 있다
- 유지보수 편리하다
- 객체 다형성 구현 가능
- 통일성 있는 클래스를 설계가능

클래스를 상속받는법
- 자식클래스명 옆에 extends 쓰고 옆에 부모클래스 쓰기
ex) public class B extends A{}
-> B클래스는 A클래스의 필드와 메소드를 쓸 수 있다 
-> A클래스는 부모클래스, B클래스는 상속받은 자식 클래스

단일상속, 다중상속
- 자바에선 클래스의 단일상속만 허용함
- C++, 파이썬은 다중상속가능 자바는 다중상속 허용하지 않음
ex) public class A extends P, K (X)



다중상속시 발생하는 문제
- public class C extends P1, P2 일때, P1 클래스 필드에 int n= 10, P2 클래스 필드에 int n = 20 이면 무슨 필드를  C가 상속받을지 문제가 생김

+ 자바는 인터페이스는 2개이상의 인터페이스 상속가능- > 2개 상속받아도 문제 발생 가능성 아주 낮다
+ 인터페이스는 2개 이상을 자식이 상속받을 순 있다.

상속의 범위
- B가 A를 상속하고, A도 부모클래스 있다면, B는 그것도(조부모의 필드, 메소드) 상속받는다
- 상속 1단계만 받는게 아니라 2,3,4.. 단계인 조부모, 조상들의 필드와 메소드도 최종적인 자식 클래스는 모두 상속받게됨

부모클래스, 자식클래스의 명칭

상속 예제1
- 그래픽 프로그램 FrameTest.java

package p2022_07_04;

import java.awt.*;
import java.awt.event.*;

public class FrameTest {
	
    private Frame f; //필드

    public FrameTest() {	//생성자
		f = new Frame( "Frame Test" );	
		f.setSize( 400, 300 );
		f.setLocation( 100, 100 );
		f.setBackground( Color.green );
		f.setVisible( true );
		f.setResizable(false);    

	f.addWindowListener( new WindowAdapter() {
		    public void windowClosing( WindowEvent e ) {
				System.exit( 0 );
		    }
    });

	}//생성자 end

    public static void main( String[] args ) {
		FrameTest ft = new FrameTest();
    }
}

- java.awt 안의 클래스 활용한 프로그램
+ 패키지에 대고 여기대고 Ctrl + shift + O 누르면 자세히 볼 수 있다

그래픽 프로그램의 생성자
- 콘솔프로그램에서 생성자가 하는일 : 객체 생성하며 필드값 초기화
- 그래픽프로그램에서 생성자가 하는일 : main메소드에서 생성자를 호출하면 위에 정의된 생성자를 호출해서 안에 들어간 내용을 실행함, 생성자 안에서 실제 그래픽 프로그램의 내용을 만들어줌

프레임 설정
- Frame : 실행시키면 나오는 창 = 1개의 frame
- java.awt.Frame 클래스가 이런 frame을 만들어준다.

 

프레임 명, 이름 정하기(위 예제 부분1)

		f = new Frame( "Frame Test" );

 

창 크기(frame크기) 설정(위 예제 부분2)

		f.setSize( 400, 300 );

- 가로 400, 세로 300으로 창 크기(frame크기) 설정
- 이 메소드는 Frame 클래스 안에 없다, 부모로부터 상속받은것

 

창 위치(frame위치) 설정(위 예제 부분3)

		f.setLocation( 100, 100 ); //왼, 위 기준 순서

- 실행시 왼쪽에서 100px, 위에서 100px떨어진 위치가 창의 초기위치값이 됨
- 좌측상단 기준 프레임이 위치할 위치를 정해줌
- 이 메소드도 Frame 클래스 안엔 없고 그 부모로부터 받은거임
- 없지만 쓸 수 있다 부모로부터 상속받은 메소드라서 

 

창 화면출력(frame화면출력) 설정(위 예제 부분4)

		f.setVisible( true );

- 화면이 출력되도록 만들어줌
- 기본값이 false라서 안보이는데 true로 해야만 화면이 나타남

 

창 크기 변경 가능, 불가능(frame 창 크기 변경) 설정(위 예제 부분4)

		f.setResizable(false);

- 크기 변경 불가능하도록 설정,
- 기본값이 true
- true하거나 이걸 주석막으면  Resizable, 즉 크기 변경 가능

 

+ 값 설정하는 메소드는 거의 set으로, 값 가져오는 메소드는 거의 get으로 시작

 

Frame 클래스 (API 문서)
Class Frame

java.lang.Object
java.awt.Component
java.awt.Container
java.awt.Window
java.awt.Frame

Frame 클래스 상속관계
- 부모가 Window클래스, 그 Window의 부모가 Container
- Object는 패키지 상관없이 최상위 슈퍼 클래스

- Frame클래스로 Frame객체 생성하면 이 Frame 클래스의 필드, 생성자, 메소드를 쓸 수 있음
- 또한 이 Frame 클래스 안에 없는 필드, 메소드도 쓸 수 있다 (부모,조부모,조상으로부터 상속받아서)
- 그래서 각 클래스들은 자기 클래스에 꼭 필요한 내용만 들어있어야한다
- 없는 내용은 상속을 받아 쓰도록 한다.
- 자기 조상중 어딘가는 있어야만 그걸 여기서 쓸 수 있다

Frame 클래스의 생성자
- Frame(String title) , 우리가 썼던 생성자
- 이걸 호출하면서 객체 생성한다

setSize() 메소드의 상속
- setSize(int width, int height) 메소드는 Frame클래스 안에 없다.
-  java.awt.Window 클래스, 즉 Frame의 부모클래스에 있고, 상속받아서 Frame 이 사용함
- Frame 클래스 API 문서창에서 Ctrl + F로 setSize()를 검색

+ Component, Object등 부모 위의 조상클래스의 것들도 다 쓸 수 있다

setLocation() 메소드의 상속
- Frame클래스 안에 없고 부모인 Window 클래스 안에 있다
- setLocation(int x, int y) : 왼쪽에서 x , 위로부터 y떨어진 곳을 초기위치로 지정

setBackground() 메소드의 상속
- 이 메소드도 Frame 클래스엔 없고 Window 클래스 안에 있다
- setBackground(Color bgColor) : 배경색을 설정하는 메소드

 

상속 예제2
- 그래픽 프로그램 FrameTestEx.java

package p2022_07_04;

import java.awt.*;
import java.awt.event.*;

public class FrameTestEx extends Frame {

    public FrameTestEx() {
	
//	f = new Frame( "Frame Test" );
	super("Frame Test");

	addWindowListener( new WindowAdapter() {
		    public void windowClosing( WindowEvent e ) {
				System.exit( 0 );
		    }
        });
	
	setSize( 400, 300 );
	setLocation( 100, 100 );
	setBackground( Color.green );
	setVisible( true );
    }//생성자 end

    public static void main( String[] args ) {
		FrameTestEx ft = new FrameTestEx();
    }
}

- 여기서도 main에선 객체 생성만 하고 생성자에서 모든 설정을 함
- 앞의 예제와 다른것은 new연산자로 직접 Frame 객체 생성하지 않고 Frame 클래스를 상속받은 FrameTestEx 클래스를 사용, 이 FrameTestEx 클래스로 객체를 만들었다
+ FrameTestEx 클래스는 setSize() 메소드 없지만 조부모인 Window가 가지고 있으므로 setSize() 쓸 수 있다.
- 이때 super();를 쓰고 있다.

 

super
- 자기 부모클래스를 의미

 

위 예제 부분1

//	f = new Frame( "Frame Test" ); 
	super("Frame Test"); //윗줄과 같은 의미

- 자기 부모 클래스의 생성자를 호출하라는 의미임
- Frame 클래스를 상속받은 FrameTestEx 클래스에서 super() 를 사용하면 부모인 Frame의 생성자를 호출

 

위 예제 부분2

	setSize( 400, 300 );

- 생성자 내부에서 메소드를 이렇게만 쓰고있다, 객체를 만들거나 클래스명. 을 사용하고 있지 않음, 정적메소드 아님
- 상속을 받아서 자기것처럼쓰기때문에 마치 자기 클래스의 메소드인것처럼 쓰고있는거임
- 자기 클래스의 메소드는 클래스명. 을 쓸 필요없이 메소드명만 쓰면 됨

 

사용자 정의 클래스에서의 상속
- 중복코드를 줄이기 위해 사용
- 클래스를 여러개 만들때 상속을 써야하는 경우가 있다
- 공통코드가 있을때 상속을 써서 상위 클래스로 만든다 (안쓰면 중복이 많이 발생한다)
- 그리고 그걸 상속받아서 여러 클래스를 만들땐 그 클래스엔 그 클래스에 필요한 것들만 쓰는거임
- 즉, 공통적이지 않는 부분들만 각자의 클래스에서 구현한다

- JSP 모델2 에서 상속활용
- 즉 클래스가 많고 거기에 공통적인 코드(내용)들이 있을때 공통의 부분을 상위 클래스로 만들고 거기서 상속을 받아서 나머지를 구현하는 방식으로 구현

상속 예제3-1(직접 상속 설계 전단계)

 

상속 예제3-1(직접 상속 설계 전단계)

class Point2D{
  private int x;
  private int y;

  public int getX( ){
     return x;
  }
  public void setX(int new_X){
    x=new_X;
  }
  public int getY( ){
     return y;
  }
  public void setY(int new_Y){
    y=new_Y;
  }
}


class Point3D{
  private int x;
  private int y;
  private int z;
 
  public int getX( ){
     return x;
  }
  public void setX(int new_X){
    x=new_X;
  }
  public int getY( ){
     return y;
  }
  public void setY(int new_Y){
    y=new_Y;
  }
  public int getZ( ){
     return z;
  }
  public void setZ(int new_Z){
    z=new_Z;
  }

}

- 상속 설계 이전단계의 코드다, 코드가 길고 중복이 많음
- Point2D클래스에 있는게 공통적인 내용임 ->Point2D를 부모로 만들자
- Point3D 클래스는 getX, getY, setX, setY, x, y 등은 다 공통이고 getZ, setZ, z 만 있으면 됨
- 공통적이지 않은 내용들을 자식클래스로 구현, 아래 3-2 예제에서 구현

 

상속예제 3-2 (3-1 예제를 상속설계)
- SuperSub00.java

package p2022_07_04;

class Point2D { // 부모클래스 : 공통적인 내용
	private int x; // 필드
	private int y; // 필드

	public int getX() { // 값 돌려주는 메소드
		return x;
	}

	public void setX(int new_X) {
		x = new_X;
	}

	public int getY() {
		return y;
	}

	public void setY(int new_Y) {
		y = new_Y;
	}
}

// 부모 클래스 안에 있는 필드와 메소드는 상속 된다.
class Point3D extends Point2D { // 자식 클래스
	private int z;

	public int getZ() {
		return z;
	}

	public void setZ(int new_Z) {
		z = new_Z;
	}
}

class SuperSub00 {
	public static void main(String[] args) {

		Point3D pt = new Point3D(); //자식클래스로 생성
		pt.setX(10); // 상속받아 사용
		pt.setY(20); // 상속받아 사용
		pt.setZ(30); // 자신의 것 사용
		System.out.println(pt.getX()// 상속받아 사용
				+ ", " + pt.getY()// 상속받아 사용
				+ ", " + pt.getZ());// 자신의 것 사용
	}
}

 

상속 정리
+ 상속을쓰게되면 클래스가 많아짐 : 부모클래스, 자식클래스, main메소드있는 클래스
- 부모클래스의 필드 : private int x, private int y;
- 부모/조상클래스의 필드, 메소드를 내것처럼쓰는게 상속
- 공통적인 내용은 상속받아 쓰자
- 자식꺼를 뺏어가는건 불가능 일방적이다

 

- 상속관계에선 부모클래스로 객체를 생성하는건 의미가 없다
- 보통은 자식클래스로 객체를 생성한다.
- setX()메소드는 Point2D클래스(부모클래스) 로부터 상속받아서 내꺼처럼 쓰고 있는거
- setX() 메소드를 써서 Point2D클래스의 x필드값의 값을 10으로 초기화함 (어차피 필드 y도 상속되니까)
- getX() 메소드 호출 시 Point2D클래스의 x필드 값을 돌려줌(어차피 필드 x도 상속되니까)

복습 / 과제 설명
https://laker99.tistory.com/20?category=1065834
- Calendar 클래스 로 날짜 시간 요일 까지 출력
- 새로 만드는게 아니라 시스템으로부터 구해오는 클래스라서 Calendar 클래스는 new 연산자로 객체 못만듬

Calendar 객체 생성법
1. 

Calendar c1 = new GregorianCalendar


- 이미 형성된 상속관계, 자식 클래스인 GregorianCalendar 로 객체를 만들어서 왼쪽의 부모에게 전달 = 레퍼런스 형변환
- 자식 객체가 부모에게 전달 = 업캐스팅
- 세번째 형변환인 레퍼런스 형변환이며, 두 클래스 사이에 상속관계가 전제되어야만 가능함

2. 

Calendar c = Calendar.getInstance();


- Calendar 클래스 안의 정적메소드 getInstance() 메소드 사용해서 객체를 구해옴, Calnedar 객체를 받음 
* 객체 = 인스턴스

- 년월일시분초 -> Calendar의 정적필드를 이용해서 구해야함(API 문서)
- 클래스명.필드명 으로 필드 사용
- 연도 구해올땐 Calendar.YEAR 필드로 get함수써서 구함

 

int y = c.get(Calendar.YEAR);
int m = c.get(Calendar.MONTH) + 1; // 0~11 이므로 +1 해주기
int d = c.get(Calnedar.DATE);

int h1 = c.get(Calendar.HOUR); // 12시간
int h2 = c.get(Calendar.HOUR_OF_DAY); // 24시간

int ap = c.get(Calendar.AM_PM); // 오전 0 오후 1
int w = c.get(Calendar.DAY_OF_WEEK); //1~7 을 돌려줌

- 1,2,3,4,5,6,7 로 일정히 증가하므로 숫자를 요일로 변환시켜주기 위해서는 String[] 클래스 배열을 사용한다 

 

		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]+"요일");

- 이렇게 배열인덱스와 맞춰주면 됨 
- "금" 은 6이 나오는데 String배열에는 인덱스 5번이므로 -1 해줌

 

문자열 처리 클래스 종류
- String, StringBuffer, StringTokenizer
1. String : 문자열을 저장함, 가장 빈도 높은 사용
2. StringTokenizer : 여러 문자들을 구분기호로 파싱할때 사용
3. StringBuffer - 가장 빈도 낮지만 알아야함

문자열 처리 클래스 차이
- 3개의 클래스가 기능이 조금씩 다르다.
- 메모리 상에서 데이터 처리하는데 차이가 있다
- String 클래스의 메소드 아주 많다

String 클래스와 메소드
- 자바에서 가장 사용빈도 높은 클래스
- java.lang 패키지 안, import필요 없다
- 지원되는 메소드 100개 넘음

 

String 클래스 예제1

- StringTest00.java

package p2022_07_01;

class StringTest00 {
	public static void main(String[] args) {
		String str1 = new String("Java Programming");
		String str2 = new String("Java Programming");

		if (str1 == str2) { // 주소 비교
			System.out.println("같다");
		} else {
			System.out.println("다르다"); // 다르다
		}
		String str3 = "Java Programming";
		String str4 = "Java Programming";

		if (str3 == str4) {
			System.out.println("같다"); // 같다
		} else {
			System.out.println("다르다");
		}

		if (str1.equals(str3)) { // 값 비교
			System.out.println("같은 값");
		} else {
			System.out.println("다른 값");
		}
	}
}
다르다
같다
같은 값

- String 클래스만 new를 써도 되고 그냥 String name = "mimi" 라고 할 수도 있다
- new연산자 쓸때마다 매번 힙메모리상에 새로운 공간을 생성하라는 표시
- 힙메모리상에 "Java Programming"을 저장하고 있다

 

- 여기서 str3와 str2의 주솟값이 같을까? 즉 같은 "Java Programming"일까?
-> 아니다 위에서든 밑에서든 new를 쓰면 그냥 단독으로 새로운 공간 가지는거임

- str3에서 힙에 Java Programming 만들어졌으므로
- String str4 = "Java Programming"; 하면 그냥 str4는 이미 str3때 만들어진 값의 주솟값을 리턴받음
-> str3 == str4 같다 (같은 주소다)

 

그림

 

참조형의 비교대상 2개
1. 비교연산자로 주솟값 비교
2. equals로 값을 비교

 

String 클래스 예제2
- ConnectString.java

package p2022_07_01;

public class ConnectString {
	
    public static void main( String[] args ) {
	// String 객체 선언
	String gemini = "gemini";
	String johnharu = "johnharu";
		
	// 두 String 객체를 "+" 연산 수행
	String tempString1 = gemini + johnharu;
	System.out.println( tempString1 );
	System.out.println( "gemini" + "johnharu" );

	// String + 정수형
	String tempString2 = tempString1 + 100;
	System.out.println( tempString2 );
    }
}
geminijohnharu
geminijohnharu
geminijohnharu100

 

위 예제 부분1

	String tempString1 = gemini + johnharu;
	System.out.println( tempString1 );

 

- 객체 + 객체 를 쓰면 주솟값이 아닌 가리키는 값들끼리를 연결해준다

 

위 예제 부분2

	System.out.println( "gemini" + "johnharu" );

- 이렇게해도 연결되어 출력된다

 

String형 자료형과 기본자료형 변수끼리 결합(위 예제 부분3)

	// String + 정수형
	String tempString2 = tempString1 + 100;
	System.out.println( tempString2 );

- String형 자료형과 기본자료형 변수끼리 산술적인 연산 +가 안된다
- 붙어서 geminijohnharu100이 출력되고 결과는 전체가 String형으로 바뀜

 

String 클래스 예제3(String과 메모리)

- StringTest01.java

package p2022_07_01;

// String 객체를 생성한 후에 메소드에 의해서 값의 변화가 일어나면
// 변경된 값을 힙메모리 영역에 다시 저장 한다.

// Garbage Collection 기능 (쓰레기 수집 기능)
// : 재사용할 수 없는 힙메모리 영역의 데이터를 모아서 지워주는 기능

class StringTest01 {

  public static void main(String[] args) {
    String str1 = "Java Programming";
    
	str1.toUpperCase();              // 대문자로 변환
    System.out.println(str1);      //메서드 호출 후에도  str1의 내용은 수정되지 않는다.(원래값출력)
	System.out.println(str1.toUpperCase()); //대문자 변환된 내용 출력

    String str2=str1.toUpperCase();  //메소드의 처리 결과를 str2에 저장
    System.out.println(str2);          //대문자 변환된 내용 출력
  }    
}
Java Programming
JAVA PROGRAMMING
JAVA PROGRAMMING

 

위 예제의 부분1

	str1.toUpperCase();              // 대문자로 변환
   	System.out.println(str1);      //메서드 호출 후에도  str1의 내용은 수정되지 않는다.(원래값출력)

- 왜 위의 예제에서 str1.toUpperCase() 하면 str1의 값을 출력했을때 대문자로 변환되어 출력되지 않을까?
- String class는 값의 변화가 일어나면 변경된 값을 힙메모리상에 저장시킴
- 하지만 이 변경된 값을 재사용하지 못할때는 가비지 콜렉터가 변경이 되더라도 지워버림
- 즉 대문자로 변경이 되었지만 가비지콜렉터 기능때문에 재사용을 못하기 때문에 그 값을 지워버리고 처음 원래의 값(소문자)을 출력시킴

 

- Java Pro 에서 str1.toUpperCase() 를 쓰면 바뀐 내용(대문자) 를 힙메모리상에 새로 저장해줌
(그림 있음 2번번호)
- 하지만 접근하는방법이 없고, 재사용이 안되기 때문에 가비지 콜렉터가 지워버림
- 그래서 str1을 출력하면 원래값을 출력함
- 힙메모리상에서 값의 변화가 일어나면 매번 그걸 힙메모리상에 따로 새로 저장하기 때문이다

 

위 예제의 부분2

System.out.println(str1.toUpperCase());

 

- 한번 대문자로 출력한 후 참조하는 방법이 없으므로 없어짐(그림 3번 표시)
- 이 이후 str1을 출력시 다시 Java Programming으로 나옴

 

변경된 값 재사용
- str2처럼 이 바뀐 결과를 저장하는 새로 힙에 생긴 공간의 주솟값을 저장을 해야함(그림 4번 표시)

위 예제의 부분3

    String str2=str1.toUpperCase();  //메소드의 처리 결과를 str2에 저장
    System.out.println(str2);

- 이 str2가 새로바뀐 결과가 저장된 힙메모리의 공간을 받아서 주솟값을 저장해야만 재사용가능하고 str2를 통해 그 바뀐 결과를 출력 할 수 있다
- 즉 가리켜주는 객체 없으면 값이 사라짐 재사용되지 않는 힙메모리 값은 가비지콜렉터가 지움

 

그림

 

값이 변할때 메모리 처리
- String 객체를 생성한 후에 메소드에 의해서 값의 변화가 일어나면 변경된 값을 힙메모리 영역에 다시 저장 한다.

 

Garbage Collection 기능 (쓰레기 수집 기능)
- 재사용할 수 없는 힙메모리 영역의 데이터를 모아서 지워주는 기능
- 자동 메모리 관리 기능임
- 개발자가 메모리 관리 신경 크게 안써도 됨

+ StringBuffer 클래스
- 메모리상에 문자열 저장하는건 공통적이지만 String과 달리 새로운 공간에 저장하진 않는다

 

변경된 값을 재사용하기

String original = "Java Programming"
String lowerCase = original.toLowerCase(); //java programming
String upperCase = original.toUpperCase(); //JAVA PROGRAMMING

- String은 이렇게 변경된 값의 공간의 주소를 저장할 변수가 있어야 재사용 가능하다.

 

String 클래스 메소드

 

String클래스의 toUpperCase() 메소드
- 문자열을 대문자로 바꿔주는 메소드

String클래스의 toLowerCase() 메소드
- 문자열을 소문자로 바꿔주는 메소드

String클래스의 length() 메소드
- 한글이든 영문이든 몇글자인지를 구해준다.
- 한칸 비어있는 공백도 1글자로 인식함
- 문자열의 길이를 구해준다. 글자수를 구해줌

String클래스의 length() 메소드 예제

- FindBlankIndex.java

package p2022_07_01;

public class FindBlankIndex {
    public static void main( String[] args ) {
		
	String message = "Java program creates many objects.";
	
	// message의 길이를 구함.
	// length() : 문자열의 길이를 구해준다. 글자수를 구해줌
	int len = message.length();

	System.out.println(len);  // len = 34;

	// message 중에서 ' '을 찾음
	for( int i=0 ; i<len ; i++ ) {
	    char c = message.charAt( i );
		if( c == ' ' ) { //공백의 인덱스 번호를 구해서 출력
		    System.out.println( "index = " + i );
		}
	}//for end
    }
}

- 공백이나 . 까지도 한글자로 포함
- 반환형 int, 문자열의 길이를 리턴
-  for문으로 루프 돌려서 0부터 len보다 작을때까지 즉 len 만큼 for문을 돌림

 

length vs length() vs size()
- 배열의 크기를 구해주는 length 속성 -> 속성이므로 ()가 없다
- String 자료가 몇글자인지 구해주는 length() 메소드 -> 메소드이므로 ()
- 자료구조에 저장된 원소의 개수를 구해주는 size() 메소드 -> 메소드이므로 ()

String클래스의 중 charAt() 메소드
- 매개변수 int 이고 안에 인덱스 번호가 들어감
- 리턴형은 char임 즉 인덱스를 받아서 거기에 해당하는 문자를 가져옴.
- 인덱스는 0번부터 시작

그림

String클래스의 중 charAt() 메소드 예제

package p2022_07_01;

public class FindBlankIndex {
	public static void main(String[] args) {

		String message = "Java program creates many objects.";

		// message의 길이를 구함.
		// length() : 문자열의 길이를 구해준다. 글자수를 구해줌
		int len = message.length();

		System.out.println(len); // len = 34;

		// message 중에서 ' '을 찾음
		for (int i = 0; i < len; i++) {
			char c = message.charAt(i);
			if (c == ' ') { // 공백의 인덱스 번호를 구해서 출력
				System.out.println("index = " + i);
			}
		} // for end
	}
}
34
index = 4
index = 12
index = 20
index = 25

- ' ' 즉 공백이 인덱스 몇변이 있는지 출력해줌 (공백을 찾아주는 코드)

 

String클래스의 indexOf() 메소드
- charAt과 반대기능의 메소드
- 특정 문자의 인덱스번호를 구해주는 메소드
- 찾고자하는 문자가 없을때는 -1을 리턴함
- API 문서에서 indexOf() 메소드 찾아보면 메소드 오버로딩 되어있다

String클래스의 indexOf() 메소드 예제1

	String message = "Java program creates many objects.";
	int index1 = message.indexOf( 'a' );

- 출력 : 1
- a란 문자의 index 번호를 구해와라
- a가 여러개 있을땐, 가장 먼저 나오는 a의 인덱스 번호를 구해라

 

String클래스의 indexOf() 메소드 예제2

	String message = "Java program creates many objects.";
	int index2 = message.indexOf( 97 );

- 출력 : 1
- 97은 10진수 아스키 코드값이므로 거기에 해당하는 영문자를 찾아줌
- 이 영문자를 찾아서 인덱스를 가져와줌
- 10진수 아스키코드(97) 에 해당되는 문자('a')의 인덱스 번호를 구함.
- 이 97을 65로 바꾸면? -> 'A'를 찾는데 찾고자하는 문자가 없으므로 -1을 리턴함

 

String클래스의 indexOf() 메소드 예제3(매개변수가 2개)

	String message = "Java program creates many objects.";

	//index번호 13번째 이후에서 'a'의 인덱스 번호를 구함
	int index3 = message.indexOf( 'a', 13 ); 
	System.out.println( index3 );

- index번호가 13번 이후에 가장 먼저나오는 'a' 의 인덱스 번호를 찾아라
- 즉 c(13) 부터 찾아라 그 'a' 는 16이 나옴
- 이렇게 위치가 지정될땐 그 이후의 문자를 찾고 위치 지정이 안되었을떈 아까의 예시처럼 가장 먼저나오는 문자의 인덱스값을 찾음

 

String클래스의 indexOf() 메소드 예제4(매개변수가 String)

	String message = "Java program creates many objects.";

	// 가장 먼저 나오는 'av'의 인덱스 번호를 구함
	int index4 = message.indexOf( "av" );
	System.out.println( index4 );

- 출력 : 1
- Java의 av 이므로 결과는 1
- 문자 한글자가 아니라 문자열이 들어가는 경우임
- 가장 먼저 나오는 av의 인덱스 번호를 구해라

 

String클래스의 indexOf() 메소드 예제5(매개변수가 2개)

	String message = "Java program creates many objects.";

	// index번호 12번 이후에 나오는 'man'의 인덱스 번호를 구함
	int index5 = message.indexOf( "man", 12 );
	System.out.println( index5 );

- 이렇게 위치가 지정될땐 그 이후의 문자열의 인덱스번호를 주고 위치 지정이 안되었을떈 아까의 예시처럼 가장 먼저나오는 문자의 인덱스값을 찾음

 

String클래스의 indexOf() 메소드 예제6(결과가 없는 경우)

	String message = "Java program creates many objects.";
	// 찾는 문자가 없는 경우에는 -1을 리턴한다.
	int index6 = message.indexOf( "java" );
	System.out.println( index6 );

- 출력 : -1
- 소문자 java가 없다 찾고자하는 결과없으면 -1 리턴한다
- 이 indexOf 메소드는 대소문자를 구분한다

 

String클래스의 trim() 메소드
- 문좌열 좌,우의 공백을 없애주는 역할

String클래스의 equals() 메소드
- boolean equals()
- 값을 비교하는 역할
- 가리키는 값들끼리 비교함

 

String클래스의 trim() 메소드 / equals() 메소드 예제

package p2022_07_01;

public class TrimTest {

    public static void main( String[] args ) {
    	
//    trim() : 문좌열 좌.우의 공백을 없애주는 역할
//    boolean equals() : 값을 비교하는 역할
	String str1 = new String( "gemini   " );
	String str2 = new String( "   gemini " );

	System.out.println( str1.equals( str2 ));
	System.out.println( str1.trim().equals( str2.trim()));
    }
}

- str1 가 가리키는 gemini 문자열 오른쪽에 공백이 있다
- str2 가 가리키는 gemini 문자열 왼쪽에 공백이있다
- 공백도 메모리상에 공간을 차지함

 

위 예제 부분1

	System.out.println( str1.equals( str2 )); //false

- 공백도 문자로 인식하므로 서로 다른 값으로 인식함.

 

위 예제 부분2

	System.out.println( str1.trim().equals( str2.trim()));

- 서로 같은값임. 
- str1.trim()은 str1이 가리키는 문자열 오른쪽 공백 없애줌(좌,우 모두)
- str2.trim()은 str2이 가리키는 문자열 왼 공백 없애줌(좌,우 모두)
- 둘다 gemini만 남게되고 값이 같으므로 true리턴

 

String클래스의 replace() 메소드
- 문자열에서 첫번째 매개변수 값을 두번째 매개변수 값으로 변환시켜줌
ex) replace("자바","JAVA") : "자바"를 "JAVA"로 치환

 

String클래스의 replace() 메소드 예제1
- ReplaceEx.java

package p2022_07_01;

public class ReplaceEx {

	public static void main(String[] args) {

	//p506
	//replace("자바","JAVA") : "자바"를 "JAVA"로 치환
		
		String oldStr = "자바는 객체지향 언어 입니다.";
		
		String newStr = oldStr.replace("자바", "JAVA");
		System.out.println(oldStr);
		System.out.println(newStr);
	}

}
자바는 객체지향 언어 입니다.
JAVA는 객체지향 언어 입니다.

 

String클래스의 replace() 메소드 예제2

 

		String oldStr = "자바는 객체지향 언어 입니다. 자바";
		
		String newStr = oldStr.replace("자바", "JAVA");
		System.out.println(oldStr);
		System.out.println(newStr);
자바는 객체지향 언어 입니다.
자바 JAVA는 객체지향 언어 입니다.JAVA

- "자바" 가 여러개 있어도 다 JAVA로 바꿈

 

+ String클래스는 메소드를 통해 값의 변화가 일어나면 매번 힙메모리상의 새로운공간에 바뀐값을저장함

 

String클래스의 substring() 메소드
- 일부 문자열만 추출
- 메소드 오버로딩되어있다
- 매개변수가 2개인 경우, 매개변수가 1개인 경우 추출하는 범위가 달라진다.

1. 매개변수 2개인경우
- 시작과 끝 인덱스를 지정한다
- 하지만 실제 우리가 추출하는건 하나 적게 추출함 즉 begInindex ~ endIndex-1까지 추출

2. 매개변수 1개인경우
- 시작 인덱스만 지정한다
- 시작 인덱스로부터 끝까지 추출하라는 의미

String클래스의 substring() 메소드 정리
- substring() : 전체 문자열에서 특정 범위의 문자를 추출하는 역할
- substring(n) : index번호 n번 부터 끝까지 추출
- substring(n1, n2) : index번호 n1번 부터 (n2-1)번 까지 추출

 

String클래스의 substring() 메소드 예제1(매개변수 1개)

	String message = "Java program creates many objects.";

	// 인덱스번호 13번 부터 끝까지 추출		
	String str1 = message.substring( 13 );
	System.out.println( str1 );
creates many objects.

- c가 13번 위치였다. 즉 13부터 모두 추출
- 13은 인덱스 번호 13번부터 끝까지 추출해서 결과를 str1 변수에 저장하고 출력시켜라는 의미

 

String클래스의 substring() 메소드 예제2(매개변수2개)

	String message = "Java program creates many objects.";

	// 인덱스번호 13번 부터 15번까지 추출
	String str2 = message.substring( 13, 16 );
	System.out.println( str2 );
cre

- c는 13, r은 14, e는 15 (15까지 추출)
- beginIndexNum이 13번 endIndexNum이 16인데 실제로는 13부터 15번까지 추출함

 

- 여기서 str1과 str2는 변경된 문자열을 가리킴(저장)
- 자바는 substring 메소드만 제공함

 

String클래스의 substring() 메소드 예제3
- SubstringEx.java
- substring() 이용해서 한글자 추출하기
- substring(그 글자 인덱스, 그 다음글자 인덱스)
+ string값 비교에 == 쓰지말고 equals쓰기

package p2022_07_01;

public class SubstringEx {

	public static void main(String[] args) {

//아래와 같이 주민번호가 있을때, 남자인지 여자인지 판별하는 프로그램을 작성하세요?

		String jumin = "900101-2233456"; // 2000년 이후 남자는 3번, 여자는 4번
		String gender = jumin.substring(7, 8);

		if (gender.equals("1") || gender.equals("3")) {
			System.out.println("남자");
		} else if (gender.equals("2") || gender.equals("4")) {
			System.out.println("여자");
		}
	}

}

- 문자끼리 비교하는거니 gender.equals("1") 라고 "1"이라고 문자를 넣어야지 숫자 1을 넣으면 안됨!
-  if-else로 해도 되지만 주민번호 첫자리 수 5(귀화한분들) 이런 경우도 있으므로 안전상 if-elseif로 해야한다

 

위 예제 부분1

		String gender = jumin.substring(7, 8);

- 이렇게 해야 7번 인덱스의 문자열을 가져옴

 

String클래스의 substring() 메소드 예제4

- 키보드로 주민번호를 입력받는다, 주민번호 문자로 받아야함(문자열 클래스로 이것저것 할 것 이므로)
- 앞자리 6자리가아니면 메세지 뿌림
- 뒷자리 7자리가아니면 메세지 뿌림 
- 이런걸 유효성 검사라고 한다
- 그리고 이 모든게 완벽한 값이면 입력한 주민번호가 남자인지 여자인지도 판별

package p2022_07_01;

import java.util.Scanner;

public class JuminCheck {

	public static void main(String[] args) {
// 키보드로 주민번호를 입력 받아서 남자인지 여자인지를 판별하는 프로그램을 작성하세요?
// 단, 주민번호 앞자리는 6자리, 뒷자리는 7자리 인지를 유효성 검사를 한다.

		// 키보드로 주민번호 입력받기
		Scanner sc = new Scanner(System.in);
		System.out.println("주민번호 앞자리를 입력 하세요?");
		String jumin1 = sc.nextLine();

		System.out.println("주민번호 뒷자리를 입력 하세요?");
		String jumin2 = sc.nextLine();

		// 남녀
		String g = jumin2.substring(0, 1); // 0번 인덱스 추출한다는 의미

		// 유효성 검사 & gender
		if (jumin1.length() != 6) {
			System.out.println("주민번호 앞자리 6자리를 입력하세요.");
		} else if (jumin2.length() != 7) {
			System.out.println("주민번호 뒷자리 7자리를 입력하세요.");
		} else if (g.equals("1") || g.equals("3")) {
			System.out.println("남자");
		} else if (g.equals("2") || g.equals("4")) {
			System.out.println("여자");
		} else {
			System.out.println("똑바로 입력 하세요.");
		}

	}
}

- if-elseif-else문 처리기때문에 처음 주민번호 앞자리 6자리가 아니면 더이상 아래쪽을 실행안함.
- 주민번호 앞자리 6자리인데 뒷자리 7자리 아니면 두번째에 걸림 아래 실행 안함
- 둘다 개수가 맞으면 이제야 남/녀 검사를함
- 주민번호는 6,7 다 맞는데 뒷자리 첫번째가 1234가 아니면 마지막인 else 구문에서 걸린다

 

+ String클래스의 split() 메소드
- 이후 뒤에서 자세히 설명함(StringTokenizer 클래스 공부 이후)
- 전체 문자에서 구분기호를 가지고 문자를 추출할때 사용함
- @ 나 / 등의 정규 표현식을 구분자로 해서 문자를 자름 이걸 파싱이라고함
- 결과를 돌려주는 자료형은 String형 1차원 배열로 돌려줌

 

+ Strping클래스의 split() 메소드는 은 StringTokenizer 와 비슷한 역할을 하지만 더 쓰기 편하다

+ String클래스의 split() 메소드 오버라이딩
- split(String regex)
- split(String regex, int limit)

 

String 클래스와 메모리 정리
- String 클래스는 메소드에서 값의 변화가 일어나면 변경된 값을 힙 메모리에 매번 새로운공간을 만들어서 사용함
- 재사용은 값을 받아주는 변수가 있을때만 사용가능하고 변경된정보에 접근이 불가능하면 가비지 콜렉터가 지움

사용빈도
String >>> StringTokenizer >>>>> StringBuffer 

 

String, StringTokenzier, StringBuffer

- 공통적 특징 : 힙메모리상에 문자를 저장함
- 하지만 메모리상에 데이터를 처리하는부분이 다름 (메모리상에 문자를 저장하는 방식이 다름)
- String : 메소드에서 값의 변화가 일어나면 변경된 값을 힙 메모리에 매번 새로운공간을 만들어서 사용함
- StringBuffer : 버퍼라는 기억장소를 쓰기때문에 값의 변화가 일어나더라도 새로운 공간에 값을 저장하지 않음. 시작 주소값이 바뀌지 않음. 값을 계속 누적하는 경우에 이 클래스 쓰는 경우가 있다

 

StringBuffer
- 사용빈도 낮음
- StringBuilder 와 비슷한 기능(이건 안함)
- StringBuffer도 java.lang에 있어서 import 안해도 됨
- Buffer라는 임시 기억공간에 문자열을 저장함, 기능적으로 String과 다르다

 

StringBuffer 생성자
- 매개변수가 int capacity로 된 생상자가 있다, 버퍼라는 임시기억장소의 크기를 생성하는 거임
- 크기를 지정하면 지정된크기로 만들어줌, 크기 설정 따로 안해도 버퍼라는 임시기억소 만듬
- 설정안하면 기본적으로 16characther임 16글자 저장하기위한 힙메모리상의 공간을 만들어줌

 

StringBuffer 예제
- StringBufferTest.java

package p2022_07_01;

public class StringBufferTest {
	public static void main(String[] args) {

		StringBuffer sb1 = new StringBuffer("gemini");
		System.out.println("sb1.length() : " + sb1.length());	//6
		System.out.println("sb1.capacity() : " + sb1.capacity());	//22

		sb1.append("A string buffer implements" + "a mutable sequence of characters");
		System.out.println("sb1.length() : " + sb1.length());	//64
		System.out.println("sb1.capacity() : " + sb1.capacity());	//64

		StringBuffer sb2 = new StringBuffer();
		System.out.println("sb2.length() : " + sb2.length());	//0
		System.out.println("sb2.capacity() : " + sb2.capacity());	//16
	}
}

 

위 예제 부분1(매개변수가 있는 생성자)

		StringBuffer sb1 = new StringBuffer("gemini");

- 매개변수가 있는 생성자로 객체를 생성하고 있다
- "gemini"가 힙메모리 상에 저장되고, sb1이 이 주소를 갖고 있다.

 

- length()메소드 지원 : 문자열길이를 구해줌
- capacity() 메소드 : 힙메모리상의 할당된 바이트 크기 알려줌 //22바이트
- append() 메소드 : 문자열을 추가함

 

- 동적으로 공간을 늘려주는 기능도 있다 자동으로 늘려줌
- 만약 22보다 큰 크기의 문자열을 넣으면 동적으로 공간을 늘려줌
- 다시 length()를 구했을때 64가 나옴
- 처음에 22바이트였던 공간을 64만큼 늘려줌

 

위 예제 부분2(기본생성자)

		StringBuffer sb2 = new StringBuffer();

- 기본생성자로 객체를 생성하고 있다
- 길이 length 는 0임
- 자동으로 16바이트(16글자공간 만들어줌) 로 만들어줌
- 아무것도 안가리키기 때문에 length()는 0

 

StringBuffer와 값의 변화
- StringBuffer는 값의 변화가 일어나더라도 시작주소값이 바뀌지 않는다
- String과 다른 특징

 

StringBuffer와 값의 변화 예제
- AppendStringBuffer.java

package p2022_07_01;

public class AppendStringBuffer {
    public static void main( String[] args ) {
		
	// StringBuffer 객체 생성
	StringBuffer sb1 = new StringBuffer( "gemini" );
	System.out.println( "sb1 = " + sb1 );

	// StringBuffer sb1에 문자열을 추가해 새로운 객체 생성
	StringBuffer sb2 = sb1.append( " is beautiful" );
	System.out.println( "sb2 = " + sb2 );
	System.out.println( "sb1 = " + sb1 );

	if(sb1 == sb2) {
		System.out.println("같은 주소"); //같은 주소
	}else {
		System.out.println("다른 주소");
	}

	// 정수형 데이타 형을 추가
	System.out.println( sb1.append( 1004 ));
	System.out.println( "sb1 = " + sb1 );
	System.out.println( "sb2 = " + sb2 );

	String str = new String(sb1); // StringBuffer를 String으로 변환
	System.out.println(str.toUpperCase());
    }
}
sb1 = gemini
sb2 = gemini is beautiful
sb1 = gemini is beautiful
같은 주소
gemini is beautiful1004
sb1 = gemini is beautiful1004
sb2 = gemini is beautiful1004
GEMINI IS BEAUTIFUL1004

 

위 예제 부분1

	// StringBuffer 객체 생성
	StringBuffer sb1 = new StringBuffer( "gemini" );
	System.out.println( "sb1 = " + sb1 );

- 힙메모리상에 "gemini"라는 값이 저장되고 그걸 sb1이 시작주소를 가지고 있다

 

위 예제 부분2

	// StringBuffer sb1에 문자열을 추가해 새로운 객체 생성
	StringBuffer sb2 = sb1.append( " is beautiful" );
	System.out.println( "sb2 = " + sb2 );
	System.out.println( "sb1 = " + sb1 );

- append() 함수 : 기존 문자열에 새로운 문자열을 이어 붙여줌 (String클래스엔 이 함수 지원안됨)
- 그리고 이걸 sb2가 주소를 가지게 함

 

위 예제 부분3

	if(sb1 == sb2) {
		System.out.println("같은 주소"); //같은 주소
	}else {
		System.out.println("다른 주소");
	}

- 출력 : 같은 주소
- 문자열이 변경되었지만 새로운 힙공간에 저장하지 않음 그러니 sb1과 sb2가 가리키는건 같음!
- 둘다 같은 문자열이 출력됨
- 즉 같은 주소, 같은 값 같은걸 가리키고 있음

그림

 

String vs StringBuffer 차이 정리
- String : 값의 변화 일어나면 새로운 공간에 그 결과 저장. 원래 값의 주솟값 != 바뀐 값의 주솟값
- StringBuffer : 값의 변화 일어나도 기존 공간에 적용, 변경된 값의 시작주솟값이 바뀌지 않음

 

위 예제 부분4

	// 정수형 데이타 형을 추가
	System.out.println( sb1.append( 1004 ));
	System.out.println( "sb1 = " + sb1 );
	System.out.println( "sb2 = " + sb2 );

	String str = new String(sb1); // StringBuffer를 String으로 변환
	System.out.println(str.toUpperCase());

- sb1에 append(1004) 함 
- 그 후에 sb1출력하나 sb2 출력하나 같은 gemini is beautiful1004 가 출력됨
- 같은주소를 리턴받았었기때문에 그렇다

 

StringBuffer로 저장된 문자열을 대문자로 바꾸기
- StringBuffer 클래스는 toUperCase() 메소드가 없어서 못쓴다 (langth()는 있음)
- String과 StringBuffer 사이는 상속관계 없으므로 String 클래스 안에 있는걸 StringBuffer가 상속받아 쓸수도 없음

 

-> String 클래스의 생성자를 활용해서 대문자로 바꿔주면 된다.
-> String 클래스 생성자를 찾아보면 매개변수가 StringBuffer인 생성자가 있다
- String(StringBuffer buffer) 생성자
- 이 생성자를 통해서 StringBuffer -> String 으로 변환 가능
- String 객체로 받아서 toUpperCase 해서 대문자 변환하기

 

StringBuffer로 저장된 문자열을 대문자로 바꾸기 예제
- InsertStringBuffer.java
- StringBuffer 클래스의 append() 메소드 : 기존 문자열에 끝 추가
- StringBuffer 클래스의 insert() 메소드 : 지정된 특정 위치에 문자열을 삽입 시킴

package p2022_07_01;

public class InsertStringBuffer {
	public static void main(String[] args) {

		StringBuffer sb1 = new StringBuffer("gemini is beautiful");
		System.out.println(sb1);

		// 인덱스 10번 위치에 very 문자를 삽입
		sb1.insert(10, "very");
		System.out.println(sb1);

		// 인덱스 0번 위치에 1004 를 삽입하라(숫자로 써도 문자가됨)
		sb1.insert(0, 1004);
		System.out.println(sb1);
	}
}
gemini is beautiful
gemini is verybeautiful
1004gemini is verybeautiful

- 처음엔 인덱스 10번위치에 "very"란 문자열을 삽입시켜라는 의미
- is beautiful 사이의 공백이 인덱스 10이다. 그 10번 뒤에 삽입 됨-> is verybeautiful
- 이후 인덱스 0번위치에 1004를 삽입하라는 의미

 

StringBuffer 클래스의 사용
- 문자열 처리 보통은 String 클래스로 다 처리가능함
- 값을 계속 누적시키거나 하는 특별한 경우들에만 StringBuffer를 사용함

 

+ 문자열 분리 방법 2가지
- 구분기호를 가지고 문자를 추출하는, 잘라서 토큰으로 추출하는 역할
1. java.util.StringTokenizer이용
2. String의 split() 메소드 활용

 

StringTokenizer 클래스
- 앞의 두 클래스와 기능이 좀 다름
- 특정 문자를 구분기호를 가지고 토큰을 구해오는 역할을 함
- 문자를 파싱해서 처리해주는 역할을 한다
- java.util 안에 있다

 

StringTokenizer 클래스 생성자
- 매개변수 1,2,3개인 3개의 생성자 중 StringTokenizer(String str, String delim) 을 주로 사용한다
- 첫번째 매개변수에는 전체 문자열 또는 그 문자열을 담은 변수명이 온다
- 두번째 매개변수에는 구분기호가들어간다, 구분기호는 @ # / 등이 될 수 있다.

 

StringTokenizer 클래스 예제1
- StringTest04.java

package p2022_07_01;

import java.util.*;

class StringTest04 {

	public static void main(String[] args) {
		StringTokenizer str = new StringTokenizer("이순신#을지문덕#강감찬#광개토대왕", "#");

//		System.out.println(str.nextToken());
//		System.out.println(str.nextToken());
//		System.out.println(str.nextToken());
//		System.out.println(str.nextToken());
//		System.out.println(str.nextToken()); // 예외발생

		// 파싱된 문자열이 모두 몇 개인지 되는지 알려줌
		int cnt = str.countTokens();
		System.out.println("파싱할 문자열의 총갯수-> " + cnt);

//		System.out.println(str.nextToken());
		while (str.hasMoreTokens()) { // 토큰이 있으면
			System.out.print(str.nextToken() + "\t");// 차례대로 파싱된 문자열을 얻어온다.
		}

	} // main() end

}

 

StringTokenizer 클래스 사용예시(위 예제 부분1)

StringTokenizer str = new StringTokenizer("이순신#을지문덕#강감찬#광개토대왕", "#");

 

- 이렇게 쓰고 두번째 자리에는 구분기호가 들어감
- 이 #으로 전체문자열을 파싱 = 자른다
- 파싱을 하고 리턴되는 "이순신" "을지문덕" 등을 토큰이라고함
- nextTokens() 메소드 : 이 토큰들을 구해오는 메소드

		System.out.println(str.nextToken());

- 하면 첫번쨰 토큰인 이순신 이 출력됨

		System.out.println(str.nextToken());
		System.out.println(str.nextToken());

- 이렇게 더 하면 이순신, 을지문덕  출력됨
- nextToken()메소드는 String형으로 리턴한다

		StringTokenizer str = new StringTokenizer("이순신#을지문덕#강감찬#광개토대왕", "#");

		System.out.println(str.nextToken());
		System.out.println(str.nextToken());
		System.out.println(str.nextToken());
		System.out.println(str.nextToken());
이순신
을지문덕
강감찬
광개토대왕

- 가져올토큰 없는데 한번 더 nextToken() 메소드를 쓰면? 
- 예외가 발생해서 프로그램이 비정상적으로 멈추게됨

Exception in thread "main" java.util.NoSuchElementException
                 at java.util.StringTokenizer.nextToken(Unknown Source)
          at p2022_07_01.StringTest04.main(StringTest04.java:14)

- NoSuchElementException 예외 발생
* 예외 : 예상하지못했던 프로그램상 오류
-> 가져올 토큰이 있는지 없는지 판별을 해야함

 

가져올 토큰이 있는지 판별(위 예제 부분2)
- 가져올 토큰이있는경우에만 출력하기

		// 파싱된 문자열이 모두 몇 개인지 되는지 알려줌
		int cnt = str.countTokens();
		System.out.println("파싱할 문자열의 총갯수-> " + cnt); //4출력

- 토큰들 : 잘려진 부분들
- countTokens() 메소드 : 토큰의 개수를 구해주는 메소드
- 토큰이있을때만 가져오기위해서 처리하기 아래에

		while (str.hasMoreTokens()) { // 토큰이 있으면
			System.out.print(str.nextToken() + "\t");// 차례대로 파싱된 문자열을 얻어온다.
		}
이순신 을지문덕 강감찬 광개토대왕

- hasMoreTokens() 메소드 : 가져올 토큰이 있는지 없는지 판별하는 역할을 함
- 결과를 돌려주는 리턴자료형은 boolean, 가져올 토큰 있으면 true,없으면 false 리턴해서 while문 제어
-> 이러면 예외가 발생할 가능성이 없다

 

nextTokens()의 특징(위 예제 부분3)

		System.out.println(str.nextToken());
		while (str.hasMoreTokens()) { // 토큰이 있으면
			System.out.print(str.nextToken() + "\t");// 차례대로 파싱된 문자열을 얻어온다.
		}

- 이순신을 위에서 부르고 while문 에서는 을지문덕 감감찬 광개토대왕 만 나옴
- 한번 nextToken()쓰면 그건 끝난것, 그 뒤부터 출력됨

 

+ String 클래스의 split() 메소드가 이와 비슷한 역할을 한다.

 

StringTokenizer 클래스 예제2
- StringTokenizerTest1.java

package p2022_07_01;

import java.util.StringTokenizer;

public class StringTokenizerTest1 {

	public static void main(String[] args) {
	
		String source1="111-111|강원도|춘천시|퇴계동";
		StringTokenizer st1=new StringTokenizer(source1,"|");
		
		String zip=st1.nextToken();
		String dou=st1.nextToken();
		String si=st1.nextToken();
		String dong=st1.nextToken();

		System.out.println("우편번호:" +zip);
		System.out.println("도:" +dou);
		System.out.println("시:" +si);
		System.out.println("동:" +dong);
	}

}
우편번호:111-111
도:강원도
시:춘천시
동:퇴계동

- String 객체 source1에 문자열들이 있다
- - StringTokenzier 는 구분기호를 1개밖에 쓰지 못한다!
- "-" 같은거까지 더 구분 못함
- split()은 여러개 구분기호로 파싱 가능
- nextToken() 의 리턴형은 String
- nextToken() 으로 토큰 구해와서 String 객체에 저장했다.

 

StringTokenizer 클래스 예제3(매개변수가 3개)
- StringTokenizerTest2.java

package p2022_07_01;

import java.util.StringTokenizer;

public class StringTokenizerTest2 {

	public static void main(String[] args) {

		String source1 = "한국 미국 태국 중국 이란";
		StringTokenizer st1 = new StringTokenizer(source1, " ");
		while (st1.hasMoreTokens()) {
			System.out.println("st1.token:" + st1.nextToken());
		}

		System.out.println();
		System.out.println();

		String source2 = "푸들,삽살개,풍산개,진돗개";
		StringTokenizer st2 = new StringTokenizer(source2, ",");
		while (st2.hasMoreTokens()) {
			System.out.println("st2.token:" + st2.nextToken());
		}

		System.out.println();
		System.out.println();

		// true : 구분기후(,)를 토큰으로 처리해준다.
		StringTokenizer st3 = new StringTokenizer(source2, ",", true);
		while (st3.hasMoreTokens()) {
			System.out.println("st3.token:" + st3.nextToken());
		}

	}

}

 

위 예제 부분1

		String source1="한국 미국 태국 중국 이란";
		StringTokenizer st1=new StringTokenizer(source1," ");

- 국가명 사이에 공백이 들어가있으니 공백으로 파싱하자
- 첫번째 매개변수에는 문자열 또는 문자열이 저장된 변수가 들어간다
- 두번쨰 매개변수에는 구분기호가 들어가는데 여기선 " " 공백으로 파싱

 

위 예제 부분2

		while(st1.hasMoreTokens()){
			System.out.println("st1.token:"+st1.nextToken());
		}

- hasMoreTokens() : 가져올 토큰이 있는지 판별
- while문 안에 가져올 토큰이있을때만 true를 리턴해서 while문 돌려서 모두 출력함
- 가져올 토큰이 없으면 false리턴

 

위 예제 부분3

		String source2="푸들,삽살개,풍산개,진돗개";
		StringTokenizer st2=new StringTokenizer(source2,",");
		while(st2.hasMoreTokens()){
			System.out.println("st2.token:"+st2.nextToken());
		}

 

매개변수 3개인 StringTokenizer(위 예제 부분4)

		//true : 구분기후(,)를 토큰으로 처리해준다.
		StringTokenizer st3=new StringTokenizer(source2,",",true);
		while(st3.hasMoreTokens()){
			System.out.println("st3.token:"+st3.nextToken());
		}
st3.token:푸들
st3.token:,
st3.token:삽살개
st3.token:,
st3.token:풍산개
st3.token:,
st3.token:진돗개

- 첫번째, 두번쨰 매개변수에 넣어야하는건 위와 같다 
- 하지만 3번째 매개변수가 boolean형이다 즉 true나 false값을 써야함
- 세번째 매개변수에 true가 오면, 그 구분기호도 파싱될 토큰으로 처리하라는 의미
- 그래서 여기는 , 도 토큰기호로 인식해서 nextToken()하면 푸들 다음의 토큰으로 , 라는 토큰이옴
- false넣으면 다른 위의 예제들과 같게 구분기호는 토큰으로 인식 안함. 

 

String클래스의 split() 메소드
- StringTokenzier과 비슷한 역할하는 "메소드"
- 기능적으로 보면 split()이 쓰기가 더 편하고 여러개의 구분기호 가지고 있어도 파싱 가능함

- String[] Split(String regex)
- 이 매개변수에 구분기호가 온다
- 이 파싱된 결과를 왼쪽의 String 1차열 배열로 리턴
- 첫번째 토큰은 0번방, 두번째 토큰은 1번방, 세번째 토큰은 2번방...

 

String클래스의 split() 메소드 예시1

- 주민번호앞자리-주민번호뒷자리 를 - 로 파싱하자

		String jumin = "900101-1234567";
		String[] j = jumin.split("-");

- 구분기호를가지고 잘라서 결과를 왼쪽의 j (String형 배열) 로 전달
- "900101"인 첫번째 토큰이 j[0], "1234567" 인 두번째 토큰은 j[1]로 들어감

 

String클래스의 split() 메소드 예제1
- SplitEx.java

package p2022_07_01;

public class SplitEx {

	public static void main(String[] args) {

// String[] split(String regex) 메소드
		
		String jumin = "900101-1234567";
		String[] j = jumin.split("-");
		
		System.out.println("주민번호 앞자리 : " + j[0]);
		System.out.println("주민번호 앞자리 : " + j[1]);
		
		for (int i = 0; i < j.length; i++) { //향상된for문
			System.out.println("주민번호 " + j[i]);
		}

	}

}
주민번호 앞자리 900101
주민번호 뒷자리 1234567
주민번호 900101
주민번호 1234567
900101
1234567

+ 나중에 배열의 크기를 잘 모르는 경우에 length속성을 꼭 써야한다

 

String클래스의 split() 메소드 예제2

		String tel = "010-1234-5678";
		String[] t = tel.split("-");
		
		for (int i = 0; i < t.length; i++) {
			System.out.println(t[i]);
		}
010
1234
5678

 

String클래스의 split() 메소드 예제3

		// @를 구분기호로 아이디명과 도메인명 파싱하기
		String email = "totoro@naver.com"; //정해진 형식이 있다.
		String[] e = email.split("@");
		
		System.out.println("아이디 : " + e[0]);
		System.out.println("도메인 : " + e[1]);
아이디 : totoro
도메인 : naver.com

 

구분기호 여러개로 파싱하기(split() 메소드 예제4)

- 구분기호 여러개 섞여있어도 파싱하는게 가능하다

		String[] names = text.split("$|,|-");

- 구분기호를 연결해서서 | (파이퍼) 로 연결하면 또는 이런 구분기호들을 이용해 파싱하겠다는 의미
- 이런건 StringTokenizer 가 지원하지 못하는 기능임

 

- SplitEx1.java

package p2022_07_01;

public class SplitEx1 {

	public static void main(String[] args) {
// p512
//		String[] split(String regex); 메소드
		
		String text = "홍길동&이수홍,박연수,김자바-최명호";
		
		String[] names = text.split("&|,|-");
		
//		for (int i = 0; i < names.length; i++) {
//			System.out.println(names[i]);
//		}
//		System.out.println();
		
		for(String name : names) {
			System.out.println(name);
		} //향상된for문
		
	}

}
홍길동
이수홍
박연수
김자바
최명호

+ | 는 구분기호로 쑬 수 없다

 

문자열 파싱하는 방법 정리
1. StringTokenizer 클래스
2. String의 split() 메소드

복습 / 예습


참조형의 메모리

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 객체배열에 넣어서 문자로 출력을 하고 있다.

복습

변수
1. 지역변수
2. 멤버변수
3. 정적 멤버변수 (= 정적필드, 나중에 공부)

객체모델링
속성 -> 필드
동작 -> 메소드

- 클래스(설계도) -> 객체
- 대부분의 클래스는 객체 생성시 new연산자 사용

필드
- 메소드 바깥쪽에 정의되는 변수
- 힙메모리에 저장되고 자동초기화된다.
- 할당시점 : new연산자로 객체 생성시 힙메모리상에 할당

생성자
- 클래스명과 동일, 앞에는 접근제어자만옴, 필드값을 초기화 시키는 역할

메소드
- 객체의 동적인 것 표현

기본자료형인 필드
- 객체생성시 힙메모리할당되며
- 자동으로 초기화
정수형 : 0
실수형 : 0.0
논리형 : false

참조형인 필드
- null , 참조하는 주소가 없다.

생성자 호출
- 생성자 매개변수에 맞는값 넣어서 생성

생성자 오버로딩
- 한개 클래스 안에 동일한 이름으로 만든 여러 생성자

this
this. : 필드 생성자 메서드 안에서 멤버변수와 매개변수 이름이 같을때사용
this() : 같은 클래스내의 생성자 호출하라는 의미

과제풀이(Lotto.java) 설명
https://laker99.tistory.com/17

- 새로 발생된 난수값과 이전의 난수값들을 비교하기 위해 중첩 for문 사용
- i-- 한 뒤 괜히 더 돌아가는걸 막기위해 break 해주는게 좋다 
- 하나 중복을 발견하면 다음꺼부터는 중복일리가 없다, 이전에 이미 다 처리되었기 때문에
- 오름차순 적용

1. num[0] = 5, num[1] = 5 일때, 안의 for문이 돌아가면서  num[0] 과 num[1]을 비교해서 같으므로 i--시킴
2. 그럼 i=0이 되고 break 되어 나옴 이해 바깥 for문에 의해 ++ 되며 i=1 이 됨
3. 다시 num[1]값을 랜덤으로 받는것

오름차순하기
- 정렬알고리즘 통해서 (버블정렬 = 자신의 옆자리에 있는 것과 비교)
- Arrays 클래스의 sort()함수이용해서 num 배열이름 넘겨주면 오름차순 정렬해줌(java.util.Arrays)

필드 = 멤버변수
- 메소드 바깥쪽에 정의됨
- 기본자료형은 초기화가 됨

파일 생성
- 메인메소드를 가진 클래스만 public class가 될 수 있다!
+ 생성자의 접근제어자 주로 public 이다.

클래스 실행하기
1. 클래스 안에 메인메소드 넣기(독립적실행가능)
2. 메인 메소드가 있는 클래스에서 실행시켜주기

 

필드로 직접 접근하기 예제

class Korean{
	//필드
	String nation = "대한민국";
	String name;
	String ssn; //전화번호
	
	public Korean(String name, String ssn) {
		this.name = name;
		this.ssn = ssn;
	}
	
	
}

public class KoreanEx {

	public static void main(String[] args) {

		Korean k1 = new Korean("박자바","011225-1234567");
		System.out.println("k1.name : " + k1.name);
		System.out.println("k1.ssn : " + k1.ssn);
		
		Korean k2 = new Korean("김자바","930525-0654321");
		System.out.println("k2.name : " + k2.name);
		System.out.println("k2.ssn : " + k2.ssn);
	}

}

- k1객체 만든 후 k1. 통해서 필드로 접근
- k2객체 만든 후 k2. 통해서 필드로 접근
- 필드 name, ssn을 private으로 바꾸게 되면 KoreanEx클래스에서  k1.name k2.ssn 해서 접근 불가(출력 불가)
다른 클래스라서, 다이렉트 접근을 막는다

 

필드값
- nation은 "대한민국"으로 초기화
- name과 ssn은 객체를 생성할때 생성자를 통해 전달된 값으로 각각 초기화됨

할당 시점
- new연산자로 힙메모리에 새로운 공간 생성할때 힙메모리상에 새로운 공간 할당받음(참조형은 다 마찬가지)
- 자료형이 String이라서(필드값) null로 자동초기화되지만 여기선 객체생성시 생성자호출시 받는 값으로 초기화 (name,ssn)
- 주소를가진 레퍼런스 변수 : k1, k2
- 필드들 nation, name, ssn 의 접근제어자가 default이므로 같은 패키지 내는 모두 접근 가능. 그래서 다른 클래스에서 k1.ssn 가능

 

그림


자바의 접근 제어자 정리

접근제어자   자신의클래스   같은패키지                하위클래스       다른패키지

private                    O                    X                                X                    X
생략(default)          O                    O                                X                    X
protected                O                   O                                O                    X
public                      O                   O                                O                   O

+ 같은 클래스 내 : 접근 제어자 의미 없다. 뭐든 접근 된다.
- private : 오직 같은 클래스에서만 됨 , 다른 클래스에서 접근하는걸 허용하지 않음, 가장 좁은 접근허용
- public : 가장 넓은 접근 허용함, 다른 패키지(폴더) 안의 클래스까지 접근가능
- default : 중간정도 접근 범위, 같은 패키지(폴더) 내에선 다 가능
- protected : 상속관련, 상속 배우고 난후 공부

접근제어자 범위 비교
가장넓음 public > default > protected > private 가장좁음

생성자 오버로딩
- 생성자 여러개 생성
- 구분되는 점이 있어야함

생성자 오버로딩 구분
1. 매개변수 자료형
2. 매개변수 개수
3. 매개변수 순서

메소드
- 언어에 따라 함수라고도 한다
- 쓰는 이유 : 객체의 동작 + 여러개 코드를 모아두고 한번 메소드가 정의되면 호출을 통해 재사용하기 위해서

메소드 만드는법
ex) public static void main(){}
1. 접근제어자 
2. static (특별한 경우에만 쓴다,공유 원할때)
3. 자료형 / void
4. 메소드이름 + ()

+ 자바에는 정적 클래스는 없다. 
+ 정적 메소드는 흔하지 않다.

 

접근제어자 예제

 

package p2022_06_29;

class Calculator {
	// 메소드
	void powerOn() {
		System.out.println("전원을 켭니다.");
		return;
	}

	int plus(int x, int y) { // 지역변수 : x, y, result
		int result = x + y;
		return result;
//		System.out.println("test");
	}
//return문 : plus() 메소드를 호출한 곳에 값을 돌려주는 역할
//return문은 메소드 가장 마지막 줄에 사용해야한다.
	double divide(int x, int y) {
		double result = x / (double) y;
		return result;
	}
	
	void powerOff() {
		System.out.println("전원을 끕니다.");
		return;
	}

}

public class CalculatorEx {
//p217 ~ 218
	public static void main(String[] args) {

		Calculator cal = new Calculator();
		cal.powerOn();
		
		int result1 = cal.plus(5, 6);
		
		byte x = 10;
		byte y = 4;
		double result2 = cal.divide(x,y);
		System.out.println("result2 : " + result2);
		
		cal.powerOff();
	}

}

- Calculator 클래스 앞에 private 쓰면 CalculatorEx 클래스에서 객체를 만들 수 없음(클래스 접근 불가)
- Calculator 클래스의 메소드 powerOff 앞에 private쓰면 cal.powerOn() 을 할 수 없음(메소드 접근 불가)

패키지 = 폴더
- 같은 폴더 안 = 같은 패키지 안
- 서로 다른 폴더 안 = 서로 다른 패키지 안 = public만 접근가능


위 예제의 부분1

	int plus(int x, int y) { // 지역변수 : x, y, result
		int result = x + y;
		return result;
		//System.out.println("test"); 오류남
        }

+ return문 : plus() 메소드를 호출한 곳에 값을 돌려주는 역할
+ return문은 메소드 가장 마지막 줄에 사용해야한다.
- 메소드가 실행되는동안 필요한 값들을 매개변수로 전달해줌(매개변수 = 지역변수)
- 메소드 실행되는동안만 스택에 값 존재, return되면 자동으로 지워짐
- 그래서 메모리 관리 크게 신경안써도 된다.

위 예제의 부분2

	cal.powerOn();

- 메인 메소드 안에서 객체 생성하며 생성자 호출후 메소드 호출
- 필드처럼 메소드에 접근할때도 객체.메소드() 로 호출함 (정적메소드가 아닌경우)

위 예제의 부분3

	int result1 = cal.plus(5, 6);


- Call by Value로 값 전달하며 메소드 호출
- plus()는 결과를 리턴자료형 int로 돌려줌 그래서 int result1으로 받아야하는것

위 예제의 부분4 (주의)

	double divide(int x, int y) {
		double result = x / (double) y;
		return result;
	}


- 리턴자료형이 double이므로 double형 값을 돌려준다
- int형인 x와 int형인 y를 산술연산시 int형으로 처리됨
ex) x = 10 , y = 4 이면 다 잘리고 2만 나온다. (손실 발생)
- 손실 발생을 막기 위해서 (double)을 붙여줘서 강제 형변환 -> 2.5
- 그걸 double로 return 시켜줌
- (double) 을 빠뜨리면 자동형변환되어서 2 -> 2.0 이 나옴(손실발생)
- 10/4 는 2.5이므로 살리려면 (double)해서 강제형변환시켜서 값이 double로 처리되도록 해야함.

위 예제의 부분5(CalculatorEx의 main 메소드 내부)

		byte x = 10;
		byte y = 4;
		double result2 = cal.divide(x,y);
		System.out.println("result2 : " + result2);


+ byte는 1바이트 정수형 자료형
- cal.divide에서 매개변수로 byte를 넘김 -> 근데 devide 메소드의 매개변수는 int 형 4바이트 이다. 
- 4바이트짜리 변수에 1바이트 짜리 값을 할당 => 컴파일러가 자동형변환시켜줌. 큰자료형으로 작은값으로 들어가므로
- 자동형변환되어서 위 코드 가능함

+ plus와 divide 메소드의 매개변수 이름들이 같지만 그 메소드 내에서만 사용되는 지역변수이므로 충돌이 발생하지 않음

메소드의 매개변수에 참조형이 오는 예제
- 값이 아닌 주솟값을 전달해야한다.
- sum1은 배열에 전달된 값들의 합을 돌려주는 함수

package p2022_06_29;

//p220 ~ 221
class Computer {
	// 주솟값 전달에 의한 메소드 호출(Call by Reference 방식)

	int sum1(int[] values) {
		int sum = 0;
		for (int i = 0; i < values.length; i++) {
			sum += values[i];
		}
		return sum;
	}

	// vargus : 전달된 값은 배열로 받음
	int sum2(int... values) {
		int sum = 0;
		for (int i = 0; i < values.length; i++) {
			sum += values[i];
		}
		return sum;
	}

}

public class ComputerEx {

	public static void main(String[] args) {

		Computer com = new Computer();
		
		int[] values1 = { 1, 2, 3 };
		int result1 = com.sum1(values1); // sum1() 메소드 호출 , 주솟값을 가진 values1을 넘김
		System.out.println("result1 : " + result1);

		int result2 = com.sum1(new int[] { 1, 2, 3, 4, 5 }); // sum1() 메소드 호출 , 배열을 만들어서 그 주소를 넘김
		System.out.println("result2 : " + result2);

		int result3 = com.sum2(1, 2, 3); // sum2() 메소드 호출 ,
		System.out.println("result3 : " + result3);

		int result4 = com.sum2(1, 2, 3, 4, 5); // sum2() 메소드 호출 ,
		System.out.println("result4 : " + result4);

	}

}

- "같은 int형 배열"의 주소값을 써서 메소드를 호출해야함
- Computer 클래스의 참조형변수인 int[] values는 아직 주솟값이 없는 상태 , new를 써서 int형 배열을 만들어 주솟값을 가진 걸 넘겨줘야함
- 그래서 main쪽에 int형 1차원배열을 만들어줌
- sum1에서 참조형이 매개변수로 왔으므로 같은 int형 배열의 주솟값을 넘겨야함
- new연산자를 아직 안썼으므로 아직 int[] values는 가리키는게 없음 
- 주솟값 전달에 의한 메소드 호출임
+ 값전달보다 주솟값 전달이 더 효율적이고 빠른 방식임

 

vargus (...)
- ...은 vargus 라고 함
- 전달된 값들은 1개일수도 여러개일수도 있지만 전달되는 값들은 모두 배열로 받음
- 매개변수가 있으면 매개변수의 개수대로 메소드 호출시 써줘야하지만 ... 은 int값을 1개 전달하든 여러개 전달하든 모두 배열로 처리됨

 

Call by Reference
- values1 int형 배열 힙메모리상에 4바이트 공간 3개 만들어지고 1,2,3이 들어가있고, 그 걸 values1이 그 스택에서 그 배열의 주소를 가지고 있음

 

	int result1 = com.sum1(values1)

- 에서 주솟값을 담고있는 values1을 전달 = 주소를 전달 = Call by Reference
- 주솟값이 없었던 Computer 클래스의 sum1의 values는 주솟값을 전달받아서 Computer 클래스의 values는 이제 이 {1,2,3} 배열을 가리키게됨
- 합을 구해서 리턴형 int로 result1에 값을 돌려줌

- 매개변수 중에서 참조형이 오는 경우 중 클래스/인터페이스가 가장 많다(배열은 많진 않다)
- API 제공 클래스 + 사용자 정의 클래스 => 이것들도 자료형이다
- 참조형변수는 주솟값을 가진다

 

매개변수에 주소값을 전달하는 법(위 예제 부분)

int[] values1 = { 1, 2, 3 };
int result1 = com.sum1(values1); // sum1() 메소드 호출 , 주솟값을 가진 values1을 넘김
System.out.println("result1 : " + result1);

int result2 = com.sum1(new int[] { 1, 2, 3, 4, 5 }); // sum1() 메소드 호출 , 배열을 만들어서 그 주소를 넘김
System.out.println("result2 : " + result2);

1.이렇게 values1 처럼 만들어진 배열공간의 주소값을 전달하는방법이 있다.
- values1이 가진 주솟값을 전달 


2.(new int[] { 1, 2, 3, 4, 5 } 처럼 오른쪽의 new연산을 써서 새로운 공간을 만들어서 그것의 주솟값을 넘겨줄 수도 있음
- 기억공간이 만들어지고 그거의 주솟값이 sum1 메소드의 매개변수로 넘어감
- 값을 받는 변수가 없기 때문에 이건 재사용이 안된다. 이후 가비지 콜렉터가 이 힙메모리상 배열을 지워버린다.
- 더이상 이 힙메모리에 접근할수없을때 해제된다.
- 할당시점은 new를 썼을때 할당된다

 

그림

 

+ 배열 생성

int[] score = {80,90,100} // new안쓰지만 힙메모리에 데이터 개수만큼 공간 만들어짐
int[] score = new int[]{80,90,100}

 

+ 배열등의 참조형을 매개변수로 쓰는이유
- 매개변수가 100개라면?
- 값들은 힙메모리에 저장시켜놓고 주솟값만 매개변수로 전달하는게 훨씬 효율적

 

vargus(위 예제 부분)

	// vargus : 전달된 값은 배열로 받음
	int sum2(int... values) {
		int sum = 0;
		for (int i = 0; i < values.length; i++) {
			sum += values[i];
		}
		return sum;
	}

- 메소드의 매개변수가 2개면 2개 전달 1개면 1개 전달 해야했었다.
- but vargus쓰면 1개 전달하든 2개전달하든 3개전달하든 모두 매개변수로 받을 수 있다
- 전달된 값은 모두 배열로 처리됨
ex) 첫번째 전달된값은 0번방 두번째 전달된 값은 1번방...
- 다만 자료형은 맞춰줘야함 int ... values 면 몇개이든 int형 값을 전달해야함

 

		int result3 = com.sum2(1, 2, 3); // sum2() 메소드 호출 ,
		System.out.println("result3 : " + result3);

- 1,2,3을 sum2로 전달하면 values가 1,2,3 을 배열로 저장함
- 전달된값들은 "같은 int형 배열"로 처리됨
- 자주쓰는 기능은 아님

 

		int result4 = com.sum2(1, 2, 3, 4, 5); // sum2() 메소드 호출 ,
		System.out.println("result4 : " + result4);

- 로 하면 1,2,3,4,5를 넘기고 배열로 받아서 처리해줌

 

메소드안에서 다른 메소드를 호출하기
- 여태껏은 메인메소드안에서만 메소드를 호출했었다
- 이젠 main 메소드가 아닌 일반 메소드안에서 다른 메소드를 호출해보자

 

package p2022_06_29;

// p227
// 클래스 내부에서 메소드 호출 : 메소드 안에서 다른 메소드 호출
class Calculator1 {
	int plus(int x, int y) {
		int result = x + y; //17
		return result;
	}

	double avg(int x, int y) {
		double sum = plus(x, y); // plus() 메소드 호출
		double result = sum / 2;
		return result;
	}

	void execute() {
		double result = avg(7, 10); //avg() 메소드 호출
		println("실행결과 : " + result); //println() 메세지 호출
	}

	void println(String message) {
		System.out.println(message);
		return;
	}
}

public class CalculatorEx1 {

	public static void main(String[] args) {

		Calculator1 mycal = new Calculator1();
		mycal.execute(); // execute() 메소드 호출
//		execute(); //오류발생
	}

}

1. 메인메소드에서 메소드 호출시
- 객체.메소드() 해서 메소드를 호출해야함

ex)

		Calculator1 mycal = new Calculator1();
		mycal.execute(); // execute() 메소드 호출
//		execute(); //오류발생

 

2. 일반메소드에서 메소드 호출시(같은 클래스 내부)
- 객체.메소드() 가 아니라 객체없이 그냥 메소드() 만으로 호출 가능하다!

ex)

		double result = avg(7, 10);

- avg() 메소드 호출 그냥 avg(7,10)만으로 호출했음

 

위 예제 흐름
- JVM이 main메소드 실행 -> mycal.execute() 호출함-> execute()이 실행됨
-> 그 메소드에서 avg메소드를 호출하면서 매개변수를 7, 10 넘겨줌
-> avg 매개변수의 x에 7, y에 10이 들어감, avg에서 다시 plus() 메소드를 7,10을 넘겨주며 호출
-> plus() 메소드에서 합을 구해서 합을 result 해서 plus()를 "호출"한곳에 값을 돌려줌 즉 avg로 돌아감
-> 그걸 avg의 sum이 받아서 %2 한뒤 돌려줌
- (주의) plus()가 돌려줄땐 int형인 17을 돌려줌, 근데 sum을 double로 받았으므로 17.0 해서 /2 해서 8.5가 result가 됨
-> 그 8.5 값을 avg를 호출한 execute()에 돌려줌, 그걸 println()메소드에 결과값을 넘겨서
-> println()이 출력시킴

+ 자바는 객체지향언어라서 호출할 메소드가 뒤에있어도 상관없다
+ execute() 아래 println() 있지만 execute()에서 println() 호출가능
+ 일반 메소드끼리는 메소드 이름만으로 서로를 호출한다

 

메소드 오버로딩(Method Overloading)
- 1개의 클래스 안에 동일한 이름을 가진 메소드를 여러개 정의하는 것.
- 생성자 오버로딩 처럼 메소드도 한개의 클래스 안에 동일한 이름의 클래스 여러개 정의할 수 있다

메소드 오버로딩 구분하는 법
1. 매개변수 자료형
2. 매개변수 개수
3. 매개변수들의 순서

- 한가지를 이상을 만족해서 구분이 되어야만 올바르게 메소드 오버로딩 시킨것임
* 나중에 메소드 오버라이딩과의 차이를 알아야 한다. 완전히 다른 개념
+ 메소드 오버라이딩 : 두 클래스 사이에 상속이 정의되어야만 사용가능

String 클래스 (API 문서)
- 필드 생성자 메소드 순
- 필드 : 메서드 바깥쪽에 정의되는 변수

- 생성자 : 클래스명과 동일, 형식상 괄호가 반드시 있다
- 매개변수가 없는 생성자는 기본생성자
- 나머지는 클래스명과 동일하게 생성자가 만들어지는데 구분이 되도록 정의됨
-> 생성자 오버로딩

- 메소드도 똑같은 이름을 가진 메소드들이 있다
ex) copyValueOf(char[] data) 와 copyValueOf(char[] data, int offset, int count)
- equlas 메소드, format 메소드들은 같은이름인 메소드가 여러개다 -> 메소드 오버로딩

 

메소드 오버로딩

class Calculator2{
	//정사각형의 면적을 구해주는 메소드
	double areaRectangle(double width) {
		return width * width;
	}
	//직사각형의 면적을 구해주는 메소드
	double areaRectangle(double width, double height) {
		return width * height;
	}
}

- 메소드가 같은 이름이다
- 매개변수가 1개인 areaRectangle 과 매개변수가 2개인 areaRectangle
- 매개변수의 개수가 다르므로 올바르게 메소드 오버로딩 되었음
- 매개변수 1개 전달하면 매개변수 1개인 areaRectangle() 이 호출되고 2개 전달하면 매개변수 2개인 areaRectanble()이 호출됨
- 메소드 오버로딩은 아무 언어나 되는게 아니라 객체지향언어만됨(c++,java는 되고 c는 안됨)

 

앞으로 공부할 내용

1. static이 붙은 정적 필드(정적변수)
2. static이 붙은 정적 메소드

변수
지역변수
멤버변수
정적변수
중에서 정적변수를 하는 것이다

3. 상수를 만드는 법 (Constant)
- final을 붙이거나 static final 을 붙인다
- 기존 변수에 final 붙이면 상수가 되는것
- final을 클래스, 필드, 메소드 에 붙일 수 있다-> 어디에 붙이냐에 따라 의미가 달라짐
4.접근제한자와 패키지 의 관계
5. getter와 setter 메소드

 

정적 필드 (정적 변수)

- static 이 붙은 변수 

ex)

static int a; // 그냥 변수앞에 static을 붙이면 정적변수가 됨

- static : 공유를 목적으로 해서 누구나 쉽게 접근하도록 만들때만 static 붙인 정적 필드형태로 만듬
- API 보면 클래스들 정적필드, 메소드들 정적메소드들 엄청 많다


ex) Math 클래스안엔 정적필드랑 정적메소드뿐
- 정적 필드는 클래스명.필드 로 사용
- 누구나 쉽게 생성할수있도록 따로 객체생성없이 클래스명.필드로 사용함

 

ex) 

int n = Integer.parseInt(String s);

- 에서 parseInt는 정적메소드라서 이렇게 클래스명.parseInt()로 사용함
- 세번째 변수인 정적멤버변수(정적 필드)
- 정적 필드 = 정적 멤버변수 = 정적 변수
- 메모리상에 할당되는 시점과 저장되는 영역이 (지역변수,멤버변수, 정적변수) 다 다르다(잠시 후 공부)

 

Math 클래스(정적 필드/메소드 예시)
- 내부에 정적 필드 뿐이다
- 정적필드 정적메소드 뿐
- 정적필드 E , PI 는 Math.E 로 접근가능
- 정적 메소드 , 정적 필드뿐이라 객체 생성할 필요가 없음
- math클래스는 생성자가 아무것도 없다 -> 생성자 자체를 못씀
- random() 메소드의 타입은 static double이다. 즉 정적메소드이고 리턴값이 double
- 정적 메소드 이므로 Math.random()으로 사용할수있다

 

정적변수의 메모리 할당 시점/장소
- 할당 시점 : 정적 멤버변수는 클래스가 메모리에 로딩되면(실행될때) 할당됨 
- 초기화 : 자동으로 설정되고 (정수형 0 실수형 0.0 논리형 false)
- 값 유지 : 프로그램이 종료될때까지 값을 유지한다
- 저장 영역 : 메모리의 static영역 (공유영역)에 자동으로 할당됨
- 저장 영역 : 공유영역 = 메소드영역 = static 영역 <->힙,스택과 다름
- 주의 : 장 오래 메모리에 상주하므로 많이쓰면 메모리가 부족해짐, 특별한경우아니면 만들지 않음

+ 특별한 경우, 반드시 정적멤버변수 만들어야하는 경우
- 싱글톤 : 객체생성을 1번만 하는 것, 이 경우엔 정적필드를 만들어야함

자동초기화
- 정적멤버변수는 자동초기화 된다.
- 배열과 마찬가지로 int는 0 , double 은 0.0, boolean은 false로 초기화 된다.
- 메소드영역에 값을 저장하고 한번 저장된값은 프로그램이 완전히 종료될때까지 값을 유지

정적 멤버변수에 접근하는 방법
- 정적 변수를 가지고 있는 클래스명으로 직접 접근 할 수 있다.

class StaticTest{
satic int a;

public static void main(String[] args) {
	System.out.println(StaticTest.a)
	}
}

- 정적메소드 사용시 클래스명.메소드()

 

정적 필드 / 정적 메소드 정리
- 정적 필드 = static이 붙은 변수
- 정적 메소드 = static이 붙은 메소드
- static이 붙은 필드를 가진 클래스가 로딩이 되면 이 정적필드는 메소드 영역에 저장이되고
자료형에 따라 기본자료형 변수들은 자동초기화됨

 

정적 멤버변수 만드는 법

- static 붙이기
- 예제 : NoneObject.java/UseNoneObject.java / UseNoneObject.java에만 메인메소드 있음

package p2022_06_29;

public class NoneObject {
    static int number = 3; // 정적 필드
    
    public static void printNumber() { // 정적 메소드
        System.out.println("number = " + number);
    }
}

- 메인메소드없으므로 독립적 실행은 안됨,
- 정적필드하나 정적메소드 하나 있는 NoneObject 클래스
- 이 클래스의 필드에 접근하고 메소드를 호출해보자

package p2022_06_29;

public class UseNoneObject {

    public static void main( String[] args ) {
    
//이 방식 잘 안쓴다
    NoneObject no = new NoneObject();
    System.out.println("no.number = " + no.number);
    no.printNumber();
    
//아래방식을 주로 쓴다
    System.out.println("NoneObject.number = " + 
					NoneObject.number);
    NoneObject.printNumber();
    
    }
}
출력
no.number = 3
number = 3
NoneObject.number = 3
number = 3

- NoneObject 클래스는 정적필드와 정적메소드를 가지고 있다
- UseNoneObject 클래스에서 접근할때 객체를 생성한 후 필드와 메소드를 사용할 수도 있지만
- 정적 필드와 정적메소드이므로 이렇게 안쓴다 (가능은 하지만 안쓴다)
- 필드 접근/메소드 호출하는 법 : NoneObject 클래스에서 .을 찍어서 정적필드, 정적메소드 로 접근

 

정적 필드 / 정적 메소드 접근 정리
- 누구나 쓸수있도록 하려고 static 붙인거임-> 객체생성해서 접근하지 않는다
- 결론 : 정적필드 , 정적메소드는 클래스명.필드, 클래스명.메소드() 해서 접근해라

정적 필드의 자동초기화
- 예제 : NoneObject.java 파일

package p2022_06_29;

public class NoneObject {
    static int number = 3; // 정적 필드
    
    public static void printNumber() { // 정적 메소드
        System.out.println("number = " + number);
    }
}

- 에서 static int number 에 3 초기화 안시킨다면?
- 자동으로 0으로 초기화시켜주므로 UseNoneObject 에서 실행해보면 0으로 출력됨

정적 멤버변수의 메모리 할당/해제(위 예제)
- NoneObject클래스가 로딩되자마자 number는 공유영역에 저장되면서 int형이니 0으로 초기화됨
- number의 값은 프로그램 종료시까지 계속 메모리에 상주함
- static 정적 필드 많이쓰면 메모리 부족

객체를 생성해서 정적필드/정적메소드에 접근(위 예제 부분)

//이 방식 잘 안쓴다
    NoneObject no = new NoneObject();
    System.out.println("no.number = " + no.number);
    no.printNumber();

- 가능은 하다
Q. 그럼 이때 new를 쓰면 정적필드는 어디로 저장될까? (질문하기) -> 그래도 메소드 영역

 

메모리 정리
- 힙 메모리에 저장 : JVM 시작할때 생성, 객체와  배열 저장, 가비지 콜랙터가 참조되지 않는 즉, 사용될수 없는 객체 제거
- 메소드영역 메모리 : static이 붙은 필드를 가진 클래스가 로딩이 되면 이 정적필드는 메소드 영역에 저장이됨.

 

static 필드의 의미(그 안의 값)

정적 필드 값의 유지 예시1 : StaticCount.java, Shared.java / 메인메소드는 Shared 클래스에만 있다

package p2022_06_29;

public class StaticCount {
    static int number = 3;
}

- 정적 필드 하나만 있다. 프로그램 종료까지 값을 계속 유지함
- 정적필드는 싱글톤을 만들때만 주로 쓴다. 객체를 1개만 생성해서 공유를 한다는 개념인 싱글톤

package p2022_06_29;

public class Shared {
    public static void main( String[] args ) {
    
        StaticCount sc1 = new StaticCount();
        System.out.println("sc1.number = " + sc1.number); //3
        
        sc1.number++;
        System.out.println("sc1.number = " + sc1.number); //4
        
        StaticCount sc2 = new StaticCount();
        System.out.println("sc2.number = " + sc2.number); //4
        
        sc2.number++;
        System.out.println("sc2.number = " + sc2.number); //5

        StaticCount.number ++;
        System.out.println("StaticCount.number = " + StaticCount.number); //6
    }
}
출력
sc1.number = 3
sc1.number = 4
sc2.number = 4
sc2.number = 5
StaticCount.number = 6

- 에서 StaticCount 클래스로 sc1라는 객체를 만들었음 
- (정적필드, 정적메소드 가진 클래스로 객체 만드는건 자주안하지만 가능하긴 함)
- sc1을 통해서 접근 된다!

 

값의 변화(값이 유지됨)
1. 처음 sc1.number 출력했더니 3 을 출력함 = 초기값이 3임
2. sc1.number++; 해서 sc1통해서 증가시킴 
3. sc1.number 출력시 4를 출력함

- 그 후 같은 StaticCount로 sc2 라는 새로운 객체도 만듬

4. 근데 힙메모리 영역이 아니라 메소드 영역이라는 공유영역이기 떄문에 sc2.number로 sc2에 접근해서 출력해도 number는 3이 아닌 가장 마지막에 저장한 값 4를 출력시킴
5. sc2.number 로 또 접근해서 ++ 증가시킴
6. sc2.number 출력시 5를 출력

- 마지막엔 객체가 아닌 StaticCount.number 로, 즉 클래스 명으로 접근한다 
6. StaticCount.number 를 ++
7. 출력하면 6이 나옴

 

정적 필드 값의 유지 예시2 : StaticTest01.java

package p2022_06_29;

class StaticTest {
	static int a = 10; // 정적 필드 : 메소드영역(공유영역) 에 저장
	int b = 20; // 인스턴스 멤버변수 : heap 메모리에 저장
}

class StaticTest01 {
	public static void main(String[] args) {
		System.out.println("StaticTest.a->" + StaticTest.a);
		StaticTest s1 = new StaticTest();
		StaticTest s2 = new StaticTest();

		System.out.println("s1.a->" + s1.a + "\t  s2.a->" + s2.a);
		System.out.println("s1.b->" + s1.b + "\t  s2.b->" + s2.b);

		s1.a = 100;
		System.out.print("s1.a->" + s1.a);
		System.out.println("\t  s2.a->" + s2.a + "  ");
		System.out.println(StaticTest.a);

		s1.b = 200;
		System.out.print("s1.b->" + s1.b);
		System.out.println("\t  s2.b->" + s2.b);
	}
}

- StaticTest01이 메인메소드가지고 있다
- StaticTest 클래스에는 static 정적 변수 1개, 일반적인 필드 1개 이렇게 있다
- 이런 일반적인 필드 는 instance 변수 또는 instance 필드 라고 부름
- 즉 a는 정적필드 b는 인스턴스필드

정적필드와 인스턴스 필드 비교
- StaicTest.a 는 정적필드기 때문에 클래스명. 으로 접근 가능
- 이때 초기값이 10으로 있기떄문에 10으로 출력됨

- 그 후 StaticTest 클래스로 new해서 객체 2개를 생성함 s1, s2
- new연산자로 할떄마다 힙메모리상에 새로운 공간을 할당받음
- 그래서 인스턴스 멤버변수인 b는 힙 메모리상에 할당받음
- 정적 변수인 a는 그대로 공유 영역에 있음

현재 상태
     a=10     //정적 멤버변수
 (공유영역)

s1             ------->  b=20
s2             ------->   b=20
                               
(Stack영역)                 (Heap영역)    


초기 상태
- b는 s1의 b, s2의 b 각각 있고, 힙메모리 상에 20으로 각각 있다.
- 이 값의 주소를 s1, s2가 스택메모리에서 갖고 있음

- a는 정적멤버변수라서 공유영역(메소드영역) 에 초기값 10을 저장하고 있는 상태
- 그래서 s1.a, s2.a는 10으로 출력됨 s1.b나 s2.b는 20으로 출력됨

변화
- s1.a 에 접근해서 값을 100으로 수정함
- s1.b 에 접근해서 값을 200으로 수정함

    a=100     //정적멤버변수
 (공유영역)

s1             ------->  b=200
s2             ------->   b=20
                               
(Stack영역)                 (Heap영역)   

변화된 상태
-  s1.a 와 s2.a 모두 출력시 100이 나옴
- 또한 클래스명으로 접근한 StaticTest.a  해도 100이 출력됨
- 즉 a는 가장 마지막으로 저장된 값이 공유됨

- s1.b만 200으로 수정됨(공유 안됨)
- s1.b를 출력하면 200, s2.b를 출력하면 20이 나옴

정적필드와 인스턴스 필드의 비교
- 정적 필드들은 마지막에 저장된 값을 계속 공유함
- 인스턴스 필드들은 클래스를 가지고 객체 생성할때마다 힙 공간 할당받으며 각각 초기값을 가지게 됨

정적 필드와 접근제어자 예제 : StaticTest02,03,04

StaticTest02.java
 
package p2022_06_29;

class StaticTest2 {
	private static int a = 10; // 정적 필드
	private int b = 20; // 인스턴스 필드

	public static void setA(int new_a) { // 정적 메소드
		a = new_a;
	}

	public static int getA() { // 정적 메소드
		return a;
	}
}

public class StaticTest02 {
	public static void main(String[] args) {
		//  System.out.println(StaticTest2.a); //a가 private으로 선언되어서 컴파일 에러 발생 
		System.out.println(StaticTest2.getA());

		StaticTest2 s1 = new StaticTest2();
		StaticTest2 s2 = new StaticTest2();

		s1.setA(10000);
		int res1 = s1.getA();
		System.out.println(res1);
		System.out.println(s2.getA());
	}
}
출력
10
10000
10000

- StaticTest2.a 로 접근이 안된다. 
- 이유 : 아무리 정적필드라도 외부클래스의 접근을 허용하지 않는 private 이 a 앞에 붙어서 다른 클래스인 StaticTest02 에서 접근시 에러 생김

 

private static int a = 10;

 

- 모순이 발생한다
- static은 공유를 하겠다는거고 private은 보호를 하는거라서 컴파일상 오류를 발생시키며 접근이 불가능하다.
- 결과적으로는 클래스명으로 접근하는 것이 허용되지 않음

 

private인 static 필드값 가져오는 방법
- getA() 메소드를 이용해서 접근한다
- getA() 메소드는 정적 메소드이고 public 이라 클래스명으로 접근가능하다\
ex)

System.out.println(StaticTest2.getA());

- 가능하다, 10이 출력됨

 

private인 static 필드값 설정하는 방법 (위 예제 부분)

		StaticTest2 s1 = new StaticTest2();
		StaticTest2 s2 = new StaticTest2();

		s1.setA(10000);
		int res1 = s1.getA();
		System.out.println(res1);
		System.out.println(s2.getA());

- StaticTest2로 새로운 객체 2개  s1, s2 생성함
- setA 메소드는 public static 이라 호출 가능하다. 클래스명으로 접근 가능하지만 이렇게 s1.setA(10000)처럼 객체로 접근도 되긴함
- s1.set(10000)으로 a값을 10000으로 셋팅
- s1.getA() 해서 접근도 되고, s2.getA() 해서도 됨 둘다 출력시 10000 됨

정적 필드와 접근제어자 결론
- private static하면 모순이 생겨서 결국은 다른 클래스에서 접근 못하는 필드임
- 그래서 StaticTest2.a가 에러생김(다른 클래스에서 호출하였기 떄문에)
-> private이 붙으면 정적 static 필드라도 다른 클래스에서 접근이 불가능함

정적 필드와 접근제어자 주의
- 정적 메소드 안에는 정적 필드만 사용가능함 (중요)
- 정적 메소드 안에 일반적인 필드 쓰면 오류발생 (저장영역과 기능이 다르기 떄문에)
- 정적메소드와 일반메소드는 기능이 다름

 

정적 필드 / 정적 메소드 주의 예제1 : StaticTest03

package p2022_06_29;

class StaticTest3 {
	private static int a = 10; // 정적 필드
	private int b = 20;

	public static void printA() { // 정적 메서드에서는 this를 사용하지 못함
		System.out.println(a);
		// System.out.println(b); //정적메소드 안에는 일반적인 필드 사용불가
		// System.out.println(this.a); //컴파일 에러 발생

	}

	public void printB() { // this는 인스턴스 메서드에서 여러 객체에 의해서
		System.out.println(b); // 메서드가 호출될 때 이를 구분하기 위해서 사용된다.
	}
}

public class StaticTest03 {
	public static void main(String[] args) {
		StaticTest3.printA();
		StaticTest3 s1 = new StaticTest3();
		StaticTest3 s2 = new StaticTest3();
		s1.printB();
		s2.printB();
	}
}

정적메소드를 쓸 때 주의사항


1. 정적 메소드에서는 this 레퍼런스 변수를 사용할 수 없다.
- this.는 힙메모리의 주소를 참조하는게 this.이고, this.는 개별적인 객체에 대한 주소를 가진 레퍼런스 변수라서 정적메소드 안에선 this. 를 사용할 수 없다


2. 정적 메소드에서는 일반적인 변수(인스턴스 필드)를 사용할 수 없다.
- 정적 메소드에서는 정적멤버변수만 사용가능함
- 일반적인 필드 = 힙메모리 이고,  정적필드 = 메소드 메모리(영역) 이라서 영역이 다르기 때문


3. 정적 메소드는 메소드 오버라이딩되지 않는다.
- static이 붙은 정적메소드는 메소드 오버라이딩이 되지 않는다.

 

+ 메소드 오버라이딩 : 두 클래스 사이 상속관계가 있을때, 부모로부터 상속되는 필드와 메소드 중, 메소드를 상속받을때, 이름과 형식은 똑같이 하면서 내부 내용은 다르게 쓰는 것.

정적 필드 / 정적 메소드 주의 예제2 : StaticTest04

package p2022_06_29;

class StaticTest4 {
	private static int a = 10; // 정적필드
	private int b = 20;

	public static void printA() {
		System.out.println(a);
//    System.out.println(b);   //컴파일 에러 발생 : 정적메소드 안 일반필드
	}

	public void printB() {
		System.out.println(b);
	}
}

public class StaticTest04 {
	public static void main(String[] args) {
		StaticTest4.printA();
		StaticTest4 s1 = new StaticTest4();
		StaticTest4 s2 = new StaticTest4();
		s1.printB();
		s2.printB();
	}
}

- 정적메소드 안에는 정적필드만 사용가능하다
- 일반 메소드 안에서만 일반필드 사용가능
- 정적 메소드 , 정적 필드는 클래스명. 해서 사용함 !    StaticTest4.printA();  
- 하지만 객체를 만들어서 객체.메소드 해서도 메소드 호출가능, 객체.필드 해서 필드 접근하는것도 가능

    StaticTest4 s1 = new StaticTest4();
    StaticTest4 s2 = new StaticTest4();
    s1.printB();
    s2.printB();

 

Math 클래스 (API 문서)

- 모두 정적필드 뿐
- 모두 정적메소드 뿐
- Math 클래스를 가지고 정적 필드와 정적메소드를 사용해보자

Math의 정적필드 2개
- E
- PI

Math의 생성자
- 생성자 자체가 없다
- 생성자는 제공되지 않는데 쓸수없다 Math 클래스로 new해서 객체생성하면 오류발생

Math의 메소드
- 모두 static 붙은 정적 메소드 -> 굳이 객체를 생성할 필요도 없다
- 그냥 Math.E , Math.random() 으로 쓰면됨

Math 클래스의 필드 사용 예제
+ Math라는 이름으로 사용자 지정 클래스 생성할 수 없다. 라이브러리에 이미 쓰고 있는 이름이라서

		System.out.println("E = " + Math.E);
		System.out.println("PI = " + Math.PI);

- Math클래스는 생성자가 제공되지 않기때문에 Math 클래스로 직접 객체를 생성할 수 없다
- 하지만 Math 클래스 = 정적 필드 + 정적 메소드 뿐이라서 객체 없어도 아무 문제 없음

Math 클래스 메소드 사용 예제(다양한 메소드 사용)

 

1. abs() 메소드
- 절대값을 구해서 결과를 돌려줌 
- abs() 메소드 여러개임 (메소드 오버로딩) , int, double, long, float등 타입별로 존재

	System.out.println("abs() = " + Math.abs(-10)); //절대값 , 결과는 10

 

2. ceil() 메소드
- 안에있는 소수점 이하 값을 무조건 올려버림 (올림) , 소수 첫째자리에서 올림함

	System.out.println("ceil() = " + Math.ceil(3.14)); //올림, 출력은 4.0

 

3. round() 메소드
- 반올림을 해주는 메소드
- 소수첫째자리에서 반올림해주고 결과는 long으로 돌려줌 11이 나옴 
- 매개변수 double, 반환은 long

	System.out.println("round() = " + Math.round(10.5)); //반올림, 출력은 11

 

4. floor() 메소드
- 무조건 내림을 해주는 메소드
- 소수점 이하는 다 버림, 매개변수 double, 반환은 double 
- 10.9 -> 10.0

	System.out.println("floor() = " + Math.floor(10.9)); //내림, 출력은 10.0

 

5. max() 메소드
- 최대값을 구해주는 메소드
- 메소드 오버로딩이 되어있다

ex) max(int a, int b) , max(double a, double b) 등
- 2개짜리 매개변수 있는 메소드들만 있다
- 자바에는 2개짜리만 제공함 -> 3개 이상이 필요하면 내가 만들어서 써야함 (파이썬은 제한 없음)
- 10과 20중 큰 값을 return 구문으로 돌려줌

		System.out.println("max() = " + Math.max(10, 20)); // 최대값 , 출력은 20

 

5. min() 메소드
- 최솟값을 구해주는 메소드
- 메소드 오버로딩이 되어있다
- min메소드도 2개짜리 매개변수 있는 메소드들만 있다

		System.out.println("min() = " + Math.min(10, 20)); // 최솟값, 출력 : 10

 

6. pow() 메소드
- 지수를 구할때 사용한다.
ex) 2의 3승 구할때 쓰는 메소드 Math.pow(2,3);
- pow(double a, double b) 이고 리턴은 double 형

		System.out.println("pow() = " + Math.pow(2,3)); // 2의 3승 , 출력은 8.0

 

7. random() 메소드
- 양수값으로 0.0보다 크거나같고 1.0보다 작은 범위의 실수형태의 난수 리턴
- 0.0 <= Math.random() < 1.0 범위의 난수 발생
- double형으로 리턴

		System.out.println("random() = " + Math.random());

 

8. sqrt() 메소드
- 제곱근을 구해주는 메소드
- 루트를 씌운값을 돌려줌
- 리턴은 double
ex) 루트5를 구할때 쓰는 메소드 Math.sqrt(5);

		System.out.println("sqrt() = " + Math.sqrt(5)); //루트5(제곱근5) , 출력은 2.23606...

 

우리가 쓰는 println() 의 구조

System.out.println("");

- System 클래스의 필드를보면 모두 정적필드
- 객체생성안하고 System.out으로 썼었던 이유 : 정적필드 중 out 이 있다
- out이 정적필드이기때문에 System.out을 쓴다

- 이 out이란 필드의 결과를 돌려주는 자료형이 PrintStream 이 리턴형이다 (객체로서 리턴)
- 즉 System.out은 자료형이 PrintStream이라는 자료형
- 이 PrintSteram 클래스를 찾아보면 println / print / printf 메소드가 들어있다(정적 메소드 아님)

+ void println()이 메소드 오버로딩되어있다. ex) void println(int i), void println(char x) 등

우리가 쓰는 Scanner 객체 생성하고 안에 System.in 썼던 이유
- Scanner 클래스를 찾아보면 Scanner(InputStream source)라는 생성자 가 있다.
- Scanner 생성자의 매개변수가 InputStream 타입이라서
- Scanner 객체 생성할때 생성자의 매개변수가 System.in 이었다
- System.in의 리턴형을 보면 InputStream 이다
+ in은 static이 붙은 정적필드라서 System.in 이라고 쓴다.

변수의 종류
1. 지역변수
2. 멤버변수
3. 정적변수

지역변수
- 메소드 안에서 정의되고 안에서 사용되는 변수
- 기본자료형일때 메소드 호출시에 스택메모리에 할당되고, 메소드 실행이 종료되면 자동으로 메모리가 해제됨

멤버변수 (= 필드 = 전역변수)
- 메소드 바깥쪽에 정의되는 변수
- 기본자료형 멤버변수는 heap 메모리 영역에 저장됨.
- 그 클래스(생성자,메소드)안에서 모두 사용이 가능함 = 전역변수
- 자동으로 초기화 됨
- 참조형을 이용해서 new 연산자로 객체를 생성시 heap 메모리 영역에 새로운 공간을 할당받는데, 그 공간이 멤버변수를 위한 공간
- 가비지 콜렉터가 필요없는 힙메모리상의 변수들을 지워줌

변수와 메모리
- 기본자료형 && 지역변수 -> 스택 메모리
- 기본자료형 && 멤버변수 -> 힙 메모리
- 참조형 && 지역변수 -> 힙 메모리에 값, 스택 메모리에 주소값
- 참조형 && 멤버변수 -> (아직 모름)

클래스 형태의 자료형
ex) Animal클래스는 클래스 형태의 자료형이다.
- 사용자가 만들어쓰는 자료형이다

클래스
- 필드
- 생성자
- 메소드

접근제어자를 사용하는 곳
- 클래스
(클래스를 구성하는)
- 필드
- 생성자
- 메소드

접근제어자 역할
- 외부 클래스에서의 접근을 막을지 허용할지 설정

생성자의 역할
- 객체를 생성할때 호출되면서 이 필드값을 원하는 값으로 초기화 시키는 역할

생성자 종류
- 매개변수가 없는 생성자 = 기본생성자
- 매개변수가 있는 생성자

생성자와 메소드의 구분
1. 생성자 앞에는 접근제어자만 온다! 
2. 생성자는 클래스명과 동일한 이름

필드의 역할
- 변수기 때문에 값을 저장하는 역할만 함

메소드
- 기능이 가장 많음
- 동적인걸 표현함

필드의 초기화
- 배열처럼 필드는 자동 초기화가 된다. (int는 0으로 초기화)

사용자정의 클래스 예시

Animal a1 = new Animal();


- Animal은 클래스 자료형
- a1은 레퍼런스 변수
- new는 연산자
- Animal() 은 생성자를 호출함

생성자 안만들면
- 컴파일러가 자동으로 기본생성자 만들고 호출

+ 생성자 만들었을땐
- 매개변수가 있는 생성자를 만들면 기본생성자는 자동으로 만들어지지않음
- 만들어진 생성자들만 사용가능

생성자 호출하는 방법
1. 객체를 생성할때 호출됨
2. this()를 통해 호출할 수도 있음

필드 접근
- 객체.필드 로 접근
ex) a1.age 처럼 .으로 접근 가능하다
ex) age만으로 접근 불가능하다
- 힙메모리의 필드에 접근하기 위해서는 반드시 주솟값을 가지고 있는 a1으로 참조해서만 접근 가능

파일과 클래스
- 한개의 소스파일안에 클래스 여러개 작성해도 나중에 바이트 코드는 따로 만들어짐
ex) 한개의 파일안에 클래스가 2개들어가는 예제 CarEx

파일명
- public 접근 제어자는 메인 메소드를 가진 클래스만 쓸 수 있고 그 클래스와 파일명이 같아야함
- 하나의 소스파일에는 public class 가 하나만 올 수 있고 public class명과 파일명이 같아야함

 

예제

 

class Car {
	// 필드(field)
	String company = "현대 자동차"; //주어진 초기값
	String model = "그랜저";
	String color = "검정";
	int maxSpeed = 350;
	int speed;

	// 생성자(Constructor)
	public Car() {// 기본 생성자

		System.out.println("생성자 호출 성공");
	}
}

public class CarEx {
	public static void main(String[] args) {

		// 객체 생성
		Car mycar = new Car();
		System.out.println("제작회사 : " + mycar.company);
		System.out.println("모델명 : " + mycar.model);
		System.out.println("색깔 : " + mycar.color);
		System.out.println("최고속도 : " + mycar.maxSpeed);
		System.out.println("현재속도 : " + mycar.speed);

		// 필드값 변경
		mycar.speed = 60;
		System.out.println("수정된 속도 : " + mycar.speed); // 60

	}

}

- 선언과동시에 초기화가 되지 않은 speed는 , 객체가 생성되어 힙메모리상에 speed 공간이 생성될때
0으로 초기화 된다
- Car()은 생성자가 아니라 생성자를 호출하는 거임

그림

 

의미있는 객체 vs 의미없는 객체

- main 메소드를 가진 CarEx 클래스로 객체를 만들면? -> 만들어지지만 의미 없는 객체
- 멤버(필드,생성자,메소드) 가 있는 클래스로 객체를 만들어야 의미있는 클래스이다.

 

생성자 호출하는 방법
1. 객체를 생성할때 호출됨
2. this()를 통해 호출할 수도 있음
-  99%는 클래스로 객체를 생성할때 생성자가 호출됨

 

ex)

		// 객체 생성
		Car mycar = new Car(); //객체를 생성할때 생성자가 호출된다.
		CarEx car = new CarEx(); // 의미 없는 객체

필드 수정하기

 

		// 필드값 변경
		mycar.speed = 60;

- 필드는 객체를 통해서 접근해야한다.

 

지역변수와 필드의 생성과 소멸
- 지역변수는 메서드 호출시 생성, 메소드 종료시 삭제
- 필드는 클래스로 객체를 생성할때 new 연산자를 통해 힙공간에 공간 할당받고, 나중에 이 공간을
참조할 수 있는 주소가 더이상 없을때 가비지 콜렉터가 이걸 쓰레기로 인식하고
힙메모리상의 그 공간을 지워버림

필드 = 멤버변수
- 기본자료형들은 자동으로 초기값이 설정됨 ex) boolean 은 false로
- 클래스,배열, 인터페이스들은 참조할 주소가 없다는 의미인 null 로 초기화됨. 
- 필드는 힙메모리상에 저장됨

 

//p303
class FieldInitValue{
	//필드
	byte byteField;
	short shortField;
	int intField;
	long longField;
	
	float floatField;
	float doubleField;
	
	char charField;
	boolean booleanField;
	
	int[] arrField;
	String referenceField;
}
public class FieldEx {

	public static void main(String[] args) {

		FieldInitValue f = new FieldInitValue();
		
		System.out.println("byteField : " + f.byteField);
		System.out.println("shortField : " + f.shortField);
		System.out.println("intField : " + f.intField);
		System.out.println("longField : " + f.longField);
		
		System.out.println("floatField : " + f.floatField);
		System.out.println("doubleField : " + f.doubleField);
		
		System.out.println("charField : " + f.charField);
		System.out.println("booleanField : " + f.booleanField);
		
		System.out.println("intField : " + f.arrField);
		System.out.println("stringField : " + f.referenceField);
		
		
	}

}

출력값

byteField : 0
shortField : 0
intField : 0
longField : 0
floatField : 0.0
doubleField : 0.0
charField :

 

초기화 값
- 정수형은 0으로 초기화
- 실수형은 0.0으로 초기화
- char 필드는 은 초기화 안된다
- 논리형 필드는 false로 초기화
- 배열과 클래스 필드는 null로 초기화 된다
* null : 참조할 주소가 없다는 의미

Q. 참조형이 필드일때 즉 String 클래스가 필드로서 있을때 이걸 어떻게 할당하나?
A. f.referenceField = "자바" 

해제시점
- f처럼 그 객체 공간을 힙메모리상에 있는 그 개게 공간을 가리키고 있는 참조 변수가 있으면 괜찮다.
- f처럼 그 공간을 가리키고있는 참조 변수가 없으면 가비지 콜렉터가 자동으로 그 힙메모리의 공간을 지움
- 그때가 해제되는 시점임 

생성자
- 생성자 앞에는 접근제어자만 온다
- 생성자를 통해서 내가 원하는 초기값을 그 객체의 필드로 초기화 시킬 수 있다
- 매개변수가 있는 필드 만들어서 할 수 있다
- 객체가 생성될때 호출되어 필드들을 초기화 시키는 역할만 함
- 기본생성자는 객체가 생성될때 컴파일러가 자동으로 생성해준다

클래스명 주의
- 동일한 패키지 안에 같은 이름의 클래스가 있을땐 오류 발생
- 동일한 패키지 = 동일한 폴더 내
- .class 라는 바이트코드는 따로 만들어지는데 같은 이름인 파일이 이미 있으므로 
- 메인메소드를 가진 클래스명으로 파일명을 일치시켜야함 = 메인메소드를 가진 클래스만 public class 일 수 있어서
- 메인메소드가 없다면 public을 가진 class 명과 일치시켜야함

 

클래스 예시 (MyDate Class)

package p2022_06_28;

class MyDate {
	private int year; // 필드
	private int month;
	private int day;

	public MyDate() { // 기본생성자(Default Constructor)
		System.out.println("[생성자] : 객체가 생성될 때 자동 호출됩니다.");
	}

	public void print() {
		System.out.println(year + "/" + month + "/" + day);
	}
}// MyDate end

public class ConstructorTest02 {
	public static void main(String[] args) {
		MyDate d = new MyDate();
		d.print();
// 접근제어자가 private 이기 때문에 외부 클래스에서 직접 접근할 수 없다.
//	System.out.println(d.year);
//	MyDate dd =  new MyDate();
	}
}

 

1. MyDate Class 필드
- MyDate Class의 필드들 접근제어자가 private이다.
2. MyDate Class 생성자
- 생성자가 1개 있다. 생성자 이름은 클래스명과 같고 앞엔 접근제어자만 있다
- 매개변수가 없는 생성자 = 기본생성자
3. MyDate Class 메소드
- static이 없다 
- 대부분의 메소드는 static 안쓴다
- 나중에 싱클톤 만들땐 정적 메소드 형태로 만듬
- void가 있으므로 return;필요없음

메소드가 하는일 3가지
- 필드값을 출력하는 일
- 필드값을 수정하는 일
- 메소드앞엔 자료값이 오기때문에 호출했을때 값을 돌려주는 역할도 가능

클래스의 실행 정리
- 메인메소드가 없는 MyDate 클래스는 main메소드가 안에 없기때문에 독립적인 실행은 불가능하고
컴파일까지만 가능
- 실행하려면 메인메소드를 추가하든지 메인메소드를 가진 클래스에서 실행을 해줘야한다.
- 클래스 내에서 자기 자신의 클래스로 객체를 만드는거 -> 의미없다
- 필드/생성자/메소드 가진 클래스로 객체 만들어야 의미있다.

 

MyDate d = new MyDate();

- new는 myDate 의 필드들을 저장할 공간을 힙메모리에 생성함
- 그리고 그 공간을 자동으로 0으로 초기화함
- 즉 year month day 의 값을 힙에 저장하기 위한 공간을 생성
- 그림

 

객체 생성시점 벌어지는 일
- 접근제어자와 상관없이 year month day는 초기값 0으로 설정
- myDate() 생성자를 호출하라는 코드로 인해 생성자 호출됨, 그 생성자로 가서 실행을 함(여기선 출력)

필드값 접근(출력)방법1
- d.year d.month d.day 로 접근시 여기선 오류가 발생한다
- private을 필드 앞에 붙이면 외부 클래스의 접근을 허용하지 않기때문에 d.year 처럼 필드에 접근이 불가능하다

필드값 접근(출력)방법2
- 메소드를 활용하는 방법을 사용해야함!
- 메소드 앞의 접근 제어자가 public인 print() 메소드를 이용하면 필드값을 출력 가능하다 d.print(); 로 필드값을 출력한다.

접근제어자와 클래스
- 필드는 private이지만 private은 같은 클래스내에서는 접근이 된다
- 그래서 MyDate안 클래스 안의 print() 메소드는 필드들에 접근이 가능한것이다.
- 가장 좁은 접근 private 가장 넓은 접근 public 이다
- public은 모두 접근 가능, 클래스나 패키지 달라도, 같은 파일이든 다른 파일이든 다 접근 가능
- private 같은 클래스 내에서만 접근 허용

생성자
- 생성자는 필드를 초기화하는 역할
- 0 대신 원하는값으로 초기화시켜야할때 생성자에서 초기화해준다

메소드
- 값을 돌려주기도 하고 수정하기도 하고 출력하기도 함

 

접근제어자
- public : 다른 패키지에서도 접근 가능
- default : 동일 패키지 내에서만 접근 가능
- protected : 상속 받은 클래스에서 접근 가능
- private : 자기 클래스에서만 접근 가능(정보은닉)

 

클래스 예시(기본생성자로 초기화)

package p2022_06_28;

class MyDate03 {
	// 필드
	private int year;
	private int month;
	private int day;

	// 생성자 : 객체를 생성할때 생성자가 호출되고, 필드값을 초기화 시켜주는 역할
	public MyDate03() { // 기본 생성자
		year = 2016;
		month = 4;
		day = 1;
	}

	public void print() { // 메소드
		System.out.println(year + "/" + month + "/" + day);
	}
}// MyDate end

public class ConstructorTest03 {
	public static void main(String[] args) {
		MyDate03 d = new MyDate03();
//    				생성자호출
		d.print();
	}
}

- 필드값이 생성자가 호출되기 전에는 0으로 모두 초기화 되었었지만
- 생성자를 호출하면서 2016 4 1 로 바뀜
- 원하는 값으로 초기값을 설정하고 싶으면 생성자를 씀

 

매개변수를 가진 생성자 예시
- 기본생성자가 아니라 매개변수를 가진 생성자
- 생성자는 기본생성자든 매개변수를 가지든 필드값을 초기화시키는 역할임 

 

클래스 예시(매개변수가 있는 생성자로 초기화)

package p2022_06_28;

class MyDate05 {
	private int year; // 필드
	private int month;
	private int day;

	public MyDate05() { // 기본생성자
	}

	public MyDate05(int new_year, int new_month, int new_day) { // 매개변수가진 생성자
		year = new_year;
		month = new_month;
		day = new_day;
	}

	public void print() { // 메소드
		System.out.println(year + "/" + month + "/" + day);
	}
}

public class ConstructorTest05 {
	public static void main(String[] args) {
		MyDate05 d = new MyDate05();
		d.print();

		MyDate05 d2 = new MyDate05(2017, 7, 19);
		// 매개변수가 있는 생성자 호출
		d2.print();
	}
}

- 기본생성자를 주석처리하면 아래에 있는  MyDate05 d=new MyDate05();  가 오류생김
- 매개변수를 가진 생성자를 만들땐 컴파일러가 기본생성자 만들어주지 않기때문에!
- 내가 아무 생성자도 안썼을떄만 기본생성자 생성해줌

 

기본생성자 자동생성 정리
- 기본생성자는 객체 생성할때 컴파일러가 자동으로 만들어 주지만,
- 예외적으로, 매개변수를 가진 생성자가 있을 경우에는 더이상 기본 생성자를 만들어 주지 않는다.
-> 원하면 내가 기본생성자도 써야함!

매개변수를 가진 생성자
- 매개변수가 있는 생성자를 쓸때 매개변수에 원하는 값 써서 초기화 
- 객체 생성할때마다 그 객체의 필드를 초기화
- 매개변수를 가진 생성자를 호출

    MyDate05 d2=new MyDate05(2017, 7, 19);
    d2.print();

- 생성자가 호출될때 생성자의 매개변수는 지역변수다.

	  public MyDate05(int new_year, int new_month, int new_day){	//매개변수가진 생성자
   			 year=new_year;
   			 month=new_month;
  			  day=new_day;
  		}
		MyDate05 d = new MyDate05();
		d.print();

    		MyDate05 d2=new MyDate05(2017, 7, 19);
    		//매개변수가 있는 생성자 호출
    		d2.print();

- 필드값을 초기화 하고 있다
- 이렇게 필드랑 이름이 다를때는 상관없지만 필드와 이 생성자의 매개변수가 이름이 같을때는  this 연산자사용(곧 공부)
- print()메소드는 필드값을 출력하는용도로 사용되고 있다.public 메소드라서 다른 메소드에서 접근 가능하다
- 2017이 new_year로, 7이 new_month로, 19가 new_day로 가서 이걸 생성자에서 year= new_year; 필드값을 원하는 값으로 초기값 설정 가능

 

호출과정
1. 한 파일 내 두개의 클래스는 이미 컴파일이 된 상태
2. JVM은 가장 먼저 main을 실행함
3. 이때 MyDate05 의 객체인 d 생성함.
4. 기본생성자를 호출함
5. 힙에 필드위한 기억공간/필드값 자동 초기화

+ 매개변수 있는 생성자 있는경우엔 기본생성자 만들어둬야함 
+ 안에 아무 내용없어도 형식이라도 만들어둬야함

 

그림



매개변수와 필드의 이름이 같은 경우
- 매개변수의 값이 필드를 초기화 할 수 없음
- 오류가 생기진 않는다.
- 필드(멤버변수) 쪽에 this. 라고 붙여야함, this. 가 있으면 이름이 같아도 값 대입 가능

 

this. 예제

 

package p2022_06_28;

class MyDate04{   
  int year;    
  int month;    
  int day;  

  public MyDate04(){
    year=2016;    month=4;    day=1;
  }
 
  public MyDate04(int year,int month,int day){
   this.year=year;
   this.month=month;
   this.day=day;
  }
  public void print(){
	System.out.println(year+ "/" +month+ "/" +day); 
  }
}// MyDate end

public class ConstructorTest04 {     
  public static void main(String[] args) {
    MyDate04 d=new MyDate04();	//1생성자호출
    System.out.println(d.year); //바로 접근해서 출력
    System.out.println(d.month);
    System.out.println(d.day);
    d.print(); //메소드통해 출력

    MyDate04 d2=new MyDate04(2017, 7, 19);
    System.out.println(d2.year); //바로 접근해서 출력
    System.out.println(d2.month);
    System.out.println(d2.day);
    d2.print();
  }
}

d객체
- 여기 필드는 디폴트 접근제어자이므로 d.year로 바로 접근해서 출력 ㅏㄱ능
- 메소드 통해서 출력하는 방법되 있다.
- '//1생성자호출'에서 기본생성자를 호출해서 year=2016,month=4,day=1 로 초기화됨

d2객체
- 또다시 heap 상에서 새로운 공간을 생성함.
- 이 공간은 d2객체의 필드들을 저장하기 위한 공간이다

this.
- 내부 레퍼런스 변수
- this는 그 객체 를 의미함
- 객체 생성되어 매개변수 있는 생성자 호출할 때, 이 객체 d2가 가진 주솟값을 갖는게 this다
- 즉 this == d2를 의미한다 ( d2를 받는다 )
- 사용법 : this.필드 = 매개변수
- 생성자 안에서 멤버변수와 매개변수가 이름이 동일한 경우에 사용

- d2객체를 생성했을 때, 매개변수를 3개 가진 생성자를 호출한다, 그럼 year month day 값은 2017, 7, 19 로 설정이 된다.
- d2가 이 것들을 가리키고 있는데 this는 이 d2가 가리키는 것들을 똑같이 가리킨다 
- 즉 d2랑 this는 같은 주소를 갖고 있다
- d2.year == this.year
+ this. 을 안썼다고 오류가 생기진 않지만 매개변수의 값이 필드로 들어가지 않음 (값전달이안됨)-> 출력시 다 0이 나오는걸로 알 수 있다

 

그림



생성자의 매개변수로 멤버변수값 초기화하는법
1. 멤버변수와 매개변수의 이름을 다르게 설정
2. 멤버변수와 매개변수의 이름이 같고, 멤버변수 앞에 this를 붙인다.

생성자의 사용법
- 객체마다 언제나 같은 값으로 필드값 다 같게 설정할땐 기본생성자를 사용하고
- 객체가 생성될때마다 초기화할 값을(필드를) 다 다르게 설정하기 위해선 매개변수가 있는 생성자를 사용하는것임!

메소드가 하는 일
- 필드값을 수정, 출력, 필드값을 돌려주기

이클립스 생성자 만들기 기능
- 이클립스에 생성자 만들어주는 기능이 있다
- 오른쪽마우스 -> Source -> Generate Constructor using Fields
- Insertion point : 생성자가 들어갈 위치 지정
- Omit call to default constructor super() : 생성자 내부에 super()를 생략하기 위해서 체크(상속 공부한 뒤 공부)
- 자동으로 생성된 생성자에도 this 사용한다


this. 정리
- 생성자에서도 사용가능하고 메소드에서도 사용가능! (메소드에서 this.쓰는거 곧 한다)
- 생성자와 메소드 안에서 멤버변수와 매개변수 이름이 동일한 경우에 주로 사용함
- ex)

public Test(int a, int b) {
	this.a = a;
	this.b = b;
}


this() 정리
- 같은 클래스안에 있는 생성자를 호출할때 사용함(다른 클래스의 생성자는 안됨)
- 객체를 생성할때만 생성자를 호출할 수 있는게 아니라 this()를 통해서도 생성자를 호출 할 수도 있다.
- this()는 많이 쓰이진 않음

+ 상속 공부 후 super. , super() 를 배울것

메소드를 통해 필드값을 set 시키는 예제 (MyDate06/ConstructorTest06)

- 생성자를 통해서 객체를 생성할 때 필드값을 초기화 시킬 수 있다.
- 하지만 "중간에" 어떤 필드값 하나를 수정하고 싶을떄 생성자는 그 역할을 할 수 없다
- 생성자는 객체 호출시에 실행되므로
-> 중간에 변경하고 싶을때 메소드를 통해서 필드값 수정할 수 있다

메소드 역할 정리
1. 필드값 출력
2. 필드값 수정/변경 (생성자는 못함) -> set
3. 리턴자료형을 통해서 필드값을 돌려주는 역할도 함 (메소드 호출한곳으로 돌려줌) -> get

 

package p2022_06_28;

class MyDate06 {
	private int year; // 필드
	private int month;
	private int day;

//  public MyDate(){	//default 생성자
//  }  
	public MyDate06(int new_year, int new_month, int new_day) {
		year = new_year; // 2017
		month = new_month; // 7
		day = new_day; // 19
	}

	public int getYear() {
		return year;
	}

	public void setYear(int year) {
		this.year = year;
	}

	public int getMonth() {
		return month;
	}

	public void setMonth(int month) {
		this.month = month;
	}

	public int getDay() {
		return day;
	}

	public void setDay(int day) {
		this.day = day;
	}

	public void print() {
		System.out.println(year + "/" + month + "/" + day);
	}
}

public class ConstructorTest06 {
	public static void main(String[] args) {

		MyDate06 d = new MyDate06(2017, 7, 19);
		d.print();

		d.setYear(2022);
		d.setMonth(6);
		d.setDay(28);
		d.print();

		System.out.println("year : " + d.getYear());
		System.out.println("month : " + d.getMonth());
		System.out.println("day : " + d.getDay());
	}
}

- 필드값들은 private
- 디폴트생성자는 쓰는 일이없으면 안만들어도됨
- 생성자로 필드값을 초기화 하고 있다
- 연도값을 수정하고 싶을땐? -> 생성자가 할수없다 메소드가 해야함 -> 메소드로 수정
- 다른 클래스에 있는 main에서 호출 하여 필드값 수정할 것이므로 메소드 접근제어자는 public / default 여야한다. 

 

그림


메소드에서 this. 사용
- setYear 메소드에서 필드와 매게변수가 또 같은 이름이다
- 매개변수값이 필드에 안들어감 즉 수정이안됨
-> 수정 위해서는 this.를 붙여줘야함
- 생성자도 그렇고 메소드 안에서도 this. 쓸 수 있다.

메소드를 통한 필드값 수정 정리
- 생성자통해 필드값 수정변경 불가능
- 또 다른 객체를 생성하면서 새로운 공간을 만들지 않도록 주의
- 기존값을 수정하기위해선 메소드를 이용해야한다

이클립스 필드값 수정해주는 메소드 생성
- 오른쪽 버튼 -> Source -> Generate Getters and Setters

Sort by
- Fields in getter/setter pairs : getYear setYear getMonth setMonth  순서
- First getters the setters : getYear getMonth setYear setMonth 순서

getters 와 setters
- set으로 시작하는 메소드를 setters 메소드
- get으로 시작하는 메소드를 getters 메소드
- getters method : getYear(), getMonth(), getDay()
- setters method : setYear(), setMonth(), setDay()

setters
- 필드값을 매개변수로 전달된 값으로 설정/수정하기 위한 메소드이다
- 생성자는 객체 생성시에 초기값 설정할떄만 가능한거고 변경은 setters 메소드로 해야한다

getters
- 이 getters 메소드 앞에 있는 자료형에 맞게 값을 돌려주는데 생성자에의해 할당되거나 수정된 필드값을 값을 호출한 곳으로 돌려줌
ex) getYear() 은 year 란 필드값을 돌려줌 return year;

this() 사용 예제
- this() : 같은 클래스 안에 있는 생성자를 호출하라는 의미로 사용됨

class MyDate10{   

  private int year;    
  private int month;    
  private int day;

  public MyDate10(){
    this(2016, 1, 1);                   
  }  
  public MyDate10(int new_year){
    this(new_year, 1, 1);                
  }  
  public MyDate10(int new_year, int new_month){
     this(new_year, new_month, 1);    
  }  
  public MyDate10(int new_year,int new_month,int new_day){
    year=new_year;
    month=new_month;
    day=new_day;
  }    

  public void print(){
	System.out.println(year+ "/" +month+ "/" +day); 
  }
}

public class ConstructorTest10 {     
  public static void main(String[] args) {
    MyDate10 d=new MyDate10(2017, 7, 19);  
    d.print();
    MyDate10 d2=new MyDate10(2017, 7);     
    d2.print();
    MyDate10 d3=new MyDate10(2017);       
    d3.print();
    MyDate10 d4=new MyDate10();          
    d4.print();
  }
}

생성자 호출
- MyDate06 예제에서 클래스의 객체를 만들 때는 다른 클래스에서 만든다
- 즉, MyDate06 예제에서 생성자를 호출 할 때는 다른 클래스의 생성자를 호출 했다.
- 일반적으로 다른 클래스의 생성자 호출도 가능하고 같은 클래스의 생성자 호출도 가능하다
ex) ConstructorTest10 클래스안의 main 메소드 안에서 MyDate10 d = new MyDate10(2017,7,19) 
하는건 MyDate10 클래스 안의 생성자 즉 다른 클래스의 생성자를 호출한거임
- 하지만 this() 는 같은 클래스 안에 있는 생성자만 호출할 수 있다

 

위 예제 생성자 부분만 보기

  public MyDate10(){
    this(2016, 1, 1);                   
  }  
  public MyDate10(int new_year){
    this(new_year, 1, 1);                
  }  
  public MyDate10(int new_year, int new_month){
     this(new_year, new_month, 1);    
  }  
  public MyDate10(int new_year,int new_month,int new_day){
    year=new_year;
    month=new_month;
    day=new_day;
  }

생성자 오버로딩
- 여기서 MyDate10 생성자가 4개다
- 생성자 이름이 같아도 구분이 된다면 같은 이름의 생성자가 여러개 있어도 됨
- 한개의 클래스 안에 여러개의 생성자를 만드는 것 = 생성자 오버로딩 (생성자의 이름은 클래스명이랑 같아야한다)

생성자 오버로딩을 위한 구분
1. 매개변수의 자료형을 다르게 하는법
2. 매개변수의 개수를 다르게 하는법
3. 매개변수가 여러개있을때 순서를 바꾸는방법! 도 된다. 자료형,개수 같아도 순서가 다르면 구분됨

+ MyDate10 클래스에선 생성자의 구분을 매개변수의 개수 로 하고 있다.

 

위 예제 설명

    MyDate10 d2=new MyDate10(2017, 7);     
    d2.print();

1. 여기서 MyDate10(2017,7) 을 할 때, 매개변수가 2개인 생성자가 위에있다

  public MyDate10(int new_year, int new_month){
     this(new_year, new_month, 1);    
  }

2. 로 가서 위의 this(new_year, new_month, 1);  가

  public MyDate10(int new_year,int new_month,int new_day){
    year=new_year;
    month=new_month;
    day=new_day;
  }

3. 인 매개변수가 3개인 생성자를 부르면서 (new_year, new_month, 1) 를 매개변수로 전달
+ 이 매개변수가 3개인 생성자가 있어야만 this(2017,7, 1); 이게 가능한거임

MyDate10 d3=new MyDate10(2017);

- 시에

  public MyDate10(int new_year){
    this(new_year, 1, 1);                
  }

- 이 생성자가 호출되서 여기서 다시 this()로 매개변수가 3개인 생성자를 호출 하면서 (2017,1,1)값을 전달

+

  MyDate10 d4=new MyDate10();

- 를 main에 쓰면

  public MyDate10(){ //기본생성자
    this(2016, 1, 1);                   
  }

- 여기로 가서 this() 통해서 매개변수가 3개인 생성자 다시 호출하면서 매개변수로 값을 2016,1,1 넘겨줌

 

생성자 오버로딩 예시(String 클래스 by api 문서)
String 클래스의 생성자
- 모두 전부 이름이 String 이고 매개변수 부분이 다르다. = "생성자 오버로딩"
- 생성자 호출할때 구분이 가능해야 생성자 오버로딩이 잘 된거임
- 우리는 String(String original) 생성자를 사용

자료형과 메모리

- 기본자료형 && 지역변수 -> 스택에 저장됨, 자동으로 초기값이 설정되지 않음.
- 기본자료형 && 멤버변수/정적변수 -> 아직 안함
- 참조형 -> 값은 힙메모리에 저장됨
- 기본자료형이라도 참조형이면 자료형에 따라 자동 초기화
- 클래스들도 필드들이 자동 초기화됨

 

new 연산자

- String 클래스를 제외한 클래스, 배열, 인터페이스는 필수적으로 new 연산자 사용함
- 힙에 새로운 공간을 형성하라는 표시

 

참조형

- 클래스, 배열, 인터페이스, 열거타입(잘 쓰지 않음)
- 값이 힙메모리에 저장됨, 그 값이 저장된 영역의 시작주소를 스택메모리에서 가짐
- 힙메모리 : 동적으로 계속 공간을 늘릴 수 있는 특징

 

메모리 영역

- 스택 메모리 영역
- 힙 메모리 영역
- 메소드 메모리 영역

 

참조형

+ 인터페이스(자료구조)
- 대표적인게 List

 

배열 정리

- 동일한 자료형만 저장가능한 정적인 자료구조
- 정적 자료구조 = 크기가 딱 정해져 있음. new int[3] 하면 딱 3개만 생성
- 배열이름.length 속성 : 배열의 크기 = 배열 방의 개수 

 

배열 매개변수 예시1
- 메소드의 매개변수가 기본자료형이 아니라 참조형 중 배열일때

 

public static void main(String[] args) {

		int[] scores; // 여기 int[] scores ; 는 아직 주소를 가지지 않은 상태

		scores = new int[] { 83, 90, 87 };

		// int[] scores = new int[] {83,90,87}

		int sum1 = 0;
		for (int i = 0; i < 3; i++) {
			sum1 += scores[i];
		}
		System.out.println("총합 : " + sum1);

		// add 메소드를 호출해서, 리턴된 총합을 sum2에 저장
		int sum2 = add(new int[] { 83, 90, 87 });
		System.out.println("총합 : " + sum2);

	} // main() end

	// 사용자 정의 메소드 : 합을 구해주는 메소드 : 배열을 매개변수로
	public static int add(int[] scores) {
		int sum = 0;
		for (int i = 0; i < scores.length; i++) {
			sum += scores[i];
		}
		return sum;
	}

- int[] scores 는 주솟값을 가지지 못한 형태다
- 메소드의 매개변수가 참조형 중 배열이다.
- 이땐 배열의 주솟값을 전달해야함
- Call by Reference 방식으로 호출해야한다.
- 이 int 형 배열의 주솟값을 전달하자
- 매개변수자리에 클래스, 배열, 인터페이스 다 올 수 있다.

 

배열 매개변수 주의(위 예제의 부분)

 

	public static int add(int[] scores) {
		int sum = 0;
		for (int i = 0; i < scores.length; i++) {
			sum += scores[i];
		}
		return sum;
	}


	public static void main(String[] args) {

		int[] scores; // 여기 int[] scores ; 는 아직 주소를 가지지 않은 상태
	}

- main의 int[] scores 는 주솟값을 가지지 못한 형태다
- new 연산자를 써야만 새로운 공간을 힙메모리에 할당받는데 아직 안썼으므로
아직 주솟값이 없는 상태
- add함수로 전달하는 건 주솟값을 전달해야함 = Call by Reference

 

	public static void main(String[] args) {
		int sum2 = add(new int[] { 83, 90, 87 });
	}

- 이 경우엔 리턴받는게 없으니 이 공간은 재사용을 못한다
- 이렇게 해서 new를 써서 add 메소드로 주솟값을 전달함
- 힙 메모리 상에 있는 "같은 자료형 "(여기선 int형) 배열의 주솟값을 전달해야함
- new를 쓸때마다 새 공간이므로 이 sum2가 가리키는 new의 공간이랑 맨 위에 scores 이 가리키는 공간은 다른 주소이다
- 힙메모리상에 불필요하게 공간을 사용하는건 Garbage Collector 프로그램이 주소를 전달한 뒤 자동으로 지워버림 = 재사용 불가

 

+ 값 전달하는거보다 주솟값을 전달하는게 처리가 빠르다
+ C언어에선 이걸 포인터로 전달함

 

참조형인 매개변수 정리
- 주솟값을 할당받기 위해선 반드시 new 연산자가 있어야함
- String s= "자바" 가 가능하므로 String s 가 매개변수로 올때만 예외적으로 바로 check("자바") 로 호출 가능
- 또는 String s = new String("파이썬") 도 가능하므로 check(new String("파이썬") 으로 호출해도 된다.
- 다른 참조형 변수는 99% new를 써야함

메소드 정리
- 메소드 앞에는 return 자료형이 반드시 와야함
- 정적메소드이기 때문에 클래스명.add 또는 같은 클래스 내에선 .add 로 생략하고도 쓸수있다
- 정적메소드 아니면 객체를 생성후 호출해야한다.

배열 초기화 정리
- int뿐아니라 정수형 배열들은 다 0 으로 초기화 됨(char제외)
- 실수는 float 는 0.0f double 은 0.0
- 클래스/인터페이스/배열은 null로 초기화
* null : 주솟값이 없다는 의미


확장 for문 = 향상된 for문
- 순차적인 자료구조인 배열, 리스트같은 곳의 원소를 끄집어낼때 사용함
- 배열에 있는 값을 원소값이 더이상 없을떄까지 하나씩 왼쪽의 변수로 옮김
- 간결하기때문에 자주 씀

 

for( 타입 변수 : 순차적인 자료구조(배열,컬렉션)) {
             실행문 ;
}

* 타입변수 : 전달 받을 값 
* 컬렉션 = 자료구조(여기선 순차적인 자료구조를 의미), 대표적인게 리스트

 

확장 for문 예제

		int[] score = { 95, 71, 84, 93, 87 };


		// 확장 for문
		int sum1 = 0;
		for(int s : score) {
			sum1 += s;
		}

- 값을 받는 변수 s 도 배열의 자료형과 같은 int 형으로 받아야함
- score 배열에 들은 원소(값)들을 왼쪽의 s변수에 하나씩 전달, 이걸 원소값이 없을때까지 반복한다
- 전달된 값을 sum1 변수에 누적 

+ 순차적인 자료구조 :List, Vector
+ stack은 순차적인 자료구조 아님 다른 방식

 

main 메소드의 매개변수

- public static void main(String[] args){}
- JVM에서 여태껏 main 실행할때 아무 값 전달하지 않았음
- 하지만 전달 할 수도 있다.
- 전달시 args[0]에 첫번째 값이, args[1]에 두번째 값이 들어감
- String 자료형이므로 숫자를 적어도 문자로 처리됨

 

main 메소드의 매개변수 활용

package p2022_06_27;

public class ArrayEx07 {

	// 절대값을 구해주는 메소드
	static int abs(int data) {
		if (data < 0)
			data = -data;
		return data;
	}

	public static void main(String[] args) {

	// args[0] = "-10", args[1] = "-20"
		System.out.println("args[0] : " + args[0]);
		System.out.println("args[1] : " + args[1]);
	// args[0] = "-10" ---> -10 : 형변환(int로)
		int num = Integer.parseInt(args[0]);
		System.out.println("절대값 : " + abs(num));
	}

}

- 이 코드를 그냥 실행시 오류
- main 메소드 통해서 값을 전달할땐 그냥 실행시 오류가 생김
- 실행시키는 방법이 다름 ! (자주 쓰는건 아니지만 알아두기)

 

이클립스로 실행법
1. RUN 초록 화살표 버튼 마우스 대고 있으면  Run Configuration  메뉴 잇다
2. 두번째 탭인 arguments 선택
3. 위칸 program arguments 에서 -10 -20 을 입력(뛰어쓰기로 args[0] args[1] 값 구분)

- args[0]에 -10, args[1]에 -20 이 전달됨
- (-10)을 써도 String[] 이 매개변수이므로 문자인 "-10" 인것임
+이클립스가 아닌 콘솔창 자바 가상머신에서 실행시

java ArrayEx07 -10 -20

- 이렇게 실행함


의미 설명

1. java : 자바 가상머신 JVM
2. ArrayEx07 :ArrayEx07.class 란 바이트 코드를 실행함
3. -10 -20 이렇게 구분해서 입력

 

- args[0]에 -10, args[1]에 -20 이 전달됨
- (-10)을 써도 String[] 이 매개변수이므로 문자인 "-10" 인것임

 

자료형 변환

- 형변환된 값을 abs 메소드에 전달해야하는데 abs는 매개변수가 int 형이므로 그래서 문자를 숫자로 일단 변경하고 메소드 호출해야함.
-이걸 절대값 구할때는 args[]에 들은 데이터는 String은 문자열 이므로 int 로 바꿔야함
- "-10"을 숫자 -10 으로 바꿀땐 

int num = Integer.parseInt(args[0]); // 자주씀 외우기

- 자바의 3가지 자료형 변환 중 두번째 자료형 변환 방법임

 

Wrapper 클래스 (자료형 변환 원리)

- 기본자료형마다 Wrapper 클래스가 있다 .
- Integer 는 int 의 wrapper 클래스임
- 그래서 Integer.parseInt("20") 을 사용해서 문자 20을 숫자 20으로 변환
- Wrapper 클래스를 쓰면 기본자료형과 참조형 사이의 자료형 변환이 가능하다 (ex) string <-> int)
- 모두 java.lang 패키지안에 있어서 import 필요없다
-  Wrapper 클래스 쓰면 다른 자료형으로 쉽게 변환 가능

 

Wrapper Class

- boolean 은 Boolean
- byte 는 Byte
- char 은 Character
- int는 Integer

 

Wrapper 클래스를 이용한 변환 방법 2가지
1.

 int num = Integer.parseInt("20")


- pasreInt는 정적메소드라서 따로 객체 생성없이 클래스명. 으로 호출 parse() 안에는 String 자료형
2. 

Integer in01 = new Integer("20");
int num01 - int01.intValue();


- 언박싱

wrapper클래스의 주요 2가지 기능
1. String -> int (이게 거의 대부분임)
2. int -> String ex) String s - String.valueOf(20);

Integer 클래스 구조 (api 문서)
java.lang.Object
java.lang.Number
java.lang.Integer
- 최상위 클래스 = 슈퍼클래스는 Object
- 부모 클래스는 Number
- 상속 관계가 이미 다 형성되어있다.


1. Integer 의 필드(변수, 상수 의 개념)
- MAX_VALUE 쓰면 int형 변수가 가질 수 있는 최대값을 구해줌(정적필드) 약 +21억
- MIN_VALUE 스면 int형 변수가 가질 수 있는 최솟값을 구해줌


2. Integer 의 생성자
- 2개뿐


3. Integer의 메소드
- 메소드 중 pasreInt 는 2개가 있다 = 메소드 오버로딩
* 메소드 오버로딩 에서 이름은 같아도 매개변수등 구분이 되어야 잘 사용한것
- parseInt (String s) : 우리가 쓴 메소드 . 타입은 static int다 정적메소드이므로 Integer.parseInt로 사용하고, int 형 변수에 결과를 저장해서 돌려줌 매개변수 안엔 String 형만 들어가야함
- parseInt (String s, int radix) 도 있다.

+ 오라클등의 DB 연동할때 java.lang.Class 클래스 사용


배열을 복사하기
- 여러 방법 있다
1. for문
2. System.arrayCopy() 메소드
3. Arrays 클래스 이용

 

for문으로 배열 복사하기

public class ArrayEx08 {

	public static void main(String[] args) {

	//p167~p168
	//배열 복사 : for문으로 배열 복사
		
		int[] oldArray = {10,20,30}; //원본 배열
		int[] newArray = new int[5]; //새로운 배열
		
		for (int i = 0; i < oldArray.length; i++) {
			newArray[i] = oldArray[i]; //배열 복사
		}
		
		//복사된 배열 출력
		for(int i : newArray) {
			System.out.print(i + "\t");
		}
	}

}

- newArray는 배열이므로 0으로 다 초기화 된 상태
- oldArray -> newArray 로 복사할때 for문돌아가면서 10이 newArray[0] 으로 20이 newArra[1]으로 30이 newArray[2]로 복사됨
- 한줄 엔터키를 안쓰고 그냥 띄우기나 \t를 쓸때는 println이 아니라 print인점 주의

 

위 예제 그림

2차원 배열 정의방법 2가지

1.

int[][] score = new int[5][3];

- 메모리상에 값 저장위한 기억공간만 생성하고 그 값이 아직 뭔지 모를때 사용
- 2차원배열은 [][]처럼 2개임, [][]가 score 뒤에 가도 됨
- new란 연산자를 쓰는 형식
- 왼쪽, 오른쪽 자료형 같은걸로 맞추기
- 첫번째 괄호에 들어가는건 행의 수 (가로방향)
- 두번째 괄호에 들어가는건 열의 수 (세로방향)
- 4바이트짜리 기억공간을 행 5, 열 3으로 15개 생성하라는 뜻. 5행 3열짜리 기억공간 생성 

 

그림

2.

int[][] score = {{0,0,0},{0,0,0},{0,0,0}};

- 값이 고정되어있을때 쓰는 방식

 

예시

 

int [][] score = { { 85,  60,  70},      //0 행
	            { 90,  95,  80},       //1 행
	            { 75,  80, 100},       //2 행
                    { 80,  70,  95},       //3 행
	            {100,  65,  80} };     //4 행

- 0행 0열에 85, 4행 2열에 80이 들어감

 

2차원 배열 인덱스
- 행 = row = 가로번호
- 열 = colume = 세로번호
- 행 번호는 가로번호 의미
- 배열에 인덱스는 0번부터니까

배열 인덱스 예시

score[0][0] = 85; //0행0열에 85점을 할당하라
score[4][2] = 80; //4행2열에 80점을 할당하라

 

2차원 배열 입력/출력

 

public class Arr04 {

  public static void main(String[] args) {
   
    int [][]score = { { 85,  60,  70},   //0 행 = 1번학생
			{ 90,  95,  80},   //1 행 = 2번학생
			{ 75,  80, 100},   //2 행 = 3번학생  
                        { 80,  70,  95},   //3 행 = 4번학생
			{100,  65,  80}    //4 행 = 5번학생
					};
    int [] subject = new int[3]; //과목총점 저장할 1차원 배열
    int [] student = new int[5]; //학생의 총점 저장
        //    subject[0]=0, student[0]=0;
    int  r, c;  
	    
    System.out.println("각 과목별 총점구하기 "); //열방향으로 다 합쳐야
    for(c = 0; c < 3 ; c++){ // 과목         
      for(r = 0; r < 5 ; r++){ //학생      
        subject[c] += score[r][c];   
      }//subject[c]=subject[c]+score[r][c];
      System.out.println(subject[c]);  
    }

    System.out.println("학생별 총점구하기");
    for(r = 0; r < 5 ; r++){    //학생      
      for(c = 0; c < 3 ; c++){  //과목    
        student[r] += score[r][c];  
      }//student[r]=student[r]+score[r][c];
      System.out.println(student[r]);
    }

  }//main() end
}// class end

- 행 열을 따로 처리해야하므로 중첩 for문을 쓴다
- 행번호는 0~4이기 때문에 for문으로 0부터 시작해서 <5까지 즉 4까지 함, == 학생수는 5명
- 그 학생 당 과목 성적을 위해서 안쪽 for문으로 0부터 2까지 3번 돌림 == 과목수 3개(국영수)
- 행과 열이 만나는 곳의 점수를 출력하면 score[row][col]
- 더 빨리 바뀌는 부분이 for문의 안쪽에 와야함 나중에 움직이는 부분이 바깥쪽에
- 과목 총점 구하기는 [0][0] [1][0] [2][0] ... 을 더해야하고 ->과목은 열이기 때문에 for문 안쪽에 r 가 와야함
- 학생별 총점 구하기는 [0][0] [0][1] [0][2] ... 를 더해야함 -> 학생은 행이기 때문에 for문 안쪽에 c가 와야함
- int [] subject = new int [3] 이나 int [] student = new int[5]; 는 자동초기화 0 이므로 sum = 0 같은
번거로운일 할 필요 X

 


객체지향언어

 

클래스
- 클래스도 자료형이다
- 배열과 메모리상 처리는 거의 비슷함

String 클래스
- 클래스 중에서 쉽게 이해할 수 있는 String 클래스로 예시들어서 설명
- 클래스 중 사용빈도 가장 높음

String 클래스와 메모리
- String 클래스로 String 객체를 만든다
- 객체를 만들면 배열과 마찬가지로 문자열 " " 들은 모두 힙메모리상에 저장됨(참조형이 가지는 공통적인 특징)
- 그 메모리의 시작주소값을 변수가 스택에서 가지고 있다

 

String name;
name = "신용권"

- 그냥 이름을 저장하는것같아 보이지만 "신용권"은 힙의 공간에 저장, 그 주소를 가진 name은 스택에서 주소를 가지고 있다.

 

String 클래스와 메모리2
- String 클래스의 경우에는 문자를 바로 할당해도 되고 new 연산자를 사용해도 된다
- 이 두가지 되는건 String 밖에 없다
- 보통의 클래스는 new 연산자를 써서만 객체 만들어야함
- 하지만 new 연산 썼을때와 쓰지 않았을때 메모리에 차이가 있다.

String name1 = "신용권";
String name2 = "신용권";

- new 연산자를 쓰지 않고 만들면 처음 한번은 "신용권"을 저장한 기억공간을 힙메모리에 만듬
- 두번째의 경우에는 새로운 공간 만들지 않고 이미 "신용권"이 저장된 공간의 주솟값을 리턴받음
- name1 == name2 주솟값이 같다

 

String name1 = new String("신용권");
String name2 = new String("신용권");

- new 연산자를 쓰면 매번 새로운 공간을 힙메모리에 생성하라는 명시적인 표시
- new 연산자를 2번 썼기 때문에 새로운 공간이 2번 만들어짐
- 그림을 보면 힙 메모리상에 공간이 따로 따로 만들어짐
- name1 != name2 주소가 다르다

 

참조형의 비교

- 참조형들은 비교대상이 2개다
- name1 == name2 처럼 비교연산자로 주솟값을 비교
- equals() 란 메소드로 값들끼리 비교

 

주솟값 비교 예시

		String str1 = "자바";
		String str2 = "자바";

		if (str1 == str2) { //비교연산자(==)로 참조하는 주소를 비교
			System.out.println("같은 주소"); //같은 주소
		} else {
			System.out.println("다른 주소");
		}



		String str3 = new String("자바");
		String str4 = new String("자바");
		
		if (str3 == str4) { //비교연산자(==)로 참조하는 주소를 비교
			System.out.println("같은 주소"); //같은 주소
		} else {
			System.out.println("다른 주소");
		}

- 비교연산자(==)로 참조하는 주소를 비교

 

그림

값 비교 예시

		if(str1.equals(str2)){ // 참조하는 값(데이터)을 비교
			System.out.println("같은 값"); //같은 값
		}else {
			System.out.println("다른 값");
		}

- 값비교 equals() 메소드를 사용
- 같으면 true를 반환

 

참조형의 비교 정리

- 비교연산자(==) : 참조하는 주소를 비교
- equals() : 참조하는 값(데이터)을 비교

 

+ 메소드를 찾는 법
ex) equals() 메소드를 어디서 찾아야할까
1. 1차적으로 api에서 equals() 메소드가 어디 붙어있는지 보자 -> String
2. String클래스 찾아야
3. String클래스 안에 없으면 그거 조상들 클래스를 찾아야
- String의 경우엔 부모가 java.lang.Object가 최상위 클래스 , 자기 부모 클래스 임. 
- String 안에 없더라도 조상이 그 메소드를 가지고 있으면 상속 받아 string 객체에서도사용할 수 있다.
- 만약 String클래스도 String의 부모클래스에도 equals()없다면 그건 없는 것임.

+ 클래스 구조
- 필드 1개 있고 생성자있다
- 생성자 : 객체를 생성할때 자동으로 호출되는 메서드, 클래스와 같은 이름이다.

 

String 클래스 구조 생성자
- 우리는 매개변수가 String으로 된 생성자를 호출해왔었음 String(String original) 을 써왔던것

 

String str3 = new String("자바")

- 에서 오른쪽은 String은 생성자를 호출하는 것임
- 생성자는 없으면 못씀 제공되는것만 쓸 수 있다

 

String 클래스 구조 메소드
- String 클래스 안 메소드 많다(기능 많다 )
- equals() 메소드의 리턴타입은 boolean, 값이 같으면 true, 다르면 false를 리턴해줌
- 그래서 이 메소드 자체를 if문 안에 넣었던 것

 

Object 클래스와 equals()

- equals() 메소드의 매개변수는 Object
- 자바의 가장 최상위 클래스가 Object임 = 슈퍼클래스= 최상위 부모 클래스
- 패키지가 엄청 많지만 그게 뭐든지 가장 위는 Object 
- 즉, Object 는 모든 클래스의 최상위 부모, 조상
- equals() 메소드 매개변수가 equals(Object anObject) 
- 값을 비교할때 Object의 자식들은 다 equals 안에 들어갈 수 있다. 모든 클래스 다 들어갈 수 있다.
- 즉, equals() 괄호 안에 int, boolean, String등 다 들어갈 수 있다
- String뿐만 아니라 Object의 자식들은 모두 비교 equals로 비교가능, 즉 모든 자료형 다 비교 가능

 

예시1

		boolean b = "자바".equals("파이썬");
		if(b) {
			System.out.println("같은 값");
		}else {
			System.out.println("다른 값");
		}

- 가능함
- 3번째 자료형형변환 방법, 레퍼런스 관련이 있다

 

예시2

		if(new Integer(30).equals(30)){
			System.out.println("같은 값");
		}else {
			System.out.println("다른 값");			
		}

- int형끼리 비교도 가능하다.
- int, double, boolean 등 모든 걸 equals 로 비교 가능
- wrapper 클래스 , 오토박싱,오토언박싱 등의 개념 앞으로 공부하는것과 연관

 

객체배열
- 객체의 주소를 참조하는(저장하는) 배열
- C++은 많이 쓰지만 String은 많이 쓰진 않음 객체배열보다 성능 좋은 list등이 있기 때문에

 

ex) String객체를 3개 저장하기 위한 배열 = 객체배열

		String[] strArray = new String[3]; // 객체배열
		strArray[0] = "Java";
		strArray[1] = "Java";
		strArray[2] = new String("Java");

- 이렇게 객체 생성시시에 2가지 방법 써서 가능
- 0번방, 1번방 가리키는 "Java"는 같은 곳임
- 0번방, 2번방 가리키는 "Java"는 서로 다른 곳음

		System.out.println(strArray[0] == strArray[1]); //주소값을 비교, true
		System.out.println(strArray[0] == strArray[2]); //주소값을 비교, false
		System.out.println(strArray[0].equals(strArray[2])); //값을 비교, true

 

사용자 정의 클래스
- String 클래스와 비슷한 방식으로 메모리상 처리가 됨

객체 지향 프로그래밍(OOP)
- 부품 객체를 먼저 만들고 이것들을 하나씩 조립해 완성된 프로그램을 만드는 기법

객체
- 물리적으로 존재하는 모든게 객체가 될 수 있다 ex) 자동차, 사람, 책
- 추상적인 것도 객체가 될 수 있다 ex) 회사, 날짜
- 현실세계에선 사람이란 객체가 있을때 사람에 대한 속성이 있다 ex)나이, 이름 => 속성
- 사람이란 객체가 있을때 있는 동작 ex) 달린다, 걷는다 => 메소드

객체 모델링
- 자바같은 객체지향언어에선 객체 모델링이란 작업을 수행한다
- 사람이란 객체의 속성을 표현할때는 '필드'라는걸가지고 속성을 나타남
- 메소드 바깥쪽에 쓰는 변수 = 멤버변수 = 필드 변수 = 객체의 속성 나타냄
- 메소드를 가지고 객체의 동작을 표현함

현실세계의 자동차 객체
- 필드를 가지고 객체의 속성에 대한 것들을 표현
- 속성 : 색상, 속도 -> '필드' 로 표현함, 필드는 쉽게 말하면 멤버변수임
- 필드는 메소드 바깥쪽에 정의되는 변수로서 멤버변수라고 불린다. 자바에선 필드라고 불림
- 동작 : 메소드를 가지고 표현. 달린다 멈춘다 등의 동작을 메소드로 표현

객체 지향 프로그래밍이 가지는 특징
1. 캡슐화
- 한개의 클래스가 만들어져 있을때 외부클래스에서 접근하지 못하도록 캡슐로 보호를 한다.
- 캡슐화위해선 접근제어자로 접근을 허용을 하기도하고 허용을 하지않기도 한다.
ex) private 써서 외부로부터 접근 막음 = 캡슐화로 안전하게 안의 정보를 보호함

2. 상속
- api에서 제공되는 클래스는 이미 상속관계 정의 다 된 상태임.
- 상속을 함으로서 중복적인 코드를 많이 줄일 수 있다
- 또 유지보수를 편리하게 해주는 기능을 제공하기때문에 상속을 많이 사용함.

ex) 부모 클래스가 있고 자식 클래스가 있을떄
- 클래스 = 필드, 메소드, 생성자 로 구성
- 상속이 되는건 2가지 뿐! 필드와 메소드만 상속이 되고! 생성자는 상속되지 않음!

3. 다형성(Polymorphism)
- 부모로부터 상속받은 것들을 다양한 형태로 바꿔서 쓴다는 것

객체와 클래스
- 설계도 역할을 하는게 클래스다
- 현실세계 : 설계도 -> 객체  를 만들어냄 (ex)설계도로 자동차를만들어냄)
- 자바 : 클래스 -> 객체. 설계도역할하는게 클래스, 클래스 가지고 객체를 무한히 많이 만들어 낼수 있다.

클래스 이름
- 하나이상의 문자로 이루어져야
- 변수명과 마찬가지로 첫번째 글자는 숫자올수없다 ex) Car 3Car (x)
- $나 _ 외의 특수문자 사용불가
- 자바 키워드는 사용할 수 없다
- 변수명,함수명,클래스명등은 한글명으로 클래스 명 쓰는건 바람직하지 않다. 웹으로 가면 여러 문제 발생!

클래스와 소스파일
- 이클립스에서 클래스를 만들면 소스파일이 생성됨 클래스이름.java 가 생성됨
- 이걸 javac.exe가 컴파일 해줘서 클래스이름.class 생성됨
- 앞으로는 한개의 .java 파일에 클래스가 여러개가 들어가는 소스파일 .java 을 만들것
- 소스 파일 당 public class 는 1개만 사용가능함! 이 public 을 가진 클래스와 파일명을 일치시켜야함
- 클래스명과 파일명이 일치되어야하는데 단, 이때 메인메소드를 가진 클래스명과 파일명을 일치 시켜야함
- 컴파일이 되면 파일 안의 여러개 클래스가 각각 따로 따로 .class 파일들로 만들어짐(클래스 수만큼)

객체 생성

new 클래스();

- 클래스와 동일한 이름의 생성자를 호출하라는 코드
- 생성된 객체는 힙메모리상에 객체가 생성됨
- new 연산자는 객체를 생성후 객체 생성 주솟값을 리턴하므로, 왼쪽의 변수가 그 주솟값을 갖고있게됨

 

객체 생성 방법 2가지

1.

클래스 변수;
변수 = new 클래스();

2.

클래스 변수 = new 클래스();

- 한줄

 

클래스 구성 멤버와 역할
- 필드 : 변수기때문에 메모리상의 값을 저장하는 역할
- 생성자 : 객체가 생성시 호출되며 필드값을 초기화하는 역할
- 메소드 : 객체의 동작적인 걸 표현하는 역할

사용자 정의 클래스
- api 에 있는 클래스를 모방하여 생성
- 메소드 바깥쪽에 사용되는 변수 = 필드 = 멤버변수, 변수기때문에 값을 저장함, 속성을 표현
- 생성자는 클래스명과 동일한 이름으로 만들어야함. 객체가 생성될때 생성자가 호출되며
필드값을 초기화시키는게 생성자의 역할
- 메소드는 객체에 대한 동작을 나타냄, ex) public void static main

 

정리
메인 메소드 안의 변수 = 지역변수 = 스택메모리 = 메소드종료시 삭제
메소드 밖의 변수 = 멤버변수 = 필드 = 전역변수 = 힙 메모리 = 초기화

 

사용자정의 클래스 만들기 예시

 

public class Animal {
//Animal 은 사용자 정의 클래스(자료형)

	
	int age; //자바에선 멤버변수, 필드(field) 라고 한다. C에선 전역변수라고 부른다.
		// : 메소드 바깥쪽에 정의되는 변수
	
	public static void main(String[] args) {

	}

}

- age는 메소드 바깥에 있고, 이 클래스 전역에 사용 가능
- 멤버변수= 필드 = 전역변수 는 메모리 중 힙메모리 상에 저장됨!
- 클래스도 참조형이기 때문에 int age; 는 힙메모리상의 공간을 할당받고 초기화 0 으로 자동초기화됨

 

* JAVA구조 : 클래스 내에 메소드가 있다

 

생성자
- 멤버 함수 중 하나
- 반드시 클래스명과 동일한 이름으로 생성해야함.
- () 괄호가 반드시 있어야한다.
- 생성자명앞에는 접근제어자만 올 수 있다.

기본생성자(default constructor)
- 생성자 중 매개변수가 없는 생성자

 

	int age; 
	public Animal() {
		System.out.println("생성자 호출 성공");
	}

 

사용자 정의 클래스와 클래스의 구조 3가지

 

public class Animal {
//Animal 은 사용자 정의 클래스(자료형)

	
	int age; //필드
	public Animal() { //생성자
		System.out.println("생성자 호출 성공");
	} 
	
	public static void main(String[] args) {  //메소드
		
		int a = 10;

	}

}

- 필드, 생성자, 메소드가 다 있는형태
- 생성자는 주로 객체생성과 동시에 필드값의 초기화를 설정하기 위한 용도로 객체가 생성될때 호출되면서 실행
+ a는 지역변수, stack 메모리 영역에 저장, 이 메소드 안에서만 사용가능
+ 지역변수와 멤버변수는 스택과 힙 이라는 다른 공간에 저장되는것 뿐만 아니라 메모리상에 저장되는 영역과 할당되는 시점이 다름

 

	public static void main(String[] args) {

		int a = 10; //지역변수
		String str = new String("자바");
		Animal a1 = new Animal();
	}

+ 이 main메소드는 Animal 클래스 내부임. Animal 클래스 내부에 Animal 클래스로 객체 만들어도 된다.

 

그림

필드 접근

    Animal     a1         =   new       Animal();
// 클래스 레퍼런스변수 연산자 생성자호출

- 이렇게 객체를 생성시 4바이트짜리 Animal 클래스의 '필드'를 저장하기 위한 기억공간을 힙에 생성함
- 그 필드는 age (=0 , 자동초기화) 이다. 그 주솟값을 a1이 가지고 있는 상태
- a1이 age가 저장된 힙메모리상의 시작주솟값을 가지고 있다.
- 이 a1으로 접근해야지만 이 age에 접근가능하다!

 

System.out.println(age); // 불가능
System.out.println(a1.age); // 로 해야함

- 반드시 a1이 가진 주소 이용해서 a1.age로 접근해야함!
- 객체 생성될때마다 새로운 age만들어지므로 어느 영역에 있는 age인지 알 수 없기 떄문이다

- age의 값을 수정하고 싶을때도  a1.age로 접근해서 수정해야한다

		a1.age = 5;
		System.out.println(a1.age); //5가 출력됨

 

생성자 호출

- 오른쪽의 Animal() 은 생성자를 호출하라는 코드임

	public Animal() {
		System.out.println("생성자 호출 성공");
	}

- 출력이 됨

 

생성자를 안쓴다면?
- 기본으로 알아서 생성해줌 

 

객체 생성2

ex) 이번에는 Animal 클래스로 다시 new 연산자로 다시 객체 생성해보자

		Animal a2 = new Animal();
		System.out.println(a2.age);

- 이러면 힙메모리상에 새로운 공간이 또 생성됨!

- 그림 참고

 

그림

- a1이 가진 주소와 a2가 가진 주소를 비교해보자

		if (a1 == a2) {
			System.out.println("같은 주소");
		} else {
			System.out.println("다른 주소");
		}
출력 : 다른 주소

- new로 힙메모리에 새로운 공간을 만들었기 때문이다

자바의 보조 제어문 break

1. switch-case문 빠져나가기 
2. 반복문 빠져나갈때 (while, for, do~while문)

- 주로 무한 루프를 빠져나올 때 break문을 이용함
- 어떤 무한루프에서 조건식을 쓰고 그 조건을 만족하면 빠져나오는게 일반적

 

for 무한루프 돌리는 방법 2가지

1. 초기, 증감, 조건 식 안적기

		for(;;)
		{
			System.out.println("무한출력");
		}

2. 조건 식 안적기

		for (int i = 1;; i++) {
			System.out.println(i + "무한출력");
			if (i == 100)
				break;
		}

break문 주의1

- break 뒤에 다른 내용 있으면 안된다.

while(true)
{
	break;
	System.out.println("출력"); // 오류생김
}

 

break문 주의2

- break문 만나는 순간 그 밑은 아예 안보고 바로 빠져나옴
- break문의 위치를 잘 설정해야함

- 비교해보기(아래 예제2개)

		while(true) {
			
			System.out.println(i+ "무한루프");
			if(i==100) break;
			i++;
			
		}

- 이러면 100번 출력

		while(true) {
			
			System.out.println(i+ "무한루프");
			i++;
			if(i==100) break;
			
		}

- 이러면 99번 출력됨 
* "if"나 "메소드"를 빠져나올땐 break가 아닌 return문을 써야함!!

 

break문 예시

- 1부터 45사이의 난수를 발생 시킬때, 6이 나올때까지 몇번 루프가 돌아가는지 구해보자

package p2022_06_24;

public class Break03 {

	public static void main(String[] args) {

		
		int i = 1;
		while (true) {

			i++;
			int num = (int) (Math.random() * 45) + 1; // 난수발생 : 1~45

			if (num == 6)
				break; // 무한루프를 빠져나옴
		}
		System.out.println("루프횟수 : " + (i - 1)); 
		System.out.println("프로그램 종료");

	}

}

- 루프횟수에서 초기값이 0이 아니라 1이니까 -1 해줌.(한번 루프 돌아도 i값이 2가 되기때문)

 

continue

- 반복문 안"에서만" 사용가능!! (while, do~while, for)
- 다시 반복문으로 돌아가라는 의미
- break문처럼 반복문 가장 위에있으면 오류가 생김
- break문처럼 if문과 함께 쓰임.

		for (int i = 1; i <= 10; i++) {

			if (i == 5)
				continue;
			System.out.println("출력 : " + i);

		}

- i==5일때 출력5는 실행되지 않음
- i==5일때 아래를 실행안하고 i++쪽으로 돌아감, 6이되고 다시 조건식 참이니 출력 : 6이 출력됨

 

메소드 호출

- 여태껏 main 메소드 안에 모든 내용을 다 집어넣었다 이젠 사용자 정의 메소드 만들고 호출해볼것
- 나중에 클래스로 객체 쓸때도 메소드는 계속 쓰므로 중요함.

 

메소드

- 여러가지 코드를 묶어둔 집합체
- 한번 정의된 메소드를 호출 통해서 재사용하기 위해 사용
- 어떤 언어에선 함수 라고 부른다.
- 각 언어마다 메소드 만드는 방법이 꽤 다르다.

 

메소드 호출 방법

- Call by Value
- Call by Reference

 

메소드 의미

접근제어자     공유      자료형     메소드명(매개변수)
public           static         void         check(){

 return   값;
}

 

접근 제어자 종류

-  public
- 생략(default접근제어자)
- private
- protected

 

접근 제어자

- 접근 허용할지 막을지 설정
- 클래스 앞에 도 붙일수 있고, 클래스를 구성하는 3가지 필드(변수), 생성자, 메소드 앞에도 붙일 수 있다
- default : 아무 표시 안하면 default 접근제어자
- public : 모든 접근을 허용한다는 의미로 사용됨, 가장 많이 사용됨

 

static 자리

- 공유를 할경우, 누구나 쉽게 접근할 수 있도록 공유원할때 붙임
- static이 붙은 메소드를 정적메소드라고 불린다.
- 어제 배운 Math 클래스는 정적메소드 밖에 없었다.
+ 아직 클래스-객체 개념 안배웠기떄문에 모두 정적메소드로 해서 공부/실습할것

 

void 자리 = 리턴자료형 자리

- void 대신 기본자료형도 들어갈 수 있고, 참조형인 클래스, 배열, 인터페이스도 여기에 올 수 있다
- void는 값을 돌려주지 않아도 된다는 의미이므로 void 가 왔을땐 마지막의 return이란 구문을 생략 할 수있다
- 자료형이 오면  return 자료형 ; 해서 자료형에 맞는값을 반드시 돌려줘야함
ex) void대신 int란 자료형이 왔을땐 int형 값을 return으로 돌려줘야함.

 

메소드 명 

ex) check()
- 예약어로 설정된 Class If Switch 같은건 메소드 명으로 쓰면안됨
- 메소드 쓸땐 괄호를 반드시 가져야함 . 괄호가 없는 메소드는 거의 없다.
- 괄호만 써도 되고, 메소드가 실행되는 동안 필요한 값이 전달되어야할 땐 변수를 쓴다. 기본자료형, 참조형 다 올 수 있다.

 

메소드 호출/반환

- 기본자료형의 경우 값을 전달한다.
ex) int형이 매개변수로 있다면 int형 값을 전달해서 호출을 해야함
- 클래스가 오면 객체를 전달해야하고, 배열이 오면 배열주소값을 전달해야한다
- void 자리에 클래스, 인터페이스, 배열등의 참조형이 올땐 주소값을 리턴해줘야 한다.

 

main 메소드

-main 메소드는 이름 바꾸지 못함
- public static void check(){}
- 개발자가 호출 할 수 없다 JVM이 해줌

 

사용자 정의 메소드 작성

- 자바는 메소드 안 메소드가 들어가는 중첩메소드 허용안함
- 즉 메인 메소드 안에 메소드가 들어갈 수 없다. (파이썬은 중첩함수 허용)
- 그러므로 메인 메소드 바깥 (위,아래) 에 메소드 작성하기

 

Main 메소드 호출 vs 사용자 정의 메소드 호출

- Main 메소드는 MethodEx01.class란 바이트 코드에서 JVM이 호출해줌. 
- 사용자 정의 메소드는 프로그래머가 직접 호출해줘야함

 

static이 붙은 정적메소드 호출 vs static이 없는 메소드 호출

- static이 붙은 메소드는 그 클래스 . 해서 바로 호출 ex) Math.random()
- static이 없는 메소드는 그 클래스로부터 객체를 생성해서 . 을 해서 메소드를 호출

 

접근 제어자

- 같은 클래스 내에선 접근 제어자가 아무 의미 없다
- protected이든 private이든 public이든 default든 같은 클래스 내에선 다 접근 가능
- 이 클래스,메소드,변수,생성자에 접근을 허용할건지 말건지를 정해둔 것임.
- 아무것도 없어도 default 접근제어자이다

 

return 자료형 적는 자리

- void 가 오든지 자료형이 오든지 둘 중 하난 반드시 와야함
- void면 return구문 생략 가능 또는 return;

 

메소드 호출 방법

- 매개변수가 없는 check() 는 그냥 check(); 라고 호출해주면 됨.

 

메소드 작성 순서
- 자바는 객체지향언어라서 메소드가 적힌 순서가 상관없다
ex) check()가 main() 보다 밑에 있어도 main()에서 check() 호출 가능
- 메소드가 적혀있는 순서가 중요한 언어가 있다.
ex) 파이썬, C

static 메소드 호출
- Math는 정적메소드만 있다. 그래서 Math.random()처럼 사용함
- 원래 static 메소드 호출 시, 클래스명.메소드명() 이 원칙이지만 같은 클래스내에 있는 정적메소드를 호출시엔 클래스명을 생략 가능
ex) MethodEx01.check(); 이지만 같은 클래스 내에선 check(); 만 작성해도 됨.

+ Math메소드의 호출법
- static이 붙은 필드 = 정적 필드 만 있다
- static이 붙은 메소드 = 정적 메소드 만 있다.
- random() 메소드는 static double random() 이다.
- 그러므로 객체 생성하지 않고 Math.random()으로 호출함.

* 클래스 : 필드, 생성자, 메소드가 있다.(api문서)

 

static이 없다면?

MethodEx01 mx = new MethodEx01();
mx.check()

- 이런식으로 객체를 생성하여 호출해야 한다.

 

매개변수가 없을때 vs 매개변수가 없을때 호출

- 매개변수가 없을때 : check(); 으로 호출
- 매개변수가 있을때 : check(ck) ; 로 호출, ck는 int값이어야

	static void check(int a) { //매개변수(parameter) : int a
		System.out.println("전달된 값 : " + a);
	}

- 즉 정수값을 전달해야 함수가 실행될때 매개변수는 스택에 자리가 잡혔다가 메소드 끝나면 지워짐
- check(30); 시 매소드 실행될때 a에게 30을 주게 되고 이 매개변수(파라미터)를 출력
* 매개변수는 지역변수

 

Call by Value

- 이렇게 매개변수가 기본자료형일떈 값을 전달해서 호출하는 것.
- 값 전달에 의한 메소드 호출 방식

Call by Reference
- 매개변수가 참조형 일땐 주소값을 가짐
- 주소값을 전달해서 호출

메소드 "오버로딩"
- 매소드 정의 할때 이름이 똑같음 check(), check(int a)
- 한개 클래스내 동일 이름 클래스 정의할 수 있는 것.
- 하지만 매개변수를 다르게 함으로서 구분이 가능하도록 해야한다. 

지역변수 정리
- 메소드 안에서 사용되는 지역변수 = 매개변수 = 스택에 저장됨 = 메소드 종료시 삭제됨
- 블럭문 안에서 사용되었던 i 같은것도 지역변수

 

메소드 예시

	static void check(int a, double d) {
		double result = a + d;
		System.out.println("전달된 값의 합 : " + result);
	}

- check(10, 10.5); 로 호출 (Call by Value)값을 전달해서 호출함
- 순서에 맞게 자료형에 맞게 전달해야함 int, double 순으로

 

매서드의 매개변수에 참조형이 오는 경우

ex) String 클래스

	static void check(String s) { 

		System.out.println("전달된 값 : " + s);
	}

- main 에서 

check("자바");
check(new String("파이썬"));

- 호출 시 둘 다 잘 출력됨.

- 바로 check("자바") 해서 객체 만들 수도 있고 new 연산자를 써서 String객체를 만들 수도 있다.

 

+ String클래스만 두가지 방법 모두 가능.
1. String s = "자바"
2. String s = new String("파이썬");

static void check(String s) { //String s = "자바"

		System.out.println("전달된 값 : " + s); 
		//String s = new String("파이썬");
}

- 바로 check("자바") 해서 객체 만들 수도 있고 new 연산자를 써서 String객체를 만들 수도 있다.

 

Call by Reference (위 예시 참고)

- Call by Reference = 주솟값 전달에 의한 매서드 호출 방식
- 우리가 볼땐 '자바' '파이썬'을 직접 전달하는거같지만 사실 주솟값을 전달하는것
- 그 데이터가 저장된 영역의 주솟값을 메소드로 전달하는것임
- "자바' "파이썬"데이터는 모두 힙이란 영역에 저장
- 매개변수 s는 스택영역에서 "자바", "파이썬" 의 주솟값을 가지게 됨

 

그림

 

Math 클래스의 리턴자료형

- Math클래스 random() 메소드의 리턴값은 double
- 그 우리는 그것을 int 강제형변환 해서 사용했었다.

 

메소드 예시1

// return문 : 메소드를 호출한곳에 값을 돌려주는 역할을 한다.
static int check01()
{
	System.out.println("출럭");
	return 50; 
	System.out.println("출럭"); //오류발생

}

- 리턴이 void가 아니므로 필수, int형 값만을 돌려줘야한다. 50.5를 리턴할순X

* 리턴구문은 메소드 가장 마지막 줄에 써야한다. 아니면 오류 발생
* 저걸 check()라는 이름을 쓸 수 없다 .  맨 위에서 check()를 썼기때문에 오류 발생
check01로 만들었다.
- Main에서 check01() 로 호출하면 출력은 되지만 리턴으로 돌려받은 값을 받지 않았으므로 그 값을 쓸수 없게됨

 

int result = check01();

- 리턴형이 int이기 떄문에 그 값을 받는 변수도 int여야함

 

값 돌려받는 2가지 방법

1. System.out.println("돌려 받은 값1 : " +  result);
2. System.out.println("돌려 받은 값1 : " +  check01());
- check01()에서 리턴값을 돌려받자마자 바로 출력해도 된다. 변수로 안받아서 출력해도됨

 

메소드 예시2

- 더블형이 리턴일땐

static double check02(int a, double d)
{
	double result = a + d;
	return result;
}

- 이 result도 이 메소드 안의 지역변수다 그래서 이 메소드 말고 다른 메소드에선 사용가능
- main 메소드에서

double result2 = check02(50,3.14);
System.out.println("돌려 받은 값3 : " + result2);
System.out.println("돌려 받은 값4 : " + check02(50,3.14));

 

return

- 메소드를 호출 한 곳으로 값을 돌려줌
- static int check01 에서 int자리에 참조형이 올땐 값이 아니라 주솟값을 돌려줌!

 

메소드 주의

- 클래스 배열 인터페이스도 매개변수 자리, 리턴 자료형자리 들어 갈 수 있다.
- 값을 돌려받을 때는 그 메소드의 리턴 자료형과 일치하는 자료형으로 값을 받아야함.
ex) int i = sc.nextInt();
- public static void main 에서처럼 이 순서 바뀌면 안됨 접근제어자 다음 static 다음 리턴자료형 다음 함수명
- 지역변수는 다른 메서드일땐 이름같아도 충돌 발생하지 않는다

System.out.println(max(n1,n2));
System.out.println(min(n1,n2));

- 가능함
- 원래는 MethodEx03.max(n1,n2)지만 같은 클래스라 생략(max는 static 함수이므로)

 

메모리
- 기본 자료형들은 값을 참조형은 주소를 저장
- 기본 자료형이라 하더라도 항상 스택에만 저장되는게 아님
- 기본 자료형 중 지역변수 만 스택이란 영역에 값이 저장됨
- 멤버,정적 변수는 기본자료형이라도 스택에 저장되지 않음

메모리 예시1
- 참조형 중 클래스 중 String 클래스 예시

String name = "신용권"


- 값인 "신용권"은 힙이란 메모리에 저장되고
- 이 저장된 값의 시작 주소값을 스택 영역에서 가지고 있다


메모리 예시2

String hobby = "독서"


- "독서" 는 힙에 저장 , 그거의 시작 주소값은 참조형 변수가 가지고 있는데 그건 스택에 있다
- (name, 2312415) 이런식으로 (주솟값 : 2312415) 스택에 있는거

 

배열

- 동일한 타입의 데이터를 연속된 공간에 저장하는 정적인 자료구조
- 변수를 확장시킨 개념이 배열 (변수는 1개의 데이터만 저장)
- 변수가 여러개 필요할때 간결하게 쓰기 위해 배열을 쓴다.
- 10개과목 점수 입력받으려면 변수가 10개나 필요함 - > 배열을 쓰면 코드가 늘어나지 않음
- 1가지 자료형 데이터만 저장 가능
- 거의 대분의 언어는 배열을 지원함
- 배열 정의 할때도 반드시 자료형을 적어야함.
- 1차원 배열은 [] 1개 2차원은[][] 2개... 

int[][] score = new int[5][3];


- 배열이름 (변수)쓰고 new를 씀 = 명시적으로 힙메모리상에 새로 공간을 만드는것
- 왼쪽이 int면 오른쪽도 int형으로 해야

 

배열 의미

int score[] = new int[3];

- 힙메모리에 int인 4바이트 연속된 공간을 3개를 생성하란 의미

 

그림

 

배열 기타
+ 우리가 여태껏 봤던 main 메소드의 매개변수는 String 형 1차원 배열
- main(String[] args)
- []는 자료형 뒤에 써도 되고 변수명 뒤에 써도 된다
- String[] args == String ar[] 도 가능하다

new
- 연산자 오퍼레이터
- 힙 메모리상에 배열을 위한 새로운 공간을 만들라는 의미
+ 클래스로 객체 생성할때 쓰는 new도 같은 원리로 힙 메모리 상에 새 공간 만들라는 의미임
- String 클래스만 new를 써도 되고 안써도 되지만 다른 클래스 99%는 new를 꼭 써야만 객체 생성 가능

배열의 초기화
- 배열을 정의 시 힙메모리 상의 연속된 공간은 자동 초기화 된다.
- 자료형에 따라 초기화 되는 값이 다르다
- int 형 배열을 정의하면 힙메모리상의 공간(배열)이 자동으로 0으로 초기화 된다.
- boolean 배열 은 false 로 double 배열 은 0.0 으로 int는 0 으로 초기화 됨
- 또는 원하는 할당값이 있을 때는

score[0] = 80;
score[1] = 90;
score[2] = 100;

 

* 지역변수는 초기화되지 않지만 참조형은 자료형에 따라  초기화 되는 값들이 있다

 

배열을 만드는 2가지 방법
1.

int score[] = new int[3]


2-1.

int[] score = {80,90,100};


2-2. int[] score = new int[]{80,90,100}

int[] score = new int[]{80,90,100}; // 도 가능함

 

 

1. int score[] = new int[3] 방법

- 배열에 어떤 값이 들어가야할지 아직 안정해지거나 모를때
- new가 반드시 들어가야함

2. int[] score = {80,90,100}; 방법
- 값이 정해져있을때 쓰는 방식
- 배열 선언과 동시에 초기화를 할 때 주로 사용

 

int[] s1 = {80,90,100};
int[] s2 = new int[]{80,90,100};
//두가지 형식으로 선언 가능하다

 

- 다른 자료형도 마찬가지

double[] d = {3.14,10.5,42.195}

 

- 같은 자료형만 가능

int[] score = {80,90,100,3.14} // 오류 발생

 

변수->배열->리스트

- 변수를 확장시킨게 배열이고 배열을 확장시킨게 리스트(List)
- 배열은 한가지 자료형만 가능하고 리스트 라는 자료구조를 쓰면 자료형 혼용가능, 동적으로 자료크기 늘릴수도있다

 

char형 배열 / String형 배열

 

char[] c = {'j','a','v','a','안'};
String[] str = {"java", "jsp","oracle"}
String[] str = new String[]{"java", "jsp","oracle"}

- 모두 가능

 

메모리 정리
- 모든 참조형으로 변수 만들땐 거의 다 new를 필수적으로 쓴다 (클래스,배열,인터페이스)
- 힙메모리상에 저장된 값은 초기화 된다!
- 스택 메모리상에 저장된 값은 초기화 되지 않음

 

선언 이후 값 할당

 

score[0] = 80; //0번 방에 80점을 할당
score[1] = 90; //1번 방에 90점을 할당
score[2] = 100; //2번 방에 90점을 할당

 

배열 자동초기화

- int형 배열은 자동초기화 0으로 됨
- double형 배열은 자동 초기화 0.0으로 됨
- char형 배열은 자동으로 초기값 설정이 안됨!
- char 배열은 자동으로 초기화가 되지 않는다.
- boolean 형 배열은 자동초기화 false 로 됨!

 

참조형 배열 예제 : String 배열

- String형 배열은 자동 초기화 null 로 됨 (초기값이 없다는 의미)
* null : 값이 없다 는 의미

배열과 반복문
- 배열을 의미있게 쓰려면 반복문을 써야(ex) 합, 곱 등 구하기

배열의 크기 구하기 : length 속성
- length란 속성 이용해서 배열의 크기 구할 수 있다.
- 메소드가 아니라서 괄호가 없다! 속성이다. 
- 그 배열이름.length 하면 된다

 

배열의 인덱스 주의
+ 배열은 인덱스 번호가 0번 부터 시작함 
- 출력시 for문 쓸때 주로 i=0 해야하는점 주의, 
- <=말고 < 써야하는거도 함께 주의 

 

배열에서의 형변환
- double형 배열 예시

	double[] dd = { 3.14, 10.5, 42.195, 50 }; 

	for (int i = 0; i < dd.length; i++) {
	 	System.out.println(dd[i] + "\t");
	}

- int형 값인 50을 넣으면? 내부적으로  double 로 바뀜(자동형변환)
- 이 반대의 경우는 안됨 double 이 int보다 크므로

- 반대로 int 형 배열에 double 형 자료를 넣어선 안됨

 

크기 구하는 방법 3가지의 비교(중요)

1. 배열크기 구할땐  length 속성
2. 문자열의 길이 구할땐 length() "메소드"
3. list같은 자료구조는 size() "메소드"

 

+ 형변환 항상 주의

double avg = (double)sum / 3; // 또는  sum/3.0
System.out.println("평균 : " + avg);

- sum은 int 형 3도 int형이라 (double)을 안쓰면 소수점 전부 짤려서 나옴.

- 살리려면 (double)을 붙여야함 또는 3.0으로 연산

 

+ 평균을 소수점 2째자리까지 출력하려면

System.out.printf("평균 : %.2f",avg); // 평균 : 86.67

- 실수값일땐 뒤에 f를 써줌, %.2 는 둘째자리까지 출력하란 뜻이고 셋째자리에서 반올림된다.

 

출력형태 정리

 %b : boolean 형식으로 출력 
 %d : 정수 형식으로 출력
 %o : 8진수 정수의 형식으로 출력
 %x / %X :16진수 정수의 형식으로 출력
 %f : 소수점 형식으로 출력
 %c : 문자형식으로 출력 
 %s : 문자열 형식으로 출력
 %n : 줄바꿈 기능
 %e / %E : 지수 표현식의 형식으로 출력

 

복습

char 자료형

- 영문자 1글자는 1바이트
- 한글자 1글자는 2바이트

 

- 하지만 char 안에는 모두 한글자만 가능

char c1 = 'k'
char c2 = '안'

 

참조형

- 기본 자료형과 달리 값 저장 방법이 다르다.

- 값은 힙에 주소는 스택에 저장된다.

 

자바의 구조, api 문서

- jre의 패키지는 비슷한 클래스끼리 묶여져 있다.
- 바이트 코드를 가져와서 import해서 사용하는것이다.
- 바이트 코드 = 기계어
- 그것의 설명서가 api문서

 

필드 : 쉽게 말하면 멤버변수

생성자

- 여기서 제공되는 생성자중 하나를 선택해서 써야함.
- 클래스명과 반드시 동일한 이름으로 되어있고, 메소드라 무조건 괄호가 있는 형태

 

if~else if~else 문

- 가장 먼저 만족한 하나만 실행하고 조건문 나간다.

 

if (score >= 90)
grade = 'A';
else if (score >= 80)
grade = 'B';
else if (score >= 70)
grade = 'C';
else if (score >= 60)
grade = 'D';
else
grade = 'F';

- 가장 먼저 해당하는 것의 문장을 실행하고 if문 전체를 나간다

ex) 90점이면 60점이상이므로 아래 else if 도 만족하지만 첫번째에서 걸리므로 'A'만 출력된다.

 

난수발생 공식

- 난수 = (정수화)(Math.random() * (상한값 - 하한값  + 1)) + 하한값;

 

난수발생 공식 설명

0.0 <= Math.random() < 1.0

- 실수형태의 난수 발생시킴.

* 자세한 설명은 아래에서

 

난수발생 예시

 

// 주사위 번호 뽑기 : 1 ~ 6
		int num = (int) (Math.random() * 6) + 1; // 1~6
		System.out.println("num = " + num);

		if (num == 1) {
			System.out.println("1번");
		} else if (num == 2) {
			System.out.println("2번");
		} else if (num == 3) {
			System.out.println("3번");
		} else if (num == 4) {
			System.out.println("4번");
		} else if (num == 5) {
			System.out.println("5번");
		} else {
			System.out.println("6번");
		}

 

난수 발생 2가지 방법

1. Math 라는 클래스 중 random()이란 '메소드'를 사용. Math.random()
2. Random 이라는 클래스를 import 하고 랜덤 객체를 생성해서 난수 발생

 

// 난수 발생
// 0.0 <= Math.random() < 1.0
//  1         ~            6

 

Math 클래스 (by API 문서)

- java.lang의 클래스이므로 import필요없다.

 

java.lang.Object
java.lang.Math

- Object 클래스가 자기 부모이다(상속관계)

 

1. Math 클래스의 필드 = 멤버변수

* 직접 클래스를 우리가 만들떈 필드를 변수 형태로 만들게 됨.
- E는 자연로그 2.7xx , PI는 파이(원주율) 3.14xx

- static 이 붙은 변수(필드) = 정적 필드
- E는 자료형이 static double
- PI도 자료형이 static double

+ 정적 필드
- 정적 필드 들은 객체를 따로 만들지 않고 클래스명.필드 로 접근해서 바로 해당 필드 값 사용가능
ex) Math.E , Math.PI 하면 값이 나옴

 

		System.out.println("E = " + Math.E); //E값
		System.out.println("PI = " + Math.PI); //PI값
		System.out.println(Math.random()); //난수 발생

 

2. Math 클래스의 생성자

- Math 클래스는 객체를 생성할 필요가 없으므로 (static) 생성자가 없다.

ex) Math m = new Math(); 라는 식으로 사용 불가!
- Math 클래스는 아무 생성자도 제공이 안된다
- 즉, 생성자 자체가 없기때문에 new를 쓰면 오류가 남. 

 

3. Math 클래스의 메소드
- 정적 메소드 = static이 붙은 메소드
- Math는 전부 static이 붙은 정적메소드 뿐이다.
- Math의 메소드도 객체를 생성해서 사용하지 않고 클래스명.메소드 해서 바로 사용함
- Math 메소드 중 random() 메소드가 난수 발생 시켜주는 메소드

 

+ random() 메소드 : 
- Type : static double
- double 형이니 실수값으로 처리됨, 양수로 double 형 값을 리턴한다.
- 0.0 보다 크거나 같고, 1.0 보다 작은 범위의 난수를 리턴 
- double이 return 되므로 정수로 값을 받고 싶으면 (int) 강제 형변환

 

Math.random() 난수 공식의 이해

- 공식 : 난수 = (정수화)(Math.random() * (상한값 - 하한값  + 1)) + 하한값;
ex) int num = (int) (Math.random() * 6) + 1; // 1~6

- 0.0 <= Math.random() < 1.0

 

1. 1.0 미만 이니 1.0 이 포함되지 않는다.
2. Math.random() * 6 을 하면 0.0 <= 난수 < 6 까지 난수발생
- 즉 5.99999..까지 난수가 발생되지 6이 발생될 수 없다.
3. 그래서 +1 을 시키는 것
4. 난수값이 0.0 <= 난수 이므로 0.0 이 나온다면 6을 곱해도 0.0 이다.
- 이걸 int로 형변환하면 0이 된다.
5. 그래서 + 하한값 을 해주는 것

 

예시1
- 1~45사이의 난수 발생

int random;
random = (int) (Math.random() * 45 + 1);
System.out.println("난수 = " + random);


예시2
// 5~70사이의 난수 발생
int r;
r = (int) (Math.random() * 66) + 5;

- 일단 5부터가 아니라 0 부터의 기준으로 생각해야한다
- 그러면 5 ~70까지 몇개의 숫자가 있는지 생각 (70-5+1)
- 그다음 5부터 시작한다 생각해서 5를 더해주면 된다.

 

switch~case문

 

  switch(변수){

	case 값1: 실행될 문장;
		break;
	case 값2: 실행될 문장;
		break; 
	default: 위의 case를 만족하지 않을때
	            실행될 문장;
     }

- case를 빠져나가려면 반드시 break;를 써야한다.
- break;를 안쓰면 밑으로 내려간다.
- 아무것도 만족 안하면 아래의 default값을 실행한다.

 

break

- 반복문, 조건문(switch~case 만)에서 빠져나갈 때 break;
- break문은 현재 위치에서 가장 가까운 switch문 또는 반복문을 벗어나는데 사용된다.
- 주로 if문과 함께 사용되어 특정 조건을 만족하면 반복문을 벗어나도록 한다.

 

switch~case문 사용법

- 그냥 case 값: 이라 적고 그걸 만족하면 그 아래있는 case 가 실행됨

		switch (score/10) {
		case 10 : 
		case 9 : 
			grade = 'A';
			break;
		case 8 :
			grade = 'B';
			break;

+ score/10 == 10일때, case 9의 문장 실행됨, 즉 100점일때 break문이 없기때문에 내려감

 

switch~case문 단점

- 100~90 이런 범위값 처리위해서 위의 예제처럼 나누기하는등의 처리가 필요함

 

 

반복문 : 반복적인 걸 할 때 사용

- for , while, do~while

 

for문

for(초기값,조건식,증감식){
	반복 실행할 문장;
}

- 초기값이 있어야함
- 비교연산자로 조건식을 씀
- 증감연산자로 증감식을 씀
- 조건식을 만족하는 경우에만 안의 식들을 수행함
- 만족안하는 경우엔 수행 안함

 

자바의 if 초기값 설정 2가지 방법

1. 선언하면서 초기화
2. 선언은 위에하고 for문 ()안에서 초기화

- 자바는 두가지 방법 다 가능하다
- C등의 언어는 2번 방법만 가능 

if문 작동원리 예시1

for (int i = 1; i <= 10; i++) { 
	System.out.println(i + "사랑해요.");
}


1. i=1로 설정된다.
2. i<=10을 만족한다
3. 1사랑해요 출력
4. i++해서 i==2가 된다
5. i<=10 만족한다
6. 2사랑해요 출력
7. i++해서 i==3이 된다.
8. ...
9. 10이 되면 <=10 만족하기떄문에
10. 10사랑해요 출력하고
11. i++되어 11이 되면
12. <=10만족하지 않기 때문에 
13. 출력안하고 나가게됨!

 

지역변수
- 지역변수는 초기화가 자동이 안됨. ->  초기화는 필수!
- 선언된 {}안에서만 사용가능
- 스택이란 메모리 영역에 공간을 할당받음
- 메소드가 실행될때 할당받고 종료되면 자동으로 지워진다
+ 멤버변수(클래스 변수, 인스턴스 변수)와 배열의 초기화는 자동(기본값으로)


if문 작동원리 예시2

int sum = 0;
for(int i = 1; i<=3; i++)
{
	sum = sum + i;
}

 

변수값 변화

변수     sum  = sum + i
                        0        1
1차           1
                        1       2
2차           3
                        3        3
3차           6
                              4 (조건 불만족) -> 끝. sum은 6이고 i는 4인 상태로 끝

- 지역변수 이므로 int sum = 0 라고 초기화를 꼭해줘야함
- 덧셈일땐 영향이 없는 0으로 초기화
+ int 형 i 도 for 문안의 지역변수 이기 때문에 for문 안에서만 사용 가능하다.
+ for문 밖에서 i를 사용하면 오류가 생김 


지역변수 정의
1. 메소드 안에서 정의되는 변수 (그 안에서만 사용가능 sum은 메인 메소드의 지역변수
2. 매개 변수
3. 블럭문(조건문, 반복문) 안에서 사용되는 변수 i는 for문 안의 지역변수

* 증감식 영역에서 i++, ++i, i=i+1, i+=1 다 가능함
+ \t는 탭키만큼 간격벌림, print("\t") 라고 하면 된다.

 

while문

while(조건문){
	반복 실행할 문장;
}


- 비교연산자로 조건문을 작성하고 조건이 참일때만 반복수행함.
- 초기값이 조건식에 안맞으면 아예 실행 안됨


while문 주의
- for문은 조건식, 증감식, 초기값 자리가 있지만 while은 조건식 외는 내가 설정해야한다
- 일반적으로, 초기값은 while문 밖 위에
- 일반적으로, 증감식은 보통 while문 맨 밑에 
- 증감식 안쓰면 항상 참이라서 무한루프가 돌아감

do~while문

do{
	반복 실행할 문장;
}while(조건식);


- 조건식이 거짓이라도 최소 1번은 실행됨
- 끝에 세미콜론 기억하기!!

do~while문 예시

int i = 1;
do {
	System.out.println(i + "사랑해요");
	i++;
}while(i<=10);


- i 초기값이 11이어도 11사랑해요 가 출력된다.
- i 가 10일때, 10사랑해요를 마지막으로 i는 11이 되어 조건 불만족하여 빠져나가게된다

do~while문 예제

System.out.println("메세지를 입력하세요?");
System.out.println("프로그램을 종료하려면 q를 입력하세요");

Scanner sc = new Scanner(System.in);
String input;

do {
	System.out.println(">");
	input = sc.nextLine();  //문자로 입력을 받는다.
	System.out.println("입력문자 : " + input);
}while(!input.equals("q"));

System.out.println("프로그램 종료");
sc.close();


- String을 입력받기 위해 .nextLine() 메소드로 입력받는다.
- do while은 최소 1번은 실행하므로 실행 하자마자 >가 출력되며 입력할 수 있음
- 그 뒤 q를 입력시 do while을 더이상 못하고 나간다
- scanner 함수를 안전하게 close()로 닫아주는게 좋다.


+ input.equals("q") 메소드
- 값을 비교할때 사용하는 메소드, 값이 일치하면 true인데 앞에 NOT연산자 !를 붙여서 q일땐 false를 만들어서 반복문을 빠져나오게 한다.

+ nextLine() 메소드
- 문자열을 받을때 nextLine() 사용
- 결과는 String 타입 자료형에 저장한다.
- 뛰어쓰기 있어도 된다. 
- 사용자가 입력한 한 줄을 통째로 받음.

지역변수 정리
- 메소드 안에서 사용되는 지역변수 = 매개변수 = 스택에 저장됨 = 메소드 종료시 삭제됨
- 블럭문 안에서 사용되었던 i 같은것도 지역변수

변수 종류
1. 지역변수 (메소드 안에서 정의)
2. 멤버변수
3. 정적변수

메소드 호출
- 괄호, 괄호안의 변수가 기본자료형으로 되었을땐 Call by Value 로
- 클래스, 재열, 인터페이스면 주소를 넘기는 방식으로 호출 Call by Reference로

자료형 변환 3가지 방법
1. 기본 자료형 변환 : 기본자료형 변수들끼리 변환 ex)double <-> int
2. Wrapper 클래스를 이용한 자료형 변환 기본자료형과 참조형사이 변환 ex)int <-> String
3. 두 클래스사이에 상속이 전제되어야가능한 (업캐스팅, 다운캐스팅) 레퍼런스 형변환

자바 패키지
- java.io.* : 입출력관련 클래스를 모아둔 패키지 ex) BufferedReader, FileReader, FileWriter, File 등
- java.net.* : 소켓통신관련 패키지
- java.sql.* : 오라클,mysql등의 데이터베이스와 연동할때

*지금까지 만든 것들은 모두 괄호 안의 지역변수
ex) main 메소드 안에서 선언한 지역변수는 main 안에서만 사용가능

지역변수가 되기 위한 조건 
1. 메소드 안에서 정의되는 변수
- 메소드 안에서만 정의되어 사용되는 변수. 그 안을 벗어나는 순간 메모리에서 지워짐
- 스택이라는 메모리 영역에 저장된다.
2. 매개변수도 지역변수다.
- 메소드 괄호안에서 사용되는 변수
3. 블럭문(조건문 , 반복문)안에서 사용되는 변수도 지역변수다.

지역변수 특징
- 해당 메소드가 호출될때 스택 메모리에 할당되고, 메소드 실행이 종료되면 자동으로 메모리가 해제된다.

기본 자료형 변환 2가지


1. 묵시적 형변환(자동 형변환) :  컴파일러가 컴파일러하면서 자동으로 형변환 시켜준다.
- 작은 자료형 데이터를 큰 자료형 데이터로 형변환할때는 자동으로 변환해준다.
- int -> float 같은 4바이트지만 float형이 더 큰 자료형으로 인식된다. 그러므로 묵시적 형변환(자동) 된다.
- byte < short = char < int < long < float < double
- long 은 8 바이트, float은 4바이트지만 float(실수형) 이 더 큰걸로 취급된다.

2. 명시적 형변환(강제 형변환) : 컴파일러가 자동으로 변환시켜주지 않는다, 우리가 직접 강제로 형변환 시켜야함
ex) int -> char, char c = 97 일때는 오른쪽은 int이므로 자동으로 형변환 안됨 그러므로 char c = (char) 97; 해야함
ex) double -> int, int a = (int) 3.14 (오른쪽은 double 이므로 강제형변환해야)

패키지 추가
- 위에 1라인 좌측의 x를 더블클릭

아스키코드
- 문자는 내부적으로 아스키코드에 따른 숫자로 표현됨(십진수)
ex) 'a'를 int 형 자동 형변환 되면 출력하면 97이 나온다.

아스키코드 값
- 'A' : 65
- 'a' : 97

명시적 형변환(강제 형변환)
- 직접 변환 시키는것, 강제 형변환
- 큰 자료 데이터 -> 작은 자료 데이터 
- 괄호안에 왼쪽과 일치되는 자료형을 써준다.
ex) char c = (char)97; 
ex) int a = (int)3.14;
ex) random 메소드 쓰면 double형 데이터가 나옴 -> int로 강제 형변환

명시적 형변환 주의점
- int -> char 강제형변환하면 아스키코드 맞는 값 나온다.
- '형변환 과정에서 데이터 손실이 일어난다'
- float -> int : 소수점 이하를 '버림' (반올림 X)
- double -> float 강제형변환 : 소수점 길이가 긴상태에서 하면 짤림, 정확성이 보장되지 않는다.

+변수 선언
- int a = 10, b = 3, c; 이런식으로 int 변수 3개 생성 가능

연산자
- 언어 공통적으로 씀
- 변수와 변수사이 관계 연결할때 씀
- 산술연산자
- 비교연산자
- 조건연산자
- 논리연산자
- 대입연산자
- 증감연산자


산술연산자 : 산술적인 연산
+ , - , * , / , % (나머지)

산술연산자 주의1
- System.out.println("a / b = " + (a/b)); // 3(몫), 
- int와 int 연산이라서 같은 int형으로 출력되는거임. 3.333..아니라 3만 나옴.
- 기본자료형끼리만 산술적인연산이 가능
ex) String 클래스 와 기본자료형 끼리 결합시 "파이썬" + 50 하면 "파이썬50" 으로 '연산'이 아닌 '결합'된다

산술연산자 주의2

int n1, n2, n3, n4, n5, total;
double avg;

total = n1 + n2 + n3 + n4 + n5;
avg = total / 5;

 

- int형인 total과 int형인 5끼리 연산했으므로 결과는 int형으로서 뒤의 소숫점이 모두 잘리게 나온다. (정수로)

처리방법
1. avg = total / 5.0
- 5.0은 더블형이므로 소숫점이 짤리지 않는다.
2. avg = (double)total / (double)5;  
- 둘 중 하나만 double넣어도됨
- int와 double을 산술연산하면 double로 처리된다. (더 큰 자료형으로 처리된다.)

산술연산과 자료형
같은 자료형끼리 산술연산 -> 같은 자료형으로 결과가 처리된다
다른 자료형끼리 산술연산 -> 더 큰 자료형으로 결과가 처리된다.

문자열 연결/결합
- + 연산자

비교연산자 (=관계연산자) : 변수의 크기 비교해줌
- 값은 true / false
- if 문 조건식 만들때 많이 사용한다. ex) if(a == b) 나 if(a != b)
- > , >= , < , <= , == , !=
- char 끼리 비교 가능(문자가 아니라 내부 아스키코드 번호로 변환되어 비교)

참조형 변수의 비교
- 기본형 변수는 값을 저장하므로 값을 연산자로 비교 가능
- 참조형 변수들은 값을 저장하지 않기때문에 주의해야함
ex) String은 참조형 변수 중 '클래스' 중 하나

지역변수
- 지역변수는 "스택 영역"에 저장됨.

참조형 변수 (클래스, 배열, 인터페이스)
- String 클래스는 기본 자료형처럼 String s1 = "50" 문자열을 저장하는것처럼 보임
- but 메모리상에서 데이터 저장방식이 다르다.
- 값을 저장하는 영역과 그 영역의 주소값을 저장하는 영역이 따로 분리되어있다.
- 값은 힙에 , 주소값 저장하는 변수는 스택에 저장된다. 배열,인터페이스도 마찬가지이다.

 

참조형 변수의 비교 예시(String)
- 참조형은 값은 모두 힙이란 영역에 저장되고, 스택이란 메모리 영역에서 변수들이 값의 시작 주소값을 가지고 있다.
- s1, s2는 이 "자바"란 값을 가리키고 있다, 즉 주솟값을 가지고 있다.

String s1 = "자바" ; 
String s2 = new String("자바")


- 이 두가지 방식은 메모리상에서 처리되는데 차이가 있다(의미가 다르다)

* String 클래스만 값을 바로 저장해도 되고 new 를 통해서 String객체 생성하는 방식으로 
만들수도 있다.

String str1 = "자바";
String str2 = "자바"; 
String str3 = new String("자바");


1. str1, str2 처럼 기본 변수처럼 선언할땐,
- "자바"가 적힌 곳의 시작 주소값을 갖게 된다.
- str2 에 같은값인 "자바"를 할당하면 str2도 str1이 가리킨 같은 "자바" 를 같이 가리키게 됨. (새로운 공간을 만들지 않음)
- 즉 str1, str2는 같은 주소가 된다.

if(str1 == str2) {
System.out.println("같은 주소");
}else {
System.out.println("다른 주소");
}


출력 : 같은 주소

2. str3처럼 new 써서 객체를 만들어 선언할땐,
- new는 새로운 공간을 힙메모리에 만들어서 자바란 값을 저장하겠다는 의미!
- 그래서 힙메모리상에 "자바"를 새로 또 만들고 주솟값을 str3가 가진 형태로 된다.(그림참고)

if(str1 == str3) {
System.out.println("같은 주소");
}else {
System.out.println("다른 주소");
}


출력 : 다른 주소

 

그림

마우스로 그린거라..



참조형 변수의 비교 (값을 비교)
- 참조형은 주소값을 비교할 때 비교연산자를 써야하는 것이고
- 참조형들은 값을 비교하려면 비교연산자로 비교할 수 없다.
- equals 메소드를 사용해서

System.out.println(str1.equals(str2)); // true
System.out.println(str1.equals(str3)); // true


- 해야 값을 비교할 수 있다.

클래스로 입력받기
- 키보드 입력받기 위한 클래스가 여러개 있다.
- java.io 패키지 안 클래스로 입력받을땐 예외처리 해야한다.
- 여기선 일단 예외처리 필요없는  Scanner 객체 생성해서 입력받자 java.utility

Scanner sc = new Scanner(System.in); //Scanner.class 라는 바이트 코드 안에 있는 클래스/메소드

int n1 = sc.nextInt(); //첫번째 값과 두번째 값 구분은 스페이스바 or 엔터키로 구분함.
int n2 = sc.nextInt();


+ Scanner 쓸때 부분 입력과 동시에 import하는법 Ctrl + Space

클래스 구조 (api 문서)
- 클래스는 생성자, 메소드, 필드 가 있다
- 클래스로 객체를 만들때 생성자를 호출하게된다
- 생성자는 클래스와 동일한 명으로 되어있고 제공되는 것들만 쓸 수 있다. (제공되지 않은 생성자로는 불가능)
- 생성자는 메소드 형태로 되어있기 때문에 괄호가 반드시 있다 


Scanner 클래스 구조
- 라이브러리는 클래스형태로 되어있다 입력을받을때 쓰는 Scanner 클래스
- Scanner 객체 만들어서 사용한다.
- java.lang 패키지 안의 클래스 아니므로 import해야함

Scanner Class는 
java.lang.Object (부모)
     java.util.Scanner 

1. Scanner 생성자
- Scanner 중 매개변수가  InputStream source라고 되어있는거를 선택하여 입력받을 수 있다. 

Scanner(InputStream source)
Constructs a new Scanner that produces values scanned from the specified input stream.
- 우리는 생성자 중 이걸 쓴다.
- (InputStream source) 안에 System.in 이라고 쓴다(입력위해)
+ system 클래스 안에 in은 자료형이 InputStream

2. Scanner는 필드는 없다.

3. Scanner 메소드
nextInt() 메소드 : 키보드로 정수형태의 값 입력 받을때 쓰는 Scanner 안의 메소드
+ nextDouble(), nextInt() 등 자료형에 따라서 있다.
- nextInt() 메소드는 return형이 int형이다. 그래서 왼쪽도 int 변수가 와야함.
- nextDouble()오면 실수형으로 처리됨 (return형이 Double)
- nextLine() 오면 내가 10 와 20 입력해도 숫자가 아니라 문자로 처리됨 (return형이 String)

Scanner sc = new Scanner(System.in); 
//Scanner.class 라는 바이트 코드 안에 있는 클래스/메소드
//표준 입력받을땐 System.in을 생성자로
int n1 = sc.nextInt();
//첫번째로 정수를 받아서 n1에 저장하란 뜻

int n1 = sc.nextInt(); //첫번째 값과 두번째 값 구분은 스페이스바 or 엔터키로 구분함.
int n2 = sc.nextInt();


+ sc.nextInt() '객체'에 메소드! 이걸 int 형 변수에 저장
+ 파일로 부터 입력을 받을때 쓰는 생성자는 Scanner(File source) , Ctrl + Space 하면 볼 수 있다

조건 연산자
변수 = (조건식) ? 값1 : 값2;
- 조건식이 참이면 값1을 변수에 할당
- 조건식이 거짓이면 값2를 변수에 할당

+ 자바는 변수선언을 꼭 위에만 할수있는건 아니다

논리연산자 : ||, &&, ! ( 자바는 기호를 써야함)
- OR연산자 , AND 연산자, NOT 연산자
- 조건식이 2개 이상인 경우에 논리연산자(||, &&) 를 쓴다.
ex) if( a>b || a>c)
ex) if( a>b && a>c)

1. OR 연산자(||)
- 둘중 하나라도 True 가 있으면 True가 됨
- 둘다 False 여야만 False가 됨

2. AND 연산자(&&)
- 둘 다 true 인경우에만 true가 되고 나머지는 false가 됨

3. NOT 연산자(!)
- 기존 논리값을 반대로 바꿔줌
- true앞에 !가 오면 false가 되고 반대도 성립

확장 대입 연산자(= 복합 대입 연산자)
- 간결히 표기할때
- a += b; 는 a+b를 먼저 수행하고 결과를 a로 다시 할당 시켜란 의미

a+=b;	// a = a + b;
a-=b; 	// a = a - b;
a*=b; 	// a = a * b;
a/=b; 	// a = a / b;
a%=b;	// a = a % b;


증감 연산자
- (++) : 1씩 증가   

++a(선행 처리) // a=a+1;
a++(후행 처리) // a=a+1;


- (--) : 1씩 감소

--a(선행 처리)   // a=a-1;
a--(후행 처리)  // a=a-1;



증감 연산자 주의
- 변수명 앞에 오느냐 뒤에오느냐에 따라 다르다.
- ++가 앞에있으면 먼저 처리하고 그 줄을 넘어가라
- ++가 뒤에있으면 그 줄을 넘어가고 연산을 수행하라.

ex)

b= 10;
b1 = b++; // 후행 연산, 이 줄에선 b가 증가하지 않음.


출력 : b = 10, b1 = 11

 

자바의 제어문
1. 조건문(=선택문)
- if문
- switch~case문
2. 반복문
- for문
- while문
- do~while문
3. 보조제어문
- break문
- continue문

1. if문

    if(조건식){
         조건식이 참인경우 실행될 문장;
    }
   if(조건식){
         조건식이 참인경우 실행될 문장;
   }else{
         조건식이 거짓인경우 실행될 문장;
   }
   // 둘 중 하나는 반드시 실행됨

 

   if(조건식1){
          조건식1이 참인경우 실행될 문장;
   }else if(조건식2){
          조건식2가 참인경우 실행될 문장;
   }else{
          위의 조건식을 만족하지 않을때 실행될 문장;
   }
// 가장 먼저 해당하는 것의 문장을 실행하고 if문 전체를 나간다
// 딱 1개만 수행된다. 즉 위에서 조건이 참인걸 만나면 수행후 if를 나감, 밑으로 내려가지 않는다.

+ Recent posts