12일차 2023-03-23 Java
패키지: polymorphism14, constructor15,
stringclass11 (StringConstructor.java,common.utility패키지의 CommonUtil.java ), inheritance16
1. 오버로딩(Overloading)
하나의 클래스 안에서 메소드 이름은 같으나 매개변수의 개수, 타입, 매개변수 순서가 다르면, 메소드 이름이 같아도 다른 메소드이다.
1-2) VarArgs기능
매개변수에 따라 동적인 메소드를 만들 수 있게 한다.(배열로)
/*
Overloading(중복정의):
하나의 클래스안에서 같은 이름의 메소드를 여러개 정의 할 수 있다.
조건:
1)매개변수 갯수가 다르거나
2)갯수가 같다면 매개변수 타입이 다르거나
3)타입과 갯수가 같다면 매개변수 순서가 달라야한다
그러면 다른 메소드로 본다.
※단, 반환타입과는 전혀 관계가 없다.
원래는 하나의 클래스안에서 메소드를 중복
정의해서 사용할 수 없다.
단,오버로딩을 적용해 같은 이름의 메소드를 중복정의 할 수는 있다.
*/
public class Overloading {
/*
* -아래 두 메소드는 같은 메소드임(오버로딩이 아님)
* -메소드명 동일,매개변수 타입 및 갯수 및 순서가 동일하기 떄문에
* 같은 메소드로 본다 즉 오버로딩이 아니다.
* -반환 타입 하고는 전혀 상관 없다.
*/
//int noOverloading(String str,Date date) {return 0;}
//int noOverloading(String str1,Date date1) {return 0;}
//메소드 오버로딩 방법]
//1]매개변수 타입이 다른 경우-양념의 종류가 다른경우
void paramTypeDiff(int param) {}
void paramTypeDiff(float param) {}
void paramTypeDiff(double param) {}
//2] 매개변수 갯수가 다른 경우-양념을 넣는 횟수가 다른경우
void paramCountDiff() {}
void paramCountDiff(int param) {}
void paramCountDiff(int param,int param2) {}
//3]매개변수 타입이 같고 갯수도 같지만
//순서가 다른 경우-양념은 같은데 넣는 순서가 다름.
void paramOrderDiff(int args1,float args2,double args3) {}
void paramOrderDiff(float args2,int args1,double args3) {}
void paramOrderDiff(double args3,float args2,int args1) {}
/*
JDK5.0이상 부터 메소드의 기능은 동일하고
매개변수의 타입이 동일한 하나의 자료형일 경우
매개변수 갯수에 따라서 매번 오버로딩 하지않고
VarArgs라는 기능을 이용해서
하나의 메소드로 처리할 수 있다.
[매개변수 형식]
메서드명(자료형 ... 매개변수명)
이때 매개변수명는 배열명이 된다.
즉 하나의 메소드로 여러 호출 형식의 메소드를
호출할 수 있다.
*/
//VarArgs기능 미 사용시 여러개 메소드 Overloading해야한다.
//매개변수로 받은 모든 값의 합을 구하는 메소드
/*
static int getTotal(int args) {
int sum=0;
sum+=args;
return sum;
}
static int getTotal(int args1,int args2) {
int sum=0;
sum+=args1+args2;
return sum;
}
static int getTotal(int args1,int args2,int args3) {
int sum=0;
sum+=args1+args2+args3;
return sum;
}
*/
//VarArgs기능 사용
static int getTotal(int... args) {
System.out.printf("args:%s,배열크기:%s%n",args,args.length);
int sum=0;
for(int i=0; i<args.length;i++) sum+=args[i];
return sum;
}
public static void main(String[] args) {
System.out.println("총합:"+getTotal(10));
System.out.println("총합:"+getTotal(10,20));
System.out.println("총합:"+getTotal(10,20,30));
}
}
sol)
2. 생성자
생성자는 클래스를 인스턴스화할 때(객체생성) new 클래스명()할 때 이걸 생성자라고 부르며 최소 실행 (우항)
ex) Person person= new Person();
Person()이걸 생성자라고 함.
생성자는 멤버변수, 멤버 메소드를 초기화하는 데 사용한다.
여기서 this 키워드를 사용하여 멤버 변수를 초기화 시킴
ex)
class Saram{//멤버변수 초기화용 메소드로 멤버변수 초기화]
String name;
String lastJumin;
//멤버변수 초기화용 메소드]
void initalize(String name,String lastJumin) {
this.name=name;
this.lastJumin=lastJumin;
}
void print() {
System.out.println(String.format("%s는 성별이 %s입니다.",name, lastJumin.charAt(0)=='1'? "남성":"여성"));
}
}
인자 생성자]
//[인자 생성자]
public Saram2(String name) {
this.name=name;
lastJumin="1234567";
System.out.println("인자 생성자(이름)");
}
이런 식으로 만드는데 인자 생성자를 만들면 컴파일러 할 때 여기서 문제가 생김
원래 컴파일러(저장)할 때 자동으로 기본 생성자가 생성되는데 인자 생성자가 있어서
자동으로 만들어지지 않음 그래서 인자 생성자를 만들 때는 기본생성자를 같이 만들어주는 게 좋다.
(안 쓰더라도...)
ex) Constructor01.java
package constructor15;
/*
1]생성자란?
: 객체가 생성될 때(인스턴스화) 최초로 실행되는 메소드를 의미.
2]생성자 특징
- 생성자 이름은 클래스명과 동일해야 한다
- 반환타입을 가져선 안된다.
- 생성자의 접근지정자로는 주로 public속성
3]생성자의 역할
- 멤버 변수를 초기화 하는 일
- 생성자를 정의하지 않았을 경우 컴파일러는
default(기본)생성자를 제공해줌
- 인자 생성자를 하나라도 정의했다면, 그 때는 컴파일러가
default(기본)생성자를 제공 해주지 않는다.
- 생성자를 다양하게 오버로딩 함으로써 다양한 초기값을 부여할 수 있다.
*/
class Saram{//멤버변수 초기화용 메소드로 멤버변수 초기화]
String name;
String lastJumin;
//멤버변수 초기화용 메소드]
void initalize(String name,String lastJumin) {
this.name=name;
this.lastJumin=lastJumin;
}
void print() {
System.out.println(String.format("%s는 성별이 %s입니다.",name, lastJumin.charAt(0)=='1'? "남성":"여성"));
}
}
class Saram2{
String name;
String lastJumin;
//[기본 생성자]디폴트 생성자
public Saram2() {
name="미상";
lastJumin="1234567";
System.out.println("기본(디폴트) 생성자");
}
//[인자 생성자]
public Saram2(String name) {
this.name=name;
lastJumin="1234567";
System.out.println("인자 생성자(이름)");
}
public Saram2(String name, String lastJumin) {
this.name = name;
this.lastJumin = lastJumin;
System.out.println("인자 생성자(이름,주민번호)");
}
void print() {
System.out.println(String.format("%s는 성별이 %s입니다.",name, lastJumin.charAt(0)=='1'? "남성":"여성"));
}
}
public class Constructor01 {
public static void main(String[] args) {
//Saram 인스턴스화/객체화/메모리 생성]
Saram saram= new Saram();
//초기화용 메소드 미 호출시]=ㅡ
//saram.print();
saram.initalize("가길동","1234567");
saram.print();
Saram2 saram21=new Saram2();
saram21.print();
Saram2 saram22=new Saram2("나길동");
saram22.print();
Saram2 saram23=new Saram2("다길동","2345678");
saram23.print();
}
}
sol)
ex) Consturctor02에 쓰는 Person클래스 쓰기 위해
package constructor15;
public class Person {
//[멤버변수]
String name;
int age;
String addr;
//[생성자]
/*
기본(default) 생성자:매개변수(인자)가 없는 생성자
형식]
public 클래스명(){
super()
}
반환타입이 없다.
멤버변수 초기화에 주로 사용.
※사용자가 기본 생성자를 정의하지 않으면 컴파일러가 자동으로 제공해줌
*/
//private Person() {}//다른 클래스에서 인스턴스화 불가하도록 막는다.
//기본 생성자]
public Person() {
//this();//[x]Recursive 재귀호출에러
this("미상",1,"부모님 주소");//[o]
/*
name="미상";
age=1;
addr="부모님 주소";*/
System.out.println("기본 생성자");
}
/*
* 인자 생성자: 매개변수가 있는 생성자
* ※인자 생성자를 정의하면 기본(디폴트) 생성자를 더이상 제공해주지 않는다.
* -생성자 오버로딩에 해당
*
*/
public Person(String name) {
this(name,1,"부모님 주소");
/*
this.name=name;
age=1;
addr="부모님 주소";*/
System.out.println("인자 생성자:namne");
}
public Person(String name,int age) {
this(name,age,"부모님 주소");
/*
this.name=name;
this.age=age;
addr="부모님 주소";*/
System.out.println("인자 생성자:namne,age");
}
public Person(String name,int age,String addr) {
this.name=name;
this.age=age;
this.addr=addr;
System.out.println("인자 생성자:namne,age,addr");
}
//[멤버 메소드]
//멤버변수 초기화용 메소드]
void initialize(String name,int age,String addr) {
this.name=name;
this.age=age;
this.addr=addr;
}
//정보출력용 메소드]
void print() {
System.out.println(String.format("[%s님의 정보]%n나이:%s%n사는 곳:%s", name,age,addr));
}
}
ex) Constructor02
package constructor15;
public class Constructor02 {
public static void main(String[] args) {
// TODO Auto-generated method stub
//기본 생성자로 객체 생성]
Person person1=new Person();
person1.print();
person1.initialize("가길동", 20, "가산동");
person1.print();
System.out.println();
Person person2=new Person("나길동");
person2.print();
Person person3=new Person("다길동", 30);
person3.print();
Person person4=new Person("라길동", 40, "청담동");
person4.print();
}
}
sol)
3. this()
this. 은 자지자신 클래스를 의미하는데 this()는 자기 자신의 생성자를 의미
이것도 생성자 안에서 사용
근데 첫 문장에 실행돼야 되는 법칙이 있음
package constructor15;
/*
this()
-자기 자신의 생성자를 의미
-항상 생성자안에서만 사용 가능
-생성자 안에서도 맨 첫번째 문장에 와야한다.
-멤버변수 갯수만큼 인자를 가진 인자 생성자를 호출하기 위해서 주로 사용
(멤버변수보다 인자가 적은 생성자 안에서)
*/
class Point{
//[멤버변수]
private int x,y;
//[기본 생성자]
public Point() {
//this();//재귀호출됨
this(1,2);//[o]
//this.x=1;
//this.y=2;
System.out.println("기본 생성자");
//this(1,2);//[x]생성자 안에서 첫번쨰 문장 이어야 한다.
}
//[인자 생성자]
public Point(int x) {
this(x,2);
//this.x = x;
System.out.println("인자 생성자:x");
}
public Point(int x, int y) {
this.x = x;
this.y = y;
System.out.println("인자 생성자:x,y");//(1번)
}
//[멤버 메소드]
void print() {
//this(1,2);//[x]생성자에서만 호출 가능
System.out.printf("x:%s,Y:%s%n",x,y);
}
}
public class Constructor03 {
public static void main(String[] args) {
//[기본 생성자로 객체 생성]
Point point=new Point();//point()객체 생성 그리고 Point()생성자 호출->this(1,2) 인자 2개인 인자생성자로 호출(1번)가서 출력 끝 이제 다시 Point()기본생성자로 가서 "기본생성자"출력
System.out.println();
point.print();//print()출력
System.out.println();
//[인자 생성자로 객체 생성]
Point point2=new Point(10);//Point(int x)호출 ->this(x,2);호출 ->Point(int x,int y)호출 "인자생성자:x,y"출력 끝 다시 Point(int x)로 가서 "인자생성자:x"출력
System.out.println();
point2.print();//Point(int x)에서 this(x,2)로 가고 Point(int x, int y)에서 x와 y를 10,2로 멤버변수를 초기화 시킴
System.out.println();
Point point3=new Point(10,20);//Point(int x,int y)호출 초기화 "인자 생성자:x,y"출력
System.out.println();
point3.print();//print()출력
}
}
sol)

