시즌 2
객체 지향 프로그래밍 ( Object-Oriented Programming ) oop
오리엔테이션
상태와 행위를 그룹핑해놓은 것
객체 : 상태와 행위로 구분해서 서로 연관되어 있는 상태와 행위를 그룹핑해놓은것 ( categorize)
객체 : 구체적인 문법적인 기능이 언어차원에서 제공되는 기능
하나의 객체 안에는 그 객체가 가지고 있는 취지 (댓글인지 본문인지) 에 따라서 기능에 연관되어 있는 변수와 메소드를 객체라는 껍데기에 가둬둔 것이고 서로 연관성이 없는 다른 로직과 구분해주는 역할을 함 : 재활용성
추상화 ( abstract )
추상화는 해결해야하는 문제 반영해야 하는 현실을 소프트웨어적으로 단순화해서 표현
하나의 프로그램이 여러개의 형태의 로직으로 이루어져있고 그 여러개의 로직안에 관련된 변수와 메소드로 이루어진 객체가 있고 이것을 다른 곳에서 활용(재활용) 할 수 있다.
객체가 다른 곳에서 여러곳에서 무엇으로 활용되는지
재활용가능하도록 부품화 하도록 한다.
컴퓨터 -> 추상화 : 모니터디스플레이, 키보드, cpu메모리등의 본체
부품들을 그룹핑해서 개념화 -> 추상화
클래스와 인스턴스 그리고 객체지향
클래스 class : 설계도 , 정의
인스턴스 instance : 설계도에따라 만들어진 제품, 호출
객체 object
중복의 제거가 중요하다. 중복되는 코드는 제거되어야 하는 대상이다.
하나의 코드를 가지고 중복되는 작업을 할 수 있어야한다.
건강한 코드 : 중복되는 코드는 없애야 한다.
중복제거 ---> 메소드를 사용하기
연관되어 있는 연산, 데이터등을 기능적으로 모아서 -> 객체지향 언어로 시작한 언어가 자바다.
클래스와 인스턴스 그리고 객체 지향 : 객체화
left = 10 ;
right = 20 ;l
sum ( left, right);
avg(left, right ) ;
left = 20 ;
right = 40 ;
sum(left, right) ;
avg(left, right) ;
두개는 연관되어 있는 두개로 구성되어 있고 그것이 반복되고 있다.
인스턴스 : 구체적인 객체
class Calculator { //설계도
int left , right; //left, right 를 선언 전역변수
public void setOprands(int left, int right) {
this.left = left; //
this.right = right; //
밑에 Calculator c1 = new Calculator(); c1 에 담겨있는 Calculator 클래스를
구체적인 제품으로 만든 인스턴스를 가리키는 것이 바로 this
}
public void sum(){
System.out.println(this.left+ this.right ) ;
밑에 보면 c1.setOprands (10, 20 ) 에서 전역변수에다가 (this.left, this.right)
값을 넣었고 그것을 다시
c1.sum 을 통해서 메소드를 호출하여
지금 여기서 전역변수의 애들 ( 10, 20 으로 변경된 ) 을 더해주는것
}
public void avg() {
System.out.println((this.left + this.right ) / 2 ) ;
}
}
public class CalculatorDemo4 {
public static void main (String[] args ) {
Calculator c1 = new Calculator(); //method 라고 하면 앞에 new 는 안붙 어 있지. Calculator() 는 객체이다. ( 인스턴스화)
//Calculator 는 데이터 타입이다.
c1.setOprands(10,20);
c1.sum();
c1.avg();
Calculator c2 = new Calculator();
// 여기나오는 Calculator 는 데이터 타입이다.
//new Calculator () 는 인스턴스화 -> c2라고 하는 변수에 담김
c2.setOprands(20,40);
c2.sum();
c2.avg();
}
}
//Calculator c1 = new Calculator(); 라고 할 때
여기서 Calculator 는 데이터 타입이다. 그것에 대한 설명 :
프로그램을 메모리에 적재시켜서 프로그램이 작동된다.
타입을 우리가 직접 만드는 것이라고 할 수 있다. 사용자 정의 데이터타입을 만드는것이라는것
내 이해 : Calculator는 class인데 그 클래스안에 내가 (설계도 안에 ) 변수도 선언하고 메소드도 만들잖아. 그래서 그것은 사용자가 정의한 데이터이고 그래서 c1은 Calculator 라는 데이터타입이라고 하는것
클래스 맴버 , 인스턴스 맴버 : 맴버란 ?
객체 : 변수와 메소드의 집합
클래스 (설계도 )
인스턴스 1 (제품1)
인스턴스 2 (제품 2 )
.....
10 , 20 과 20 , 40 과같이 인스턴스 안에 들어있는것 : 인스턴스 변수라고 한다.
인스턴스마다 서로다른 값을 가지고 있기 때문에
인스턴스의 소유가 아니고 클래스의 소유인 변수가 존재한다.
클래스의 변수(전역변수) / 인스턴스의 변수
클래스의 멤버 변수는 모든 인스턴스에서 똑같은 값을 같는다 ( int left, int right )
인스턴스에 직접 접근하지 않아도 클래스에 소속되어 있는 변수에 접근해서 값을 사용할 수 있다.
클래스 맴버, 인스턴스 맴버 : 클래스 변수
class Calculator{
static double PI = 3.14; // 파이는 모든 객체가 똑같은 값을 가지면 된다. (클래스 변수 : 클래스의 변수이기 때문에 클래스에 따라서 만들어진 모든 인스턴스들은 그 클래스가 가지고 있는 값을 자연스럽게 가지고 있는 것이다. )
static 키워드 : static 뒤에 따라오는 변수는 static 한 변수가 되는 것 -> 이 변수가 class 에 소속이 된다라는 뜻 -> 저 변수를 모든 인스턴스에서 동일한 값으로 가지고 오게 된다. 동 일한 값이 된다.
int left, right;
public void setOprands(int left, int right) {
this.left = left;
this.right = right;
}
public void sum () {
System.out.println(this.left + this.right) ;
}
public void avg() {
System.out.println((this.left + this.right) / 2 ) ;
}
}
public class CalculatorDemo1 {
public static void main (String[] args ) {
Calculator c1 = new Calculator () ;
System.out.println(c1.PI) ; //3.14가 출력된다.
Calculator c2 = new Calcilator();
System.out.println(c2.PI); //3.14 가 출력된다.
System.out.pritnln(Calculator.PI) ; //인스턴스의 설계도라고 할 수 있는 Calculator 라는 클래스에서 직접 접근도 가능하다.
}
}
또하나의 예제 )
class Calculator2 {
static double PI = 3.14 ;
static int base = 0 ; //static 이기 때문에 base 는 Calculator 2 의 변수 ( 인스턴스의 변수가 아님 )
int left, right ; -> static 이 붙어 있지 않기 때문에 이것은 인스턴스에서만 유효한 변수가 된다.
public void setOprands ( int left , int right) {
this.left = left;
this.right = right;
}
public void sum () {
System.out.println(this.left + this.right + base ) ;
}
public void avg () {
public class CalculatorDemo2
public static void main (String[] args) {
Calculator2 c1 = new Calculator2();
c1.setOprands(10, 20 ) ;
//30출력
c1.sum();
Calculator2 c2 = new Calculator2();
c2.setIOprands(20, 40 ) ;
*Calculator2.base = 10 ;
--> 클래스 변수 base 의 값을 10으로 지정했다.
c1.sum(); 40 출력
c2.sum(); 70출력
클래스 맴버, 인스턴스 맴버 : 클래스 메소드
*컨트롤 : 롤오버를 하면 링크가 생겨서 원하는 곳으로 갈 수 있다. 이전으로 가려면 위에 있는 옐로 화살표를 쓰면됨.
클래스 맴버, 인스턴스 맴버 : 타입별 비교
1.인스턴스 메소드는 클래스 맴버에 접근 할 수 있다.
//인스턴스 메소드 : 인스턴스에 속해있는 메소드 static 이라는 것이 붙어 있지 않은
2. 클래스 메소드는 인스턴스 멤버에 접근 할 수 없다.
// 클래스라고 하는 것은 언제나 메소드보다 먼저 존재하고 있다.
클래스 설계도 -> 구체적인 제품인 인스턴스를 나중에 만든다.
클래스 메소드는 클래스를 기반으로 만들어진 인스턴스에 접근하는 것이기 때문에 아직 생성되지 않은 인스턴스에 접근하는 것은 불가능하겠지?
(논리적으로 생각하면 되는 부분 )
클래스를 만들때 아직 만들어지지 않은 인스턴스에 접근할 수는 없겠지.
*static 이 붙어 있어 -> 클래스변수
class C1 {
static int static_variable = 1; //static 이 붙었으니까 클래스변수
int instance_variable = 2; // 인스턴스 변수
static void static_static() { //클래스 메소드가 클래스 변수(static_variable)에 접근
System.out.println(static_variable) ;
}
static void static_instance () {
//클래스 메소드에서는 인스턴스 변수에 접근 할 수 없다.
// System.out.println(instance_variable);
}
void instance_static(){
System.out.println(static_variable);
}
void instance_instance() {
System.out.println(instance_variable)
}
}
public class ClassMemberDemo {
public static void main(String[] args ) {
C1 c = new C1();
//인스턴스를 이용하여 정적 메소드에 접근 -> 성공
//인스턴스 메소드가 정적 변수에 접근 -> 성공
c.static_static();
//인스턴스를 이용하여 정적 메소드에 접근 -> 성공
//정적 메소드가 인스턴스 변수에 접근 -> 실패
c.static_instance();
//인스턴스를 이용하여 인스턴스 메소드에 접근 -> 성공
//인스턴스 메소드가 클래스 변수에 접근 -> 성공
C1.static_static();
//클래스를 이용하여 클래스 메소드에 접근 -> 성공
//클래스 메소드가 인스턴스 변수에 접근 -> 실패
C1.static_instance();
//클래스를 이용해서 인스턴스 메소드에 접근 -> 실패
//C1.instance_static();
// 클래스를 이용해서 인스턴스 메소드에 접근 -> 실패
//C1.instance_instance();
* 인스턴스 변수 -> Non-Static Field
클래스 변수 -> Static Field
클래스[인스턴스][클래스메소드][인스턴스메소드] -> 메소드 -> 변수로 접근한다고하면
클래스에서 -> 인스턴스는 안됨.
유효범위 ( 1/4) 유효범위란 ? scope
이름중복문제 해결위해 나옴
public class ScopeDemo {
static void a () {
int i = 0 ; //지역변수
}
//i라는 변수는 a라는 메소드 안에서 선언되고 있기에 i 변수는 a 메소드 바깥쪽에 영향을 미칠 수 없다
public static void main(String[] a
for(int i = 0 ; i < 5 ; i++ ) {
a();
System.out.println(i);
}
}
}
//따라서 메인에서 a 메소드 바깥에서 for문의 i에 영향을 미치지 않는다.
유효범위 (2/4) - 전역변수, 지역변수
디렉터리 바깥쪽에서 사용하면 이름의 충돌현상을 완화시킬 수 있다.
public class ScopeDemo2 {
static int i ;
// i 는 클래스에 직접적으로 속해있는 직속변수 : 전역변수
static void a(){
i = 0 ;
}
public static void main ( String[]
for( i = 0 ; i < 5 ; i++) {
a();
System.out.println(i);
}
}
}
consol : 계속 0 만 나오고 영원히 반복된다.
a(){} 메소드 안에 i를 int i 로 바꿔주거나
메인메소드 안에 있는 for 문에 있는 i를 0 으로 바꿔주면 됨
범위가 전혀 달라짐
*중괄호 안에서만 유효한 지역변수
유효범위 ( 3/4) : 다양한 유효범위
public class ScopeDemo4 {
static void a () {
String title = "coding evertbody";
}
public static void main (String[] args) {
a();
System.out.println(title);
}
}
title 은 컴파일에러가 발생되어 있다.
title 은 a에 들어있고 main 입장에서는 존재하지 않는것.
또다른 예
public class ScopeDemo5 {
public static void man(String[] args) {
for(int i = 0 ; i < 5 ; i++ ) {
System.out.println(i);
}
System.out.pritnln(i); //for문의 바깥에 있는거 ..
}
}
여기서도 컴파일 에러가 발생할 수 있다.
static void a () {
int i = 10 ;
b();
}
static void b () {
System.out.pritnln(i); //얘네는 메소드 b를 호출한 메소드 a 나 메인에 있는 i를 사용하는 것이 아님
}
public static void main(String[] args) {
int i = 1;
a();
}
* 정적인 유효범위 : lexical ( static ) scope ) ( 자바로 추정 ㅋㅋ )
동적인 유효범위 : dynamic scope
유효범위 ( 4/4 ) : this
class C {
int v = 10;
void m() {
int v = 20;
System.out.println(v);
System.out.println(this.v); //전역변수를 프린트하고 싶으면 this 붙이기
}
}
main ~~
객체지향프로그래밍에서는 전역변수사용을 금기시하고 있다.
생성자
객체에서 초기화를 할 수 있도록 하는 것
class Calculator {
int left , right;
public Calculator(int left , int right) {
this.left = left; //클래스의 생성자 ( 만약 없으면 자동으로 생성 해줌)
this.right = right;
}
public void sum() {
System.out.println(
Calculator c1 = new Calculator(10, 20) ; 클래스가 아니라 생성자.
c1.sum();
c1.avg();
앞에서는 생성자가 없었는데 생성자를 만들어서 객체를 만들때 객체가 반드시 해야하는 작업이 있다면 그것을 생성자에 만들어줘서 그 절차를 줄일 수 있도록 또는 반드시 해야하는 작업을 놓치지 않을 수 있도록 만들어준것 클래스와 같은 이름이네
상속
기존의 객체를 그대로 유지하면서 어떤 기능을 추가하는 방법이 없을까?
이런 맥락에서 등장하는 것이 상속
부모클래스 = super 클래스
하위클래스 = sub 클래스
class Calculator (부모) {
int left, right ;
public void setOprands(int left, int right) {
this.left = left;
this.right = right;
}
public void sum() {
System.out.pritnln(this.left + this.right) ;
}
public void avg() {
System.out.println(this.left + this.right) / 2 ) ;
}
}
class substractionalableCalculator (자녀) extends Calculator {
public void substract() {
System.out.println(this.left - this.right) ;
}
}
public class CalculatorDemo1 {
public static voud main(String[] args) {
SubstractionalableCalculator c1 = new substractionalableCalculator() ;
c1.setOprands(10, 20) ;
c1.sum();
c1.avg();
c1.substract();
}
다양한 종류의 상속
상속을 여러개 할 수 있고
상속이 된 자녀에 또 자녀를 만들 수 있다
코드의 중복을 없애준다.
상속과 생성자
생성자는 객체를 생성한다. 초기화 작업을 할 수 있다.
package ~~
public class ConstructorDemo {
public static void main(String[] args) {
constructorDemo c = new ConstructorDemo();
}
}
여기서는 오류가 생기지 않는다. ConstructorDemo 객체를 생성할 때 생성자를 생성하지 않으면 자바에서 자동으로 매개변수가 없는 기본 생성자(클래스와 이름은 같으면서 메서드를 가지고 있지 않은 ) 를 만들어주기 떄문에 c라는 변수로 객체생성을 해줄 수 있다.
package ~~~
public class ConstructorDemo {
pubic ConstructorDemo(int param1 ) {} // 생성자를 생성했는데 파라미터가 존재 (기본생성자가 아닌 생성자 )
public static void main(String[] args) {
ConstructorDemo c = new ConstructorDemo(); 여기에 에러가 발생한다. 인자가 없어 ConstructorDemo 는 인자가 없는 생성자를 가지고 있지 않기 때문에 (그리고 자동으로 기본생성자가 만들어 진 것이 아니기 때문에 )
}
}
상속과 생성자 : super
class Calculator {
int left, right ;
public Calculator(int left, int right ) {
this.left = left;
this.right = right;
}
class SubstractionableCalculator extends Calculator {
public SubstractionableCalculator(int left, int right ) {
this.left = left;
this.right = right;
}
public void substract() {
System.out.println(this.left - this.right ) ;
}
}
public class CalculatorConstructorDemo5 {
public static void main(String[] args) {
SubstractionableCalculator c1 = new SubstractionableCalculator(10, 20 ) ;
// SubstractionableCalculator 객체생성을 하면 그 아이는 Calculator 를 상속받은 것이 기 때문에 자기 클래스를 호출하기 전에 부모클래스의 생성자를 자동으로 먼저 호출하도록 자바는 만들어져있다. 부모 생성자 Calculator는 기본생성자가 아니라 파라미터를 가지고 있다. -> 하위클래스가 상속을 받을때 상위클래스의 생성자를 호출해줘야 하는데 기본생성자가 아니기때문에 에러가 난다. ---> Calculator 라는 클래스에 기본생성자를 정의해주면 된다는 것
Substration
c1.sum()
c1.avg();
c1.substract() ;
--> class Calculator {
int left, right;
public calculator () {} //이렇게 부모클래스에 기본생성자를 생성해줘야 한다.
public Calculator(int left, int right) {
this.left = left;
this.right = right;
}
부모클래스가 만약 매개변수가 있는 생성자를 생성하면 기본생성자가 없으니까 하위생성자는 상위생성자를 호출할 수 없기때문에 -> 부모클래스에 기본생성자를 만들어준다.
-> 기본생성자를 만들지 않고도 객체가 동작하도록 할 수 있다.
: 상위클래스 생성자 하위클래스 생성자가 동일하다면
하위클래스에서 생성자를 만들지 말고 상위클래스에서 복사해서 사용하기 : super
class SubstractionableCalculator extends Calculator {
public SubstractionableCalculator(int left, int right ) {
super(left, right) ; super (부모클래스의 생성자)
SubstractionableCalculator의 매개변수 left와 right 는 super(부모클래스의 ) left, right 에 들어가게 되는것
}
......................
정리 : 하위클래스가 상위클래스를 참조할 수 있는 키워드 super
하위클래스가 부모클래스의 초기화를 먼저하고 자기자신의 초기화를 해야한다면
super () 밑에 써준다. : 상속받은 자식클래스만이 해야하는 초기화과정을 해줄 수 있다.
super () 밑에써줘야한다. 항상 하위클래스의 초기화클래스는 super 를 호출한다음에 써줘야한다. 상위클래스초기화먼저 (super) -> 하위클래스의 초기화 그 다음
댓글
댓글 쓰기