public class Student {
1. fileds 변수들 (객체의 속성)
2. Constructors 생성자들
3. methods 메소드들 (객체의 행위)
}
public static void main()
public
으로 되어있어야만 함!!!void
어떤 시점에 어떤 데이터가 어디에 들어가는지
총 5가지가 있다.
3 -> 2 -> 4-> 1-> 5
public class InstanceTest { //feilds - 1 int a= myCall("1번출력"); static int b = myCall("2번출력"); //constructor -2 public InstanceTest(){ } //method -3 public static int myCall(String msg){ System.out.println(msg); return 100; } public void printMsg(String msg){ int a = 100; System.out.println(msg); } }
// java Main => 실행 public class Main { public static void main(String[] args) { InstanceTest test; //지역변수 선언 System.out.println("3번"); int k = InstanceTest.myCall("4번"); test = new InstanceTest(); test.printMsg("5번"); } }
main()을 사용하기 직전에 특수한 처리(library loading)을 사용하기 위해 사용
메인메서드가 실행되기 직전에 프로그램에서 필요한 라이브러리같은것들을 로딩할 필요가 있을때 사용한다
public class MyClass {
//필드
int aaa;
static int bbb = staticCall();
//default 생성자는 꼭 써주기
public MyClass(){
}
//static block
//메인메서드가 실행되기 직전에 프로그램에서 필요한 라이브러리같은것들을 로딩할 필요가 있을때 사용한다
static{
System.out.println("static block!");
}
//메서드
static int staticCall(){
System.out.println("staticCall 호출되었어요!");
return 100;
}
public static void main(String[] args) {
System.out.println("main 호출");
}
}
1. staticCall 호출되었어요!
2. static block!
3. main 호출
- 자바에서는 패키지를 이용해서 관련 클래스들을 그룹화 한다
- 패키지를 사용하면 외부로부터 제공 받는 여러 라이브러리, 프레임워크를 구분해서 사용할 수 있도록 하는게 패키지이다
- 패키지를 사용하는 가장 중요한 이유는 클래스 이름에 대한 유일성을 보장 할 수 있다.
내가 클래스를 만들어서 사용하는것도 중요하지만 외부의 클래스를 잘 사용하는것도 중요!
- 중복되는 코드
class Student { String name; //이름 (중복) String mobile; //전화번호 (중복) String dept; //학과 } class Teacher { String name; //이름 (중복) String mobile; //전화번호 (중복) String subject; //과목 } class Staff { String name; //이름 (중복) String mobile; //전화번호 (중복) String salary; //월급 }
- extends 를 사용하여 상속을 구현한다
- 자바는 단일상속만 지원한다
- extends 뒤에 하나만 온다는 뜻!
- 왜 단일상속만 허용할까?
- 2개이상이되면 어디서 상속을 받는지 모호하게된다.
그래서 다중상속을 하지 않는다
- 대신 상속의 상속을 받도록은 가능 (상속 계층구조) → 동시에 2개이상- 상속은 항상 옳을까?
- 객체지향의 축이 되는게 상속임으로 좋다.
- 그러나 상속관계를 갖게된다면 상위클래스와 하위클래스가 강하게 결합하게 된다
//상위클래스 class Person { String name; //이름 String mobile; //전화번호 } //person을 확장시켜서 독립적으로 사용한다 class Student extends Person{ String dept; //학과 } class Teacher extends Person{ String subject; //과목 } class Staff extends Person{ String salary; //월급 }
- Person의 기능하나를 더 추가하고 싶어! 그러면 Person을 수정해야함. 필요할때마다 Person을 건들이게 되면 불필요한 기능이 추가될 수 있다.
- 기존의 기능을 그대로 유지하면서 새로운 기능을 추가하는 방법.
이것이 상속이다
java.lang.Object
- Object 클래스가 패키지화 되어서 묶여 있다
import java.lang.*; //저렇게 안쓰는 이유는 lang*모두 들어있어서 //상위클래스 //원래는 java.lang.Object 이다 class Person extends Object { String name; //이름 String mobile; //전화번호 } class Student extends Person{ String dept; //학과 } public class Main{ public static void main(String[] args) { //객체가 만들어지는 순서 // Person p = new Person(); Student s = new Student(); } }
//상위클래스
class Person {
String name; //이름
String mobile; //전화번호
}
class Student extends Person{
String dept; //학과
}
public class Main{
public static void main(String[] args) {
//객체가 만들어지는 순서
// Person p = new Person();
Student s = new Student();
}
}
- 인스턴스가 만들어 지려면 생성자가 반드시 호출되어야 한다
- 상위에서부터 항위에 생성자가 계속 호출되고 난 뒤 객체가 생성된다
- 상위클래스의 생성자가 먼저 호출된다
//상위클래스
class Person extends Object {
public Person(){ //default 생성자
super();
}
String name; //이름
String mobile; //전화번호
}
class Student extends Person{
public Student(){ //default 생성자
super(); //생성자를 안쓰면 최상위의 super()이 나온다
}
String dept; //학과
}
public class Main{
public static void main(String[] args) {
//객체가 만들어지는 순서
//생성자를 호출하면서 객체를 만듦
Student s = new Student();
}
}
- 만약 매개변수가 들어오는(내가만든) 생성자라면?
- 형식에 맞춰서 적용시켜야한다
class Person extends Object {
public Person(String name){ //내가만든 생성자
this.name = name;
}
String name; //이름
String mobile; //전화번호
}
class Student extends Person{
public Student(){
super("홍길동"); //명시적으로 형식을 맞춰야한다 -> 아니면 생성못함
}
String dept; //학과
}
public class Main{
public static void main(String[] args) {
//객체가 만들어지는 순서
// Person p = new Person();
//생성자를 호출하면서 객체를 만들고 -> 생성자의 연속호출이 된다
Student s = new Student();
//서브클래스는 슈퍼클래스와 같다
//Person s = new Student();
}
}
상속관계의 초기화 과정
- 상속 관계에서 자식 클래스를 인스턴스화하면 부모 클래스의 객체도 인스턴스화가 진행된다.
- 자식클래스의 객체가 인스턴스화 되기 위해서는 먼저 부모 클래스의 객체가 인스턴스화 되어야 한다
- 따라서 상속 구조에서 가장 상위의 부모 클래스부터 차례로 인스턴스화가 진행되게 된다.
하위클래스가 상위클래스를 재정의하여 사용 가능하다
this.supper
- this: 현재사용하는 객체에 대한 referrence 참조
- super : 현재 사용하는 객체에 대한 referrence 참조이지만 타입은 상위클래스의 타입이다
- super(): 상위클래스의 생성자 호출
- this(): 자신의 클래스가 가지고 있는 다른 생성자를 호출한다
//상위클래스
class Supperclass{
//static Method
static int staticCall(String msg){
System.out.println(msg);
return 100;
}
//fields
int a = staticCall("1번 입니다");
static int b = staticCall("2번 입니다");
//constructor
public Supperclass(){
staticCall("3번 입니다");
}
public Supperclass(int i){
this();//자신의 다른 생성자 호출(인자가없는)
staticCall("4번 입니다");
}
//method
public void myFunc(){
System.out.println("5번 입니다");
}
}
public class InheritanceTest extends Supperclass{
//fields
int c = staticCall("6번 입니다");
static int d = staticCall("7번 입니다");
//constructor
public InheritanceTest(){
super(100);
staticCall("8번 입니다");
super.myFunc();
}
@Override
public void myFunc() {
System.out.println("9번 입니다");
}
public static void main(String[] args) {
System.out.println("10번 입니다");
Supperclass obj = new InheritanceTest();
obj.myFunc();
}
}
2번 입니다
7번 입니다
10번 입니다
1번 입니다
3번 입니다
4번 입니다
6번 입니다
8번 입니다
5번 입니다
9번 입니다
- 슈퍼클래스 정보가 먼저 메모리에 올라간다.
- static이 호출되어 2번입니다가 출력
- Inheritacetest class도 메모리에 올라간다
- static이 호출되어 7번입니다가 출력 (클래스정보 다올라감)
- main() 실행 → 10번입니다 출력
Supperclass obj = new InheritanceTest();
객체를 생성하기위해 인자가 없는 생성자 호출하러감- public InheritanceTest(){
super(100); → 상위클래스로 호출하러감
staticCall("8번 입니다");
super.myFunc();
}- 객체공간이 생성 → 1번 호출
- 생성자 초기화 → 3번입니다
- this가 끝나서 → 4번이 호출 (상위가 다 끝남)
- 상위가 끝났음으로 이제 super(100); 실행. int c = staticCall(6번실행)
- 그다음 staticCall 8번 실행
- 내가 가지고 있는 myFuncfh 5번이 찍힘
- 마지막 생성자가 완료
상위타입으로 myFunch를 실행함 → 상위의 5번이 다시 찍힐것 같지만 객체에 대한 타입이 상위 타입이라고 해도 만약 오버라딩된 메서드가 하위에 존재한다면 메서드는 오버라딩된 메서드를 사용한다.- 이것을 동적 바인딩이라고 한다 → 9번이 찍힌다
오버로딩 VS 오버라이딩?
- 오버로딩(Overloading)
하나의 클래스에서 같은 이름을 가진 메소드가 있더라도 매개변수의 개수 또는 타입이 다르면, 같은 이름을 사용해서 메소드를 정의할 수 있다- 오버라이딩(Overriding)
상속관계에서 일어남으로 두개의 클래스에서 일어난다
부모 클래스의 메소드를 재정의하는 것이므로, 자식 클래스에서는 오버라이딩하고자 하는 메소드의 이름, 매개변수, 리턴 값이 모두 같아야 한다.
- 상속관계가 성립되어있고 자식 클래스의 인스턴스가 부모 클래스 타입의 변수로 참조되면 실제 인스턴스화 객체가 자식 객체일 경우에도 자식 클래스가 갖고 있는 인스턴스 메소드를 호출 할 수 없다
- 부모 클래스 타입의 변수로 참조하고 있는 자식 인스턴스 객체의 메소드를 호출하기 위해서는 down-casting이 이루어져야 한다. (클래스타입을 부모가 아닌 자식으로 바꾸는 것)
- 단 재정의하고 있는 메소드의 경우 up-casting(부모로 바꿔도)상황에서도 자식 클래스의 재정의 메소드가 호출된다