。゚(*´□`)゚。

코딩의 즐거움과 도전, 그리고 일상의 소소한 순간들이 어우러진 블로그

[네이버클라우드] 클라우드 기반의 개발자 과정 7기/웹프로그래밍

[NC7기-41일차(6월22일)] - 웹프로그래밍 22일차

quarrrter 2023. 6. 22. 17:28

스태틱 필드와 스태틱 블럭 


package bitcamp.test;

 

class A {

static int v1;

static void m1() {}

static {

System.out.println("A 클래스의 스태틱 블록 실행! "); //클래스가 로딩될때 바로 실행됨

}

 

}

 

//인스턴스를 만드려고 하는 시점, 메서드를 로딩하는 시점, 스태틱변수를 쓰려고하는 시점에 class 로딩됨 !

public class Exam01 {

public static void main(String[] args) {

A obj; // 레퍼런스변수를 선언할땐 A클래스가 로딩되지 않음

 

//A.v1 = 100; //클래스를 사용하는 시점(=인스턴스변수를 쓰려고 할때 )에 클래스가 로딩되고,

//A.m1(); //위에서 로딩됐기때문에 클래스가 두번 로딩되지 않음

//obj = new A(); // A를 로딩해야 하기때문에 class A가 로딩됨

 

}

}


Class.forName("bitcamp.myapp.test.A"); //강제 로딩할때 쓰는 메서. fully-qualified class name(패키지명을 포함한 파일명) = FQName = QName

 

package bitcamp.test;

 

class A {

static int v1;

static void m1() {}

static {

System.out.println("A 클래스의 스태틱 블록 실행! "); //클래스가 로딩될때 바로 실행됨

}

}

 

 

public class Exam01 {

public static void main(String[] args) {

A.v1 = 100; //클래스를 사용하는 시점(=인스턴스변수를 쓰려고 할때 )에 클래스가 로딩되고,

 

 

//예외를 던지는 메서드를 사용할 땐 try를 사용해야하고

try {

Class.forName("bitcamp.test.A"); //강제 로딩할때 쓰는 메서드. fully-qualified class name(패키지명을 포함한 파일명) = FQName = QName

} catch(ClassNotFoundException e){//예외를 받는 메서드를 추가해야함 {

System.out.println("클래스를 못 찾네");

}

}

}


package bitcamp.test;

 

class A {

//static 블럭을 잔뜩 만들어도 컴파일할때 한개로 합쳐짐 , 그래서 한 클래스 안에 스태틱 블럭을 많이 만드는건 의미 없음

static int v1 =111; // variable initializer 변수 초기화 문장 , 컴파일 하면 스태틱 블럭 맨 앞으로 간다

// 초기화 문장으로 인해 static 블럭이 하나로 합쳐진다. 그리고 static 블럭안으로   v1 =111; 들어가고 static int v1; 으로 바뀜 , 필드선언과 초기화를 분리시킴 

어디에 위치하든 초기화 문장을 필드선언과 스태틱블럭으로 나뉘어지고 , 필드 선언이 맨 위로 올라가고 스태틱 블럭은 순서대로 하나로 합침 .

static void m1() {}

//static 블럭을 잔뜩 만들어도 컴파일할때 한개로 합쳐짐 , 그래서 한 클래스 안에 스태틱 블럭을 많이 만드는건 의미 없음

static {

v1 = 100;

System.out.println("A 클래스의 스태틱 블록 실행!1 ");

v1 = 200;

System.out.println("A 클래스의 스태틱 블록 실행!2 ");

v1 = 300;

System.out.println("A 클래스의 스태틱 블록 실행! 3");

System.out.println(v1);

}

static int v2 = 222;

static void m1() {}

}


static이 안 붙은 { System.out.println("111"); } 이건 인스턴스 블럭

인스턴스 생성할 때마다 인스턴스 블럭 실행된다. 

인스턴스 블럭은 생성자로 복사된다. 

생성자를 안 만들면 컴파일러가 생성자를 만들고 그 안에 인스턴스를 갖다 넣음. => 구니까 굳이 밖에다 만들지 말고 생성자 안에 넣기 . 생성자안에 인스턴스 상관없이 무조건 그 순서대로 생성자 바로 아래에 붙음. 원래 생성자 안에 있던 문장은 그 아래로 내려감. 생성자가 여러개면 인스턴스블럭들이 생성자에 다 들어감

 

정리할때:

인스턴스 블럭을 하나로 위에 다 뽑아내고 생성자를 밑에두기 


인스턴스 변수가 생성자 안으로 다 들어감

 

1. 변수 초기화 문장이든 인스턴스 변수든 순서대로 생성자 안에 들어감 

// 문법을 헷갈리지 않도록 하기 위해서 가능한 다음 순서로 코드를 작성하라.

// 1) 필드 선언 및 초기화 문장

// 2) 스태틱 블록 (가능한 한 개의 블록으로 묶어라.)

// 3) 인스턴스 블록 (가능한 한 개의 블록으로 묶어라.)

// 4) 생성자 (기본 생성자를 먼저 두고 파라미터 개수에 따라 나열하라.)

 


 

기존 코드 수정

 

복사방식

Calculator() 를 그대로 Calculator2로 복사해서 새 기능 추가 // 단점: 본 코드의 버그가 그대로 따라올수있고, 기존 파일 수정하면 복사한 파일도 또 고쳐줘야함

 

상속 extends (원 기능 고대로 권한 받기)

기존 코드를 상속받아서 Calculator2에 새기능 추가 

* 기존 클래스의 소스 코드가 필요없다! 클래스 파일만 있으면됨. 

* 단점은 일부 기능만 상속 받을 순 없다는거,,! 

 

 

상속의 의미

상속이란 : 수퍼클래스의 사용권을 획득하는 것. 내 것처럼 사용하는 것 

obj에 D의 주소가 저장됐더라도 컴파일러는 문법만 따져서 컴파일 오류남
컴파일하고 싶으면 형변환시켜서 해야함

 

클래스로딩, 인스턴스 생성과정

클래스는 1번만 로딩됨..! 

상속 받은 수퍼 클래스를 먼저 메모리에 로딩한다. 

해당 클래스를 메모리에 로딩한다.

수퍼클래스 인스턴스 변수를 heap에

해당 클래스 인스턴스 변수를 heap에

수퍼 클래스부터 생성자를 실행하며 해당 클래스까지 내려온다. 

 

 

생성자 호출순서 

파라미터가 없는 생성자: 기본생성자  = default constructor

올라가면서 call, super클래스부터 실행하면서 내려옵니다 /찐 수퍼는 Object

 

오후

수퍼클래스에 기본 생성자가 없을 때,,! 

 

A에 기본 생성자 없음 

package com.eomcs.oop.ex05.h;

 

public class B extends A {

int v2;

 

B() {

// 수퍼 클래스의 어떤 생성자를 호출할지 지정하지 않으면 컴파일러는

// 다음과 같이 수퍼 클래스의 기본 생성자를 호출하라는 명령을 붙인다.

//

// super(); //만약 수퍼 클래스에 기본 생성자가 없으면 컴파일 오류가 발생한다!

 

// 해결 방법?

// - 개발자가 직접 수퍼 클래스에 있는 생성자를 호출하라!

super(100);

 

System.out.println("B() 생성자!");

}

}


상속

다중 상속(불가! )

자바에서 다중 상속 안 됨 ! (만약 가능하다면 수퍼클래스에 같은 이름의 메서드가 있으면 충돌나서 안됨)

c++은 다중 상속됨 

 

specialization 상속 

기존 클래스를 상속받아 특별한 기능을 덧붙인다 , ,!! 

 

Generalization 상속(일반화)

 

리팩토링 과정에 수행하는 방법

서브클래스들의 공통 분모를 추출하여 수퍼클래스를 정의하는 방법

메서드나 파라미터 명이 다르더라도 기능이 비슷하면 뽑아낼 수 있다고 생각해야한다

뽑아내고 서브 클래스상 공통분모 제거하기

 

** Overridng : 상속받은 메서드를 서브클래스의 역할에 맞게 수퍼클래스의 메서드를 재정의하는것

 

직접 사용하려고 만든 클래스가 아니고 유지보수용이므로 직접 사용 못하게 막아야하는데 

서브클래스를 만들어 사용하도록 제한하는 문법: 추상 클래스 (abstract)

public abstract class Car {

추상클래스를 파라미터로 이용하면 다형적 변수를 이용할 수 있다. 

추상클래스에 레퍼런스가 있다는 건: new 인스턴스 하겠다는 뜻이 아니고 car클래스를 상속받아 만든 서브클래스의 인스턴스를 받겠다는 뜻. (Car car) Car를 상속 받아 만든 서브클래스의 인스턴스를 받겠다는 뜻 !  추상클래스는 인스턴스를 생성할 수 없다!  어떤 메서드의 리턴 타입이 추상타입이면 ,, 그 추상클래스를 상속 받은 서브클래스를 리턴한다는 뜻 ! 

추상클래스만 추상메서드를 가질 수 있음 

 

추상메서드

super클래스 메서드 중 서브에서 재정의할 메서드라면,, 추상메서드를 쓴다. 구현 안 하고 정의만 ,,!! 바디빼기! 

다른 말루,, 서브클래스에게 반드시 overridng하라고 강제할 때 사용함 ! 

이렇게 = > abstract void run() ;

run: 메서드 시그니처

void: 메서드 리턴타입 

{...} : 메서드 바디  


OOP

Object Oriented Promgram

객체 지향 프로그램 

1. 상속 

2. 다형성 : 다형적 변수, 오버로딩, 오버라이딩

3. 캡슐화 접근범위: private (default) protected public 


다형적 변수 : 

레퍼런스는 같은 타입의 객체를 가리킬수있고 그 클래스의 서브클래스 객체까지 가리킬수있다! 

하위클래스의 레퍼런스로 상위클래스의 인스턴스를 가리킬수없다. 

vehicle vehicle2 = null;

vehicle2 = bike;

vehicle2= car;

vehicle2= truck;

 

Car c = new Sedan(); // c에 어떤 객체가 담기든 컴파일러는 신경 안쓰고 문법적으로 가능한지만 체크 

c.cc=

c.model =

c.capacity =

c.sunroof =true; => 오류 !!!! c는 Car에 들어있는 인스턴스만 따짐 !!!! 

((Sedan)c).sunroof = true; // OK!

((Sedan)c).auto = true; // OK!

 

다형적 변수의 형변환

Vehicle v1 = new Sedan(); 

v1을 Vehicle로 알고 행동

// => 형변환 하라!

((Sedan)v1).cc = 1980;

((Sedan)v1).valve = 16;

((Sedan)v1).sunroof = true;

((Sedan)v1).auto = true;

컴파일러는 문법적으로만 접근함 ..! 실제 머가 들어가던지 관심없음 

상속 받을 때만 생성 !! 

 

연산자: instanceof

메서드가 아니고 연산자임 

왼쪽에(v)에 들어있는 레퍼런스의 주소가 오른쪽의 클래스의 인스턴스인지 검사.

수퍼클래스도 인스턴스로 판단함

v instanceof Sedan; true/false

v가 어디에 포함되어있는지, 그클래스나 super클래스까지 확인하고 싶으면 instance of / True ~

 

Vehicle v 에는 sub클래스들 다 들어올 수 있음 ! 

 

getClass()

레퍼런스가 가리키는 인스턴스의 실제 클래스 주를 리턴한다.

==> 연산자를 사용하여 특정클래스의 인스턴스인지 좁혀서 검사할수있다.

 

클래스명.class => 클래스 정보를 가지고 있는 스태틱 변수

여기서 class는 파일 확장자가 아니고, 클래스 타입인 스태틱 필드임 ,,!!! 

Sedan.class    =>세단이라는 클래스 정보를 갖고 있는 인스턴스를 가리키는 레퍼런스, 총 정보를 담고 있는 ,,,,
클래스 / 스태틱변수  // 

컴파일러가 static Class class를 속에서 만듬/  클래스 정보를 담고있는 스태틱 변수 
1.자바의 모든 클래스는 static class 주소를 담고 있는 레퍼런스 변수를 갖고 있는데, 그 변수 명은 class
2.class 변수안에는 클래스 정보를 담고 있는 인스턴스 주소가 저장되어있다. 
3.클래스 정보라 함은,, 클래스 명, public, private, default, final 여부 , superclass, interface, 생성자 메서드, 필드 등 ,, , 

vehicle v = new Sedan();

세단 설계도에 따라서 인스턴스가 생성되고 

getclass가 리턴하는건 주어진 인스턴스 주소로 따라가서 로딩된 클래스의 스태틱변수의 주소값 

메서드 에리어에서 세단class의 주소를 찾아내서 뱉어냄 

클래스 정보를 갖고있는 인스턴스 주소를 뱉어냄

다형성 - 오버로딩(overloading)

A : m() , m(int), m(String)

파라미터 형 (개수,순서,타입)이 다 다르더라도 같은 기능을 한다면 같은 이름을 부여하는 것 

B(extends A) : m (int, int, int)   : 오버로딩

B(extends A) : m (int)   : 오버라이딩

 

** Overridng : 상속받은 메서드를 서브클래스의 역할에 맞게 수퍼클래스의 메서드를 재정의하는것

=> 원래 메서드보다 접근 범위가 같거나 커야한다. 원래의 메서드보다 접근 범위가 줄어들면 안된다. 

변수명은 달라도 상관없음, private 메서드는 접근할 수 없기 때문에 overriding 안 됨. 

 

// 메서드 정의 앞에 @Override를 붙여라

@Override // <= 컴파일러야, 내가 상속받은 메서드를 재정의한다고 했는데, 혹시 실수는 없는지 검사해 줄래?

 

 

// this.필드명// - 현재 클래스에서 해당 필드를 찾는다. 없으면 상위 클래스로 따라 올라가면서 찾는다.

// super.필드명// - 상위 클래스에서부터 해당 필드를 찾는다. 없으면 계속 상위 클래스로 따라 올라간다.

package com.eomcs.oop.ex06.c;

public class Exam0130

 public class Exam0140 {

 

 

 상속과 수퍼클래스

A2의 test를 끌고 왔지만 this는 현재 실행하는 A3!&nbsp; super는 a2의 super인 A

[클래스]

this는 어떤 클래스를 끌고와도 현재 클래스(실제 인스턴스의 클래스 관점)!  (A3)

super는 super가 정의된(소속된) 클래스에서 super클래스를 가리킴(A)

중간 클래스 건너뛰고 super super는 호출할 수 없음 ,, ,!!!!!! 

 

[레퍼런스 필드]

레퍼런스를 형변환하면 오버라이딩 전 해당 클래서의 인스턴스 변슈를 가르킬수있다.

 

 

[메서드]

레퍼런스가 가리키는 필드
레퍼런스가 가리키는 메서드
static class A {
String name = "A";
String tel = "A: 010-1111-1111";
boolean working = true;
}


static class A2 extends A {
int age = 20;
}


static class A3 extends A {
int age = 30;
String tel = "A3: 010-1111-2222";
}


static class A4 extends A3 {
String age = "40";
boolean working = false;
}




public static void main(String[] args) {
A4 obj1 = new A4();


System.out.println(obj1.name); // "A"
System.out.println(obj1.age); // "40"
System.out.println(obj1.working); // false
System.out.println("-----------------------------");


// 레퍼런스를 형변환 하면 오버라이딩 하기 전,
// 해당 클래스의 인스턴스 변수를 가리킬 수 있다.
System.out.println(((A3)obj1).age); // 30
System.out.println(((A3)obj1).working); // true -> 없으면 수퍼 클래스의 필드를 가리킨다.
System.out.println("-----------------------------");
static class X {
void m1() {
System.out.println("X의 m1()");
}
void m2() {
System.out.println("X의 m2()");
}
}




static class X2 extends X {
@Override
void m1() {
System.out.println("X2의 m1()");
}
}




static class X3 extends X2 {
@Override
void m2() {
System.out.println("X3의 m2()");
}
}




static class X4 extends X3 {
@Override
void m1() {
System.out.println("X4의 m1()");
}


void x() {
System.out.println("X4의 x()");
}
}


public static void main(String[] args) {
X4 x4 = new X4();
x4.m1(); // X4.m1()


// 인스턴스 필드와 달리 메서드의 경우는
// 레퍼런스에 대한 형변환에 상관없이
// 실제 레퍼런스가 가리키는 클래스에서 메서드를 찾아 올라간다.
//
((X3)x4).m1(); // X4.m1()
((X3)x4).m2(); // X3.m2()
// ((X3)x4).x(); // 컴파일 오류!


((X2)x4).m1(); // X4.m1()
((X)x4).m1(); // X4.m1();


X3 x3 = x4;
X2 x2 = x4;
X x = x4;


x3.m1(); // X4.m1()
x2.m1(); // X4.m1()
x.m1(); // X4.m1()
}

리턴타입

오버라이딩 메서드의 리턴 타입은 서브 클래스로도 가능하다 ,, !!!  // super클래스는 안 됨 !!!!! 

static class CarFactory {
Car create() {
return new Car();} }

static class SedanFactory extends CarFactory {
// 오버라이딩 메서드의 리턴 타입은
// 서브 클래스도 가능하다.
@Override
Sedan create() {
return new Sedan();} }