4. String생성자
String클래스의 생성자는 new String(chArr); or newString(chArr,4,2) 이렇게 표현됨
여기서 4,2는 이건 4 인덱스에서 2개를 출력하는 걸 뜻함
String 생성자로 byte [] 형 배열을 문자로 변환하는 건 new String() 이렇게 변환가능하고
문자열을 byte [] 형 배열로 변환하는 건 String클래스의 getByte()를 사용하여 변환한다.
char [] 형 배열을 문자열로 반환하는 건 valueOf(char [])로 변환이 가능
그리고 코드에서 new String (chArr,4,2) 이렇게 있는데 이건 4 인덱스부터 2개 출력하는 걸 뜻함
문자열을 char [] 형 배열로 바꾸는 건 String클래스의 toCharArray()로 변경.
package stringclass11;
import java.util.Scanner;
import common.utility.CommonUtil;
public class StringConstructor {
public static void main(String[] args) {
//※String과 StringBuffer사이는 서로 생성자로 변환
//[String클래스의 생성자]
//1]byte형 배열을 문자열로 변환
//String(byte[] bytes) 생성자 이용
//String(byte[] bytes,int 시작인덱스,int 길이)
byte[] bArr= {65,66,67,68,69,48};
String byteToString = new String(bArr);
System.out.println("byte[]를 String으로 변환:"+byteToString);
byteToString = new String(bArr,2,2);
System.out.println("byte[]를 String으로 변환:"+byteToString);
//1-1]문자열을 byte형 배열로:String 클래스의 getBytes()
// bArr=byteToString.getBytes();
for(int i=0;i < bArr.length;i++)
System.out.println(String.format("bArr[%d]:%c",i,bArr[i]));
//2]char형 배열을 문자열로 변환
// 생성자 혹은 static String valueOf(char[])이용
//String(char[] value)
//String(char[] value, int offset, int count)
char[] chArr= {'H','I','!',' ','안','녕'};
String charToString = new String(chArr);
System.out.println("char[]를 String으로 변환:"+charToString);
charToString = new String(chArr,4,2);
System.out.println("char[]를 String으로 변환:"+charToString);
//2-1]문자열을 char형 배열로:String클래스의 toCharArray()
chArr=charToString.toCharArray();
for(int i=0;i < chArr.length;i++)
System.out.println(String.format("chArr[%d]:%c",i,chArr[i]));
//3]아스키나 유니코드값이 저장된 int형 배열을 문자열로 변환
int[] codePoints = {50,51,65,66,44032,94};
String intToString = new String(codePoints, 0,codePoints.length);//String 클래스의 생성자 중에서 인자로 (int[] codePoints, int offset, int count)
System.out.println("int[]를 String으로 변환:"+intToString);
//문)문자열을 int형배열로 변환하여라
String str="ABC123가각";
int[] intArray=CommonUtil.convertStringToIntArray(str);
for(int i=0;i < intArray.length;i++)
System.out.println(String.format("intArray[%d]:%c",i,intArray[i]));
/*
문]Scanner클래스로 문자열를 입력받아
(nextLine()사용) char형 배열로 변환해서
출력하고
또한 입력받은 문자열을 숫자(Integer.parseInt()사용)로 변환해서 2를 곱한
값을 출력 해라.단 입력받은 문자열이 숫자 형식이 아니면
숫자 형식일때까지 계속 입력받아서
위의 결과를 출력해라.
*/
Scanner sc = new Scanner(System.in);
while(true) {
System.out.println("숫자형태의 문자열을 입력하세요?");
String value = sc.nextLine();
chArr=value.toCharArray();
for(int i=0;i < chArr.length;i++)
System.out.println(String.format("chArr[%d]:%c",i,chArr[i]));
//if(!CommonUtil.isNumber(value)) {
if(!value.matches("\\d+")) {//\\d는 [0-9]와 같은 표현식이며 0~9까지의 숫자 중 하나를 나타냄 +는 앞[0-9]의 패턴을 하나 이상을 받아야된다(첫입력이 숫자이여야 한다)
System.out.println("숫자 형식이 아닙니다");//정규표현식으로 표현(한개이상)!있으니 숫자가 아니면 아래 "숫자 형식이 아닙니다"출력
continue;//while문 첫번째 숫자형태의 문자열을 입력하세요? 입력받기로 돌아감
}
System.out.println("2를 곱한 값:"+Integer.parseInt(value)*2);
break;
}
}/////////////main
}////////////////class
sol)
CommonUtil.convertStringTointArray(str);을 쓰기 위해 코드
package common.utility;
public class CommonUtil {
//문자열을 int[]배열로 변환
public static int[] convertStringToIntArray(String str) {
int[] intArray = new int[str.length()];
for (int i = 0; i < str.length(); i++) {
intArray[i] = (int) str.charAt(i); // 각 문자의 유니코드 값을 정수형 배열에 저장
}
return intArray; // 변환된 정수형 배열 반환
}
}
5. singleTon
인스턴스객체를 new 하면서 한 개씩 메모리가 생성되는데 이걸 낭비방지를 위해
만약 객체 한 개만으로도 만들 상황이 된다면, 싱글톤 패턴을 사용하여
메모리를 최소한으로 할당하기 위함.
또한, 객체 정적 객체(인스턴스) 하나만으로 시스템을 만들기 위함(이 객체는 static영역에 올라간다)
생성할 때 private static이 붙음=> private으로 invisible 하기 위함
package constructor15;
/*
싱글톤 디자인: 클래스를 설계하는
디자인 패턴의 하나로
하나의 인스턴스 즉 하나의 메모리를
생성해
이를 공유하고자 할때 사용하는 패턴 즉 하나의 메모리를 서로 공유해서
사용함으로 값 변경시 문제가 발생할 수 있는
경우는 읽기 전용으로 하자.
예]java.util패키지의 Calendar클래스
방법]
1.생성자의 접근 지정자를 private으로 한다
2.정적 메소드로 해당 클래스의 객체를 반환하도록 정의한다.
*/
//싱글톤으로 미 설계시]
class NoSingleTone {
// [멤버변수]
int noShareVar;
// [멤버 메소드]
void print() {
System.out.println("noSharVar:" + noShareVar);
}
}
//싱글톤으로 설계시]
class SingleTone{
//[멤버변수]
int shareVar;
private static SingleTone single=new SingleTone();
/*
private static SingleTone single와 같다
public SingleTone() {
single=new SingleTone();
}*/
//[생성자]
//1.접근지정자를 private 으로 지정. 접근을 막음
private SingleTone() {}
//[멤버 매소드]
//2.정적 메소드로 해당 클래스의 객체를 반환하도록 정의한다.
//getInstance 메소드를 통해 한번만 생성된 객체를 가져온다.
public static SingleTone getInstance() {
return single;
}
void print() {
System.out.println("shareVar:"+shareVar);
}
}
public class SingleTonDesign {
public static void main(String[] args) {
// 싱글톤으로 미 설계시]
// new 할때마다 메모리가 생긴다
NoSingleTone no1 = new NoSingleTone();
no1.noShareVar = 100;
no1.print();
NoSingleTone no2 = new NoSingleTone();
no2.noShareVar = 200;
no2.print();
System.out.println(String.format("no1:%s,no2:%s,no1의 noShareVar:%s,no2의 noShareVar:%s%n ", no1, no2,
no1.noShareVar, no2.noShareVar));
//싱글톤으로 설계시]
//SingleTone st1=new SingleTone();//[x]인스턴스화 불가
SingleTone st1= SingleTone.getInstance();
st1.shareVar=100;
st1.print();
SingleTone st2= SingleTone.getInstance();
st2.shareVar=200;
st2.print();
System.out.println(String.format("st1:%s,st2:%s,st1의 ShareVar:%s,st2의 ShareVar:%s%n ", st1, st2,
st1.shareVar, st2.shareVar));
}
}
sol)
6. 상속(super)
단일 상속만 가능 클래스 하나만 상속.(나중에 implement를 하지만... 일단)
자식 is a 부모 가 성립
선생은 사람이다.
(반대로 사람은 선생이다? 모든 사람이 선생인가? 반대는 안됨)
자식클래스 extends 부모 클래스로 상속을 받음
원래 Object를 상속을 받고 있는데 생략하고 쓰고 있었고 super();도 생략 가능
ex) Person과 Person을 상속받는 코드 2개
Person.java
package inheritance16;
/*
클래스 상속:
-단일 상속만 지원(클래스 하나만 상속받을 수 있다)
-IS A 관계 성립해야 한다.
자식 IS A 부모
-extends 키워드 사용
-private접근 지정자가 붙은 부모의 멤버는 상속은 받으나 접근 불가.
-형식]
접근지정자 [지정자] class 자식클래스명 extends 부모클래스명{
}
*/
public class Person extends Object{//모든 클래스는 특정 클래스를 상속받지 않으면 Object를 자동으로 상속받는다
//[멤버 변수]
String name;
int age;
String addr;
//[기본 생성자 생성]
public Person() {
super();//Object의 기본 생성자:public Object(){}
System.out.println("Person의 기본 생성자");
}
//[멤버 메소드]
String getPerson() {
return String.format("이름:%s,나이:%s,주소:%s",name,age,addr);
}
void printPerson() {
System.out.println(getPerson());
}
}
Student.java
package inheritance16;
//[Student is Person성립]
public class Student extends Person{
//[멤버변수]
//이름과 나이의 주소는 재사용]
String stNumber;//학번,Student클래스에서 새롭게(확장)한 멤버변수
//기본 생성자]
public Student() {
//super();//컴파일때 자동생성// Person의 기본 생성자.생략해도 자동으로 호출된다.
System.out.println("Student의 기본 생성자");
}
//인자 생성자]
public Student(String name,int age,String addr,String stNumber) {
//super();
this.name=name;
this.age=age;
this.addr=addr;
this.stNumber = stNumber;
System.out.println("Student의 인자 생성자");
}
//[멤버 메소드]
void study() {
System.out.println(String.format("나이가 %s인 %s가 공부하다", age,name));
}
String getStudent() {
return String.format("%s,학번:%s", getPerson(),stNumber);
}
void printStudent() {
System.out.println(getStudent());
}
}
Teacher.java
package inheritance16;
//[Teacher is a Person성립]
public class Teacher extends Person {
//[멤버 변수]
//이름과 나이와 주소는 재사용]
String subject;//과목, Teacher클래스에서 새롭게(확장)한 멤버변수
//인자 생성자]
public Teacher(String name,int age,String addr,String stNumber) {
//super();
this.name=name;
this.age=age;
this.addr=addr;
this.subject = stNumber;
System.out.println("Teacher의 인자 생성자");
}
//[멤버 메소드]
//Person에서 정의한 메소드는 재사용
void teach() {//Teacher클래스에서 새롭게 추가한(확장)한 메소드
System.out.printf(String.format("%s샘이 %s과목을 가르치다",name,subject));
}
String getTeacher() {
return String.format("%s,과목:%s",getPerson(), subject);
}
void printTeacher() {
System.out.println(getTeacher());
}
}
위 코드를 실행 PersonAPP.java
package inheritance16;
public class PersonApp {
/*
* 자식의 생성자 호출시:
* 부모 기본 생성자->자식생성자
*/
public static void main(String[] args) {
System.out.println("[기본 생성자로 객체 생성:Student]");
Student student1=new Student();
student1.printStudent();
student1.name="가길동";
student1.age=20;
student1.addr="가산동";
student1.stNumber="2023학번";
System.out.println(student1.getStudent());
System.out.println("[인자 생성자로 객체 생성:Student]");
Student student2=new Student("나길동",20,"청담동","2023학번");
student2.printStudent();
student2.study();
/*
* 인자 생성자를 정의해서 더이상 기본 생성자를
* 제공해주지 않음으로...
* 기본 생성자로 객체 생성하려면
* 기본생성자를 직접 정의해주어야 한다.
* */
//Teacher teacher=new Teacher();//[x]
Teacher teacher=new Teacher("나교사", 40, "인천", "자바");
teacher.printTeacher();
teacher.teach();
}
}
sol)
※중요 Teacher클래스에 기본생성자가 없고 인자생성자만 만들었는데
PersonApp에서 Teacher teacher=new Teacher();하는 순간 빨간 줄이 생긴다
이유는 인자 생성자를 만들어서 기본생성자는 컴파일러에서 자동으로 만들어주지 않아서
이를 해결하기 위해 PersonApp에서 인자 3개를 넣어서 객체(인스턴스화)하던가
Teacher teacher=new Teacher("나교사", 40, "인천", "자바");
아니면 Teacher에서 기본 생성자를 만들면 해결.
자식클래스는 부모클래스를 상속받으면서 추가로 멤버변수를 사용할 수 있다
물론 부모클래스를 재활용한 오버라이딩 가능
6-2) super()
this()가 자기 자신클래스(자신의 생성자)를 뜻한다면, super()(상속)은 부모클래스의 생성자를 말한다
this와 비슷하다
super를 언제 써야 하는가?
일단 this키워드만 사용한 코드이다
Animal.java
package inheritance16;
/*
super키워드:
-인스턴스화된 부모 클래스를 지칭한다.
-즉 부모 클래스의 멤버(인스턴스형 멤버)에 접근할때 사용
-※자식클래스와 부모클래스의 멤버
(메소드,변수)
명이 동일할때 구분해주기 위한 키워드
-정적 메소드안에서 사용불가(this와 같다)
super():부모의 생성자 호출
자식의 생성자 안에서만 호출 가능
this()와 super()동시호출 불가
자식의 생성자(기본,인자)에서는
super()로 명시하지 않으면 무조건
먼저 부모의 기본 생성자를 호출한다.
super()역시 항상 첫문장으로 기술
자식의 생성자에서 super()를 명시하지
않아도
자동으로 부모의 기본 생성자를 먼저
호출한다
만약 부모의 기본 생성자가 아닌 인자
생성자를 호출하려면
직접 super(인자들)를 이용해서
호출해주면 된다.
*/
/*
* =====================================================
* super() | this()
* =========================+===========================
* 부모의 생성자 호출 | 자신의 생성자 호출
* =========================+===========================
* 자식의 생성자 안에서 호출 | 자신의 생성자 안에서 호출
* =========================+===========================
* 항상 첫문장에 기술
* =====================================================
* this()와 super()는 한 생성자 안에서 동시에 호출 불가
* =====================================================
*/
public class Animal {
// [멤버변수]
String species;
int year;
String gender;
//기본 생성자]//이게 없으면 Dog클래스 만들때 (아래 인자생성자는 있고)
public Animal() {}
// 인자생성자]
public Animal(String species, int year, String gender) {
this.species = species;
this.year = year;
this.gender = gender;
}
// [멤버 메소드]
void prinhtAnimal() {
System.out.println(String.format("종:%s,나이:%s,암수:%s", species, year, gender));
}
}
Animal을 상속받은 Dog.java
package inheritance16;
public class Dog extends Animal{
//[멤버 변수]
String dogKind;//[확장한 멤버]
int year;//Dog에서 새롭게 추가(확장)한 멤버 변수
//기본 생성자]
public Dog() {
super();
}
// public Dog(String species, int year, String gender,String dogKind) {
this.species=species;
this.gender=gender;
this.year=year;
this.dogKind=dogKind;
}
//[맴버 메소드]
void bark() {
System.out.println(year+"살인 "+dogKind+"가 짖다");
}
void printDog() {
prinhtAnimal();
System.out.println("개 종류:"+dogKind);
}
static void staticMethod() {
}
}
실행하기 위한 코드 AnimalApp.java
package inheritance16;
public class AnimalApp {
public static void main(String[] args) {
Dog dog=new Dog("포유류",2,"수컷","치와와");
dog.printDog();
dog.bark();
}
}
sol)
원래라면 나이 부분에 2가 되어야 하는데 0이 나왔다 뭔가 호출할 때 다른 곳에 저장되었다고 판단된다.
보면 Dog.java에서 멤버변수선언된 게 String dogKind와 int year이 있다. 여기에 2가 저장되어서
printDog()메소드에 printAnimal();를 호출하면 Animal 에서 출력하는데 여기에도 멤버변수year이 있다.
그럼 여기서 문제이다. Dog의 멤버 변수에 year=2가 저장되어 있는데 printAnimal() 메서드가 있는 Animal클래스에서는 year이 0으로 초기화되어있는데 이걸 출력한 것이다
따라서 자식클래스가 같은 이름의 멤버변수를 선언함으로써 가져가게 된다.
AnimalApp의 dog객체의 "포유류,2,"수컷","치와와"는
Dog.java의 매개변수인 year에 2 저장 새로운 멤버변수인dogKind는 "치와와"
Animal.java의 매개변수 species에 "포유류" gender에 "수컷"이 저장된다
Animal의 year은 멤버변수니 0으로 첨에 생성때 초기화 되어있음.
이걸 변경하기 위해 코드의 변경된 부분 체크.
year을 super.year=year;로 (상속)부모클래스의 멤버변수에 저장함.
Animal.java
package inheritance16;
public class Animal {
// [멤버변수]
String species;
int year;
String gender;
//기본 생성자]//이게 없으면 Dog클래스 만들때 (아래 인자생성자는 있고)
public Animal() {}
// 인자생성자]
public Animal(String species, int year, String gender) {
this.species = species;
this.year = year;
this.gender = gender;
}
// [멤버 메소드]
void prinhtAnimal() {
System.out.println(String.format("종:%s,나이:%s,암수:%s", species, year, gender));
}
}
Dog.java
package inheritance16;
public class Dog extends Animal{
//[멤버 변수]
String dogKind;//[확장한 멤버]
int year;//Dog에서 새롭게 추가(확장)한 멤버 변수
//기본 생성자]
public Dog() {
super();
}
//
public Dog(String species, int year, String gender,String dogKind) {
/*
this.species=species;
this.gender=gender;
//this.year=year;//<=여기부분을 부모클래스인 Animal의 year로 바꿔주면된다.
super.year=year;//위 코드를 이걸로 바꿔줌
*/
super(species,year,gender);//부모클래스 인자생성자3개짜리를 불러서 초기화해줌
this.dogKind=dogKind;
//super(species,year,gender);////[x]항상 첫문장이여야 한다
}
//[맴버 메소드]
void bark() {
//super//[x]생성자 안에서만 호출 가능
//System.out.println(year+"살인 "+dogKind+"가 짖다");
System.out.println(super.year+"살인 "+dogKind+"가 짖다");
}
void printDog() {
prinhtAnimal();
System.out.println("개 종류:"+dogKind);
}
static void staticMethod() {
//super.//[x]인스턴스 메소드에서만 사용가능
}
//방법1:super키워드로 부모의 year로 접근해서 반환 이건 AnimalApp에서 dog.year을 접근하기 위함
int getAnimalYear() {
return super.year;
}
}
AnimalApp.java
package inheritance16;
public class AnimalApp {
public static void main(String[] args) {
Dog dog=new Dog("포유류",2,"수컷","치와와");
dog.printDog();
dog.bark();
//Dog의 year속성 접근:인스턴스 변수로 접근
System.out.println(dog.year);//0//dog.하면 dog의 멤버만 뜬다
//동일한 필드(멤버변수)가 존재할때 부모의 필드에 접근하기:자식의 인스턴스 변수로
System.out.println("방법1:부모의 year를 반환하는 메소드 호출:"+dog.getAnimalYear());
System.out.println("방법2:자식에서 메소드 정의하지 않고 형변환:"+((Animal)dog).year);//Animal타입으로 year을 부른다
}
}
sol)