다형성(polymorphism)

조상 클래스 타입 참조 변수로 자손 타입 객체를 가리키는

실제 생성된 인스턴스가 무엇인지가 가장 중요하다.

 

public class Test {
	public static void main(String[] args) {
		Tv tv = new SmartTv();
		tv.down();
		tv.up();
//		tv.search(); 사용 못한다. Tv클래스를 보면 search()없기 때문
		//실제 생성된 객체는 SmartTv이기에 타입을 변경하면 호출할 수 있다.
		((SmartTv)tv).search();
	}
}

class Tv{
	void up() {}//채널 업
	void down() {}//채널 다운
}
class SmartTv extends Tv{
	void search() {}//인터넷 검색기능
}

원래 생성된 객체가 SmartTv니까 문제가 없다. 만약 Tv라면 어떻게 될까?

컴파일러는 오류를 못잡는다. 즉, 런타임 예외가 발생하게 된다. (실행 중 예외) 

형변완 예외 발생

이 때문에 형변환 시에 무조건 instanceof 연산자로 형변환가능한 경우만 형변환되도록 하는 것이 중요하다.

 

위까지가 다형성의 사전 지식

public class Test {
	public static void main(String[] args) {
		Tv tv = new SmartTv();
		tv.down();
		tv.up();
	}
}
class Tv{
	void up() {
		System.out.println("일반 TV 채널 업");
	}//채널 업
	void down() {
		System.out.println("일반 TV 채널 다운");
	}//채널 다운
}
class SmartTv extends Tv{
	void up() {
		System.out.println("스마트 TV 채널 업");
	}//채널 업
	void down() {
		System.out.println("스마트 TV 채널 다운");
	}//채널 다운
	void search() {}//인터넷 검색기능
}
///////////////////////////////////////
스마트 TV 채널 다운
스마트 TV 채널 업

실제 동작은 생성된 객체 구현부로 동작되는 것을 알 수 있다. 이를 통한 다형성 사례

public class Test {
	public static void main(String[] args) {
		SmartTv tv1 = new LGSmartTv();
		SmartTv tv2 = new SamsungSmartTv();
		tvTest(tv1);
		tvTest(tv2);
	}
	//앞으로 새로운 스마트 TV가 추가되어도 기존 아래 코드는 수정할 일이 없다.
	static void tvTest(SmartTv smartTv) {
		smartTv.down();
		smartTv.up();
		smartTv.search();
	}
}
class Tv{
	void up() {
		System.out.println("일반 TV 채널 업");
	}//채널 업
	void down() {
		System.out.println("일반 TV 채널 다운");
	}//채널 다운
}
//객체 생성을 막음
abstract class SmartTv extends Tv{
	void up() {
		System.out.println("스마트 TV 채널 업");
	}//채널 업
	void down() {
		System.out.println("스마트 TV 채널 다운");
	}//채널 다운
	void search() {
		System.out.println("스마트한 검색");
	}//인터넷 검색기능
}

class LGSmartTv extends SmartTv{
	void up() {
		System.out.print("LG");
		super.up();
	}
	void down() {
		System.out.print("LG");
		super.down();
	}
	void search() {
		System.out.print("LG의 ");
		super.search();
	}
}
class SamsungSmartTv extends SmartTv{
	void up() {
		System.out.print("삼성");
		super.up();
	}
	void down() {
		System.out.print("삼성");
		super.down();
	}
	void search() {
		System.out.print("삼성의 ");
		super.search();
	}
}
////////////////////////////////
LG스마트 TV 채널 다운
LG스마트 TV 채널 업
LG의 스마트한 검색
삼성스마트 TV 채널 다운
삼성스마트 TV 채널 업
삼성의 스마트한 검색

객체지향 원칙 캡슐화, 추상화, 상속, 다형성을 기반으로 다양한 디자인 패턴들이 존재한다.

 

인터페이스(interface)

일종의 추상클래스

추상클래스 처럼 추상메서드를 갖지만 추상클래스보다 추상화 정도가 높다

 

개발 코드가 객체에 종속되지 않게 하여 객체를 교체할 수 있도록 한다. (OCP, 변경엔 닫혀있고, 확장엔 열려있어야한다)

객체 간 느슨한 결합을 위한 핵심

객체지향 원칙에 구현보다는 인터페이스에 맞춰서 프로그래밍한다는 원칙도 있다.

 

인터페이스 모든 멤버변수는 public static final이다. 그렇기에 생략해도 컴파일러가 일괄적으로 붙여준다.

모든 메서드는 public abstract다.

 

인터페이스 간 상속도 당연히 된다. expands 키워드, 인터페이스를 클래스가 구현하면 implements

 

느슨한 결합 예시

public class Test {
	public static void main(String[] args) {
		LgTv lgTv = new LgTv();
		tvTest(lgTv);
	}
	//지금 구조에서 기존 코드(tvTest)를 절대 건드리지 말고 SamSungTv로 바꿔 동작하게 할 수 있나? 
	public static void tvTest(LgTv lgTv) {
		lgTv.volDown();
		lgTv.volUp();
	}
}
class LgTv{
	void volUp() {}
	void volDown() {}
}

