[JAVA]_6일차

전희주·2023년 4월 12일
0

JAVA

목록 보기
6/24

지난 강의 리뷰

클래스 생성 총 정리

  • 1) 클래스(main함수 X) 생성
package p03;

public class Cat {

	// 인스턴스 변수 (필드) 
	String name;
	int age;
	String sex; 
	
	// 생성자
	// 명시적으로 지정해주지 않으면, 기본 생성자가 자동으로 제공됨 
	// 명시적으로 만들면 기본 생성자는 자동생성 안됨 
    // public Cat() {} ; 
	
	// 명시적으로 여러 생성자 생성 ==> 오버로딩 생성자 (핸들링 클래스 내 호출 해 사용) 
	
	public Cat() {}
	public Cat(int n) {}
	public Cat(String n) {}
	public Cat(String n, int a) {}
	
	
	public Cat(String n, int a, String s) {
	name = n; 
	age = a;
	sex = s; 
	}
	// Cat c = new Cat("야옹이", 2, "암컷"); <= Dog.java 
	// 야옹이가 n에 저장되고, n을 인스턴스 변수 name에 저장 (인스턴스 변수 초기화 수행) 
	
	
}
  • 2) 핸들링 클래스(main함수 O) 내 호출을 통한 인스턴스 변수 값 초기화, 메서드 호출해 실행
package p03;

public class TestCat {

	public static void main(String[] args) {
		
		// 객체의 인스턴스 변수 초기화 방법 2가지 
		// 1. 생성자 사용 
		// 생성자 이용해서 초기화 하는 방법은 초기화 시점이 가장 빠른 방법이다. 
		//heap 메모리에 인스턴스 변수 할당 후(객체 생성)과 동시에 값이 초기화 됨
		       // 생성자 생성 후 핸들링 클래스의 main() { }내 호출하여 사용 필 
		Cat c = new Cat("야옹이", 2, "암컷");
		
		
		
		// 인스턴스 변수에 직접 접근해서 초기화하는 방법은 초기화 시점이 매우 늦다 
	    /*	c.name = "야옹이"; // 객체 생성 이후에 name 변수에 값을 할당
		    c.age = 2;
		    c.sex = "암컷"; 
		*/
		
		
	}

}

메서드 실행 흐름

  • return 용도:

    • 호출된 곳으로 리턴 값 전달할 용도
    • 메서드 중지
  • 메서드 호출 시 전달하는 인자값 종류

    • call by value: 기본값 전달
      • 넘겨받은 메서드에서 값을 변경해도 원래 값은 영향 x
    • call by value reference: 참조값(클래스, 배열) 전달 (주소값 전달)
      • 넘겨받은 메서드에서 값을 변경하면 원래 값이 영향을 받는다.
  • 객체 지향 프로그래밍의 4가지 특징
    : 추상화, 상속, 다형성, 캡슐화

정보은닉과 캡슐화

class Abc{
    int a;
    int b;

    public Abc(a,b){
        this.a = a;
        this.b = b;
    }
}
Abc abc = new Abc(1,2); //불가능 
  • 우리는 abc.a=error; abc.b=1; 과 같이 해당 변수에 직접 접근하여 그 값을 수정할 수 있다.

  • 위 예제에서는 크게 문제가 되지않는다. 하지만 이런 접근은 위험하다.

  • 개발자의 실수로 이어질 수도 있으며 안정성 또한 떨어진다.

class Abc{

    private int a;
    private int b;

    public Abc(a,b){
        this.a = a;
        this.b = b;
    }
}
  • private로 선언되는 인스턴스 변수와 메소드는 선언된 클래스 내부에서만 접근이 가능하다.
  • 이렇게 설정해 줄 경우 메소드를 사용하지 않고 직접 해당 변수에 접근하는 일을 막을 수 있기 때문에 안정성을 높일 수 있다.
package p02;



public class Cat {

	// 필드
	String name; 
	private int age; // 인스턴스 변수는 직접 접근하면 에러나서 접근 지정자로 private 설정해두는게 관례 
	String sex;
	
	//생성자 
	public Cat() {
		
	}
	
	public Cat(String name, int age, String sex) {
		this.name = name;
		this.age = age;
		this.sex = sex;
	}

