Static Member, 상속
for문같은 반복문 안에서 메소드를 호출하면 호출 될때마다 힙 메모리에 해당 메소드가 호출되어 메모리를 더 많이 쓰게된다.
계속 바뀌는 값이면 어쩔 수 없지만 바뀌지 않는 고정된 값이라면 반복문에 들어가기 전 변수에 해당 값을 할당한 뒤 반복문을 돌려주는게 더 효율적이다.
Instance member
stack과 heap 영역에 할당된다.
인스턴스 멤버란 객체를 생성한 후 사용할 수 있는 필드와 메소드를 말한다. 클래스 멤버는 객체에 소속된 멤버이기 때문에 객체 없이는 사용할 수 없다. 객체가 가지고 있는 고유의 값이라고 생각하면 될 것 같다.
Static member
method 영역에 할당된다.
static(정적) 멤버란 클래스의 고정된 멤버로서 객체를 생성하지 않고 사용할 수 있는 필드와 메소드를 말한다. 이들을 각각 정적필드, 정적 메소드라고 부른다.
객체에 할당되지 않은, 클래스에 할당되어 해당 클래스로 생성된 모든 객체에서 공유된다.
따라서 해당 클래스를 통해 접근이 가능하고 모든 객체에서 해당 member값에 접근할 수 있다.
static member의 접근법
인스턴스 변수와 스테틱 변수는 접근 방법이 다르다. 인스턴스 변수는 객체참조 변수를 통해서 사용되지만 (obj.num) staticNum 변수는 static변수 즉 객체의 소유가 아니라 클래스에 정의된 공유변수 이므로 어떤 객체의 소유도 아니다.
따라서 클래스명.정적변수 의 형식으로 엑세스 하는것이 권장된다. (StaticTest.staticNum)
API에서 제공되는 static 변수도 동일한 방법으로 접근해서 사용한다. (Math.PI)
static 메소드의 특징과 static 블럭
객체가 없어도 실행된다는 특징 때문에 정적 메소드를 선언할 때는 이들 내부에 인스턴스 필드나 인스턴스 메소드를 사용할 수 없다. 또한 객체 자신의 참조인 this 키워드도 사용이 불가능하다.
package oop.basic;
// static 메소드의 특징과 static 블럭
public class StaticMethodDemo {
static int staticNum;
// static 블럭 - 클래스로더에 의해서 클래스에 대한 정보가 method area에 올라갈때 한 번 실행
static {
staticNum = 100;
System.out.println("static블럭 - 클래스가 로딩될때 한 번 실행하는 코드를 정의할 목적");
System.out.println("static블럭 - 자원에 대한 정보를 한 번 인식시키거나 엑세스할때");
System.out.println("static블럭 - 클래스가 로딩될때 한 번만 실행되므로 static 변수를 초기화 할 목적");
}
public StaticMethodDemo() {
System.out.println("StaticMethodDemo의 기본 생성자");
}
// static method와 non-static method의 차이점과 사용방법
// static method 는 static member의 값을 조작하거나 유틸리티처럼 메소드를 편하게 사용하기 위한 목적
// 자원을 엑세스 하거나 모든 객체에서 공통으로 사용하는 기능을 표현하는 경우 사용
public static void test() { // 정적메소드
// 1. static method 에서 static method 호출
// => 일반적인 방법으로 접근
// 자신의 클래스 내부에서 선언된 메소드는 메소드 명만 입력해서 호출할 수 있다.
show();
System.out.println("test");
}
public void display() {
// 2. non - static method 에서 non - static method 호출
// => 일반적인 방법으로 접근
change();
System.out.println("display");
}
public void change() { // 인스턴스 메소드
// 3. non - static method 에서 static method 호출
// => 일반적인 방법으로 접근
show();
System.out.println("change");
}
public static void show() { // 정적메소드
// 4. static method 에서 non - static method 호출
// show가 메모리에 있는 상태에 바로 examtest를 확인할 수 없으므로 에러 발생
// 같은 클래스에 정의된 메소드라고 하더라고
// static 메소드 안에서 non - static 메소드를 호출하는 경우
// 객체생성 후 참조변수를 통해서 호출해야 한다.
// examtest(); => error
StaticMethodDemo obj = new StaticMethodDemo();
obj.examtest();
System.out.println("show");
}
public void examtest() { // 인스턴스 메소드
System.out.println("examtest");
}
}
package oop.basic;
// StaticMethodDemo를 테스트할 수 있는 클레스
public class StaticMethodDemoTest {
public static void main(String[] args) {
StaticMethodDemo obj = new StaticMethodDemo();
System.out.println(StaticMethodDemo.staticNum);
System.out.println("====================");
// static 블럭은 한번만 실행된다.
StaticMethodDemo obj2 = new StaticMethodDemo();
System.out.println("====================");
// static멤버는 클래스명.메소드명()
StaticMethodDemo.test();
obj2.display();
System.out.println("====================");
// Integer 클래스에 정의된 parseInt메소드는 static 메소드이므로 클래스 명으로 엑세스
// 숫자형식의 문자열을 int 타입으로 변환하는 메소드
int num = Integer.parseInt("100");
System.out.println(num + 200);
}
}