class SamSungTv{
	void volUp() {}
	void volDown() {}
}

절대 불가능하다.

public class Test {
	public static void main(String[] args) {
		LgTv lgTv = new LgTv();
		SamSungTv samSungTv = new SamSungTv();
		//자동 형변환된다.
		tvTest(lgTv);
		tvTest(samSungTv);
	}
	//지금 구조에서 기존 코드(tvTest)를 절대 건드리지 말고 SamSungTv로 바꿔 동작하게 할 수 있나? 
	public static void tvTest(Tv tv) {
		tv.volDown();
		tv.volUp();
	}
}
interface Tv{
	void volUp();
	/*public abstract*/void volDown();
}
class LgTv implements Tv{
	public void volUp() {}
	public void volDown() {}
}

class SamSungTv implements Tv{
	public void volUp() {}
	public void volDown() {}
}

객체지향을 시작으로 다양한 디자인 원칙, 더 나아가 디자인 패턴에서 중요한 핵심은 기존코드를 수정하지 않고 새로운 기능을 손쉽게 추가하는 것이다.

익명 클래스(anonymous class)

이름 없는 클래스, 이유는 선언과 객체 생성을 동시에 하기 때문이다.

일회용으로 쓰거나, 오직 하나의 객체만을 생성한다.

 

public class Test {
	public static void main(String[] args) {
		new AnonymousTest();
	}
}
class AnonymousTest {
	public AnonymousTest() {
		System.out.println("객체 선언과 동시에 생성");
	}
}
////////////////////
객체 선언과 동시에 생성
public class Test {
	public static void main(String[] args) {
		Runnable runnable = ()->Test.call("1");
		Thread thread = new Thread(runnable);
		thread.start();
		call("0");
	}
	static void call(String msg) {
		for(int i = 0; i< 10000 ; i++) {
			System.out.print(msg);
		}
	}
}

람다식은 익명 구현 객체이다.

 

 

 

 

 

 

 

 

 

'개발 > 자바(JAVA)' 카테고리의 다른 글

컴포지트 패턴 연습 - 1  (0) 2023.04.13
기본형 배열 List로 변환하기  (0) 2023.03.10
객체 지향 - 5  (0) 2023.02.01
객체 지향 - 4  (0) 2023.01.31
객체 지향 - 3  (0) 2023.01.29

super

참조변수 super

super 자손 클래스에서 조상 클래스로부터 상속받은 멤버를 참조하는데 사용되는 참조변수

 

모든 인스턴스 메서드 내에는 자기 자신 객체의 주소this부모의 주소 super 지역 변수로 저장 되어있다.

참고로 매개변수도 그 메서드 블록안에 로컬 변수다.

public class Test {
	public static void main(String[] args) {
		SubMan man = new SubMan();
		man.call();
	}
}
class SuperMan {
	public int intValue = 1;
}
class SubMan extends SuperMan{
	int intValue = 12;
	void call() {
		int intValue = 123;
		System.out.println(intValue);
		System.out.println(this.intValue);
		System.out.println(super.intValue);
	}
}
/////////////////
123
12
1

super() - 조상 클래스의 생성자

Object 클래스를 제외한 모든 클래스의 생성자의 줄에는 반드시 자신의 다른 생성자 또는 조상의 생성자를 호출해야 한다. this(), super()

 

class Class1{
	//기본 생성자와 기본 조상 클래스 생성자( super() )는 컴파일러가 자동 추가해준다.
	public Class1() {
		super(); // 모든 생성자(this(), super() )는 무조건 다른 생성자를 "첫줄"에 호출해야한다
	}
}
//수동으로 기본생성자를 추가하는 것이 일반적으로 옳은 프로그래밍이다.

Object를 제외한 모든 클래스는 상속받은게 없다면 자동으로 Object를 상속한다.

만약 명시적으로 상속받은게 있다면, 부모 클래스가 Object를 상속받는다. 부모 클래스도 상속받은게 있다면 그 부모 클래스가 Object를 상속받는다. 

//상속받은게 없다면 자동으로 Object를 상속 받는다.
class A /*extends Object*/{
}
class B extends A{
}

이유는 조금만 생각해보면 당연하다.

구조적으로 상속받는 객체가 있어야 상속을 받을 수 있다. 부모 없이 자식이 있을 수 없는 것과 같다.

A.class 파일 속을 열어보면 위와 같은 정보를 볼 수 있다.

 

패키지(package)

서로 관련된 클래스의 묶음

관리 편리함

이름이 중복되도 패키지만 다르면 상관없다. (네임스페이스)

 

import

컴파일러에게 소스코드에 사용되는 클래스가 속한 패키지를 알려준다.

클래스를 사용할 패키지 이름을 생략할 있다.

패키지.* 컴파일 단에서 시간이 조금 걸리는 것이지 실행 성능 저하는 전혀 없다.