	//메서드 
	// setter 메서드 (인스턴스 변수에 값을 설정 ==> 값 변경도 설정에 해당) 
	// getter 메서드 (인스턴스 변수에 값을 조회) 
	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}

	public int getAge() {
		return age;
	}
	
	// 검증작업 
	public boolean ageCheck(int age) {
		boolean result = true; 
		if(age > 0 && age < 20) {
			result = false; 
		}
			
		return result; 
	}

	public void setAge(int age) {
		
		// 검증 작업 
		if(ageCheck(age))
		{
			this.age = age; 
		}else {
			System.out.println("입력 age 값을 다시 확인하세요");
		}
		
		
	}

	public String getSex() {
		return sex;
	}

	public void setSex(String sex) {
		this.sex = sex;
	}
	
	// 추가 기능에 해당되는 메서드 지정 
	

}
package p02;


import java06.Cat;

public class TestCat {

	public static void main(String[] args) {
		
		
		// 야옹이 2 암컷, 나비 1 숫컷 
		Cat c1 = new Cat("야옹이",2, "암컷");
		
		//나이 수정 
		//c1.age = 300; // 논리적으로 문제가 됨. 
		c1.setAge(300);
		//인스턴스 변수에 접근하려면 클래스 내부에서 getter와 setter 메소드를 사용해야 합니다. 
        
        
		//System.out.printf("이름:%s 나이:%d 성별:%s", c1.name, c1.age, c1.sex);

	
	}

}
  • 이를 통해 클래스 외부에서 인스턴스 변수에 접근하는 것을 제한하면서, 데이터를 보호할 수 있습니다.
  • 이러한 접근 제어 방식은 정보 은닉이라는 객체 지향 프로그래밍의 개념 중 하나입니다.

package

  • 1) 목적: 클래스 파일 관리

    • 윈도우 폴더 비슷
    • 패키지는 클래스 당 한 개 생성 가능
  • 2) 문법

    • package 패키지명;
      or
    • package 패키지명.서브패키지명;
      ex) com.daou
    • package 지정하지 않으면 default package라고 부른다
  • Window 메뉴에서 Show View -> Navigator를 선택

  • 3) 유일한 값 지정

    • IP 번호 (도메인)
  • 4) package가 다르면 기존 방식으로 접근이 안된다.

    • 패키지명.클래스
      예) com.daou.Cat = new com.daou.Cat();

public class TestMain {

	public static void main(String[] args) {
		
		com.daou.Cat c = new com.daou.Cat(); // 내가 접근하고자 하는 Cat이 어디에 있는지 알려주면 에러가 발생하지 않음 
		com.daou.Cat c2 = new com.daou.Cat(); // 내가 접근하고자 하는 Cat이 어디에 있는지 알려주면 에러가 발생하지 않음 

	}

}
  • 5) 자바 API는 package로 제공된다.
    • java.
    • 자바API는 반드시 import 해야 사용 할 수 있다.
      cf) 예외: java.lang은 import하지 않아도 사용 가능
import 패키지명.클래스명;
import 패키지명.*;
  • 같은 패키지 내에서 클래스 이름이 중복될 수 없음
package com.example;

public class A {
    //...
}
package com.example;

public class A { // 에러: 이전에 선언된 클래스와 이름이 중복됩니다.
    //...
}
package com.example;

import otherpackage.A;

public class B {
    A a = new A(); // 패키지 otherpackage에 있는 A 클래스를 사용합니다.
    //...
}
  • 실습
package com.app1;

public class A {
	
	public String name = "com.app1.A";

}
package com.app2;

public class A {
	
	public String name = "com.app2.A";

}
package com.app1;
// 두 패키지 모두 명시적으로 지정하거나 
// 둘 중 하나의 클래스를 import 패키지명.클래스명;
import com.app1.A; 

public class TestA {