Singleton
생성자로 객체를 생성해주고 생성된 하나의 인스턴스만을 리턴해주는 방법이다.
싱글톤(Singleton)은 디자인 패턴 중 하나로, 어떤 클래스가 단 하나의 인스턴스만을 가지도록 보장하는 패턴이다. 이 패턴을 사용하면 어떤 클래스의 인스턴스가 어디서든 동일하게 접근 가능하며, 이를 통해 전역적으로 접근 가능한 상태나 공유 리소스를 관리할 수 있다.
package oop.basic;
// 동시접속에 대한 처리 - 객체의 멤버변수나 메소드를 접근하는 부분의 부분 로직이나 메소드 앞에
// synchronized 처리 해줘야 한다.
public class Singleton {
private static Singleton singleton = new Singleton();
private Singleton() {
System.out.println("인스턴스를 생성했습니다.");
}
public synchronized static Singleton getInstance() {
return singleton;
}
}
상속
클래스 상속
현실에서 상속은 부모가 자식을 선택해서 물려주지만, 프로그램에서는 자식이 부모를 선택한다.
자바에서 상속은 다음과 같은 특징을 가지고 있다.
- 여러개의 부모 클래스를 상속할 수 없다. 그러무로 extends 뒤에서는 단 하나의 부모 클래스만 와야 한다.
- 부모 클래스에서 private 접근 제한을 갖는 필드와 메소드는 상속 대상에서 제외된다. 그리고 부모 클래스와 자식 클래스가 다른 패키지에 존재한다면 default 접근제한을 갖는 필드와 메소드도 상속 대상에서 제외된다.
package oop.inheritance;
/*
* [[ 상속관계에서 멤버변수가 갖는 특징 ]]
* 1. 상속관계에서 상위클래스에 선언된 멤버변수는 하위클래스에서 접근이 가능하다.
* 2. 상위클래스에서 선언된 변수와 동일한 이름의 멤버변수를 하위 클래스에서 정의하면 하위클래스 내부에서는 부모클래스의 멤버 변수보다
* 하위클래스의 멤버변수가 우선순위가 높다.
* (외부에서 사용되는 경우는 선언된 참조변수의 타입이 뭐냐에 따라 달라진다.)
* 3. 하위클래스 내부에서 상위클래스의 멤버를 접근하고 싶다면 super키워드를 이용해서 접근한다.
* this -> 자기 자신의 객체
* super -> 부모의 객체
* 4. 상위클래스의 멤버가 private으로 정의되어 있으면 하위클래스에서 접근할 수 없다.
*/
class Super{
int num = 10;
}
class Sub extends Super{
// 필드의 재정의
int num = 100;
public void display() {
System.out.println("num => " + num);
System.out.println("부모의 num => " + super.num);
}
}
public class InheritanceTest1 {
public static void main(String[] args) {
Sub obj = new Sub();
obj.display();
System.out.println("obj의 num =>" + obj.num);
}
}
package oop.inheritance;
/*
* [[ 상속관계에서 메소드가 갖는 특징 ]]
* 1. 상위클래스에서 정의된 메소드를 하위클래스에서 호출할 수 있다.
* => 하위클래스 타입의 참조변수를 통해서도 상위클래스의 메소드를 사용할 수 있다.
* 2. 상위 클래스에 정의된 메소드와 동일한 메소드를 하위클래스에 정의하면 하위클래스의 메소드가 우선으로 인식된다.
* => 상위클래스에 정의된 메소드의 시그니쳐(리턴타입, 메소드면, 매개변수갯수, 매개변수 타입)가 동일한 경우 이를
* 메소드 재정의라고 한다. 즉 메소드 오버라이딩이라 한다.
* 3. 상위클래스의 메소드를 호출하려면 super를 이용해서 호출
*
*/
class Parent{
public void display() {
System.out.println("부모의 display");
}
}
// 메소드 오버라이딩
class Child extends Parent{
public void test() {
System.out.println("자식클래스의 test");
}
public void display() {
System.out.println("자식의 display()");
super.display(); // 부모의 display
}
}
public class InheritanceTest2 {
public static void main(String[] args) {
Child obj = new Child();
obj.display();
obj.test();
}
}
package oop.inheritance;
/*
* [[ 상속관계에서 생성자가 갖는 특징 ]]
* 1. 모든 클래스의 최상위 클래스는 java.lang.Object다.
* => 자바에서는 객체가 갖는 공통의 특징을 java.lang.Object에 정의해놓고 상속하는 클래스가 없는 경우
* 컴파일러를 통해 자동으로 상속받을 수 있도록 하고있다.
* => JVM에서 실행될때 문제가 없으려면 내부에서 인식하는 공통의 타입을 갖고 있어야 하며
* java.lang.Object
* 2. 상위클래스가 먼저 메모리에 올라갈 수 있도록 모든 생성자의 첫 번째 문장에는 super()가 생략되어 있다.
* 즉, 부모클래스의 기본생성자를 호출하는 명령문이 생략
* -------------------
* super()
* |
* |____ 기본으로 부모의 기본 생성자가 호출되고 있으나 명시적으로 매개변수가 있는 부모의 생성자를 호출할 수 있다.
* 명시적으로 부모의 생성자를 호출하면 컴파일러는 super()를 생성자의 첫 문장에 추가하지 않는다.
*
*
* => 단, 생성자 호출문이 없는 경우
* 3. 부모의 매개변수가 있는 생성자를 호출하는 경우 super()를 이용한다.
* super(매개변수1, 매개변수2 ....)
* ---------------------------
* |_ 부모클래스의 매개변수있는 생성자를 호출
*
* 4. 부모클래스는 직접 생성해서 쓰지 않으므로 부모가 갖고 있는 멤버변수는 자식 객체를 통해 설정하는 것이 일반적
* 5. 생성자는 상속되지 않는다.
*
*/
class SuperA {
private String name;
private int age;
public SuperA(String name, int age) {
this.name = name;
this.age = age;
}
public SuperA() {
System.out.println("부모의 생성자");
}
}
class SubA extends SuperA{
String subdata;
public SubA(String name, int age, String subdata) {
super(name,age);
this.subdata = subdata;
System.out.println("자식의 생성자");
}
}
class SuperB {
String name;
public SuperB(String name) {
this.name = name;
}
}
class SubB extends SuperB {
public SubB(){
super("String");
}
}
public class InheritanceTest3 {
public static void main(String[] args) {
SubA obj = new SubA("name", 26,"subdata");
}
}