, 주의할 것은 해당 패키지에 모든 클래스를 표현하는 것이지 하위 디렉토리는 포함하지 않는다

 

Static import

static 멤버(static 변수&메서드) 사용할 클래스 이름을 생략할 있게 해준다.

 

 

제어자(modifier)

접근 제어자 : public, protected, default, private

그 외 : static, final, abstract, native, transient, synchronized, volatile, strictfp

 

접근 제어자는 단 하나만 사용가능

나머지는 복수도 가능

 

제어자들 간 순서는 상관없지만, 접근 제어자는 관례상 가장 왼쪽에 둠

 

static

클래스가 메모리에 로드될 때 단 한번, 생성(또는 수행)된다. 클래스에 귀속된다.

public class Test {
	public static void main(String[] args) {
		//바로 사용 가능
		System.out.println(C.a);// 답은 뭘까?
		new C();
		new C();
		new C();
		C a = new C();
		//비권장법 사용법, 클래스 변수는 무조건 클래스이름으로 접근
		System.out.println(a.a);
		//권장 사용법
		System.out.println(C.a);
		System.out.println(a.b);// 답은 뭘까?
	}
}
class C{
	static int a = 0;
	static int b = 0;
	static {
		a++;
	}
	public C() {
		b ++;
	}
}
////////////////////////////
1
1
1
4

final

변경하지 못하게 한다. 이것만 알면 된다.

 

변수 => 상수, 메서드 => 오버라이드 불가 , 클래스 => 상속 불가

 

final 변수는 상수이기에 선언과 동시에 초기화해야 하나 

인스턴스 변수인 경우에 한에 생성자에서 초기화 되도록 있다.

 

 

abstract

메서드에만 붙는다고 생각하면 된다. 이유는 구현부가 없다는 것을 표현하기 때문이다.

클래스에 붙는 이유는 abstract 메서드가 존재함을 알리기 위한 성격이다.

abstract class C{
	abstract void call();
}

//이런식으로도 사용된다. 상속을 강제한다.
//(abstract붙으면 추상 클래스로 new연산자를 사용 못한다.)
//
abstract class D{
	void call() {}
}

접근제어자 final과 abstract 를 사용한 디자인 패턴도 있다.

템플릿 메서드

abstract class C{
    //골격에 해당하는 메서드는 오버라이딩 못하게 막는다.
	final void call() {
		System.out.println("무언가... 작업중...");
		call2(); // 서브클래스에게 행동을 위임한다.
		call3();
		hook();
	}
	abstract void call2();
	void call3() {
		System.out.println("다른 메서드 호출....");
	}
    //구현을 강제하지 않는 메서드를 hook메서드라 한다.
    //그냥 넘어가도 되고 향후 필요할 때 hook부분을 재정의해서 쓰면된다.
    //반드시 hook이름 안써도된다. 관례 아님. 이렇게 쓰는걸 hook메서드라 하는 것
	void hook() {}
}
class D extends C{
	@Override
	void call2() {
		System.err.println("나만의 메서드...");
	}
}

접근 제어자 

말그대로 접근 제어,

private 같은 클래스 내

default 같은 클래스 내, 같은 패키지 내

protected 같은 클래스 내, 같은 패키지 내, 다른 패키지라도 상속해서 사용 가능

public 전부 허용

 

접근제어자는 캡슐화에 핵심적인 역할을 한다. 

 

데이터가 유효한 값을 유지하도록, 또는 민감한 데이터를 외부에서 함부로 변경하지 못하도록 제한을 한다.

이를 정보 은닉, 캡슐화라 한다.

 

클래스 내부에서만 필요한 정보를 외부에 노출시키지 않아 복잡도를 줄인다.

 

접근제어자가 public이면 메서드를 변경한 후에 오류가 없는지 테스트해야하는 범위가 넓다.

private이면 클래스 내부에서만 확인하면 된다.

 

자바빈즈 패턴은 접근 제어자를 활용한 패턴이다.

모든 변수는 private으로 두고 메서드로만 접근하게 한다. 메서드는 동작을 정의하기 때문에 사용자 접근에 대한 검증과 데이터 유효성 검사 등을 수행할 수 있다.

 

쉽게 생각해보자, 특정 데이터를 권한 있는 사용자에게만 보여주고 싶다. 메서드 없이 변수로는 죽었다 깨어나도 구현 못한다. 

 

생성자의 접근 제어자 prviate을 두면 객체를 외부에서 생성을 못한다.

이말은 클래스 자체적으로 객체를 생성해서 외부에 건낸다. 이를 싱글턴 패턴이라 한다.

class Singleton{
    //제어자 중심으로 유심히 보자
	private static Singleton singleton;
	private Singleton() {
	}
	public static Singleton getInstance() {
		if(singleton == null) {
			singleton = new Singleton();
		}
		return singleton;
	}
}

객체 생성을 못하니 static 키워드를 쓴 것을 볼 수 있다.

싱글턴 목적은 어플리케이션 내에 반드시 하나의 객체만 존재하는 것을 보장하기 위함이다.

 

실제로 위 같이 사용은 안한다. (멀티 쓰레딩 문제)