	public static void main(String[] args) {
		
         A a = new A(); 
         System.out.println(a.name);
         
         com.app2.A a2 = new com.app2.A(); 
         System.out.println(a2.name);
	}

}
  • +) Java API(Java Application Programming Interface)는 Java 표준 라이브러리를 말하며, Java 언어로 개발된 애플리케이션을 작성할 때 필요한 클래스, 인터페이스, 메소드, 상수 등의 집합을 제공합니다.

  • Java API는 패키지로 제공되며, 각 패키지에는 특정한 기능을 수행하는 클래스와 인터페이스가 포함되어 있습니다.

  • Java API는 JDK(Java Development Kit)에 포함되어 있으며, JDK를 설치하면 자동으로 사용할 수 있습니다.

import

import 패키지명.클래스명;
import 패키지명.*;

  • 1) 목적: package가 다른 경우 접근하기 위해서 경로 지정 용도
  • 2) 문법: import 패키지명.클래스;
    • import로 여러 번 지정 가능
      cf) package는 클래스 당 한 번만 지정 가능
  • 단축키: ctrl + shift + o
  • 단축키: 클래스명 + ctrl + space
import com.daou.Cat;

//import를 사용해 패키지 경로 지정하는 방법
// import com.daou.Cat; 

public class TestMain2 {

	public static void main(String[] args) {
		
		/*com.daou.Cat c = new com.daou.Cat(); // 내가 접근하고자 하는 Cat이 어디에 있는지 알려주면 에러가 발생하지 않음 
		com.daou.Cat c2 = new com.daou.Cat(); // 내가 접근하고자 하는 Cat이 어디에 있는지 알려주면 에러가 발생하지 않음 
		*/
		
		Cat c = new Cat(); 
		Cat c2 = new Cat(); 
	}

}

접근 지정자

  • 접근지정자는 객체지향의 4대 개념(추상화, 캡슐화(은닉화), 상속, 다형성)에서 캡슐화와 관련되어 있다.
    • 정보 보안과 관련
  • 접근지정자에는 public, protected, default, private 4종류가 있으며 각 접근지정자의 접근가능범위는 private < default < protected < public 순이다.

(cf. 제한 강도: private > default > protected > public)

접근지정자(접근제한자) 사용

  • 4개의 접근 지정자는 클래스, 변수, 메서드, 생성자에 사용 가능

    • 클래스 : public, default
    • 생성자 : public, protected, default, private
    • 멤버변수 : public, protected, default, private
    • 멤버메소드 : public, protected, default, private
    • 지역변수 : 접근제한자 사용 불허
  • public

    • 제한이 없다 => package가 달라도 접근 가능
    • 공개 정도가 가장 높고 어디에서든 자유롭게 접근할 수 있다.
  • protected

    • package가 다르면 접근 불가
      • 단, 상속 관계면 package가 달라도 접근 가능 (default는 안됨.)
    • 같은 패키지 내에서 접근이 가능하고 다른 패키지에서도 상속을 받은 클래스 내부에서는 사용 가능하다. public과 다른 점은 다른 패키지의 자식 클래스 외부에서는 접근할 수 없다는 것이다.
  • default (package private)

    • 같은 패키지 내에서만 접근이 가능하다. 아무런 접근 지정자가 없을 경우 이 옵션이 자동으로 적용된다.
  • 상속 불가

  • private

    • 동일 클래스 내에서만 접근이 가능한 가장 낮은 단계의 자유도를 갖는다.
    • 상속 불가

    상속

  • 부모클래스(parent class)로부터 상속받은 자식클래스(children class)는 부모클래스의 모든 자원과 메서드 등을 자신의 것 처럼 사용 할 수 있습니다.

  • 하위클래스로 상속이 안되는 2가지 접근 지정자 : default, private

package com.app1;

public class Super {
	
	public int n1 = 10; 
	protected int n2 = 20; 
	         int n3 = 30; 
	private int n4 = 40; 

}
package com.app2;

import com.app1.Super;

public class Sub extends Super{
	
	private int m = 10; 
	
	public void info()
	{
		System.out.println(n1); 
		System.out.println(n2); 
		// System.out.println(n3);
		// System.out.println(n4); private으로 인스턴스 변수 지정되어있음 
		
		System.out.println(m); 
		
	}

}

