일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | 5 | ||
6 | 7 | 8 | 9 | 10 | 11 | 12 |
13 | 14 | 15 | 16 | 17 | 18 | 19 |
20 | 21 | 22 | 23 | 24 | 25 | 26 |
27 | 28 | 29 | 30 | 31 |
- XLF
- 자바
- 미국주식
- object
- 금리인상
- Java
- 객체지향
- 잉여현금흐름
- mco
- 인플레이션
- 프로그래머스
- S&P500
- 알고리즘
- 금리인하
- StringBuffer
- 현금흐름표
- 주식
- 접근제어자
- 배당성장
- javascript
- etf
- 다형성
- 주린이
- 무디스
- 제태크
- 오버라이딩
- 기업분석
- FCF
- 백준
- 그리디 알고리즘
- Today
- Total
오늘의하루
[자바의 정석] 제어자 & 다형성 본문
제어자(modifiers)
제어자는 클래스, 변수, 메서드의 선언부에 사용되어 부가적인 의미를 부여하며 크게 접근 제어자와 그 외의 제어자로 나눠집니다.
- 하나의 대상에 여러 개의 제어자를 조합해서 사용할 수 있지만 접근제어자는 단 하나만 사용할 수 있다.
접근 제어자 : public, protected, default, private
그 외 제어자 : static, final, abstract, native, transient, synchronized, volatile, strictfp
그 외의 제어자 알아보기
static - 클래스의, 공통적인
static이 사용될 수 있는 곳은 멤버 변수, 메서드, 초기화 블록이다.
대상 | 의미 |
멤버변수 | 1. 모든 인스턴스에 공통적으로 사용되는 클래스 변수가 된다. 2. 클래스 변수는 인스턴스 생성없이 접근이 가능하다. 3. 클래스가 메모리에 로드될 때 생성되며 프로그램 종료시 소멸한다. |
메서드 | 1. 인스턴스 생성 없이 호출이 가능한 static 메서드가 된다. 2. static 메서드 내에서는 인스턴스 멤버들을 사용할 수 없다. |
class StaticTest{
static int width = 200; // static 변수
static int height = 120; // static 변수
static{ // static 초기화 블록
// static 변수의 복잡한 초기화 수행
}
static int max(int a, int b){ // static 메서드
return a > b ? a : b;
}
}
final - 마지막의, 변경될 수 없는
fianl이 사용될 수 있는 곳은 클래스, 멤버 변수, 메서드, 지역변수이다.
- 대표적인 final 클래스로는 String과 Math가 있다.
대상 | 의미 |
클래스 | 변경될 수 없는 클래스이며 확장 될 수 없는 클래스가 된다. - final로 지정된 클래스는 다른 클래스의 부모가 될 수 없다. |
메서드 | 변경될 수 없는 메서드이며 오버라이딩을 할 수 없다. |
멤버변수 | 변수 앞에 fianl이 붙으면 값을 변경할 수 없는 상수가 된다. |
지역변수 |
final class FinalTest{
final int MAX_SIZE = 10; // 멤버변수 (상수)
final void getMaxSize(){
final LV = MAX_SIZE; // 지역변수 (상수)
return MAX_SIZE;
}
}
class Child extends FinalTest{ // Error! 상속 받을 수 없다.
void getMaxSize(){} // Error! 오버라이딩 할 수 없다.
}
생성자를 이용한 final 멤버 변수 초기화
final이 붙은 멤버 변수는 상수이며 보통은 선언과 초기화를 동시에 하지만 인스턴스 변수의 경우 생성자에서 초기화할 수 있다.
class Card{
final int NUMBER;
final String KIND;
static int width = 100;
static int height = 250;
Card(String kind, int num){ // 생성자로 final멤버변수 초기화
KIND = kind;
NUMBER = num;
}
Card(){
this("HEART", 1); // Card("HEART", 1) 호출
}
public String toString(){ // toString 오버라이딩
return " " + KIND + " " + NUMBER:
}
}
Card c = new Card();
c.NUMBER = 5; // Error! 상수는 변경할 수 없다.
System.out.println(c.KIND); // HEART
System.out.println(c.NUMBER); // 1
abstract - 추상의, 미완성의
abstract가 사용될 수 있는 곳은 클래스, 메서드이다.
대상 | 의미 |
클래스 | 클래스 내에 추상 메서드가 선언되어 있음을 의미한다. |
메서드 | 선언부만 작성하고 구현부는 작성되지 않는 추상 메서드임을 알린다. |
abstract class AbstractTest{ // 추상 클래스
abstract void move(); // 추상 메서드
}
접근 제어자 알아보기
접근 제어자는 멤버 또는 클래스에 사용되어 외부로부터 접근을 제한합니다.
대상 | 의미 |
private | 같은 클래스 내에서만 접근이 가능하다. 사용하는 곳 : 멤버 |
(default) | 같은 패키지 내에서만 접근이 가능하다. 사용하는 곳 : 클래스, 멤버 |
protected | 같은 패키지 내에서, 그리고 다른 패키지의 자식 클래스에서 접근이 가능하다. 사용하는 곳 : 멤버 |
public | 접근 제한이 없다. 사용하는 곳 : 클래스, 멤버 |
접근 제어자를 이용한 캡슐화
캡슐화란 외부로부터 불필요한 접근으로부터 데이터를 보호하는 방법을 말한다.
class Time{
private int hour;
private int minute;
private int second;
Time(int hour, int minute, int second){
}
public int getHour(){return hour;}
public int getMinute(){return minute;}
public int getSecond(){return second;}
public void setHour(int hour){
if(hour < 0 || hour > 23){
return;
}
this.hour = hour;
}
public void setMinute(int minute){
if(minute < 0 || minute > 59){
return;
}
this.minute = minute;
}
public void setSecond(int second){
if(second < 0 || second > 59){
return;
}
this.second = second;
}
public String toString(){
return hour + ":" + minute + ":" + second;
}
}
// ======================================================
Time t = new Time(12,35,10);
System.out.println(t); // == System.out.println(t.toString());
t.hour = 5; // Error! 멤버변수의 접근제어자가 private이기 때문에 직접 접근할 수 없다.
t.setHour(5); // OK
System.out.println(t)는 System.out.println(t.toString())과 같으며 toString 메서드는 생략이 가능하다.
생성자의 접근 제어자
일반적으로 생성자의 접근 제어자는 클래스의 접근제어자와 일치하며 생성자에 접근 제어자를 사용함으로써 인스턴스의 생성을 제한할 수 있다.
final class Singleton{
private static Singleton s;
private Singleton(){ // 생성자
// ....
}
public static Singleton getInstance(){
if(s == null){
s = new Singleton();
}
return s;
}
}
Singleton s1 = new Singleton(); // Error! 생성자의 접근제어자가 private이기 때문에 접근 불가
Singleton s2 = Singleton.getInstance(); // OK
// getInstance는 static메서드 이기 때문에 인스턴스 생성없이 호출 가능
// getInstance 메서드 안에서 생성자 호출이 가능하다.
제어자의 조합
대상 | 사용 가능한 제어자 |
클래스 | public, (default), final, abstract |
메서드 | 모든 접근 제어자, final, abstract, static |
멤버변수 | 모든 접근 제어자, final, static |
지역변수 | final |
- 메서드에 static과 abstract를 함께 사용할 수 없다.
- static 메서드는 구현부가 있는 메서드에만 사용할 수 있기 때문이다.
- 클래스에 abstract와 final을 동시에 사용할 수 없다.
- fianl 클래스는 부모가 될 수 없는데 abstract는 자식 클래스가 상속을 받아 추상 메서드의 구현부를 완성해야 하기 때문이다.
- abstract메서드의 접근제어자가 private일 수 없다.
- abstract메서드는 자식 클래스에서 구현해 주어야 하지만 접근 제어자가 private일 경우 자식 클래스에서 접근이 불가능하여 구현부를 완성할 수 없기 때문입니다.
- 메서드에 private과 final을 같이 사용할 필요는 없다.
- 접근 제어자가 private인 메서드와 fianl인 메서드 모두 오버 라이딩을 할 수 없다는 의미이기 때문에 중복된다.
다형성(polymorphism)
다형성은 하나의 참조 변수로 여러 타입의 객체를 참조할 수 있는 것이며 부모 타입의 참조 변수로 자식 타입의 객체를 다룰 수 있는 것이다.
class Tv{
boolean power;
int channel;
void power(){power = !power;}
void channelUp(){++channel;}
void channelDown(){--channel;}
}
class CaptionTv extends Tv{
String text;
void caption(){/* 내용 생략 */}
}
Tv t = new CaptionTv();
// 부모 타입의 참조변수 t는 자식 타입의 객체 CaptionTv를 다룰 수 있다.
참조 변수의 형 변환
서로 상속관계에 있는 타입 간의 형 변환이 가능하다.
자식 타입에서 부모 타입으로 형 변환은 Up Casting (형 변환 생략 가능)
부모 타입에서 자식 타입으로 형 변환은 Down Casting (형 변환 생략 불가능)
class Car{
String color;
int door;
void drive(){
System.out.println("drive Brrrr");
}
void stop(){
System.out.println("stop!");
}
}
class FireEngine extends Car{
void water(){
System.out.println("water");
}
}
class Ambulance extends Car{
void siren(){
System.out.println("siren");
}
}
Car c = null;
FireEngine fe1 = new FireEngine();
FireEngine fe2 = null;
fe1.water(); // OK
c = fe1; // c = (Car)fe1; 자식타입 FireEngine에서 부모타입 Car로 형변환
c.water(); // Error!
fe2 = (FireEngine)c; // 부모타입 Car에서 자식타입 FireEngine으로 형변환
fe2.water(); // OK
instanceof 연산자
참조 변수가 참조하는 인스턴스의 실제 타입을 체크하는 데 사용하며 instanceof의 연산 결과가 true이면 해당 타입으로 형 변환이 가능하다.
- A instanceof B는 A가 가리키는 실제 객체가 B 또는 B의 자식 타입인지 확인하는 것이다.
class InstanceofTest{
FireEngine fe = new FireEngine();
if(fe instanceof FireEngine){
System.out.println("This is a FireEngine instance");
}
if(fe instanceof Car){
System.out.println("This is a Car instance");
}
if(fe instanceof Object){
System.out.println("This is a Object instance");
}
}
/*
결과
This is a FireEngine instance
This is a Car instance
This is a Object instance
*/
참조 변수와 인스턴스 변수의 연결
- 멤버 변수가 중복 정의된 경우 참조 변수의 타입에 따라 연결되는 멤버 변수가 달라진다.
- 메서드가 중복 정의된 경우 참조 변수와 상관없이 실제 인스턴스에 정의된 메서드가 호출된다.
class Parent{
int x = 100;
void method(){
System.out.println("This is Parent Method");
}
}
class Child extends Parent{
int x = 200;
void method(){ // 오버라이딩
System.out.println("This is Child Method");
}
}
Parent p = new Child(); // 다형성 - 부모타입의 참조변수로 자식타입의 객체를 다룰 수 있다.
Child c = new Child();
System.out.println(p.x); // 100 (멤버변수는 참조변수 타입에 영향을 받는다.)
p.method(); // This is Child Method
System.out.println(c.x); // 200
c.method(); // This is Child Method
매개변수의 다형성
참조형 매개변수는 메서드 호출 시 자신과 같은 타입 또는 자식 타입의 인스턴스를 넘겨줄 수 있다.
class Product{
int price;
}
class Tv extends Product{}
class Computer extends Product{}
class Audio extends Product{}
class Buyer{
int money = 1000;
void buy(Product p){ // 매개변수의 다형성
money = money - p.price;
}
// 매개변수의 다형성을 사용하지 않을 경우
// - 제품이 많아 질수록 계속 만들어줘야 하는 불편함이 있다.
void buy(Tv t){/* 내용 생략 */} // 오버로딩
void buy(Computer c){/* 내용 생략 */} // 오버로딩
void buy(Audio a){/* 내용 생략 */} // 오버로딩
}
Buyer b = new Buyer();
Product p1 = new Tv();
Product p2 = new Computer();
Product p3 = new Audio();
b.buy(p1);
b.buy(p2);
b.buy(p3);
여러 객체를 하나의 배열로 다루기
부모 타입의 배열을 만들면 각 요소에 자식의 객체를 담은 수 있다.
Product p1 = new Tv();
Product p2 = new Computer();
Product p3 = new Audio();
// 위에 코드를 배열로 만들어보자
Product p[] = new Product[3];
p[0] = new Tv();
p[1] = new Computer();
p[2] = new Audio();
'JAVA' 카테고리의 다른 글
[자바의 정석] 예외처리 (0) | 2022.10.19 |
---|---|
[자바의 정석] 추상클래스 인터페이스 내부클래스 정리 (0) | 2022.10.19 |
[자바의 정석] 상속 & 오버라이딩 & package & import (0) | 2022.10.17 |
[자바의 정석] 생성자 & 변수의 초기화 (0) | 2022.10.14 |
[자바의 정석] 변수와 메소드 & 메소드 오버로딩 & JVM 구조 (0) | 2022.10.14 |