클래스 (Class)
자동차를 생각해보자.
> 자동차에는 가속 페달을 밟고, 엔진은 기름을 공급받아 동력을 생산하고, 엔진에서 나온 동력을 적정 수준으로 변환하고, 바퀴로 전달하는 변속기 등이 있다.
~~ 여러가지 도구, 재료, 사용자, 기계와 같은 "객체"들이 존재한다.
1. 객체와 클래스
자동차이기 위해 가져야하는 정보와, 기능...에 대한 정보를 담는 것이 클래스.
- 기본적으로 자바의 기능 수행을 위한 코드는 클래스 내부에만 존재함.
ex.
- Car 라고 하는 class
public class Car {
// 자동차의 설계도(?)
public String brand; // 브랜드
public String name; // 차종
public int fuel; //탱크상태
public void beep() { // 클락션을 울리는 기능 (메서드)
System.out.println("빵~");
}
public void printInfo() { // 자동차 정보를 모두 출력하는 기능
System.out.println(String.format("name:\t%s", name));
...
}
}
- 속성 (attribute) : 하나의 객체가 가질 수 있는 성질 또는 데이터 정의.
- brand, name, fuel ...
- 메서드 : 반복해서 활용할 기능들을 모아놓는 역할.
- Car 객체를 만듦. (Car class를 바탕으로 만들어진 객체!) = 클래스의 인스턴스.
- 속성에는 '.' 을 이용해 접근 가능
- 속성에도 데이터 할당 가능.
- 값을 가져올 때도 '.'을 활용해 가져올 수 있음.
- 객체의 메서드를 호출할 때도 '.'을 활용해 호출 가능.
public static void main(String[] args) {
Car myCar = new Car(); // Car 객체 생성
// Car class의 속성에 데이터 할당하기
myCar.name = "K5";
myCar.brand = "Kia";
myCar.fuel = 72;
// 메서드도 사용 가능
myCar.beep();
myCar.printInfo();
}
즉, Car는 클래스 (~설계도~)
myCar는 Car의 인스턴스인 객체 (~실체~)
** 정적(static) 제어자
: 속성이나 메서드 앞에 static 추가하면됨.
정적 메서드/ 정적 변수는 만들어진 인스턴스에 소속되는 것이 아니라~ 클래스 자체에 소속됨!
~~> 그러므로 인스턴스를 굳이 만들지 않고도 바로 접근 가능.
- 정적 변수 : 모든 객체를 만드는데 필요한 상수나 설정, 또는 전체 몇개의 객체가 만들어졌는지 세는 용도로 많이 활용.
- 정적 메서드 : 단순기능을 모아두는 클래스에서 굳이 인스턴스를 만들지 않고도 활용할 수 있도록 하는 용도로 많이 활용.
public class Car {
public static int count = 0;
public String name;
...
}
public static void main(String[] args) {
Car myCar = new Car();
Car.count++; //static 속성이므로 객체.count를 사용
myCar.name = "K5";
}
2. 접근 제어자
: 속성이나 메서드에 덧붙여서 속성과 메서드에 접근에 대한 권한을 조절.
- public : 아무나 사용가능
- private : 클래스 내부에서만 사용 가능.
~!~ 정보 은닉 (Information Hiding) : 접근 제어자를 통해 객체의 구체적인 정보 노출을 방지한다. ~!~
~!~ 캡슐화 (Encapsulation) : 기능과 정보를 하나의 클래스로 묶어놓는 개념. ~!~
public class Car {
private String name;
private String brand;
private int fuel;
public void printInfo() {
System.out.println(String.format(
"name:\t%s\nbrand:\t%s\nfuel:\t%s",
name, brand, fuel
));
}
}
public static void main(String[] args) {
Car someCar = new Car();
someCar.name = "K5"; // 불가능
someCar.brand = "Kia"; // 불가능
someCar.fuel = 72; // 불가능
someCar.printInfo(); //가능 (public)
}
그러나,
무작정 다 접근하지 못하게 한다면 ? 너무 한정적인 상황이 된다.....
private일 경우 다른 클래스에서는 변경도 못하고, 확인도 불가능하게 됨. ㅠㅡㅠ
원래 목적은 클래스 밖에서 그 Car의 name, brand, fuel을 변경하지 못하게 하지만, 그래도 외부에서 확인은 가능하게 하고싶었다...
>> 그럴 땐 어떻게 해야할까?
~~> public 접근 제어자를 가진 메서드를 만들어 해당 메서드가 private 속성을 반환하게 만들 수 있다.~
이를 쉽게 할 수 있는 메서드는? GETTER & SETTER 메서드 > 해당 속성을 직접적으로 다룰 때 사용하는 것이다.
public class Car {
private String name;
private String brand;
// ...
public String getName() {
return name;
}
public String getBrand() {
return brand;
}
// ...
}
public static void main(String[] args) {
Car someCar = new Car();
System.out.println(someCar.getBrand());
System.out.println(someCar.getName());
}
Getter메서드를 쓰면 ? private name과 brand를 확인 가능하게 만든다!
+ Setter : private fuel을 변경하고 싶다면....? setter를 사용해보자
* this : 객체 자신을 가르키는 키워드
public void setFuel(int fuel) {
this.fuel = fuel;
}
- 생성자 (Constructor)
: 객체를 생성할 때 호출하는 특수한 메서드.
- 생성자 메서드 이름은 클래스와 동일하게 만듦.
- 따로 만들지 않을 시 아무 정보도 받지 않는 기본 생성자가 만들어진다.
- 생성자를 만들면 기본 생성자는 사라짐.
- 생성자도 메서드 오버로딩이 된다!
+ 한번 설정되면 변하지 않도록 만들기 위해서 final을 붙일 수도 있다.
private final String name; > 다시 변경이 불가능하다.
public class Car {
private static int count = 0;
private String brand;
private String name;
private int fuel;
//생성자
public Car() { // 기본 생성자
count++;
}
//변수를 넣은 생성자
public Car(String brand, String name, int fuel) {
this.brand = brand;
this.name = name;
this fuel = fuel;
count++;
}
=> 이렇게 만들어진 생성자는 new 키워드와 함께 활용 가능.
3. 자바의 데이터 저장
클래스.. 객체... ? 메모리의 어디에 저장될까...? 결국 모두 비트로 표현되고,,,, 어디에 어떤식으로 저장될지가 궁금하다!
>> Stack Memory (LIFO, Last In First Out)
- 모든 메서드 (main 포함)는 호출 시 stack memory에 필요한 공간을 할당받음. > 프레임 단위로 올라간다.
- 메서드가 종료되면, 프레임이 stack에서 사라지고, 모든 값이 사라진다.
- 원시타입(Primitive Type)은 stack memory의 공간에 데이터가 직접 들어간다.
- 원시타입? : int, char, boolean, byte, short, long, float, double
>> Heap Memory
- 클래스 인스턴스를 비롯한 객체들은 Stack에 직접 데이터를 작성하지 않음. > Heap space라는 별도의 공간에 저장.
- 메서드의 호출 및 종료와 상관 없이 객체의 데이터가 저장되어 있다.
- 총 공간이 stack에 비해 더 크지만, 공간할당에 걸리는 시간이 더 길다.
- 원시타입 제외한 모든 참조 타입들(String, 배열, interface 등)이 heap memory에 저장.
- new 키워드를 만나면 heap상에 객체(클래스의 인스턴스 객체)를 만듦. + 이때 생성된 객체가 어디있는지(Reference)를 stack 변수에 저장함.
- 객체 내에 또다른 참조 타입이 있다면 그것도 heap에 생성
- 더이상 객체를 참조하는 변수가 없다면 Garbage Collector가 공간을 비워줌.
유연성이 필요한 객체 저장을 위해서는 Heap Space 사용하고,
전체적인 코드 수행 및 메서드 메모리 관리를 위해 Stack Memory 사용한다.
** Pass by Value vs Pass by Reference
: 메서드를 호출할 때 인자가 전달되는 방식
- pass by value : 전달된 인자의 값만 복사하는 방식.
인자로 전달한 데이터가 사실 실제 데이터가 아니라 그 데이터와 동일한 "값"이 복제된 것이므로, 함수 내부에서 이 값을 변경한다해도, 함수 밖의 변수에는 영향이 없다.
- pass by reference : 전달된 인자가 실제로 존재하는 공간을 전달하는 방식.
인자로 전달한 데이터가 존재하는 공간이 어딘지가 전달되기 때문에 함수 내부에서 해당 값을 조작하면, 실제로 그 데이터가 조작된 것이므로 함수 바깥에서도 변화가 유지된다.
자바는...? 100% pass by value... 값만 전달할 뿐!!!!
int a = 10;
int b = 20;
swap(a,b);
System.out.println(a); //10
System.out.println(b); //20
public static void swap(int a, int b) {
int tmp = a;
int a = b;
int b = tmp;
}
~~> BUT!! 진짜 의미는 전달된 인자가 같은 곳에 있는지가 중요!
public static void main (String[] args) {
Car someCar = new Car("K5", "Kia", 72); // someCar는 Stack의 main 프레임에 있음.
someCar.drive(10);
refuel(someCar);
System.out.println(someCar.getFuel()); //결과값 : 100
}
public static void refuel(Car car) { // car는 Stack의 refuel 프레임에 있음. (refuel메서드 호출)
car.setFuel(100);
}
// 그러나, 전달한 값은 someCar가 Heap에 존재하는 위치... > 이 객체가 someCar 객체와 같다.
** 결론 :
기술적 의미에서는 pass by value가 맞지만
인자로 전달된 객체는 결국 같은 객체를 사용한다...!
현상을 보고 기술이 어떨지에 대한 선입견을 가지지 말고, 본질을 배우려고 노력하자.
4. String 및 Wrapper class
1) String
: 참조 타입.
- 유틸리티 메서드 사용 가능 (ex. String.format)
2) 원시 타입 Wrapper class
: 원시 타입 자료형들을 객체지향적 관점에서 사용할 수 있도록 동일한 데이터를 들고 있을 수 있는 wrapper class를 제공.
- 본래의 원시타입들을 들고 있으면서 각 자료형을 다룰 때 유용한 메서드와 상수를 제공.
- 데이터 할당도 가능 (할당 연산자 등 활용)
- Autoboxing and unboxing : 원시타입과 호환된다
메서드 | 기능 |
Integer.parseInt(String s) | 문자열이 나타내는 정수 반환 |
Double.parseDouble(String s) | 문자열이 나타내는 실수 반환 |
Character.isDigit(char ch) | 문자가 숫자를 나타내는지 확인 |
Character.isLetter(char ch) | 문자가 글자를 나타내는지 확인 |
string.length() | 문자열의 글자수 반환 |
string.substring(int beginIndex) | 문자열을 beginIndex부터 자른 문자열을 반환 |
string.charAt(int index) | 문자열의 index 위치의 char를 반환 |
string.indexOf(String str) | 주어진 문자열이 시작하는 index 반환 |
string.split(String regex) | 주어진 정규표현식을 기준으로 문자열을 나눠 배열로 반환 |
'Programming > Java' 카테고리의 다른 글
예외처리 (Exception Handling) (1) | 2023.11.28 |
---|---|
객체지향 프로그래밍 (1) | 2023.11.28 |
메서드 (Methods) (1) | 2023.11.23 |
제어문 (Control Statements) (1) | 2023.11.22 |
연산자 (Operators) (0) | 2023.11.21 |