static 키워드

  • 1) 사용:

    • 클래스: 중첩 클래스에서만 가능
    • 변수: static 변수 (클래스 변수)
      • int n; 인스턴스 변수
      • static int n2; static 변수
    • 메서드: static 메서드
      • public void a() { } 인스턴스 메서드
      • public static void b() { } static 메서드
  • 2) 특징:

    • 프로그램 실행할 때 메모리에 올라간다
      => 대표적인 메서드는 main 메서드이다.

    • method area에 저장된다.

    • 단 한 번 생성된다

    • 객체 생성 (new)과 관련 없다.

      • 인스턴스와 무관 (heap 무관, this 키워드 무관)
      • static 메서드는 객체를 생성하지 않고 사용(new 키워드 사용 불가)
      • 객체 생성 후에 메모리에 올라가는 인스턴스 변수 사용 불가

      https://jooona.tistory.com/m/164

  • static 메서드에서 new 키워드를 사용할 수 없는 이유

    • static 메서드는 객체 생성과 무관하게 클래스의 메모리에 이미 적재된 상태에서 실행되는 메서드
    • 객체 생성을 위해 필요한 생성자를 호출할 수 없음.
  • static 메서드에서 this 키워드를 사용할 수 없는 이유

    • this는 인스턴스를 가리키는 참조 변수

    • 따라서 인스턴스를 생성하지 않는 static 메서드 내부에서는 this 키워드를 사용할 수 없습니다.

    • 따라서 static 메서드에서는 this를 사용하여 인스턴스의 메서드나 변수에 접근할 수 없습니다.

package p01;

public class Cat {
	
	
	int n; // 인스턴스 변수, new (객체 생성)시 heap 메모리에 생성, new 할 때마다 매번 생성
	static int n2; // static 변수(클래스 변수),  프로그램 실행 시 method area에 생성, 단 한번 생성 
	
	// 인스턴스 메서드, new(객체 생성)할 때 heap 메모리에 생성 
	public void a() {
		System.out.println("a 메서드");
	}
	
	// static 메서드, 프로그램 실행 시 생성 
	// 주의할 점은 인스턴스 변수, this 사용 불가 ==> 이유는 아직 생성 안됨 
	public static void b() {
		//System.out.println(n);//n은 인스턴스 변수이므로, 객체 생성 후 heap에 메모리 할당 하고나서 사용가능하다 
		System.out.println(n2);//n2은 static 변수이므로, 바로 사용가능하다 
		System.out.println("b 메서드");
		// System.out.println(this); //인스턴스를 생성하지 않는 static 메서드 내부에서는 this 키워드를 사용할 수 없다. 
	}

}


// JVM 메모리 할당 시점이 static 이 먼저임 (static area)에 먼저 할당 되고, 인스턴스 변수가 new 키워드로 객체 생성 하여 heap 내 할당되는 건 이후 단계 
// 즉, 인스턴스 변수는 시점이 static 메서드가 static area에 할당된 이후이므로, 
// static 메서드는 아직 할당되지 않은 인스턴스 변수 및 인스턴스를 가리키는 참조값인 this에 접근할 수 없음 
package p01;

public class TestMain {

	public static void main(String[] args) {
		
		
		// static 메서드는 객체 생성 없이 바로 호출 가능 
		// static 메서드는 여러 인스턴스에서 공유 가능 
		// static 메서드는 인스턴스에 속하지 않고 클래스에 속하며, 
		// 클래스의 모든 인스턴스에서 공유될 수 있습니다. 
		// 이는 static 메서드가 객체 생성과 무관하게 클래스의 로딩 시점에 이미 메모리에 적재되기 때문입니다.
		System.out.println(Cat.n2);
		Cat.b(); 

		
		
		// 인스턴스 메서드는 반드시 new 키워드로 객체 생성 후 호출 가능 
		Cat c = new Cat(); 
		System.out.println(c.n);
		c.a(); 

		
		// 인스턴스 메서드는 반드시 new 키워드로 객체 생성 후 호출 가능 
		Cat c2 = new Cat(); 
		System.out.println(c.n);
		c2.a(); 

		
	}

}
  • JVM에서 클래스 로딩 시에는 static 블록이 먼저 실행되며, static 멤버 변수들은 이 때 클래스 영역(static area)에 메모리가 할당됩니다. 그리고 인스턴스 변수들은 객체 생성 시에 heap 영역에 메모리가 할당됩니다.

  • 따라서, static 메서드에서는 객체가 생성되지 않은 시점에서 호출될 수 있기 때문에 인스턴스 변수나 this 참조를 사용할 수 없습니다.

  • 이에 반해 인스턴스 메서드는 객체가 생성되고 나서 호출되기 때문에, 인스턴스 변수나 this 참조를 사용할 수 있습니다.

  • JVM 클래스 로딩 과정

    • static 영역: 프로그램 시작 시 JVM에 의해 static 역이 할당됩니다.
    • main 스레드: JVM은 main 스레드를 생성하고, 스택 역을 할당합니다.
    • 객체 생성: new 연산자를 사용하여 객체를 생성할 때, 영역에 객체가 할당됩니다.
    • 메서드 호출: 메서드가 호출될 때, 해당 메서드에서 사용하는 지역 변수와 매개변수가 스택에 할당됩니다.
  • 이러한 순서로 메모리가 할당되며, 할당된 메모리는 사용이 끝나면 Garbage Collector에 의해 자동으로 해제됩니다. (더 이상 메모리 주소를 참조할 수 없음)