enum Singleton{
	SINGLETON;
	void call() {
		System.out.println("이렇게 사용");
	}
}

객체 생성을 JVM에 위임해 멀티 쓰레드 문제에서 완전히 자유롭다.

 

 

 

 

 

 

 

 

'개발 > 자바(JAVA)' 카테고리의 다른 글

기본형 배열 List로 변환하기  (0) 2023.03.10
객체 지향 - 6  (0) 2023.02.03
객체 지향 - 4  (0) 2023.01.31
객체 지향 - 3  (0) 2023.01.29
객체 지향 - 2  (0) 2023.01.27

상속 (Inheritance)

기존 클래스로 새로운 클래스를 작성하는 (코드의 재사용)

상속을 통해서 클래스를 작성하면 보다 적은 양의 코드로 새로운 클래스를 작성할 있다.

또한 코드를 공통적으로 관리할 있기 때문에 코드의 추가 변경이 용이하다

상속 특성상 상속하면 수록 기능이 많아진다.

 

extends 키워드로 상속한다

확장

생성자와 초기화 블록은 상속되지 않는다.

자바는 단일 상속 객체지향 언어이다.

 

접근제어자 private, default 멤버는 엄밀히 말하면 상속은 되지만, 서브 클래스에서 접근이 불가한 것

클래스의 관계 - 포함 관계(composite)

상속 이외에 클래스를 재사용하는 방법은 클래스의 멤버로 다른 클래스 타입 참조변수를 선언하는

단일 상속만 되는 자바에서 일반적으로 포함 관계가 훨씬 좋다고 여겨진다.

public class Ex1 {
	public static void main(String[] args) {
		//상위 클래스 타입으로 하위 클래스 타입을 다룰 수 있다. 다형성의 핵심
		SuperClass superClass = new SubClass();
		superClass.call();
	}
}
class  SuperClass{
	//일반적으로 멤버변수는 private이 옳다. 데이터 접근은 메서드로 하는 것이 일반적으로 옳다.
	private Composite composite;
	//슈퍼 클래스 생성자는 서브 객체 생성 시 자동으로 호출 된다. 즉, 
	//즉, 슈퍼클래스 객체와 서브 클래스를 묶어 하나 처럼 쓰는 것이다.
	public SuperClass() {
		composite = new Composite();
	}
	public void call() {
		composite.call();
	}
}

class SubClass extends SuperClass{
	//자동으로 컴파일러가 추가 1
//	public SubClass() {
	//자동으로 컴파일러가 추가 2
//		super();
//	}
}

class Composite{
	public void call() {
		System.out.println("구성과 위임");
	}
}

 

구성과 위임

클래스간의 관계 결정하기

클래스를 작성하는데 상속관계를 맺어 줄지, 포함관계를 맺어줄지

 

분류법

상속관계 , is-a 관계, ~는 ~이다, is-a-kind-of , ~는 ~의 분류이다. 이 표현이 더 정확하다는 책도 있다.

포함관계(구성관계) , has-a 관계, ~는 ~를 가지고 있다.

이 내용을 좀 더 이해하려면, 객체지향만을 주제로 한 책을 읽어봐야 한다.

 

앞자리에 하위클래스가 오고 뒤에 상위 클래스가 온다.

 

예시) 오리는 동물이다.  OK , 오리는 동물을 가지고 있다. Not OK

 

객체 지향의 상속이라는 특성을 올바르게 활용하면 리스코프 치환 원칙을 준수하게 된다.

 

단일 상속(single inheritance)

자바는 단일 상속만 허용한다.

다중 상속은 복합적인 기능을 가진 클래스를 쉽게 만들 있다는 장점이 있다

하지만 클래스 간의 관계가 매우 복잡해진다.

 

다중 상속이 된다면 문제점

조상 메소드 이름은 같지만 구현부가 다른 경우 어떤 것을 실행할 것인가? (충돌 문제)

 

자바는 인터페이스로 다중 상속과 유사한 효과를 낼 수 있다.

 

상속과 구성 관계를 확장한 다양한 디자인 패턴도 존재한다.

 

오버라이딩(overriding)

상속받은 조상의 메서드를 자신에 맞게 변경하는

메서드 시그니처는 완전히 동일해야 한다.(반환타입, 매개변수, 이름)

class A{
	A getInstance() {
		return this;
	}
}
class B extends A{
	//단, 자손 타입으로 반환하는 것은 예외적으로 허용된다.
	B getInstance() {
		return this;
	}
}

오버라이딩 조건

  • 접근 제어자를 조상 클래스의 메서드보다 좁은 범위로 변경할 수 없다
  • 예외는 조상 클래스의 메서드보다 많이 선언할 수 없다.
    조상 클래스 메서드 예외보다 더 상위 예외를 선언할 수 없다는 뜻(예외도 계층이 존재한다)
  • 인스턴스 메서드를 static 메서드로 또는 그 반대로 변경할 수 없다.
class AA{
	void method() throws Exception{	}
	protected void method2(){	}
	static void method3() {}
}


