본문 바로가기
Programming Language/Java

[국비] Java 내용정리 Day11

by tpleehan 2021. 11. 20.

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

  1. setter는 숨겨진 변수에 값을 저장하기 위한 메서드
  2. 메서드 내부에 데이터 유효성 검증 로직을 작성하여 적절한 데이터만 멤버변수에 저장시키고 접근제한자는 public으로 설정하여 외부에서 누구나 사용할 수 있게 한다.
  3. 메서드 이름은 일반적으로 set + 멤버변수이름 으로 지정한다.

getter method

  1. getter는 숨겨진 변수의 값을 참조할 때 사용하는 메서드
  2. 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

댓글