- 남궁성 님의 자바의정석 - 기초편 강의를 간략히 정리한 내용입니다.
객체지향 언어 = 프로그래밍 언어 + 객체지향개념 (규칙)
자바의 다양한 속성
- 캡슐화
- 상속
- 추상화
- 다형성
클래스의 정의
객체를 정의해 놓은것, 설계도
클래스의 용도
클래스는 객체를 생성하는데 사용
객체의 정의
실제로 존재하는 것, 사물, 개념
객체의 용도
객체가 가지고 있는 기능과 속성에 따라 다름
인스턴스 화란?
클래스를 인스턴스(객체)로 만드는 과정
TV클래스 -> 제품생성 (인스턴스화 ) -> 제품 (인스턴스, 객체 )
객체의 생성과 사용
예시 클래스)
class Tv{
String color;
boolean power;
int channel;
void power() {
power = !power;
}
void channelUp() {
channel++;
}
void channelDown() {
channel--;
}
}
// 객체의 생성
Tv t; // Tv 클래스 타입의 참조변수 t를 생성
t = new Tv(); // Tv 인스턴스를 생성 후, 생성된 Tv인스턴스의 주소를 t에 저장
//객체의 사용
t.channel = 7; // Tv 인스턴스의 멤버변수 channel의 값을 7로 한다.
t.channelDown(); // Tv 인스턴스의 메서드 channelDown()을 호출한다.
System.out.println("현재 채널은 " + t.channel + " 입니다.");
선언위치에 따른 변수의 종류
class Variables {
int iv; // 인스턴스 변수
static int cv; //클래스 변수, 공유변수 , static 변수
void method() {
int lv = 0; //지역변수, local variable
}
}
변수의 종류 | 선언위치 | 생성시기 | 기타 |
클래스 변수 (class variable) |
클래스 영역 | 클래스가 메모리에 올라갈 때 | 객체생성 불필요 |
인스턴스 변수 (instance variable) |
인스턴스가 생성되었을 때 | 객체생성 필요 | |
지역변수 (local variable) |
클래스 영역 이외의 영역 (메서드, 생성자, 초기화 블럭 내부) |
변수 선언문이 생성되었을 때 |
메서드
- 반복적으로 수행되는 여러 문장을 메서드로 작성.
- 1개의 기능만 수행되게 작성.
메서드 = 선언부 + 구현부
반환타입 메서드이름 ( 타입변수명, 타입변수명 ,... ) { // 선언부
//메서드 호출 시 수행될 코드 (구현부)
}
int add (int a, int b) {
int result = a+b;
return result;
}
메서드의 호출
메서드 이름( 값1, 값2, ... ) //메서드 호출 방법
int result = add(3,5) // int add를 호출하고, 결과를 result에 저장
호출 스택 ( call stack )
스택 (stack) : 밑이 막힌 상자. 순차적으로 쌓인다.
스택은 Last In First Out, First In Last Out 순서를 따른다.
호출스택 실행과정 예시.
class CallStackTest {
public staic void main(String[] args) {
firstMethod();
}
static void firstMethod() {
secondMethod();
}
static void secondMethod() {
System.out.println("secondMethod()");
}
}
호출 스택의 특징
메서드 수행에 필요한 메모리가 제공되는 공간
메서드가 호출되면 호출스택에 메모리 할당, 종료되면 해제된다.
맨위에 메서드 하나만 실행 중 , 나머지는 대기중
자바의 스택과 힙
스택(Stack)
로컬 변수와 함수호출을 저장하는데 사용되는 메모리 영역 ( LIFO : Last In First Out )
Stack에서는 Primitive 타입 , Heap영역에서 생성된 Object 타입의 데이터의 참조값이 할당된다.
Thread당 하나씩 생성되며 각 Thread 간 Stack 영역을 접근할 수 없다.
힙(Heap)
프로그램 실행 중 동적으로 할당된 데이터를 저장하는데 사용되는 메모리 영역
힙 영역에서는 모든 Object 타입의 데이터가 할당이 된다. ( 모든 객체는 Object 타입을 상속받는다)
생명주기가 길다.
왜냐하면 Object의 크기가 크고, 서로 다른 코드블럭에서 공유가 되기 떄문에.
Heap은 Stack처럼 Thread마다 하나씩존재하는게 아니라 여러개의 Thread가 있어도
힙은 단 하나의 영역만 존재
GC ( Garbage Collection )
가비지컬렉션은 자바의 메모리 관리방법중에 하나로 JVM(자바 가상머신)의 Heap 영역에서
동적으로 할댕한 메모리 영역 중 필요없게 된 메모리 영역을 주기적으로 삭제하는 프로세스를 말한다.
C나 C++에는가비지 컬렉션이 없어 수동으로 메모리 할당과 해제를 해줘야되는 반면
자바는JVM (자바 가상머신)의 가비지컬렉션이 메모리관리를 대행해 주기 떄문에
특정 경우를 제외하고, 메모리 누수 문제에 대해 개발자가 매번 완벽하게 관리하지 않아도 된다는 장점이 있다.
인스턴스 메서드와 static 메서드의 차이
public class MyMath2 {
long a, b;
static long add(long a, long b) { // 클래스 메서드 (static 메서드)
return a + b;
}
long add() { // 인스턴스 메서드
return a + b;
}
}
public class MyMathTest2 {
public static void main(String[] args) {
System.out.println(MyMath2.add(200L,100L)); // 클래스 메서드 호출
MyMath2 mm = new MyMath2();
mm.a = 200L;
mm.b = 100L;
System.out.println(mm.add()); //인스턴스 메서드 호출
}
}
인스턴스 메서드
- 인스턴스 생성 후 "참조변수.메서드이름()" 으로 호출
- 인스턴스 멤버(인스턴스 변수, 인스턴스 메서드) 와 관련된 작업을 하는 메서드
- 메서드 내에서 인스턴스 변수 사용가능
static 메서드(클래스 메서드)
- "클래스이름.메서드이름() "으로 호출
- 인스턴스 멤버와 관련없는 작업을 하는 메서드
- 메서드내에서 인스턴스 변수 사용불가
생성자 (constructor)
인스턴스가 생성될 때마다 호출되는 인스턴스 초기화 메서드
- 이름이 클래스 명과 같아야 한다.
- 리턴값이 없다.
- 모든클래스는 반드시 생성자를 가져야한다
public class Car {
String color;
String gearType;
int door;
Car(){} //기본생성자
Car(String color, String gearType, int door){ // 매개변수가 있는 생성자
this.color = color;
this.gearType = gearType;
this.door = door;
}
}
멤버변수의 초기화
1. 명시적 초기화
2. 초기화 블럭
3. 생성자
public class Car {
int model = 4; // 기본형 (primitive type) 변수의 초기화
EngineConfig engin = new EngineConfig(); // 참조형(reference type) 변수의 초기화
String color;
String gearType;
int door;
static{ // 인스턴스 초기화 블럭
}
{ // 클래스 초기화 블럭
}
Car(){} //기본생성자
Car(String color, String gearType, int door){ // 매개변수가 있는 생성자
this.color = color;
this.gearType = gearType;
this.door = door;
}
}
상속 (Inheritance)
기존의 클래스로 새로운 클래스를 작성하는 것.
두 클래스를 부모와 자식으로 관계를 맺어주는 것.
class Point {
int x;
int y;
}
//상속받는게 없을 경우
class Point3D {
int x;
int y;
int z;
}
//상속을 받을경우
class Point3D extends Point {
int z;
}
자손의 변경은 부모에 영향을 주지 않지만.
부모의 변경은 자손에 영향을 미친다.
포함관계 ( composite) 란?
클래스의 멤버로 참조변수를 선언하는 것
//기존
class Circle {
int x; // x좌표
int y; // y좌표
int r; // 반지름
}
class Point {
int x;
int y;
}
class Circle {
Point c = new Point(); // 원점
int r; // 반지름
}
클래스간의 관계 결정하기
- 상속관계 : ~은 ~이다. ( is - a )
- 포함관계 : ~는 ~을 가지고 있다. ( has - a)
// 포함
class Circle {
Point c = new Point();
int r;
}
//상속
class Circle extends Point {
int r;
}
class Point {
int x;
int y;
}
- 원은 점이다. - Circle is a Point
- 원은 점을 가지고 있다. - Circle has a Point
포함관계가 적절하다!
단일상속 ( Single Inheritance )
자바는 단일 상속만을 허용한다. ( C++는 다중상속 허용 )
비중이 높은 클래스 하나만 상속관계로 나머지는 포함관계로 한다.
Object 클래스 - 모든 클래스의 조상
부모가 없는 클래스는 자동적으로 Object 클래스를 상속받는다.
모든 클래스는 Object에 정의된 11개의 메서드를 상속받는다.
toString(), hashCode(), equals(Object obj)
class Circle extends Object{
Point p;
int r;
Circle(){
p = new Point();
}
}
public class InheritanceTest {
public static void main(String[] args) {
Circle c = new Circle();
System.out.println("c = " + c.toString());
System.out.println("c = " + c);
}
}
결과
c = hello.core.java.Circle@7eda2dbb
c = hello.core.java.Circle@7eda2dbb
메서드 오버라이딩 ( overriding )
상속받은 조상의 메서드를 자신에 맞게 변경하는 것
오버라이딩의 조건
- 선언부가 조상 클래스의 메서드와 일치해야 한다.
- 접근제어자를 조상 클래스의 메서드보다 좁은 범위로 변경할 수 없다.
- 예외는 조상 클래스의 메서드보다 많이 선언할 수 없다.
오버로딩과 오버라이딩의 차이
오버로딩 (overloading) : 기존에 없는 새로운 메서드를 정의 (new)
오버라이딩(overriding) :상속받은 메서드의 내용을 변경하는것.( change, modify )
참조변수 super
객체 자신을 가리키는 참조변수, 인스턴스 메서드(생성자) 내에만 존재
조상의 멤버를 자신의 멤버와 구별할 때 사용
public class SuperTest {
public static void main(String[] args) {
Child c = new Child();
c.method();
}
}
class Parent{
int x = 10;
}
class Child extends Parent {
int x = 100;
void method(){
System.out.println("x = " + x);
System.out.println("this.x = " + this.x);
System.out.println("super.x = " + super.x);
}
}
결과
x = 100
this.x = 100
super.x = 10
제어자 (modifier)
클래스와 클래스의 멤버 (멤버 변수, 메서드) 에 부가적인 의미 부여
접근제어자 : public, protected, (default), private
그 외 : static, final, abstract, native, transient, syncronized, volatile, strictfp
final
final class Final { // 조상이 될 수 없는 클래스
final int MAX_SIZE = 10; // 멤버변수 상수
final void getMaxSize(){ //오버라이딩 불가능한 메서드
final int LV = MAX_SIZE; // 지역변수 상수
}
}
보통 상수 네이밍은 대문자로 하며 단어사이는 " _ "로 한다.
abstract - 추상
abstract class AbstractTest { // 추상클래스(추상 메서드를 포함한 클래스)
abstract void move(); // 추상메서드, 구현부가 없는 메서드
}
private : 같은 클래스 내에서만 접근이 가능하다.
(default) : 같은 패키지 내에서만 접근이 가능하다.
protected : 같은 패키지 내에서, 그리고 다른 패키지의 자손 클래스에서 접근이 가능하다.
public : 접근제한이 없다.
접근제어자를 사용하는 이유는
외부로부터 데이터를 보호하기 위해서 사용한다.
package hello.core.java.pkg1;
public class MyParent {
private int prv; // 같은 클래스
int dft; // 같은패키지
protected int prt; // 같은패키지 + 자손 (다른 패키지)
public int pub; // 접근제한 x
public void printMembers(){
System.out.println("prv = " + prv);
System.out.println("dft = " + dft);
System.out.println("prt = " + prt);
System.out.println("pub = " + pub);
}
}
class MyParentTest{
public static void main(String[] args) {
MyParent p = new MyParent();
System.out.println("prv = " + p.prv); // 오류발생.
System.out.println("dft = " + p.dft);
System.out.println("prt = " + p.prt);
System.out.println("pub = " + p.pub);
}
}
package hello.core.java.pkg2;
import hello.core.java.pkg1.MyParent;
public class MyChild extends MyParent {
public void printMembers(){
System.out.println("prv = " + prv);//에러
System.out.println("dft = " + dft);//에러
System.out.println("prt = " + prt); //정상, 다른패키지지만 자손
System.out.println("pub = " + pub);
}
}
class MyParentTest2{
public static void main(String[] args) {
MyParent p = new MyParent();
System.out.println("prv = " + p.prv);//에러
System.out.println("dft = " + p.dft);//에러
System.out.println("prt = " + p.prt);//에러
System.out.println("pub = " + p.pub);
}
}
인터페이스의 장점
- 개발시간 단축
- 변경에 유리한 유연한 설계 가능
- 표준화가 가능
예시) JDBC - 서로 관계없는 클래스들을 관계를 맺어줄 수있다.
디폴트 메서드와 static 메서드
- 인터페이스에 디폴트 메서드, static 메서드 추가 가능 (jdk 1.7부터)
- 인터페이스에 새로운 메서드(추상 메서드) 추가하기 어려움.
- 디폴트 메서드는 인스턴스 메서드(인터페이스 원칙 위반) 예외.
- 여러 인터페이스와 디폴트 메서드 간에 충돌 발생 시 직접 @Overriding
interface MyInterface {
void method();
default void newMethod(){}
}
내부 클래스 (inner class)
class A {
...
class B{
}
}
객체 생성 없어도 A 멤버변수 접근 가능
내부 클래스의 장점
- 내부 클래스에서 외부 클래스의 멤버들을 쉽게 접근 가능하다.
객체를 안만들고도 접근가능 - 코드의 복잡성을 줄일 수 있다. (캡슐화)
내부 클래스 예시
public class Outer {
private int outerIv = 0;
private static int outerCv = 0;
class InstanceInner{
int iiv = outerIv; //외부 클래스의 private 멤버도 접근가능하다.
int iiv2 = outerCv;
}
static class StaticInner {
//static 클래스는 외부 클래스의 인스턴스 멤버에 접근 불가능하다.
//int siv =outerIv;
static int scv = outerCv;
}
void myMethod() {
int lv = 0;
final int LV = 0;
class LocalInner {
int liv = outerIv;
int liv2 = outerCv;
int liv3 = lv; // jdk1.8부터 에러 아님
int liv4 = LV;
}
}
}
익명 클래스 ( anonymous class )
이름이 없는 일회용 클래스, 정의와 생성을 동시에한다.
예시1)
public class ananymous {
public static void main(String[] args) {
Button b = new Button("Start");
b.addActionListener(new EventHandler());
}
}
class EventHandler implements ActionListener{
public void actionPerformed(ActionEvent event){
System.out.println("action occurred!!!");
}
}
예시2)
public class ananymous {
public static void main(String[] args) {
Button b = new Button("Start");
b.addActionListener(new ActionListener(){
public void actionPerformed(ActionEvent event){
System.out.println("action occurred!!!");
}
});
}
}
프로그램의 오류
- 컴파일 에러 : 컴파일 시 발생하는 에러
- 런타임 에러 : 실행 할 때 발생하는 에러
- 논리적 에러 : 작성 의도와 다르게 동작
JAVA의 런타임 에러
- 에러 : 프로그램 코드에 의해 수습될 수 없는 심각한 오류
- 예외 : 프로그램 코드에 의해 수습될 수 있는 다소 미약한 오류
예외처리의 정의와 목적
- 정의 : 프로그램 실행 시 발생할 수 있는 예외의 발생에 대비한 코드를 작성하는 것.
- 목적: 프로그램 비정상 종료 막고, 정상 실행상태 유지하는 것.
예외 클래스의 계층 구조
cheked 예외, unchecked 예외
checked 예외 : 컴파일러가 예외 처리 여부를 체크 ( 예외 처리 필수 )
unchecked예외 : 컴파일러가 예외 처리 여부를 체크 안함 ( 예외 처리 선택 )
checked 예외 예시)
class checkedException {
public static void main(String[] args) {
try {
throw new Exception();
} catch(Exception e) {}
}
}
- IOException
- ClassNotFoundException
unchecked예외 예시)
class uncheckedException {
public static void main(String[] args) {
throw new RuntimeException();
}
}
- NullPointerException
- IndexOutOfBoundsException
연결된 예외 ( chained exception )
한 예외가 다른 예외를 발생시킬 수 있다.
예외 A가 예외 B를 발생시키면 A는 B의 원인 예외 (cause exception)
public class Throwable implements Serializable {
private Throwable cause = this;
public syncronized Throwable initCause( Throwable cause ) {
return this;
}
}
예시)
void install() thorws InstallException {
try{
startInstall();
copyFiles();
} catch( SpaceException e ) {
InstallExcepiton e ie = new InstallException("설치중 예외발생"); // 새로운 예외 생성
ie.initCause(e); // InstallException의 원인 예외를 SpaceException으로 지정
throw ie; // InstallException을 발생시킨다.
} catch (MemoryException me) {
...
}
여러 예외를 하나로 묶어서 다루기위해서 사용
checked 예외를 unchecked 예외로 변경하려고 할때 사용.
예시)
static void startInstall() throws SpaceException {
if( !enoughSpace()){
throw new SpaceException("설치할 공간이 부족합니다");
}
if(!enoughMemory()) {
throw new RuntimeException(new MemoryException("메모리가 부족합니다."));
}
}
hashCode()
객체의 해시코드를 반환하는 메서드
Object클래스의 hashCode()는 객체의 주소를 int로 변환해서 반환
equals()를 오버라이딩하면, hashCode()도 오버라이딩 해야한다.
=> equals()의 결과가 ture인 두 객체의 해시코드는 같아야 하기 때문이다.
toString()
Object클래스의 to String
public String toString() {
return getClass().getName() + "@" + Integer.toHexString(hashCode());
//설계도 객체.클래스이름.@.위치_16진수(객체주소)
}
객체를 문자열로 변환하기 위한 메서드.
equals(Object obj)
객체 자신과 주어진 객체(obj)를 비교.
Object클래스의 equals는 객체의 주소를 비교 ( 참조변수 값 비교 )
public boolean equals(Object obj) {
return (this == obj);
}
오버라이딩하여 사용할 경우 예시
public class Session {
private int maxUserCount;
private int currentUserCount;
private Long id;
@Override
public boolean equals(Object o) {
if (this == o){
return true;
}
if (o == null || getClass() != o.getClass()){
return false;
}
Session session = (Session) o;
return Objects.equals(id, session.id);
}
@Override
public int hashCode() {
return Objects.hash(id);
}
}
StringBuffer클래스
String 처럼 문자형 배열 ( char[] ) 을 내부적으로 가지고 있다.
그러나 String(불변) 과 달리 변경할 수 있다 (mutable)
배열은 길이 변경불가, 공간이 부족할 시 새로운 배열 생성해야된다.
StringBuffer은 저장할 문자열의 길이를 고려하여 적절한 크기로 생성해야된다.
equals()가 오버라이딩되어있지 않다.(주소비교)
따라서. StringBuffer을 String으로 변환 후 equals로 비교해야된다.
StringBuilder
StringBuffer은 동기화되어있다. 멀티쓰레드에 안전( thread-safe )
래퍼 클래스 ( wrapper )
8개의 기본형을 객체로 다뤄야할 떄 사용하는 클래스
기본형 | 래퍼클래스 |
boolean | Boolean |
char | Character |
byte | Byte |
short | Short |
int | Integer |
long | Long |
float | Float |
double | Double |
오토박싱과 언박싱
JDK 1.5이전에는 기본형과 참조형간 연산 불가능
class boxTest{
public static void main(String[] args) {
ArrayList<Integer> list = new ArrayList<>();
list.add(100); //jdk1.5이전에는 에러
list.add(new Integer(100)); // Deprecated
list.add(Integer.valueOf(100));
Integer i = list.get(0); //list에 저장된 첫번재 객체를 꺼낸다.
int k = list.get(0); // intValue()로 Integer를 int로 변환( 언박싱 )
}
}
기본형의 값을 객체로 자동변환하는 것을 오토박싱 그 반대는 언박싱
https://youtube.com/playlist?list=PLW2UjW795-f6xWA2_MUhEVgPauhGl3xIp
https://velog.io/@jeong11/Java-OOP-callstack
https://www.youtube.com/watch?v=_WkMhytqoCc&ab_channel=%EB%B0%B1%EA%B8%B0%EC%84%A0
'스터디 > 2023_스프링부트' 카테고리의 다른 글
[study] HTTP 웹 기본 지식 (1) | 2023.07.23 |
---|---|
[study]자바의정석 11~14 chapter (0) | 2023.07.18 |
[study] http 멱등성 알아보자 (0) | 2023.07.03 |
[study]Spring IOC와 DI (0) | 2023.06.26 |
[study]스프링 기본 및 핵심원리 (0) | 2023.06.26 |