class BB extends AA{
	@Override
	//조상보다 더 많은 예외 안됨
	void method() throws Throwable{
		// TODO Auto-generated method stub
		super.method();
	}
	@Override
	//접근제어자 더 좁게 불가.
	private void method2() {
		// TODO Auto-generated method stub
		super.method2();
	}
	/**
	 * static 멤버는 클래스에 속한 것이지, 인스턴스에 속한게 아니다.
	 * 	따라서 오버라이딩이란 개념이 없다. 야에 별개다. 
	 * AA.method3(), BB.method3() 앞에 변수가 아니라 클래스로 명확히 구분이 가능하다.
	 */
	static void method3() {}
}

 

 

 

 

 

'개발 > 자바(JAVA)' 카테고리의 다른 글

객체 지향 - 6  (0) 2023.02.03
객체 지향 - 5  (0) 2023.02.01
객체 지향 - 3  (0) 2023.01.29
객체 지향 - 2  (0) 2023.01.27
객체 지향 - 1  (0) 2023.01.25

JVM 메모리 구조

JVM 시스템으로부터 메모리를 할당 받는다

 

1. 메서드 영역(method area) 
프로그램 실행 중 어떤 클래스가 사용되면.(지연로딩)

JVM은 해당 클래스의 클래스파일(*.class)을 읽어서 분석하여 클래스에 대한 정보(클래스 데이터)를 이곳에 저장한다.

이 때. 그 클래스의 클래스변수(class variable)도 이 영역에 함께 생성된다. 

2. 힙(heap) 
인스턴스가 생성되는 공간. 프로그램 실행 중 생성되는 인스턴스는 모두 이곳에 생성된다. 
즉 인스턴스변수(instance vanable)들이 생성되는 공간이다. 

3. 호출스택 (call stack 또는 execution stack) 
호출스택은 메서드의 작업에 필요한 메모리 공간을 제공한다. 메서드가 호출되면,
 호출스택에 호출된 메서드를 위한 메모리가 할당되며, 이 메모리는 메서드가 작업을 수행하는 동안 지역변수(매개변수 포함)들과 연산의 중간결과 등을 저장하는데 사용된다. 그리고 메서드가 작업을 마치면 할당되었던 메모리공간은 반환되어 비워진다. 

 

호출 스택의 특징

메서드가 호출되면 수행에 필요한 만큼의 메모리를 스택에 할당받는다. 
메서드가 수행을 마치고나면 사용했던 메모리를 반환하고 스택에서 제거된다. 
호출스택의 제일 위에 있는 메서드가 현재 실행 중인 메서드이다. 
아래에 있는 메서드가 바로 위의 메서드를 호출한 메서드이다. 

public class CallStack {
	public static void main(String[] args) {
		System.out.println(factorial(10));
	}
	public static long factorial(int num) {
		if(num == 0) return 1;
		long result = 0;
		result = num * factorial(--num);
		return result;
	}
}

제일 위가 현재 실행 중 가장 아래가 제일 먼저 호출된 메서드

 

기본형 매개변수- 참조형 매개변수

자바에서 메서드를 호출할 매개변수로 지정한 값은 복사해서 넘겨준다

기본형이면 데이터 복사되지만 참조형이면 주소가 복사된다

 

기본형 매개변수는 변수의 값을 읽기만 할 수 있다.

참조형 매개변수는 변수의 값을 읽고 변경할 수 있다.

public class PrimitiveType {
	public static void main(String[] args) {
		int pValue = 10;
		System.out.println("기본형 변경 전 : "+ pValue);
		int copyPValue = pValue;
		copyPValue = 20;
		System.out.println("기본형 읽고읽은 값 변경 : "+ pValue + "원본에는 영향 안 감");
		System.out.println(pValue == copyPValue);
		
		Referencetype rValue = new Referencetype();
		System.out.println("참조형 변경 전 : "+ rValue);
		Referencetype copyRValue = rValue;
		copyRValue.value = 2000;
		System.out.println("참조형 읽고읽은 값 변경 : "+ rValue + "원본에 영향 감 ");
		System.out.println(rValue == copyRValue);
	}
}

class Referencetype{
	int value = 1000;
	@Override
	public String toString() {
		return value+"";
	}
}
기본형 변경 전 : 10
기본형 읽고읽은 값 변경 : 10원본에는 영향 안 감
false
참조형 변경 전 : 1000
참조형 읽고읽은 값 변경 : 2000원본에 영향 감 
true

재귀호출(recursive call)

메서드 입장에서는 자기 자신을 호출하는 것과 다른 메서드를 호출하는 것은 차이가 없다.

'메서드 호출'이라는 것이 그저 특정 위치에 저장되어 있는 명령들을 수행하는 것일 뿐이기 때문이다.

재귀호출은 무한 루프 위험성이 있어 종료 조건문이 필수적이다.

재귀호출은 반복문보다 성능이 떨어진다. 따라서 재귀호출은 성능적 이점보다 논리적 간결함이 주는 이점이 때만 사용한다.

 

 

 

 

 

 

