Java_OOP1
클래스, (게더,세터), 상속, 오버라이딩, 반복문 포스팅할 예정입니다.
문제 위주로 정리했습니다.
각 문제를 풀어보시고, 테스트해보시면 좋을 것 같습니다.
필요한 이유
여러사람이 협업을 하는 과정에서 좀더 체계적이고, 분업화된 시스템으로 개발하기 위해 필요합니다.
클래스란 ?
-> 만들고자 하는 객체 특징,동작
-> (속성,기능)
을 설계
객체(또는 인스턴스)를 생성하는 하나의 공장(=틀, 주문서)
즉, 클래스는 마트이고, 객체는 각 상품들이다. 각 상품들은 속성과 데이터를 가진다.
객체는 어떻게 만들지 ?
원하는 속성과 기능을 생각하고 구현
객체의 특징 --> 속성
객체의 동작 --> 메서드 = 함수
1000000 // 가격
2020 // 년식
red // 색상
Farm-machine is moving.
Fram-machine is digging.
Fram-machine is grinding.
class FarmMachine{
// 속성
int price; //가격
int date; //연식
String color; //색상
// 기능/동작/행동(메서드)
// 메서드는 여러가지로 구현(구성)될 수 있음.
void move(){
System.out.println("FarmMachine is moving");
}
void dig(){
System.out.println("FarmMachine is digging");
}
void grind(){
System.out.println("FarmMachine is grinding");
}
}
public class Main{
public static void main(String[] args) {
// 객체 생성
FarmMachine fm = new FarmMachine(); // new 키워드가 클래스의 주소를 반환하는 역할 해줌 (객체는 참조형타입)
System.out.println(fm);
// 생성된 객체에 속성 값 입력
fm.price = 1000000000;
fm.date = 2023;
fm.color = "red";
// 속성 값 출력
System.out.println(fm.price);
System.out.println(fm.date);
System.out.println(fm.color);
// 동작 수행하기
fm.move(); // 호출
fm.dig();
fm.grind();
}
}
String fm_price = String.format("%,d",1000000000);
System.out.println(fm_price);
System.out.println(String.format("%,d",fm.price);
3번, java.text.DecimalFormat 클래스 활용
쉼표를 찍는다는건 int형을 string으로 바꾸겠다는 것입니다.
이유 : 콤마( , )는 문자열이기 때문에 String타입에 저장해야 하기때문입니다.
int형 숫자를###,###
포맷에 맞춰 문자열로 바꿔주는 함수를 만들어놓고 필요할때마다, 사용하는 것입니다.
// 숫자-> 천단위 콤마 찍기
public String Comma(int input) {
DecimalFormat df = new DecimalFormat("###,###");
String input_str = df.format(input);
return input_str;
}
// 이때, 인자값으로 진수를 지정해서 출력
문자열을 숫자로 변환 시키는 방법 -- > Integer.parseInt()
사용
parseInt() --> Integer 클래스의 static으로 지정되어있음 --> 객체의 생성없이 바로 "클래스명.parseInt()"로 직접 호출해서 사용 가능
-> 해당 진수에 맞는 값이 됨.
Integer.parseInt("1000",
2);
--> 1000에 2진수로 지정한거임 --> 콘솔창에는 10진수 숫자를 출력하게해줌.
즉, 2번째 인자값에 진수를 입력하는거임.
System.out.println(Integer.parseInt("A",16));
System.out.println(Integer.parseInt("D",16));
System.out.println(Integer.parseInt("FF",16));
1+2=3
1 + 2 = 12 -------------------------[진수 지정] 2022
2022
1
9
516
10
15
255
-------------------------[진수 지정]
public class Main{
public static void main(String[] args) {
int a =1;
int b =2;
int c = a + b;
System.out.println("`a+b =" + c);
// 2, 문자열끼리 연산
String a1 = "1";
String b1 = "2";
String c1 = a1 + b1;
System.out.println("a1+b1=" + c);
// 문자열 끼리 연산은 바로 뒤에 붙어버림.
// 클래스 타입 확인
System.out.println(c1.getClass().getName());
// 3, 문자열 --> 숫자로 변환 후 연산
int a2 = Integer.parseInt(a1);
int b2 = Integer.parseInt(b1);
int c2 = Integer.parseInt(c1);
System.out.println(a1); // 1
System.out.println(b1); // 2
System.out.println(a2+b2); // 3
System.out.println("-----------진수 지정 ");
System.out.println(Integer.parseInt("2022"));
System.out.println(Integer.parseInt("2022", 10)); // 출력 값은 당연히 10진수로 보여지게 됨.
System.out.println(Integer.parseInt("1", 2));
System.out.println(Integer.parseInt("1001", 2)); // 문제속의 문제, 무엇이 출력될까 ?
System.out.println(Integer.parseInt("1004", 8)); // 문제속의 문제, 무엇이 출력될까 ?
System.out.println(Integer.parseInt("A",16)); // 문제속의 문제, 무엇이 출력될까 ?
System.out.println(Integer.parseInt("D",16)); // 문제속의 문제, 무엇이 출력될까 ?
System.out.println(Integer.parseInt("FF",16)); // 문제속의 문제, 무엇이 출력될까 ?
System.out.println("-----------진수 지정 ");
}
}
(1) 하나의 파일에 2개 이상의 클래스를 작성할 수 있다.
(2) 3개의 클래스가 있다면 자바 파일명이 될 수 있는 것은 public 키워드가 붙은 클래스이다.
(3) 하나의 파일에 있는 3개의 클래스에 모두 public 키워드를 붙일 수 있다.
(4) 한 파일내 3개 이상의 클래스에 모두 public 키워드를 안붙일 수 있다.
(5) 한 파일내 3개 이상의 클래스에 모두 public 키워드가 없다면 클래스중 어느 것이라도 파일명이 될 수 있다.
(6) 자바 파일에 클래스가 한개 있다면 클래스명이 곧 파일명이 되어야 한다.
new
키워드로 클래스의 객체(또는 인스턴스)가 생성될 때, 제일 먼저 자동적으로 호출되는 특별한 메서드class Person{
// [1] : 속성
int age;
String name;
// [2] : 생성자
Person(){ // 객체 생성시 자동으로 호출됨. (인자값=파라미터 없는 생성자)
}
// [3] : 메서드
void move(){
System.out.print("Perosn is Move");
}
}
나이 : 20, 이름 : 홍길동
나이 : 30, 이름 : 이순신
나이 : 40, 이름 : 을지문덕
class Person{
// 1. 속성
int age;
String name;
// 2. 생성자
Person(){}// 클래스명과 동일하게
Person(int age,String name){ // 받는 인자값이 있음, 반환 값만 없음. 인자값은 마음대로 받을 수 있음
this.age = age;
this.name = name; // this 는 생성된 각 객체의 자기 자신(객체)을 가리킴 -> 이유 : 편하게 값을 넣기 위해서.
}
// 3. 메서드
void printPerson(){
System.out.println("name : " + name + "\t age : "+ age );
}
}
public class Main{
public static void main(String[] args) {
// 객체 생성
new Person();
Person p1 = new Person(20, "홍길동"); // new 는 주소를 생성하고, 그 주소 값을 반환하는 것 까지가 하는 역할임
System.out.println(p1); // 주소값 출력
p1.printPerson();
Person p2 = new Person(30, "이순신");
p2.printPerson();
Person p3 = new Person(40, "권율");
p3.printPerson();
}
}
부모 || 슈퍼
클래스자식 || 서브
클래스extends
키워드 사용부모 클래스→걷는중~
이름 : 슈퍼맨, 나이 : 20, 성별 : 1, 파워 : 100
이름 : 원더우먼, 나이 : 30, 성별 : 1, 파워 : 100
이름 : 원더우먼, 나이 : 30, 성별 : 2, 파워 : 300
자식 클래스→2배로 빨리 걷는중~
class Person {
//Field
int gender;
int power;
//Constructor
Person() {
this.gender = 1; // 1 : 남성, 2 : 여성
this.power = 100; // 기본 파워
}
//Method
void walk() {
System.out.println("walking");
}
}
class Hero extends Person {
// Field
String name;
int age;
//Constructor
Hero() {
}
Hero(String name, int age) {
this.name = name;
this.age = age;
}
//Method , 오버라이딩||오버라이드 (재정의)
void walk() {
System.out.println("2.em walking");
}
void eat() {
System.out.println("eating");
}
// 객체의 정보 출력
void displayPerson(){
System.out.println("성별: "+gender+"\t 나이: "+ age +"\t 파워: "+power);
}
}
class Villain extends Person {
}
public class Inheritance {
public static void main(String[] args) {
// 객체 생성
Person kim = new Person();
// kim.eat(); // Err :: Hero 에 있는 메서드라서 에러뜸. Person 클래스에는 해당 메서드가 없음.
kim.walk();
// 상속 객체 생성
Hero man = new Hero("슈퍼맨", 20);
System.out.println(man.name);
System.out.println(man.age);
System.out.println(man.gender); // walk 메서드 정의 안했으면, 부모 클래스 필드(변수) 호출함
System.out.println(man.power); // 부모 클래스 필드(변수) 호출함
man.walk();
man.eat();
man.displayPerson();
}
}
Hero(String name, int age) {
// 1
this.name = name; // 2
this.age = age; // 3
}
-> 2~3 이 수행되기 이전에, 1번 위치에 부모 클래스의 생성자를 호출하는 부분이 있음 (지금은 생략됨).
즉, 1번줄에서 부모 클래스의 생성자를 호출하러 가서 초기화됨.
즉, 컴파일러는 부모클래스(gender,power)를 먼저 초기화하고, 자식클래스에서 생성한 부분(name,age)을 초기화함.
--> 이렇게 해서 총 4개를 초기화됨.
super()
써서 부모클래스 표현 가능함.super()
이 생략되어있음 //Method , 오버라이딩||오버라이드 (재정의)
void walk() {
System.out.println("2.em walking");
}
Hero h2 = new Hero("원더우먼",30);
h2.displayPerson();
h2.gender = 2;
h2.power = 300;
h2.displayPerson();
h2.walk(); // 자식클래스가 재정의해놓았기 떄문에, 오버라이딩 부분 사용함. 없으면 부모클래스꺼 사용함.
해당 문제는 계속 반복하는 것이 좋음.
여기서 중요한 문법을 다룸과 동시에 기본이 되기 때문에, 빠르게 다루는 것이 키포인트
이해하고, 시간을 단축시키는 것이 중요함. (자동화된 툴을 사용하지 않고 작성하기)
중요한 부분을 정말 많이 담고있는 코드입니다.
자주 연습하고, 코드를 일일이 설명할 수 있어야합니다.
// 부모클래스
class Person {
// Field
private String name; // private 로 지정해줘서, 이 멤버에 접근할 수 없음
private int age; // but, 해당 클래스 내에서만 사용할 수 있음. --> 외부에서 변경 및 수정이 불가능함, 근데 부모클래스의 멤버는 private 으로 하지만 지양함.
private int height; // private 타입을 getter, setter 를 통해서 외부에서 접근하려고 존재함.
private int weight;
//Constructor 생성자
Person(){}
Person(String name, int age, int height, int weight) {
this.name = name;
this.age = age;
this.height = height;
this.weight = weight;
}
//Method
public String getName() { // 값 세팅했으니까, 값을 가져와야함 (getter)
return name;
}
// 값 세팅 = 반환 값 필요 x = void 사용
public void setName (String name){ this.name = name; } // 전달된 p1 세팅 (setter)
public int getAge(){return age;}
// 전달받은 메서드의 인자값을, 멤버 내 필드에 세팅해주는거임.
public void setAge(int age){this.age = age;}
public int getHeight(){return height;}
public void setHeight(int height){this.height=height;}
public int getWeight(){return weight;}
public void setWeight(int weight){this.weight=weight;}
//추가
public void move(){
System.out.println("Moving,,");
}
}
class Villain extends Person {
// Field
String unique_key;
int weapon; // 1~9 숫자로 무기 분류 -- > 1:창, 2:방패, 3:총 ...
double power;
//Constructor
Villain(){}
// 파라미터에 부모클래스 멤버필드까지 추가해서 받아줌
Villain(String name, int age, int height, int weight,String unique_key, int weapon, double power){ // 객체가 생성될 때, 해당 생성자가 제일 먼저 호출되니까,
// 이 생성자를 통해서 객체의 초기값(멤버필드)을 초기화해줘야함.
// 따라서, 인자값을 7개 받아줌. but 부모 클래스에 초기화된 것이 있음.
// 부모 클래스 가리켜서, 부모클래스의 생성자 가져옴.
super(name,age,height,weight);
// 해당 부분을 안가져와서 초기값만 나왔음.
// 나머지 값 3개를 세팅해줌.
this.unique_key = unique_key;
this.weapon = weapon;
this.power = power;
}
//Method
public String getUnique_key(){return unique_key;} // 호출만 하면됨.
public void setUnique_key(String unique_key){this.unique_key = unique_key;}
public int getWeapon(){return weapon;} // 호출만 하기때문에, 인자값이 없고, 멤버변수의 weapon 을 사용해줌
public void setWeapon(int weapon){this.weapon=weapon;}
public double getPower(){return power;} // 파워의 값을 리턴해서 가져 오기만 하면되니까
public void setPower(double power){this.power=power;}
// 정보 출력, printPerson()
public void printPerson(){
System.out.println("===============================");
System.out.println("악당 name : " + getName()); // private 이니까 get 메소드만 이용해서 가져와줌
System.out.println("악당 age : "+getAge());
System.out.println("악당 height : "+getHeight());
System.out.println("악당 weight : "+getWeight());
System.out.println("악당 number : "+getUnique_key());
System.out.println("악당 weapon : "+getWeaponName(getWeapon())); // getWeapon() :: 정수 값(1~9)으로 가져옴. 따라서 별도의 조건문을 사용해줌
// 윗 행부분에서 getWeapon(숫자1~9)이 getWeaponName 메서드로 전달되어서, 만약 2이면 방패가 출력된다는거임.
System.out.println("악당 power : "+getPower());
System.out.println("===============================");
}
//getWeaponName()
public String getWeaponName(int a){ // 반환되는 타입이 문자열로 반환되기 때문에, 타입은 String으로 반환해줌.
// 전달되는 인자값은 int로 전달되서 인자값의 타입은 int
String weapon;
switch (a){
case 1:
weapon = "창";
break;
case 2:
weapon = "방패";
break;
case 3:
weapon = "총";
break;
default:
weapon = "===";
break;
}
return weapon; // 리턴을 해줌과 동시에, 이 함수를 호출한 호출부로 다시 전달해줌.
// 즉, getWeaponName(getWeapon())); 이 부분에서 getWeapon(숫자1~9)이 getWeaponName 메서드로 전달되어서, 만약 2이면 방패가 출력된다는거임.
}
}
class Hero extends Person{
}
public class Inheritance{
public static void main(String[] args) {
// 1, 객체 생성
Villain v1 = new Villain("좀비",20,180,80, "15001231",2,99.5); //
v1.printPerson();
System.out.print(v1.getName()+" ");
v1.move(); // 부모 클래스의 move() 메서드를 호출
// 2, 객체생성
Villain v2 = new Villain("도깨비",30,175,70, "11001231",1,77.5);
v1.printPerson();
System.out.print(v2.getName() + " ");
v2.move();
// 3, 객체생성
Villain v3 = new Villain("몽달귀신", 40, 150, 40, "101111234", 3, 25.5);
v3.printPerson();
System.out.print(v3.getName() + " ");
v3.move();
}
}
해당 코드의 빌런클래스의 Constructor 로직
getter, setter
를 통해서 외부에서 접근하려고 존재함.(위 전체 코드를 기반으로 설명)
내가 물건을 전달해 줄때는, 메인메서드의 set의 값을 set메서드의 인자값으로 전달해줘야 하지만, 내가 받는 것은 필요가 없음. --> 가만히 서 있다가, 간호사가 주는거 받으면 되니까. (예시임) --> 밑(메인메서드)에서 get메서드를 호출만 하면 되는거임. --> 호출만 하면, set의 인자값을 받아서 setting이 되었으니, 가져오는거임. --> 이러한 이유때문에, 따로 인자값을 넣어서 호출할 필요가 없음.
set 메서드는 전달 받은 인자 값을 멤버 Field내에 세팅(초기화)함.
//Method
public String getName() { // 값 세팅했으니까, 값을 가져와야함 (getter)
return name;
}
// 값 세팅 = 반환 값 필요 x = void 사용
public void setName (String name){ this.name = name; } // 전달된 p1 세팅 (setter)
getName()
: 이 메서드는 name 필드의 값을 가져와서 반환하는 getter입니다.setName(String name)
: 이 메서드는 name 필드에 값을 설정하는 setter입니다. 파라미터로 전달된 name 값을 name 필드에 할당합니다.따라서, getName()
은 값을 반환하기 위해 return 키워드를 사용하고,
setName(String name)
은 반환 값이 필요 없으므로 void 키워드를 사용합니다.
보통 set (setter, 값 설정)을 먼저 작성하고, get (getter, 값 호출) 작성하면 더 쉬움.
class Person{
//Field
private String name;
private int age;
//Constructor
Person(){}
Person(String name, int age){
this.name = name;
this.age = age;
}
//Method
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 class Array {
public static void main(String[] args) {
// 1. 객체배열 생성
Person[] PA = new Person[5]; // 타입 [] 배열명 = 객체생성 --> 타입은 어느 출신인지 묻는거.(저장할 수 있는 객체배열 공간을 만들어줌)
PA[0] = new Person("홍길동", 20);
PA[1] = new Person("김길동",21);
PA[2] = new Person("성길동",22);
PA[3] = new Person("준길동",23);
PA[4] = new Person("문길동",24);
for (int i = 0; i < PA.length; i++) {
System.out.print(PA[i].getName()+" "+PA[i].getAge()); // private 로 되어있어서 PA[i].name 로 바로 접근 못함 -> 게터,세터 이용해야함 (간호사 이용)
System.out.println();
}
}
}
해당 코드를 print() 메서드를 생성해서 출력하는 방법 및 필자의 풀이해설
class Person{
//Field
private String name;
private int age;
//Constructor
Person(){}
Person(String name, int age) {
this.name = name;
this.age = age;
}
//Method
public void setName(String name){
this.name = name;
}
public String getName(){
return name;
}
public void setAge(int age){
this.age = age;
}
public int getAge(){
return age;
}
public void print(){
System.out.println(getName()+"\t"+getAge());
}
}
public class Inheritance{
public static void main(String[] args) {
Person[] PA = new Person[5];
PA[0] = new Person("ㅎ", 1);
PA[1] = new Person("ㅎd", 2);
PA[2] = new Person("ㅎ2", 3);
PA[3] = new Person("ㅎ3123", 4);
PA[4] = new Person("ㅎasd", 5);
for (int i = 0; i < PA.length; i++) {
PA[i].print();
}
}
}
import java.util.*;
class Person{
//Field
String name;
int age;
//Constructor
Person(){}
Person(String name, int age){
this.name = name;
this.age = age;
}
//Method
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 class Array {
public static void main(String[] args) {
// 객체배열 생성
Person[] PersonArray; // Person 타입의 객체 배열 변수 선언
PersonArray = new Person[10]; // Person 객체의 참조값을 원소로 가지는 배열 공간 5개 생성 -- > 5명 객체 생성할테니 주소 저장해라.
// loop 돌면서 Person() 객체생성
for (int i = 0; i < PersonArray.length; i++) {
PersonArray[i] = new Person(i+"번쨰 후보자 --> 나이 :", 20+i); //만약 new Person(i, i+20); 하면 에러 나는 이유 ? --> 파라미터로 문자열, 정수를 받는데, 여기선 두개 다 정수로 해서 에러남
// [2-1] :: 게더, 세터 메서드 사용해서 출력
// System.out.println(PersonArray[i].getName()+" "+ PersonArray[i].getAge());
// [2-2] :: 배열 인덱스 사용해서 출력 --> 단, 이렇게 쓰려면 private 선언을 삭제하고 써야함
// System.out.println(PersonArray[i].name+"의 나이는 "+PersonArray[i].age+" 살 입니다."); // 이렇게 해주려면 Field 부분에서 private 삭제하고 사용해야함.
// [2-3] :: printf
// System.out.printf("%s %d살 입니다.\n", PersonArray[i].name, PersonArray[i].age);
}
}
}
필자는 슈퍼클래스의 멤버는 private로 설정해주고, getter , setter를 사용하는 것을 매우 권장합니다.
같은 이름의 메서드(Method)나 생성자(Constructor)를 여러 개 정의하여 매개변수의 유형과 수에 따라 다른 구현이 가능하게 하는 것을 의미합니다.
즉, 같은 이름으로 다양한 매개변수를 받아 처리할 수 있도록 하는 것입니다.
반면,
상위 클래스에서 정의된 메서드를 하위 클래스에서 재정의하여 사용하는 것을 의미합니다. 즉, 상위 클래스의 메서드를 하위 클래스에서 수정하여 자신의 필요에 맞게 재정의할 수 있도록 해주는 것입니다.
정의하는 객체 : 오버로딩은 같은 클래스 내에 메서드나 생성자를 다시 정의하는 것을 의미합니다.
반면, 오버라이딩은 상위 클래스의 메서드를 하위 클래스에서 재정의하여 사용하는 것을 의미합니다.
제어 시점 : 오버로딩은 컴파일 시점에서 결정됩니다.
반면, 오버라이딩은 런타임 시점에서 결정됩니다.
매개변수의 유무 : 오버로딩은 메서드나 생성자를 호출할 때 인자의 유무에 따라 다른 동작을 할 수 있도록 해줍니다.
반면, 오버라이딩은 메서드의 시그니처가 동일한 경우, 인자의 유무에 관계없이 오버라이딩된 메서드가 호출됩니다.
반환형 : 오버로딩은 호출할 메서드의 반환형이 다르더라도 메서드 오버로딩을 할 수 있습니다.
반면, 오버라이딩은 상위 클래스의 메서드와 동일한 반환형을 가져야 합니다.
상속과 관계 : 오버로딩은 상속과 직접적인 관련이 없습니다.
반면, 오버라이딩은 상위 클래스의 메서드를 하위 클래스에서 재정의하기 때문에 상속과 관계가 있습니다.