Super
- 모든 생성자에는 super()가 기본 내장되어 있다.
- 자식 객체가 생성될 때는 부모의 객체도 생성이 되어야
- 부모의 속성과 기능이 실존하게 되고, 자식에게 물려 줄 수 있기 때문이다.
Super 설명
- 현실에서도 부모 없이는 자식이 존재하지 않듯, 객체지향 프로그램에서도 자식 객체를 생성하면 부모객체가 자동으로 생성된다.
- 하지만 모든 객체는 생성자를 호출해야만 생성되는데, 자식 객체 생성시 어디에서 부모의 생성자를 호출되었을까?
- 그에 대한 답은 자식 생성자에 있다.
- 자식 클래스에서 부모 클래스의 메서드를 오버라이딩하게 되면, 부모 클래스의 메서드는 숨겨지고 오버라이딩된 메서드가 호출된다.
- 자식 클래스에서 부모의 원본 메서드를 호출하려면 부모의 주소를 갖고 있는 super키워드를 사용한다.
package this_super;
public class Player {
String name;
int level;
int atk;
int hp;
Player() {
System.out.println("Player의 기본 생성자 호출");
// System.out.println("this의 주소값: " + this);
this.level = 1;
this.atk = 3;
this.hp = 50;
}
Player(String name) {
this(); // 같은 클래스의 다른 생성자를 부르는 문법
System.out.println("Player의 2번 생성자 호출");
// System.out.println("this의 주소값: " + this);
// level = 1;
// atk = 3;
// hp = 50;
this.name = name;
}
Player(String name, int hp) {
this(name); // 다른 생성자의 호출은 생성자 내에서 최상단에 위치해야 한다.
System.out.println("Player의 3번 생성자 호출");
// this.name = name;
this.hp = hp;
}
void characterInfo() {
System.out.println("*** 캐릭터의 정보 ***");
System.out.println("# 아이디: " + name);
System.out.println("# 레벨: " + level);
System.out.println("# 공격력: " + atk);
System.out.println("# 체력: " + hp);
}
}
package this_super;
public class Warrior extends Player {
int rage;
/*
Warrior() {
super();
}
*/
Warrior(String name) {
super(name);
this.rage = 60;
}
@Override
void characterInfo() {
super.characterInfo();
System.out.println("# 분노: " + rage);
}
}
package this_super;
public class Mage extends Player {
int mana;
Mage(String name) {
super(name);
this.mana = 100;
}
@Override
void characterInfo() {
super.characterInfo();
System.out.println("# 정신력: " + mana);
}
}
package this_super;
public class Hunter extends Player {
String pet;
Hunter(String name) {
super(name);
this.pet = "댕댕이";
}
@Override
void characterInfo() {
super.characterInfo();
System.out.println("# 펫 이름: " + pet);
}
}
package this_super;
public class MainClass {
public static void main(String[] args) {
Player p1 = new Player();
// System.out.println("p1의 주소값: " + p1);
p1.name = "플레이어1";
p1.characterInfo();
System.out.println("------------------------");
Player p2 = new Player("플레이어2");
// System.out.println("p2의 주소값: " + p2);
p2.characterInfo();
System.out.println("------------------------");
Player p3 = new Player("플레이어3", 100);
// System.out.println("p3의 주소값: " + p3);
p3.characterInfo();
Warrior w1 = new Warrior("전사1");
w1.characterInfo();
Mage m1 = new Mage("마법사1");
m1.characterInfo();
Hunter h1 = new Hunter("사냥꾼1");
h1.characterInfo();
}
}
접근제한자(Accees Modifier)
- main()이 포함되지 않은 대부분의 클래스들을 외부 클래스에서 사용할 목적으로 설계된 라이브러리 클래스이다.
- 라이브러리 클래스를 설계할 때는 외부 클래스에서 접근할 수 있는 멤버와 접근할 수 없는 멤버로 구분해서 필드, 생성자, 메서드를 설계하는 것이 좋다.
Modifier | Same Class | Same Package | Other Package & Subclass | Other Package(Universe) |
public | Yes | Yes | Yes | Yes |
protected | Yes | Yes | Yes | NO |
default | Yes | Yes | NO | NO |
private | Yes | NO | NO | NO |
- 접근제한자를 붙이지 않으면 defalut 제한으로 설정된다.
- 클래스에는 public과 defalut만 사용가능하다.
- 필드, 메서드, 생성자에는 4가지 제한자를 모두 사용할 수 있다.
클래스 접근제한자
package modi.cls.pac1;
/*
- default(package friendly)제한자는 접근 제한자를
붙이지 않은 형태이며, 같은 패키지 내에서만 접근을 허용한다.
*/
class A {
B b = new B(); // public
}
package modi.cls.pac1;
// public 제한자는 접근 제한 자체가 없는 형태 (어디에서나 사용이 가능)
public class B {
// 클래스 A의 접근제한자는 default이기 때문에
// 동일 패키지 내부의 클래스에서는 접근이 가능하다.
A a = new A();
}
package modi.cls.pac2;
import modi.cls.pac1.*;
public class C {
// A a = new A(); (x) default -> 같은 패키지 내에서만 접근을 허용
B b = new B(); // public
}
생성자 접근제한자
package modi.constructor.pac1;
public class A {
A a1 = new A(true);
A a2 = new A(50);
A a3 = new A(3.14);
//생성자 선언
public A(boolean b) {}
A(int i) {} //default
private A(double d) {}
}
package modi.constructor.pac1;
public class B {
A a1 = new A(true); // public
A a2 = new A(50); // default
// A a3 = new A(5.56); (x) private
}
package modi.constructor.pac2;
import modi.constructor.pac1.A;
public class C {
A a1 = new A(false); // public
// A a2 = new A(23); (x) default
// A a2 = new A(2.34); (x) private
}
객체 접근제한자
package modi.member.pac1;
public class A {
public int x;
int y; // default
private int z;
public A() {
x = 1;
y = 2;
z = 3;
method1();
method2();
method3();
}
public void method1() {}
void method2() {} // default
private void method3() {}
}
package modi.member.pac1;
public class B {
public B() {
A a = new A();
a.x = 1;
a.y = 2;
// a.z = 3; (x) private
a.method1();
a.method2();
// a.method3(); (x) private
}
}
package modi.member.pac2;
import modi.member.pac1.A;
public class C {
public C() {
A a = new A();
a.x = 1; // public
// a.y = 2; (x) default
// a.z = 3.14 (x) private
a.method1(); // public
// a.method2(); (x) default
// a.method3(); (x) private
}
}
Protected 접근제한자
package modi.protec.pac1;
public class A {
protected int x;
int y; //default
protected A(int i) {}
A(double d) {}
protected void method1() {}
void method2() {}
}
package modi.protec.pac1;
public class B {
A a1 = new A(30); // protected
A a2 = new A(3.14); // default
public B() {
a1.x = 1;
a1.y = 2;
a1.method1();
a1.method2();
}
}
package modi.protec.pac2;
import modi.protec.pac1.A;
public class C extends A {
// A b = new A(30); (x) protected
// A a2 = new A(5.67); (x) default
public C() {
/*
- protected 제한자는 패키지가 다른 경우
두 클래스 사이에 상속 관계가 있다면
super 키워드를 통해 참조를 허용한다.
*/
super(30);
// super(5.67); (x) default
super.x = 1;
// super.y = 2; (x) default
super.method1();
// super.method2(); (x) default
// A a = new A(30); (x)
}
}
캡슐화
- 캡슐화란 객체의 필드, 메서드를 하나로 묶고, 실제 구현 내용을 감추는 것을 말한다.
- 외부 객체는 다른 객체의 내부의 구조를 알지 못하며 객체가 의도적으로 노출한 필드와 메서드만 이용할 수 있다.
- 캡슐화를 사용하는 이유는 외부의 잘못된 사용으로 인해 객체가 손상되지 않도록 하는데 있다.
- 일반적으로 객체지향 프로그래밍에서 객체의 속성(필드)은 객체 외부에서 직접적으로 접근하는 것을 막는다.
- 그 이유는 외부에서 필드에 마음껏 접근할 경우 객체의 무결성이 깨질 수 있기 때문이다.
- 예) 고양이의 몸무게는 음수가 될 수 없는데 외부에서 필드값을 음수로 변경하게 되면 객체의 무결성이 깨진다.
- 접근제한자 private을 사용하여 필드접근을 차단하는 것까지는 좋지만 문제는 외부에서 해당 필드값을 제어할 수단이 사라진다.
- 캡슐화의 의도는 필드 완전 접근 차단보다는 객체의 무결성을 해치는 값 저장을 방지하는 것이 목적이기 때문에 메서드를 통해 제약조건을 설정하여 필디를 제어할 수 있도록 한다.
- 메서드를 사용하면 매개값을 통한 값 검증로직을 구성할 수 있기 때문에 객체지향프로그래밍에서는 메서드를 통한 필드값 제어를 선호한다.
- 값 변경을 위해 사용하는 메서드를 setter라고 부르며, 값 참조를 위해 사용하는 메서드는 getter라고 부른다.
- setter는 객체의 필드값을 변경할 때 사용하는 메서드로 외부에서 접근해서 필드값을 변경할 수 있도록 접근 제한자는 public으로 설정한다.
- 매개변수로 필드에 초기화할 값을 받고, 해당 값을 검증한 뒤 필드에 초기화한다.
- 관례상 setter의 이름은 set + 필드명(첫 글자 대문자)로 지정한다.
- getter는 객체의 필드값을 참조할 때 사용하는 메서드이다.
- 외부에서 접근하여 필드값을 참조할 수 있도록 접근 제한자는 public으로 설정한다.
- 외부에 필드값을 전달할 때 값을 형식에 맞게 바꾸어줄 수 있다.
- 관례상 getter의 이름은 get + 필드명(첫 글자 대문자)로 지정한다.
- 필드의 타입이 boolean인 경우 이름은 is + 필드명으로 지정한다.
- 외부에서 직접 변수에 접근할 수 없도록 멤버변수에 private 제한을 붙인다.
- 캡슐화는 데이터에 접근 제한을 걸어 정보(데이터)를 보호하는 것이 목적이지만 private을 설정하면 데이터 접근 자체가 불가능해진다.
- 데이터의 유효성을 검증할 수 있는 제어문이 포함된 메서드를 사용하여 데이터의 접근을 허용하도록 설계하기 위해 사용하는 메서드는 getter / setter 메서드라고 부른다.
setter method
- setter는 숨겨진 변수에 값을 저장하기 위한 메서드
- 메서드 내부에 데이터 유효성 검증 로직을 작성하여 적절한 데이터만 멤버변수에 저장시키고 접근제한자는 public으로 설정하여 외부에서 누구나 사용할 수 있게 한다.
- 메서드 이름은 일반적으로 set + 멤버변수이름 으로 지정한다.
getter method
- getter는 숨겨진 변수의 값을 참조할 때 사용하는 메서드
- setter와 마찬가지로 public 제한을 통해 외부에 메서드를 공개하고 이름은 일반적으로 get + 멤버변수 이름으로 지정한다.
캡슐화 Wrong-example
package encap.bad;
public class MyBirth {
int year;
int month;
int day;
void birthInfo() {
System.out.printf("내 생일은 %d년 %d월 %d일 입니다. \n", this.year, this.month, this.day);
}
}
package encap.bad;
public class MainClass {
public static void main(String[] args) {
MyBirth my = new MyBirth();
my.year = 22021;
my.month = 311;
my.day = -02;
my.birthInfo();
}
}
캡슐화 Best-example
package encap.good;
public class MyBirth {
private int year;
private int month;
private int day;
public void setYear(int year) {
if (year > 1900 && year < 2022 ) {
this.year = year;
} else {
System.out.println("잘못 된 연도 입력입니다.");
}
}
public void setMonth(int month) {
if (month < 1 || month > 12 ) {
System.out.println("잘못 된 월 입력입니다.");
} else {
this.month = month;
}
}
public void setDay(int day) {
if (day < 1 || day > 31) {
System.out.println("잘못 된 일 입력입니다.");
} else {
this.day = day;
}
}
public int getYear(String pw) {
if (pw.equals("abc1234")) {
return this.year;
} else {
System.out.println("비밀번호가 틀렸습니다.");
return 0;
}
}
public int getMonth() {
return this.month;
}
public int getDay() {
return this.day;
}
}
package encap.good;
public class MainClass {
public static void main(String[] args) {
MyBirth my = new MyBirth();
// my.day = 25; (x)
my.setYear(2021);
my.setMonth(11);
my.setDay(02);
System.out.printf("내 생일은 %d년 %d월 %d일 입니다.\n",
my.getYear("abc1234"), my.getMonth(), my.getDay());
}
}
Person 프로그램
- 스캐너를 이용하여 Person객체를 생성하는데 필요한 정보를 입력 받기 입력 받은 정보를 토대로 Person객체를 생성한 후 여러 개의 Person 객체를 배열에 담아둔다.
- 배열의 크기는 3개로 지정. 반복문을 이용하여 입력을 반복해서 받는다.
- 입력이 끝나면 배열 안에 있는 모든 주소값을 순회하여 각 객체의 personInfo()를 호출한다.
package obj_array;
public class Person {
private String name;
private int age;
private String gender;
public Person() {}
public Person(String name, int age, String gender) {
super();
this.name = name;
this.age = age;
this.gender = gender;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public String getGender() {
return gender;
}
public void setGender(String gender) {
this.gender = gender;
}
void personInfo() {
System.out.printf("이름: %s\n나이: %d세\n성별: %s\n",
this.name, this.age, this.gender);
}
}
package obj_array;
public class MainClass {
public static void main(String[] args) {
// Person kim = new Person("김길동", 32, "남자");
// Person lee = new Person("이영희", 25, "여자");
// Person park = new Person("박철수", 50, "남자");
//
// kim.personInfo();
// lee.personInfo();
// park.personInfo();
// int[] arr = new int[5];
// Person[] people = new Person[3];
// people[0] = new Person("김철수", 32, "남자");
Person[] people = {
new Person("김철수", 32, "남자"),
new Person("이영희", 25, "여자"),
new Person("박철수", 50, "남자")
};
// System.out.println(Arrays.toString(people));
// people[0].personInfo();
// people[1].personInfo();
// people[2].personInfo();
// for(int i = 0; i < people.length; i++) {
// people[i].personInfo();
// }
for(Person p : people) {
p.personInfo();
}
}
}
package obj_array;
import java.util.Scanner;
public class ArrayInsert {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
Person[] people = new Person[3];
for(int i = 0; i < people.length; i++) {
/*
Person p = new Person();
System.out.printf("이름을 입력하세요: ");
p.setName(sc.next());
System.out.printf("나이를 입력하세요: ");
p.setAge(sc.nextInt());
System.out.printf("성별을 입력하세요: ");
p.setGender(sc.next());
people[i] = p;
*/
System.out.printf("이름을 입력하세요: ");
String name = sc.next();
System.out.print("나이를 입력하세요: ");
int age = sc.nextInt();
System.out.print("성별을 입력하세요: ");
String gender = sc.next();
people[i] = new Person(name, age, gender);
System.out.println("*** 정보 입력 완료 ***");
} // 입력 받는 반복문 종료
System.out.println("--------------------");
for(int i = 0; i < people.length; i++) {
people[i].personInfo();
System.out.println();
}
/*
for(Person p : people) {
p.personInfo();
System.out.println();
}
*/
sc.close();
}
}
캡슐화를 이용한 Score 프로그램
- 객체
- 이름, 국어, 영어, 수학, 총점, 평균(double)을 담을 수 있는 객체를 디자인한다.
- 학생의 모든 정보를 한 눈에 확인할 수 있게 scoreInfo() 메서드를 선언한다.
- 메서드 내부에는 출력문을 이용해서 모든 정보를 출력한다.
- 캡슐화를 구현해서 작성한다. (생성자는 마음대로 한다.)
- Score 객체를 담을 수 있는 배열을 선언 배열의 크기는 100개로 지정
- Score 프로그램
- 반복문을 이용해서 사용자에게 이름, 국어, 영어, 수학 점수를 입력 받는다.
- 입력 받은 점수를 토대로 Score 객체를 생성 후 총점과 평균을 직접 구한다.
(직접 작성하거나 메서드를 이용해서 계산하는건 마음대로 한다.) - 객체 생성 후 미리 만들어 놓은 배열에 객체를 추가한다.
- 이름 입력란에 '그만' 이라고 입력하면 반복문을 종료한다.
- 반복문이 종료되면 배열 내부에 있는 객체들을 순회하면서 scoreInfo()를 모두 부른다. (반복문)
주의) 입력이 중간에 그만두어진다면, 배열의 나머지 인덱스는 모두 null로 가득 차게 된다. (null.scoreInfo() -> 에러)
package obj_array;
public class Score {
private String name;
private int kor;
private int eng;
private int math;
private int total;
private double avg;
public Score() {
}
public Score(String name, int kor, int eng, int math) {
super();
this.name = name;
this.kor = kor;
this.eng = eng;
this.math = math;
total = kor + eng + math;
avg = total / 3.0;
}
public String getName() {
return name;
}
public int getKor() {
return kor;
}
public int getEng() {
return eng;
}
public int getMath() {
return math;
}
public int getTotal() {
return total;
}
public void setTotal(int total) {
this.total = total;
}
public double getAvg() {
return avg;
}
public void setAvg(double avg) {
this.avg = avg;
}
public void scoreInfo() {
System.out.println("*** 학생의 정보 ***");
System.out.println("이름: " + this.name);
System.out.println("국어점수: " + this.kor + "점");
System.out.println("영어점수: " + this.eng + "점");
System.out.println("수학점수: " + this.math + "점");
System.out.println("총점: " + this.total + "점");
System.out.printf("평균점수: %.2f점 ", this.avg);
System.out.println();
}
}
package obj_array;
import java.util.Scanner;
public class ScoreMain {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
Score[] scores = new Score[100];
// int count = 0;
for (int i = 0; i < scores.length; i++) {
System.out.println("*** 학생 점수 입력 프로그램 ***");
System.out.println("입력을 취소하려면 \"그만\"이라고 작성해주세요.");
System.out.print("이름을 입력하세요: ");
String name = sc.next();
if (name.equals("그만")) {
System.out.println("입력을 종료합니다.");
break;
}
System.out.print("국어점수를 입력하세요: ");
int kor = sc.nextInt();
System.out.print("영어점수를 입력하세요: ");
int eng = sc.nextInt();
System.out.print("수학점수를 입력하세요: ");
int math = sc.nextInt();
scores[i] = new Score(name, kor, eng, math);
/*
Score s = new Score();
int total = kor + eng + math;
double avg = total / 3.0;
scores[i] = new Score(name, kor, eng, math, total, avg);
*/
}
System.out.println("-----------------------");
for (Score s : scores) {
if (s == null) {
break;
}
s.scoreInfo();
}
sc.close();
}
}
'Programming Language > Java' 카테고리의 다른 글
[국비] Java 내용정리 Day13 (0) | 2021.11.23 |
---|---|
[국비] Java 내용정리 Day12 (0) | 2021.11.21 |
[국비] Java 내용정리 Day10 (0) | 2021.11.10 |
[국비] Java 내용정리 Day09 (0) | 2021.11.06 |
[국비] Java 내용정리 Day08 (0) | 2021.11.05 |
댓글