'개발 > 자바(JAVA)' 카테고리의 다른 글

객체 지향 - 4  (0) 2023.01.31
객체 지향 - 3  (0) 2023.01.29
객체 지향 - 1  (0) 2023.01.25
파일 옮기기  (0) 2022.07.25
변수의 타입  (0) 2022.07.07

자바 객체지향 언어

  • 코드 재사용성이 높다. 
  • 코드 관리가용이하다.
  • 신뢰성이 높은 프로그래밍을 가능하게 한다.

 

객체 지향 프로그래밍

부품에 해당하는 객체를 먼저 만들고, 이걱들을 하나 씩 조립해서 완성된 프로그램을 만드는 기법

 

객체 간의 관계

  • 상속관계
  • 사용관계
  • 집합관계

객체 지향 프로그래밍 특징

    • 캡슐화
      객체의 필드, 메서드를 하나로 묶고, 실제 구현내용을 감추는 것
      접근 제한자를 통해 구현
      감추는(보호하는) 이유는 외부의 잘못된 사용으로 손상을 막기 위함
    • 상속
      상위 객체가 가진 필드와 메서드를 하위 객체에게 물려주는 또한 상위 객체 변경이 하위 객체에게 영향을 미치므로 유지보수성도 상승 한다.
      , 상위 객체를 재사용하여 빠른 설계와 코드 재사용성 상승으로 개발 효율이 올라간다.
    • 다형성
      같은 타입이지만 실행 결과가 다양한 객체를 이용할 수 있는 성질
      부모 클래스(인터페이스) 타입으로 자식 객체를 다루는 것
    • 추상화
      공통된 성질을 뽑아 상위 타입으로 만든다.

 

클래스와 객체

클래스는 객체를 정의해 놓은 것

클래스는 객체를 생성하는데 사용된다.

 

new 연산자

new 연산자 뒤엔 반드시 생성자를 호출한다.

클래스에 new 연산자를 사용해 객체를 생성, 생성된 객체는 자바 heap 영역에 존재하며, 그 주소 값를 리턴한다.

 

객체의 구성요소

속성 - 멤버변수, 특성, 필드, 상태

기능 - 메서드 , 함수, 행위

 

 

클래스의 구성 멤버

필드

객체가 가져야할 데이터

상태, 정보, 다른 객체의 참조변수

 

생성자

new 연산자와 같이 사용되어 클래스로부터 객체를 생성할 호출되는 메서드

객체 초기화 담당

heap영역에 생성 주소를 리턴

아무 것도 없을 컴파일러가 기본 생성자를 추가해준다.

, 명시적으로 다른 생성자를 만들었으면 기본생성자는 추가 안해준다

명시적 초기화 이유는 복잡 초기화를 위함이다.

 

메소드

객체에 동작에 해당

객체간 데이터 전달

필드 수정 등등

메소드 선언부 - 리턴타입, 메소드이름, 매개변수(파라미터) 선언

이를 시그니처(signature)라고도 한다.

 

클래스의 다른 정의

객체지향의 관점에서 클래스는 객체를 생성하기 위한 , 클래스는 속성과 기능으로 정의된다.

 

클래스를 바라보는 3가지 관점

  • 설계도 
  • 데이터와 함수의 결합
  • 사용자 정의 데이터 타입

변수와 메서드

선언위치 변수종류

클래스 변수, 인스턴스 변수, 지역변수 종류가 있다.

구분 방법은 선언 위치이다.

 

멤버 변수를 제외하고는 전부 지역 변수이며

그중 static 붙은 것을 클래스 변수라 한다.

public class Variables {
	int iv; //인스턴스 변수, 객체와 같은 생명주기 , 힙영역에 위치
	static int cv;// 클래스 변수 JVM과 같은 생명 주기, 메서드 영역에 위치
	
	void method() {
		int lv = 0; //지역변수.  스택 영역에 위치
		//지역변수는 선언과 동시에 초기화를 해줘야 한다.
	}
}

1. 인스턴스 변수(instance variable)

클래스 영역에 선언

클래스의 인스턴스가 생성되었을 생성된다.

각각 독립적인 저장공간을 가진다.(서로 다른 가능)

인스턴스 마다 고유한 상태를 유지해야하는 경우 인스턴스 변수를 사용

객체가 제거 같이 소멸

 

2. 클래스 변수(class variable)

인스턴스 변수 앞에 static 키워드를 붙인

클래스가 메모리에 올라갈 생성되며, 인스턴스 생성 없이 바로 사용 가능

모든 인스턴스가 공통된 저장공간을 공유한다.

JVM 종료될 같이 소멸

 

3. 지역 변수(local variable)

메서드 내에 선언, 메서드 내에서만 사용 가능

메서드 종료 같이 소멸

해당 블록에서만 유효 { }

 

클래스 변수 아무때나 사용가능하다.

프로그램 시작과 동시에 고정으로 생성되기 때문이다.

클래스 변수의 수정은 전역 영향을 미친다.

