오늘은 static과 상속에대해서 배웠다. 컨디션이 꽤나 안 좋은 날이었지만,,, 어려운 내용이기에 열심히 들어보았다.
static - 클래스변수
1. 메모리 static 영역에 1번만 생성된다. → 초기화 1번만 수행
모든 객체가 공유한다. (공유변수)
2. static 메소드에서는 static 변수만 사용 가능
static 메소드에서는 this를 참조할 수 없다
3. static변수나 메소드는 호출시 클래스명으로 직접 호출 할 수 있다.
객체로도 호출이 가능하다
4. static{ } - 초기화 영역
- 생성자보다도 먼저 수행한다.
StaticMain.java
package class__;
class StaticTest {
int a; //필드(클래스 꺼) -> 초기화 끝남(0값 가지고있음)
// new 생성해서 써야함. / 클래스 소속 o
static int b; //필드, 초기화 / 그냥 갖다쓰면 됨.
// 클래스 소속 x //클래스 변수
//static - 공유변수(같이 쓰자)
static { //자바가상머신이 시작하자마자 여기 먼저 처리됨.(미리 올라옴)
//(main 불리자마자 여기부터 초기화하고 new하면 생성자메소드 초기화)
System.out.println("static 초기화 영역");
b = 7;
}
public StaticTest() {
System.out.println("default 생성자");
this.a = 7; //일반변수는 생성자에서 초기화시켜줌.
}
public void calc() {
a++;
b++;
}
public void disp() {
System.out.println("a = " + this.a + "\t b = " + StaticTest.b);
//static 변수는 출신만 밝히면 됨.
}
public static void output() {
System.out.println("static method...");
//System.out.println("a = " + this.a + "\t b = " + StaticTest.b);
//static 영역에는 this x
// error - static 메소드에서는 static 변수만 사용 가능
// static 메소드에서는 this를 참조할 수 없다
}
}
//---------------
public class StaticMain {
public static void main(String[] args) { //static이므로 this가 없다.
//StaticTest st = new StaticTest();
//a, b 접근 가능? o
//System.out.println("a = " + st.a);
//System.out.println("b = " + StaticTest.b);
StaticTest aa = new StaticTest(); //클래스에 a잡힘 //static 영역에 b잡힘
aa.calc();
aa.disp(); //a = 1 b = 1
System.out.println();
StaticTest bb = new StaticTest(); //클래스에 새로운 a 잡힘 //b 새로 안잡힘.
bb.calc();
bb.disp(); //a = 1 b = 2
System.out.println();
StaticTest cc = new StaticTest(); //클래스에 또 새로운 a 잡힘 //b 새로 안잡힘.
cc.calc();
cc.disp(); //a = 1 b = 3
System.out.println();
StaticTest.output(); //클래스명.메소드 (이렇게해도 호출가능)
aa.output(); // 객체명.메소드
}
}//class StaticMain
static 초기화 영역
default 생성자
a = 8 b = 8
default 생성자
a = 8 b = 9
default 생성자
a = 8 b = 10
static method...
static method...
import static
: 간단하게 static 상수 또는 메소드를 호출할 때 사용
ImportStatic.java
package class__;
//import static java.lang.Math.random;
//import static java.lang.Math.pow;
import static java.lang.Math.*; //와일드 카드, 모든 것(all)
import static java.lang.System.out;
import static java.util.Arrays.sort;
import java.util.Arrays;
public class ImportStatic {
public static void main(String[] args) {
//System.out.println("난수 = " + Math.random());
System.out.println("난수 = " + random());
//System.out.println("2의 5승 = " + Math.pow(2, 5));
System.out.println("2의 5승 = " + pow(2, 5));
int[] ar = {25, 78, 32, 40, 55};
//Arrays.sort(ar); //return 값 없다.
sort(ar);
for(int data : ar)
System.out.print(data + " ");
//System.out.println();
out.println();
String[] ar2 = {"apple", "strawberry", "applemango", "pineapple", "tomato"};
sort(ar2);
for(String data : ar2)
System.out.print(data + " ");
}
}
난수 = 0.5264059054829953
2의 5승 = 32.0
25 32 40 55 78
apple applemango pineapple strawberry tomato
근데 이 방법은 뭐를 참조한지 잘 모르기때문에 굳이 안 쓰는게 좋다고 하셨다.
private(나만) < default(같은 패키지에서만) < protected(나, 내 자식들) < public(전부 다)
상속 (inheritance)
: is~a 관계 ~이다
: 클래스의 재 구현
자동차 ← 택시(돈 벌 수 있는 수단) 택시는 자동차이다. (택시가 자동차를 상속한다.)
1. 상속받는 클래스는 상속해주는 클래스의 생성자와
private를 제외한 모든 것을 상속받는다.
2. Super class : 상속해 주는 클래스(부모)
Sub class : 상속받는 클래스(자식)
3. 접근제한자 protected는 Sub class에서 접근이 가능하다
4. Sub class로 객체를 생성하면 Super class와 자신의 생성자를 모두 호출한다.
5. 다중상속을 할 수 없다.
[형식]
class Sub클래스명 extends Super클래스명{ }
Override 메소드
1. Super클래스와 Sub클래스에 똑같은 메소드가 존재
2. 모든 우선권은 Sub클래스가 갖는다.
3. Super, Sub 클래스의 접근제어자(Modifier)는 틀려도 되지만
Super보다 Sub클래스의 접근제어자(Modifier)가 더 커야한다.
Overload(쌍둥이) Override(부모-자식)
1. 하나의클래스 1. 상속관계
2. 메소드명이 똑같다. 2. 다 똑같아야 함.
3. 인수의 개수, 인수의 형이 틀린 경우. 3. 접근제어자(Modifier)는 틀려도되지만
반드시 자식클래스가 더 커야한다.
this 와 this()
1. this 는 자신의 클래스의 참조값을 갖고 있다.
2. this() 는 Overload된 다른 생성자를 호출 할 수 있다.
3. this()는 생성자의 첫줄에 써야 한다.
super 와 super()
1. super 는 부모클래스의 참조값을 갖고 있다.
2. super() 는 부모클래스의 생성자를 호출 할 수 있다.
3. super() 는 생성자의 첫줄에 써야 한다.
Super.java
package inheritance;
public class Super {
protected double weight, height;
public Super() {
System.out.println("Super 기본 생성자");
}
//생성자 하나도 없으면 기본생성자 생성
public Super(double weight, double height) {
System.out.println("Super 생성자");
this.weight = weight;
this.height = height;
}
public void disp() {
System.out.println("몸무게 = " + weight);
System.out.println("키 = " + height);
}
}
SubMain.java
package inheritance;
public class SubMain extends Super{//나 자신의 참조값은 this / 부모의 참조값은 super
private String name;
protected int age;
public SubMain() {
System.out.println("SubMain 기본 생성자");
}
public SubMain(String name, int age, double weight, double height) {
//3. 부모 생성자 호출 가능 (본인도 생성자일 때) -> 생성자는 생성자끼리 호출가능
super(weight, height); //첫 번째 줄에 적어야함. -> 부모한테 갔다가 돌아옴
//super 없으면 기본생성자 부름
System.out.println("SubMain 생성자");
this.name = name;
this.age = age;
//1.
//this.weight = weight;
//this.height = height;
//2.
//super.weight = weight;
//super.height = height;
}
public void output() {
System.out.println("이름 = " + name);
System.out.println("나이 = " + age);
//System.out.println("몸무게 = " + weight);
//System.out.println("키 = " + height);
disp(); //호출 super 생략
}
public static void main(String[] args) {
//생성자 2번 호출 (본인꺼랑 부모꺼 같이 메모리에 잡음)
SubMain aa = new SubMain("홍길동", 25, 85.3, 178.6);
aa.output();
System.out.println();
aa.disp(); //내꺼도 내꺼 부모꺼도 내꺼
// 먼저 this에서 찾고 없으면 super에 가서 찾음.
//몸무게 = 85.3
//키 = 178.6
System.out.println("---------------------");
//자식꺼만 잡는게 아니라 부모꺼도 같이 잡음
Super bb = new SubMain("코난", 13, 35.8, 156.7);
//bb라는 애는 Super을 가리킴.(Super만 참조함)
//bb.output() - error / output()함수 참조할 수 x
bb.disp();
//몸무게 = 85.3
//키 = 178.6
}
}
bb.output()이 안 되는 이유
- bb 변수는 Super 타입이다. 즉, bb는 Super 클래스의 인스턴스를 가리킬 수 있는 참조 변수이다.
- 그러나 실제로 bb가 가리키는 객체는 SubMain의 인스턴스다.
- bb 변수의 타입은 Super이기 때문에, Super 클래스에 정의된 메소드만 호출할 수 있다.
- SubMain 클래스의 output() 메소드는 Super 클래스에 정의되지 않았기 때문에, Super 타입의 참조 변수를 사용하여 output() 메소드를 호출하려고 하면 컴파일러는 이를 유효하지 않은 메소드 호출로 간주하고 에러를 발생시킨다.
- 런타임에 실제 객체의 타입이 SubMain이라는 것을 알고 있지만, 컴파일 타임에는 참조 변수의 타입만을 고려하기 때문에 SubMain 클래스의 메소드에 접근할 수 없다.
[요약]
- bb는 Super 타입의 참조 변수이기 때문에 Super 클래스에 정의된 메소드만 호출할 수 있다.
- SubMain 클래스에 정의된 output() 메소드는 Super 클래스에 정의되어 있지 않기 때문에 Super 타입의 참조 변수를 통해서는 접근할 수 없다.
Super 생성자
SubMain 생성자
이름 = 홍길동
나이 = 25
몸무게 = 85.3
키 = 178.6
몸무게 = 85.3
키 = 178.6
---------------------
Super 생성자
SubMain 생성자
몸무게 = 35.8
키 = 156.7
ChildMain.java
package inheritance;
public class ChildMain extends Super {
private String name;
protected int age;
public ChildMain() {
System.out.println("ChildMain 기본 생성자");
}
public ChildMain(String name, int age, double weight, double height) {
super(weight, height);
System.out.println("ChildMain 생성자");
this.name = name;
this.age = age;
}
public void disp() {
System.out.println("이름 = " + name);
System.out.println("나이 = " + age);
//disp(); //본인꺼 부르러감
super.disp();
}
밑에 코드가 좀 헷갈리는데 설명을 차근차근 해보자면
오버라이딩은 자식 클래스가 부모 클래스의 메소드를 재정하는 것을 의미한다. 이는 자식 클래스가 부모 클래스의 기본 동작을 변경하거나 확장할 수 있게 한다.
오버라이드 (Override): 자식 클래스에서 부모 클래스에 정의된 메소드를 동일한 시그니처(즉, 동일한 이름, 동일한 매개변수, 동일한 반환 타입)로 재정의하는 것을 의미한ㄷ다.
이를 통해 자식 클래스는 부모 클래스의 메소드 대신 자신이 정의한 메소드를 사용할 수 있다.
자바에서 메소드 오버라이드를 할 때 지켜야 할 규칙:
- 메소드의 이름, 반환 타입, 매개변수 목록이 부모 클래스의 메소드와 동일해야 한다.
- 접근 제어자는 부모 클래스의 메소드와 같거나 더 넓은 범위여야 한다 (예: 부모 클래스의 메소드가 protected이면, 자식 클래스의 메소드는 protected나 public이어야 한다).
- 오버라이드된 메소드는 부모 클래스의 예외 선언과 호환되어야 한.
public static void main(String[] args) {
ChildMain aa = new ChildMain("홍길동", 25, 85.3, 178.6);
aa.disp(); //우선은 내꺼에서 먼저 찾음.
System.out.println("---------------------");
//자식꺼만 잡는게 아니라 부모꺼도 같이 잡음
Super bb = new ChildMain("코난", 13, 35.8, 156.7);
//bb라는 애는 Super을 가리킴.(Super만 참조함)
bb.disp(); //모든 우선권은 자식에게 있음. ChildMain의 disp()호출
//오버라이드는 무조건 자식 먼저.
}
}
Super 생성자
ChildMain 생성자
이름 = 홍길동
나이 = 25
몸무게 = 85.3
키 = 178.6
---------------------
Super 생성자
ChildMain 생성자
이름 = 코난
나이 = 13
몸무게 = 35.8
키 = 156.7
Super bb = new ChildMain("코난", 13, 35.8, 156.7);
- bb는 Super 타입의 참조변수지만, 실제로는 ChildMain 객체를 참조한다.
- 이 때도 ChildMain의 매개변수 있는 생성자가 호출되어 초기화가 진행된다.
bb.disp();
- bb는 Super 타입이지만 실제 객체는 ChildMain이기 때문에, ChildMain 클래스의 disp() 메소드가 호출된다.
- 오버라이딩된 메소드 호출에서는 항상 실제 객체 타입의 메소드가 호출된다. 따라서 ChildMain의 disp()가 실행된다.
[요약]
- 오버라이드된 메소드는 부모 클래스 타입의 참조변수를 통해 호출해도 자식 클래스에서 재정의한 메소드가 실행된다.
- 이는 다형성의 중요한 예로, Super 타입의 변수가 실제로 ChildMain 객체를 참조할 때도, 자식 클래스에서 재정의된 메소드가 호출된다는 것을 보여준다.
ShapeMain.java
package inheritance;
import java.util.Scanner;
class ShapeTest{
protected double area;
protected Scanner scan = new Scanner(System.in);
public ShapeTest() {
System.out.println("ShapeTest 기본생성자");
}
public void calcArea() {
System.out.println("도형을 계산합니다.");
}
public void dispArea() {
System.out.println("도형을 출력합니다.");
}
}
//------------
class SamTest extends ShapeTest{
protected int base, height;
public SamTest() {
System.out.println("SamTest 기본생성자");
System.out.print("밑변 : ");
base = scan.nextInt();
System.out.print("높이 : ");
height = scan.nextInt();
}
@Override //바로 밑에있는 줄에만 먹힘.
public void calcArea() {
area = base * height / 2.;
}
@Override
public void dispArea() {
System.out.println("삼각형 넓이 = " + area);
}
}
//------------
class SaTest extends ShapeTest{
protected int width, height;
SaTest(){
System.out.println("SaTest 기본생성자");
System.out.print("가로 : ");
width = scan.nextInt();
System.out.print("세로 : ");
height = scan.nextInt();
}
@Override
public void calcArea() {
area = width * height;
}
@Override
public void dispArea() {
System.out.println("사각형 넓이 = " + area);
}
}
//------------
class SadariTest extends ShapeTest{
protected int top, bottom, height;
SadariTest(){
System.out.println("SadariTest 기본생성자");
System.out.print("윗변 : ");
top = scan.nextInt();
System.out.print("밑변 : ");
bottom = scan.nextInt();
System.out.print("높이 : ");
height = scan.nextInt();
}
@Override
public void calcArea() {
area = (top + bottom) * height / 2.;
}
@Override
public void dispArea() {
System.out.println("사다리꼴 넓이 = " + area);
}
}
//------------
public class ShapeMain {
public static void main(String[] args) {/*
//1:1관계, 결합도 100%로 묶임. SamTest()클래스를 부르려면 sam 리모콘 필요
SamTest sam = new SamTest();
sam.calcArea();
sam.dispArea();
System.out.println();
SaTest sa = new SaTest();
sa.calcArea();
sa.dispArea();
System.out.println();
SadariTest sad = new SadariTest();
sad.calcArea();
sad.dispArea();
System.out.println();*/
ShapeTest shape;
//다형성, 부모는 모든 자식클래스 참조할 수 있다.
shape = new SamTest();
shape.calcArea();
shape.dispArea();
System.out.println();
shape = new SaTest();
shape.calcArea();
shape.dispArea();
System.out.println();
shape = new SadariTest();
shape.calcArea();
shape.dispArea();
System.out.println();
}
}
ShapeTest 기본생성자
SamTest 기본생성자
밑변 : 2
높이 : 7
삼각형 넓이 = 7.0
ShapeTest 기본생성자
SaTest 기본생성자
가로 : 5
세로 : 5
사각형 넓이 = 25.0
ShapeTest 기본생성자
SadariTest 기본생성자
윗변 : 6
밑변 : 5
높이 : 4
사다리꼴 넓이 = 22.0
'JAVA' 카테고리의 다른 글
DAY 7 - HOMEWORK - 클럽 회원관리 (2024.07.11) (0) | 2024.08.12 |
---|---|
DAY 8 - 메서드 / VarArgs / StringBuffer / StringBuilder (2024.07.12) (0) | 2024.08.12 |
DAY 10 - instanceOf / 추상클래스 / final (2024.07.16) (0) | 2024.08.12 |
DAY 11 - interface / iterator (2024.07.17) (0) | 2024.08.12 |
DAY 12 - 접근제한자 / 중첩클래스 (2024.07.18) (0) | 2024.08.12 |