+) 메모리 구조

  • Java 내부에서는 Example ex = new Example(10);가 어떤 형태로 생성이 되냐하면 아래의 그림과 같이 생성이 됩니다.


static 추가

  • static 블럭 <-> instance 블럭
  • static { 실행문 }
  • 프로그램 실행 시 실행문이 자동 실행
  • Java에서 static 블럭은 클래스가 로드될 때 (즉, 인스턴스를 생성하기 전에) 실행되는 코드 블럭
  • static 블럭은 클래스 변수나 클래스 메서드의 초기화를 수행하는 데 사용
  • static import
    • import static 패키지명.클래스명.변수
    • import static 패키지명.클래스명.메서드
    • 연산을 위해서는 "10"을 특정 메서드(Integer.parseInt)를 통해 정수값으로 바꿔줘야함
package p04;
import static java.lang.Math.PI;
public class TestMain {

	public static void main(String[] args) {
		
		// 1. "10" ---> 10 
		int num = Integer.parseInt("10"); 
		System.out.println(num+1);

		// 2. "10.3" --> 10.3 
		float f = Float.parseFloat("10.3"); 
		System.out.println(f);
		
		// 3. pi값 
		double pi = Math.PI;
		System.out.println(PI);
	}

}
package p04;
// 가독성 문제로 일반 java SE 환경에서는 잘 사용 안됨. 안드로이드에서 주로 사용 됨. 

import static java.lang.Float.parseFloat;
import static java.lang.Integer.parseInt;
import static java.lang.Math.PI;

public class TestMain2 {

	public static void main(String[] args) {
		
		// 1. "10" ---> 10 
		int num = Integer.parseInt("10"); 
		System.out.println(num+1);

		// 2. "10.3" --> 10.3 
		float f = Float.parseFloat("10.3"); 
		System.out.println(f);
		
		// 3. pi값 
		double pi = Math.PI;
		System.out.println(PI);
	}

}
 

final 키워드

  • 1) 사용
    • 클래스 : public final class 클래스명 { }
      -> 상속 불가
    • 변수: final int NUM = 10;
      -> 값 변경 불가 (상수) : 대문자로 기재 필
    • 메서드: public final void a() { } ;
    • final 클래스:
      • final로 선언된 클래스는 상속할 수 없습니다.
      • 따라서 final 클래스는 하위 클래스를 생성할 수 없습니다.

final 변수

  • 변수 앞에 final 키워드가 사용되면 변경 불가능한 변수, 즉 상수로써 이용된다.

final 메서드

  • 메소드에 final 키워드를 적용하면 오버라이딩, 즉 재정의가 불가능한 메소드가 된다.
  • 아래 코드와 같이 SubMethod 클래스로 부모 클래스에 상속 받아 메소드를 오버라이딩하려고 하면 빨간 줄이 그인다.

final 클래스

  • 클래스에 final 키워드를 적용하면 그 클래스는 상속 불가한 클래스가 된다.
  • 아래 코드를 보면 FinalClass에 final을 적용한 결과 상속 받으려는 서브 클래스에 오류 표시가 나타난다.

0개의 댓글