클래스 변수의 초기화는 묵시적으로 가능하다.

클래스로부터 생성된 객체들이 공유하는 데이터를 클래스 멤버로 만든다.

하나의 메모리를 같이 공유(메서드 영역)

 

인스턴스 변수는 인스턴스가 생성돼야 사용 가능하다.

인스턴스는 힙영역에 동적으로 할당 되기 때문이다.

인스턴스 변수의 변화는 해당 인스턴스만 영향을 미친다.

인스턴스 변수의 초기화는 묵시적으로 가능하다.

필요한 필드나 메서드는 같지만 객체마다 서로 다른 값이 필요한 경우 인스턴스 멤버로 쓴다.

객체마다 별도의 데이터 공간이 할당된다(힙영역)

 

지역 변수는 메서드 구현부 블록 {} 안에서만 유효하다.

스택 영역에 저장되며 블록 {} 벗어나면 소멸한다.

지역 변수의 변화는 해당 메소드에만 영향을 미친다.

지역 변수는 반드시 명시적 초기화 해줘야 한다.

 

메서드

특정 작업을 수행하는 문장을 작업단위로 묶어서 이름을 붙인

 

값을 받아서 처리하고, 결과를 반환

중요한 것은 메서드가 어떤 작업을 수행하는 필요가 없다는 것이다.

, 메서드에 넣을 (입력) 결과(출력) 알면 된다.

그래서 메서드를 내부가 보이지 않는 '블랙박스'라고도 한다.

 

 

메서드를 사용하는 이유 가지

높은 재사용성(reusability)

Java API에서 제공하는 메서드들을 생각해보자

만들어 놓으면 번이고 다른 프로그램에서 사용이 가능하다.

 

중복된 코드 제거

반복되는 코드를 묶어서 하나의 메서드로 작성해 놓으면

반복되는 코드 대신 메서드 호출 번으로 대체가 가능하다.

, 코드량과 코드 유지보수성이 증가한다.

코드 변경에도 유리하다.

 

프로그램 구조화

main()메서드 안에 어플리케이션 코드를 집어넣을 수는 없다.

작업 단위로 나눠서 여러 개의 메서드에 담아 프로그램의 구조를 단순화 시키는 것이 필수적이다.

 

메서드의 선언과 구현

메서드는 크게 부분, 선언부와 구현부로 이뤄져 있다.

void method(){ // 이외 선언부, 선언부의 다른 이름 시그니처
/*{}속이 구현부*/
}

반복적으로 수행되는 여러 문장을 하나의 메서드로 작성

하나의 메서드는 가지 기능만을 수행하도록 작성(재사용, 이식성)

 

반환 값은 있을 수도 있고 없을 수도 있지만

반환 값이 있을 경우 반드시 1개만 반환한다.

만약 여러 개를 값을 반환하고 싶다면 배열이나 객체로 반환한다

리턴 값은 당연히 반환 타입과 일치해야한다.

모든 메서드는 반드시 하나의 return문이 있어야한다.

반환 값이 없는 void경우 컴파일러가 자동으로 추가해 준다.

 

메서드 선언부는 후에 변경사항이 발생하지 않도록 신중히 작성해야한다. 메서드를 호출하는 부분이 전부 변경되기 때문이다.

 

 

 

 

 

 

'개발 > 자바(JAVA)' 카테고리의 다른 글

객체 지향 - 3  (0) 2023.01.29
객체 지향 - 2  (0) 2023.01.27
파일 옮기기  (0) 2022.07.25
변수의 타입  (0) 2022.07.07
변수  (0) 2022.07.03

기본형 변수 타입

  • 문자형
    문자 : char 
  • 숫자
    정수 : byte, short, int, long
    실수 : float, double
  • 논리형
    boolean

총 8개

 

기본형과 참조형

기본형은 실제 값을 저장한다

8개가 존재한다.

성능상 이점 때문에 사용한다.

 

참조형은 어떤 데이터가 저장된주소 값을 저장한다.

기본형을 제외한 모든 것이다 참조형이다

배열, 클래스, 열거형 …

32bit JVM 쓰면 참조변수 크기는 32bit

64bit JVM 쓰면 참조변수 크기는 64bit이다.

 

 

기본형

정수형과 실수형이 존재 정수형의 대표는 int, 실수형의 대표는 double

종류\크기(byte) 1 2 4 8
논리형 boolean      
문자형   char    
정수형 byte short int(기본) long
실수형     float double(기본)

boolean 타입은 제어문이나 반복문에서 주로 사용된다.

char타입은 사실 아스키코드로 숫자에 문자가 매핑되어있다. 따라서 반복문도 가능하다

public class CharEx {
	public static void main(String[] args) {
		for(char a = 65; a < 91 ; a ++) {
			System.out.print(a+",");
		}
	}
}
// 결과 : A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S,T,U,V,W,X,Y,Z,

숫자형 타입은 작은 데이터에서 큰 데이터로 자동 형변환이 된다. 

일부 예외도 있지만 크게 중요하지 않다.

 

'개발 > 자바(JAVA)' 카테고리의 다른 글

