객체지향개념1,2을 계속 까먹어서 정리했다.
클래스 : 객체를 정의해 놓은 것
객체 : 실제로 존재하는 것, 모든 인스턴스를 대표하는 일반적인 용어
인스턴스 : 특정 클래스로부터 생성된 객체(예 : Tv 인스턴스)
예 : TV 클래스
Class Tv {
// 변수
String color; // 색깔
boolean power; // 전원상태
int channel; // 채널
//메소드
void power() {power = !power;}
void channelUp() {channel++;}
void channelDOwn() {channel--;}
}
클래스명 변수명; // 클래스의 객체를 참조하기 위한 참조변수 선언
변수명 = new 클래스명(); // 클래스의 객체를 생성 후,객체의 주소를 참조변수에 저장
Tv t; // Tv 클래스 타입의 참조변수 t를 선언
t = new Tv(); // Tv 인스턴스를 생성한 후, 생성된 Tv 인스턴스의 주소를 t에 저장
Class Tv {
// 변수
String color; // 색깔
boolean power; // 전원상태
int channel; // 채널
//메소드
void power() {power = !power;}
void channelUp() {channel++;}
void channelDOwn() {channel--;}
}
class TvTest {
public static void main(String args[]) {
Tv t; // Tv 인스턴스를 참조하기 위한 변수 t를 선언
t = new Tv(); // Tv 인스턴스 생성
t.channel =7; // Tv 인스턴스의 멤버변수 channel의 값을 7로 한다
t.channelDown(); //Tv 인스턴스의 메소드 channelDOwn(()을 호출
System.out.println("현재 채널은 " + t.channel + "입니다.");
}
}
channel 의 값을 7로 했기 때문에 이 사진에서 channel의 값은0 이 아닌 7.
후에 channelDown 메소드에 의해 6이 된다.
참조변수에는 하나의 값(주소)만이 저장될 수 있으므로 둘 이상의 참조변수가 하나의 인스턴스를 참조하는 것은가능하지만하나의 참조변수로 여러 개의 인스턴스를 가리키는 것은 가능하지 않다.
많은 수의 객체를 다뤄야 할 때 객체를 배열로 다룬다.
객체 배열 안에 객체가아닌 객체의 주소가 저장된다.
객체 배열을 생성하는 것은 객체를 다루기 위한 참조 변수들이 만들어진 것 뿐.
객체가 저장되지 않음.
따라서 객체를 생성해서 객체 배열의 각 요소에 저장해야 한다.
Tv[] tvArr = new Tv[3]; // 참조변수 배열(객체 배열)을 생성
// 객체를 생성해서 배열의 각 요소에 저장
tvArr[0] = new Tv();
tvArr[1] = new Tv();
tvArr[2] = new Tv();
Tv[] tvArr = {new Tv(), new Tv(), new Tv()};
Tv[] tvArr = new Tv[100];
for(int i = 0; i < tvArr.length; i++) {
tvArr[i] = new Tv();
}
변수의 종류 : 클래스 변수 = static 변수(cv), 인스턴스 변수 (iv), 지역 변수(lv)
인스턴스 변수는 인스턴스가 생성될 때 마다 생성되므로 인스턴스마다 각기 다른 값을 유지할 수 있지만, 클래스 변수는 모든 인스턴스가 하나의 저장공간을 공유하므로, 항상 공통된 값을 갖는다.
각 Card 인스턴스는 자신만의 kind 와 number 를 유지하고 있어야 하므로 인스턴스변수,
카드의 width 와 height 는 모든 인스턴스가 공통적으로 같은 값을 유지해야하므로 클래스 변수로선언
class Ex6_3 {
public static void main(String args[]) {
System.out.println("Card.width = " + Card.width);
System.out.println("Card.height = " + Card.height);
// 클래스 변수 (static 변수) 는 객체생성 없이 직접 사용 가능
Card c1 = new Card();
c1.kind = "Heart";
c1.number = 7; // 인스턴스 변수의 값 변경
Card c2 = new Card();
c2.kind = "Spade";
c2.number = 4; // 인스턴스 변수의 값 변경
System.out.println("c1은 " + c1.kind + ", " + c1.number + "이며, 크기는 (" + c1.width + ", " + c1.height + ")");
System.out.println("c2는 " + c2.kind + ", " + c2.number + "이며, 크기는 (" + c2.width + ", " + c2.height + ")");
System.out.println("c1의 width와 height를 각각 50, 80으로 변경합니다.");
c1.width = 50; // 클래스 변수의 값 변경
c1.height = 80; // 클래스 변수의 값 변경
System.out.println("c1은 " + c1.kind + ", " + c1.number + "이며, 크기는 (" + c1.width + ", " + c1.height + ")");
System.out.println("c2는 " + c2.kind + ", " + c2.number + "이며, 크기는 (" + c2.width + ", " + c2.height + ")");
}
}
class Card {
String kind;
int number;
static int width = 100;
static int height = 250;
}
// 실행 결과
// Card.width = 100
// Card.height = 250
// c1은 Heart, 7 이며, 크기는 (100,250)
// c2는 Spade, 4 이며, 크기는 (100,250)
// c1의 width와 height를 각각 50, 80으로 변경합니다.
// c1은 Heart, 7 이며, 크기는 (50, 80)
// c2은 Spade, 4 이며, 크기는 (50, 80)
메소드를 사용하는 이유
메소드를 호출해야만 구현부 {} 의 문장들이 수행된다.
public class Computer {
int sum1(int[] values) {
int sum = 0;
for(int i = 0; i <values.length; i++) {
sum += values[i];
}
return sum;
}
int sum2(int ... values) {
int sum = 0;
for(int i = 0; i < values.length; i++) {
sum+=values[i];
}
return sum;
}
}
public class ComputerExample {
public static void main(String[] args) {
Computer myCom = new Computer();
int[] values1 = { 1, 2, 3 };
int result1 = myCom.sum1(values1);
System.out.println("result1 : " + result1);
int result2 = myCom.sum1(new int[] { 1, 2, 3, 4, 5 });
System.out.println("result2 : " + result2);
int result3 = myCom.sum2(1, 2, 3);
System.out.println("result3 : " + result3);
int result4 = myCom.sum2(1, 2, 3, 4, 5);
System.out.println("result4 : " + result4);
}
}
// result1 : 6
// result2 : 15
// result3 : 6
// result4 : 15
반환값의 유무에 관계없이 모든 메소드에는 적어도 하나의 return문이 있어야한다.
반환 타입이 void인 경우, return문없이 아무런 문제가 없었던 이유는 컴파일러가 메소드 마지막에 return;
을 자동적으로 추가해주었기 때문이다.
메소드를 호출할 때 매개변수(parameter)로 지정한 값을 메소드의 매개변수에 복사해서 넘겨준다.
매개변수의 타입이 기본형(primitive type)일 때는 기본형 값이 복사 되지만,
참조형(reference type)이면 인스턴스의 주소가 복사된다.
기본형 매개변수 : 변수의 값을 읽기만 할 수 있다. - 기본형으로 선언하면 저장된 값만 얻기 때문
참조형 매개변수 : 변수의 값을 읽고 변경할 수 있다. - 참조형으로 선언하면 값이 저장된 곳의 주소를 알 수 있기 때문
이해하기 위해 호출 스택을 보면 도움이 된다.
인스턴스 메소드
참조변수.메소드이름()
으로 호출클래스 메소드 (static 메소드)
클래스이름.메소드이름()
으로 호출class MyMath2 {
long a, b;
// 인스턴스 변수 a, b만을 잉요해서 작업하므로 매개변수가 필요없다.
long add() { return a + b; } // a, b는 인스턴스 변수
long subtract() { return a - b; }
long multiply() { return a * b; }
double divide() { return a / b; }
// 인스턴스 변수와 관계없이 매개변수만으로 작업이 가능하다.
static long add(long a, long b) { return a + b; } // a, b는 지역변수
static long subtract(long a, long b) { return a - b; }
static long multiply(long a, long b) { return a * b; }
static double divide(long a, long b) { return a / (double)b; }
}
class Ex6_9 {
public static void main(String args[]) {
// 클래스 메서드 호출. 인스턴스 생성없이 호출가능
System.out.println(MyMath2.add(200L, 100L));
System.out.println(MyMath2.subtract(200L, 100L));
System.out.println(MyMath2.multiply(200L, 100L));
System.out.println(MyMath2.divide(200L, 100L));
MyMath2 mm = new MyMath2(); // 인스턴스를 생성
mm.a = 200L;
mm.b = 100L;
// 인스턴스 메서드는 객체생성 후에만 호출이 가능함.
System.out.println(mm.add());
System.out.println(mm.subtract());
System.out.println(mm.multiply());
System.out.println(mm.divide());
}
}
하나의 클래스에 같은 이름의 메소드를 여러개 정의하는 것
오버로딩의 조건
class Ex6_10 {
public static void main(String args[]) {
MyMath3 mm = new MyMath3();
System.out.println("mm.add(3, 3) 결과:" + mm.add(3,3));
System.out.println("mm.add(3L, 3) 결과: " + mm.add(3L,3));
System.out.println("mm.add(3, 3L) 결과: " + mm.add(3,3L));
System.out.println("mm.add(3L, 3L) 결과: " + mm.add(3L,3L));
int[] a = {100, 200, 300};
System.out.println("mm.add(a) 결과: " + mm.add(a));
}
}
class MyMath3 {
int add(int a, int b) {
System.out.print("int add(int a, int b) - ");
return a+b;
}
long add(int a, long b) {
System.out.print("long add(int a, long b) - ");
return a+b;
}
long add(long a, int b) {
System.out.print("long add(long a, int b) - ");
return a+b;
}
long add(long a, long b) {
System.out.print("long add(long a, long b) - ");
return a+b;
}
int add(int[] a) { // 배열의 모든 요소의 합을 결과로 돌려준다.
System.out.print("int add(int[] a) - ");
int result = 0;
for(int i=0; i < a.length;i++)
result += a[i];
return result;
}
}
https://blog.naver.com/heartflow89/220955879645
생성자에 대해 잘 설명되있는 블로그
인스턴스를 생성할 때 "클래스 객체변수 = new 클래스();" 라는 구문을 사용하고 이때 "클래스();"는 생성자를 호출하는 의미
[출처][JAVA/자바] 생성자(Constructor)와 초기화|작성자 JOKER
매개변수가 없는 생성자
생성자가 하나도 없을 때만, 컴파일러가 자동 추가
클래스이름() {} // 기본 생성자
Point() {} // Point 클래스의 기본 생성자
Card c = new Card();
1. 연산자 new에 의해서 메모리(heap)에 Card 클래스의 인스턴스가 생성된다.
2. 생성자 Card()가 호출되어 수행된다.
3. 연산자 new의 결과로, 생성된 Card 인스턴스의 주소가 반환되어 참조변수 c에 저장된다.
class Data_1 {
int value;
// 기본생성자 추가할 필요가 없음. 생성자가 없기떄문에 컴파일러가 자동 추가
}
class Data_2 {
int value;
Data_2() {} // 기본 생성자를 추가하면 에러가 사라짐
Data_2(int x) { // 매개변수가 있는 생성자.
value = x;
}
}
class Ex6_11 {
public static void main(String[] args) {
Data_1 d1 = new Data_1();
Data_2 d2 = new Data_2(); // 기본 생성자를 호출하기 때문에 compile error발생
// Data_2 d2 = new Data_2(10); // 기본생성자 안쓸거면 이렇게 써야됨
}
}
기본 생성자가 컴파일러에 의해서 추가되는 경우는 클래스에 정의된 생성자가 하나도 없을 때 뿐이다.
class Car {
String color; // 색상
String gearType; // 변속기 종류 - auto(자동), manual(수동)
int door; // 문의 개수
Car() {}
Car(String c, String g, int d) {
color = c;
gearType = g;
door = d;
}
}
class Ex6_12 {
public static void main(String[] args) {
Car c1 = new Car();
c1.color = "white";
c1.gearType = "auto";
c1.door = 4;
Car c2 = new Car("white", "auto", 4);
System.out.println("c1의 color=" + c1.color + ", gearType=" + c1.gearType+ ", door="+c1.door);
System.out.println("c2의 color=" + c2.color + ", gearType=" + c2.gearType+ ", door="+c2.door);
}
}
인스턴스를 생성한 다음에 인스턴스변수의 값을 변경하는 것보다 매개변수를 갖는 생성자를 사용하는 것이 코드를 보다 간결하고 직관적으로 만든다.
클래스를 작성할 때 다양한 생성자를 제공함으로써 인스턴스 생성 후에 별도로 초기화를 하지 않아도 되도록 하는 것이 바람직하다.
생성자에서 다른 생성자 호출할 때 사용
조건
인스턴스 자신을 가리키는 참조변수, 인스턴스의 주소가 저장되어 있다.
SET, GET 메소드를 사용하는 이유는 외부로부터 변수값에 직접적으로 접근하는것을 막기 위해서다. 직접 접근하게 되면 값이 변하게 되고 그러면 데이터 무결성이 깨질 수 있기 때문이다.
대표적으로 자바에서는 함수를 통해 값을 전달받고, 전달하고 방식을 권장하고 있다.
또한 클래스 내에서 변수 private(캡슐화, 정보은닉)를 선언해서 외부에서 접근할 수 없도록 한다.
getter는 private를 외부로 꺼내는 메서드, setter는 private에 값을 넣는 메서드이다.
private 변수를 다른 클래스에 꺼내는 메서드는 get + 변수명(첫글자 대문자)
private 변수에 값을 초기화하는 메서드는 set + 변수명(첫글자 대문자)
Getter :
내부의 멤버변수에 저장된 값을 외부로 리턴.
메개변수는 없고, 리턴값만 있는 (void 불가) 메서드로 정의한다.
메서드명은 주로 getXXX() 메서드 형식으로 지정
XXX은 해당 멤버변수의 변수명을 사용.
Setter :
외부로부터 데이터를 전달받아 멤버변수에 저장.
매개변수만 있고, 리턴값은 없는 (반드시 void) 메서드로 정의.
class A {
private int num = 10;
public int getNum() {
return a;
}
public void setNum(int a) {
this.a = a;
}
}