객체 지향 - 1  (0) 2023.01.25
파일 옮기기  (0) 2022.07.25
변수  (0) 2022.07.03
자바란?  (0) 2022.07.02
폴더, 파일 수 탐색  (0) 2022.05.27

하나의 타입, 하나의 값을 저장할 수 있는 메모리 공간

 

int var = 0;

int는 변수의 타입, var는 변수 메모리 공간의 이름

자바는 강타입 언어로 타입을 명확히 한다.

 

변수의 초기화

메모리는 자바 프로그램 뿐만아니라 모든 프로그램이 공유하는 h/w자원이다.

따라서 그 공간에 잔여 값이 남아 있을 수도 있다. 

 

변수 초기화란 변수 사용 전에 처음으로 값을 저장하는 것을 말한다.

	public class Var {
	      static int classVariable;
	      int instanceVariable;
	      
	      //main()도 메서드이므로 로컬영역이다.
	      public static void main(String[] args) {
	            VarEx1 instance = new VarEx1();
	            int localVariable;
	            System.out.println(classVariable);
	            System.out.println(instance.instanceVariable);
	//          System.out.println(localVariable);
	      }
}

기본형 인스턴스 변수와 클래스 변수는 각각 정해진 기본값으로 초기화가 자동으로 된다.

기본형 지역변수는 선언과 동시에 초기화를 반드시 해야한다.

 

 

두 변수의 값 교환하기

현실의 사고방식으로는 바꿔치지를 생각할 있지만 여기는 기계속이다. 불가능하다.

  1. 먼저 a temp 임시 저장한다
  2. a 자리에 b 값을 넣는다.
  3. b 자리에 temp 값을 넣는다.

물컵 잔에 내용물을 바꾼다고 생각하면 쉽다.

아니면 실제로 코드상으로 변수 2개로만 바꿀려고 시도해보자. 그러면 왜 temp가 필요한지 이해가 잘된다.

 

변수명 규칙

  • 대소문자 구분한다/ 길이제한 없다
  • 예약어를 사용하면 안된다
  • 숫자로 시작하면 안된다
  • 특수문자는 _ , $ 허용한다

예약어는 대부분 자바 문법상 사용하는 단어들이다. 따라서 외울 생각을 할필요가 없다

int, long, for, ....

다만 예약어가 포함되어 있다고 사용이 다 불가능하지 않다. intSum 이런 것은 된다. 

즉, 딱 그 예약어 단어 사용이 불가능하다.

추가 권장사항

  • 클래스 이름은 글자를 대문자로한다
  • 여러 단어 이름은 단어 글자를 대문자로 한다
  • 상수의 이름은 대문자로만 사용하며 단어 구분은 _ 한다

 

 

'개발 > 자바(JAVA)' 카테고리의 다른 글

파일 옮기기  (0) 2022.07.25
변수의 타입  (0) 2022.07.07
자바란?  (0) 2022.07.02
폴더, 파일 수 탐색  (0) 2022.05.27
File  (0) 2022.05.26

1996년 출시한 객체지향 프로그래밍 언어

 

자바의 특징

  • 운영체제에 독립적이다.
    JVM만 설치되면 된다. JVM은 거의 모든 운영체제별로 준비가 되어있다.
    따라서 하나의 코드로 모든 환경에서 사용이 가능하다.

  • 객체지향언어이다.
    코드의 재사용성, 유지보수가 편리하다
  • 자동 메모리 관리
    메모리를 관리해주는 가비지 컬렉터가 존재해 개발자는 메모리 관리에 힘을 쓰지 않고 개발에만 집중할 수 있다.
  • 네트워크와 분산처리를 지원한다.
  • 멀티쓰레드를 지원한다.
    멀티쓰레드는 운영체제에 따라 구현 방법도 상이하고, 처리방법도 다르지만 자바는 멀티쓰레드 관련 API를 제공한다.
    따라서 사용법만 알면 손쉽게 구현이 가능하다
  • 동적로딩을 지원한다.
    애플리케이션 실행 시 모든 클래스가 로딩되지 않고 필요한 시점에 로딩할 수 있다.

JVM(Java Virtual Machine)

모든 자바 코드를 실행하기 위한 프로그램

자바와 일반 소프트웨어 차이

  • 단점
    일반 애플리케이션은 OS 거치고 컴퓨터로 코드 전달따라서 속도가 느리다.
    하지만 극복을 위해 요즘엔 바이트코드(컴파일된 자바코드) 하드웨어의 기계어로 바로 변환해주는 JIT컴파일러와 향상된 최적화 기술이 적용되어서 속도 격차를 많이 줄였다.
  • 장점
    하나의 코드로 모든 플랫폼에서 실행이 가능하다.

'개발 > 자바(JAVA)' 카테고리의 다른 글

파일 옮기기  (0) 2022.07.25
변수의 타입  (0) 2022.07.07
변수  (0) 2022.07.03
폴더, 파일 수 탐색  (0) 2022.05.27
File  (0) 2022.05.26

+ Recent posts