class Exercise3_1 {
public static void main(String[] args){
int x = 2;
int y = 5;
char c = 'A'; // 'A'의 문자 코드는 65
System.out.println(1 + x << 33);
System.out.println(y >= 5 || x < 0 && x > 2);
System.out.println(y += 10 - x++);
System.out.println(x+=2);
System.out.println(!('A' <= c && c <= 'Z'));
System.out.println('C'-c);
System.out.println('5'-'0');
System.out.println(c+1);
System.out.println(++c);
System.out.println(c++);
System.out.println(c);
}
}
풀이
1. 1+2 (3를 33만큼 왼쪽으로 이동 -> (32+1bit)1번만 이동 0011 -> 0110 = 6 2. true || false && false = false 논리연산자 &&가 ||보다 우선순위가 더 높다 true || true = true 3. 15-2++ = 13 4. (2++) + 2 = 5 5. !(true && true) = false 6. 67-65 = 2 7. 5 8. 66 9. B 10. B 11. C
[3-2] 아래의 코드는 사과를 담는데 필요한 바구니(버켓)의 수를 구하는 코드이다. 만일 사과의 수가 123개이고 하나의 바구니에는 10개의 사과를 담을 수 있다면, 13개의 바구니가 필요할 것이다. (1)에 알맞은 코드를 넣으시오.
class Exercise3_2 {
public static void main(String[] args){
int numOfApples = 123; // 사과의 개수
int sizeOfBucket = 10;
// 바구니의 크기(바구니에 담을 수 있는 사과의 개수)
int numOfBucket = ( /*(1)*/ );
// 모든 사과를 담는데 필요한 바구니의 수
System.out.println("필요한 바구니의 수 :"+numOfBucket);
}
}
[3-3] 아래는 변수 num의 값에 따라 ‘양수’, ‘음수’, ‘0’을 출력하는 코드이다. 삼항 연산자를 이용해서 (1)에 알맞은 코드를 넣으시오. (삼항 연산자 2번 사용)
class Exercise3_3 {
public static void main(String[] args){
int num = 10;
System.out.println( /* (1) */ );
}
}
[실행결과]
양수
풀이
(num>0) ? "양수" : ((num<0) ? "음수" : '0')
[3-4] 아래는 변수 num의 값 중에서 백의 자리 이하를 버리는 코드이다. 만일 변수 num의 값이 ‘456’이라면 ‘400’이 되고, ‘111’이라면 ‘100’이 된다. (1)에 알맞은 코드를 넣으시오.
class Exercise3_4 {
public static void main(String[] args){
int num = 456;
System.out.println( /* (1) */ );
}
}
[실행결과]
400
풀이
(num/100)*100
[3-5] 아래는 변수 num의 값 중에서 일의 자리 1로 바꾸는 코드이다. 만일 변수 num의 값이 ‘333’이라면 ‘331’이 되고, ‘777’이라면 ‘771’이 된다. (1)에 알맞은 코드를 넣으시오.
class Exercise3_5 {
public static void main(String[] args){
int num = 333;
System.out.println( /* (1) */ );
}
}
[실행결과]
331
풀이
((num/10)*10)+1
[3-6] 아래는 변수 num의 값보다 크면서도 가장 가까운 10의 배수에서 변수 num의 값을 뺀 나머지를 구하는 코드이다. 예를 들어, 24의 크면서도 가장 가까운 10의 배수는 30이다. 19의 경우 20이고, 81의 경우 90이 된다. 30에서 24를 뺀 나머지는 6이기 때문에 변수 num의 값이 24라면 6을 결과로 얻어야 한다. (1)에 알맞은 코드를 넣으시오.
class Exercise3_6 {
public static void main(String[] args){
int num = 24;
System.out.println( /* (1) */ );
}
}
[실행결과]
6
풀이
(((num/10)+1)*10) - num
[3-7] 아래는 화씨(Fahrenheit)를 섭씨(Celsius)로 변환하는 코드이다. 변환공식이 ‘C’ = 5/9 x (F - 32)’ 라고 할 때, (1)에 알맞은 코드를 넣으시오. 단, 변환 결과값은 소수점 셋째자리에서 반올림해야한다. (Math.round()를 사용하지 않고 처리할 것)
class Exercise3_7 {
public static void main(String[] args){
int fahrenheit = 100;
float celcius = ( /* (1) */ );
System.out.println("Fahrenheit:"+fahrenheit);
System.out.println("Celcius:"+celcius);
}
}
[3-10] 다음은 대문자를 소문자로 변경하는 코드인데, 문자 ch에 저장된 문자가 대문자인 경우에만 소문자로 변경한다. 문자코드는 소문자가 대문자보다 32만큼 더 크다. 예를들어 ‘A’의 코드는 65이고, ‘a’의 코드는 97이다. (1)~(2)에 알맞은 코드를 넣으시오.
[2-8] 참조형 변수(reference type)와 같은 크기의 기본형(primitive type)은? (모두 고르시오)
int
long
short
float
double
풀이
참조형 변수는 64bit JVM을 사용하면 8byte : double
32bit JVM을 사용하면 4byte : int, float
[2-9] 다음 중 형 변환을 생략할 수 있는 것은? (모두 고르시오)
byte b = 10;
char ch = 'A;
int i = 100;
long l = 1000L;
a. b = (byte)i;
b. ch = (char)b;
c. shrot s = (short)ch;
d. float f = (flaot)l;
e. i = (int)ch;
풀이
int(4) → byte(1) 크기가 작기 때문에 불가능
byte(1) → char(2) 음수는 변환 불가능
char(2) → short(2) 크기는 같지만, 음수 변환 불가능
long(8) → float(4) 크기가 작아서 실수 생략 가능하므로 가능
char(2) - int(4) 가능
[2-10] char 타입의 변수에 저장될 수 있는 정수 값의 범위는? (10진수로 적으시오)
풀이
0~65536 = 2^16-1
[2-11] 다음 중 변수를 잘못 초기화 한 것은? (모두 고르시오)
a. byte b = 256;
b. char c = '';
c. char answer = 'no';
d. float f = 3.14
e. double d = 1.4e3f;
풀이
byte : -128~127 불가능
char : 한개의 문자가 아니라 불가능
char : 두개의 문자 불가능
float : 리터럴 뒤에 f가 오지 않아서 불가능
[2-12] 다음 중 main 메서드의 선언부로 알맞은 것은? (모두 고르시오)
a. public static void main(String[] args)
b. public static void main(String args[])
c. public static void main(String[] arv)
d. public void static main(String[] args)
e. static public void main(String[] args)
풀이
a, b, c, e
[2-13] 다음 중 타입과 기본값이 잘못 연결된 것은? (모두 고르시오)
a. boolean - false
b. char - '\\u0000' // 16진수 저장
c. float - 0.0
d. int - 0
e. long - 0
f. String - ""
객체(Object) : 물리적으로 존재하거나 추상적으로 생각할 수 있는 것 중에서 자신의 속성을 가지고 있고, 다른 것과 식별 가능한 것.
속성 = 필드(field)
동작 = 메소드(method) : 객체들 사이의 상호작용 수단은 메소드
객체 모델링(Object Modeling) : 현실 세계의 객체를 소프트웨어 객체로 설계하는 것
메소드 호출 : 객체가 다른 객체의 기능을 이용하는 것
객체 간의 관계 : 집합 관계, 사용 관계, 상속 관계
[객체 간의 관계]
객체 지향 프로그래밍의 특징
캡슐화(Encapsulation)
객체의 필드, 메소드를 하나로 묶고, 실제 구현 내용을 감추는 것
외부 객체는 객체의 내부 구조를 알 수 없다.
자바 언어는 캡슐화된 멤버를 노출시킬 것인지, 숨길 것인지 접근 제한자(Access Modifier) 사용
상속(Inheritance)
부모가 가지고 있는 재산을 자식에게 물려주는 것
코드의 중복 최소화 가능
유지 보수 시간 최소화
다형성(Polymorphism)
같은 타입이지만 실행 결과가 다양한 객체를 이용할 수 있는 성질
자바는 다형성을 위해 부모 클래스 또는 인터페이스의 타입 변환을 허용
부모 타입에는 모든 자식 객체 대입 가능
인터페이스 타입에는 모든 구현 객체가 대입 가능
다형성으로 인해 객체는 부품화가 가능
객체와 클래스
현실에서 객체는 설계도를 바탕으로 만들어진다.
자바에서의 설계도는 클래스(class)이다.
클래스(class)
객체를 생성하기 위한 필드와 메소드가 정의되어 있다.
클래스로부터 만들어진 객체를 해당 클래스의 인스턴스(instance)라고 한다.
인스턴스화 : 클래스로부터 객체를 만드는 과정
객체지향 프로그래밍 개발 3단계
클래스 설계
설계된 클래스를 가지고 사용할 객체 생성
생성된 객체 사용
클래스 선언
클래스 이름은 자바의 식별자 작성 규칙을 따른다.
일반적으로 소스 파일당 동일한 이름의 하나의 클래스를 선언한다.
두 개 이상도 가능하지만, 컴파일을 하면 바이트 코드 파일은 클래스를 선언한 개수만큼 생기기 때문에, 파일 이름과 일치하지 않는 클래스 선언에 public 접근 제한자를 붙이면 컴파일 에러가 발생한다.
[자바의 식별자 작성 규칙]
객체 생성과 클래스 변수
new 연산자
클래스로부터 객체를 생성하는 방법.
연산자 뒤에 생성자가 온다.
new 연산자로 생성된 객체는 메모리 힙(heap) 영역에 생성된다.
힙 영역에 객체를 생성시킨 후, 객체의 주소를 리턴한다.
클래스 변수 = new 클래스();
[new 연산자 사용 후 메모리 구조]
클래스의 2가지 용도
라이브러리(API)용 : 다른 클래스에서 이용할 목적으로 설계
실행용 : main() 메소드를 제공하는 역할
프로그램을 하나의 클래스로 구성할 수 있지만, 객체 지향 프로그램은 대부분 라이브러리와 실행 클래스가 분리되어 있다.
public class studnet { // 라이브러리 클래스
}
public class StudentExample { // 실행 클래스
public static void main(String[] args){
...
}
}
클래스의 구성 멤버
필드(Field)
객체의 데이터가 저장되는 곳
변수와 비슷하지만. 변수는 생성자와 메소드 내에서만 사용되고 생성자는 메소드가 실행 종료되면 자동 소멸한다. 하지만 필드는 메소드 전체에서 사용되고, 객체가 소멸되지 않으면 객체와 함께 존재한다.
생성자(Constructor)
객체 생성 시 초기화 역할 담당
생성자는 메소드와 비슷하지만, 클래스 이름으로 되어 있고, 리턴 타입이 없다.
생성자가 성공적으로 실행되면 힙(heap) 영역에 객체가 생성되고 객체의 주소가 리턴된다.
모든 클래스는 생성자가 반드시 존재한다.
기본 생성자
중괄호 블록 내용이 비어있는 기본 생성자. 클래스 내부에 생성자 선언을 생략하면 컴파일러가 자동으로 추가한다.
클래스에 생성자를 선언하지 않아도 new 연산자 뒤에 기본 생성자를 호출해서 객체 생성이 가능하다.
[기본 생성자 자동 생성][기본 생성자로 객체 생성 가능]
메소드(Method)
객체의 동작에 해당하는 실행 블록
객체 간의 데이터 전달 수단
public class ClassName{
int fieldName; // 필드
ClassName() {...} // 생성자
void methodName() {...} // 메소드
}
외부 클래스에서 Car 필드 값 읽기와 변경
public class Car {
// 필드
String company = "현대자동차";
String model = "그랜저";
String color = "검정";
int maxSpeed = 350;
int speed;
}
public class CarExample {
public static void main(String[] args){
// 객체 생성
// 다른 클래스의 필드 값을 사용하기 위해서는 다른 클래스의 객체를 생성해야한다.
Car myCar = new Car();
// 필드 값 읽기
System.out.println("제작회사 " + myCar.company);
System.out.println("모델명 " + myCar.model);
System.out.println("색깔 " + myCar.color);
System.out.println("최고속도 " + myCar.maxSpeed);
System.out.println("현재속도 " + myCar.speed);
// 필드 값 변경
myCar.speed = 60;
System.out.println("수정된 속도 " + myCar.speed);
}
}
기본 생성자 대신 명시적 생성자 선언
명시적 생성자의 매개 변수는 new 연산자로 생성자를 호출할 때 외부의 값을 생성자 블록 내부로 전달한다.
public class Car {
// 생성자
Car(String color, int cc) {
}
}
public class CarExample {
public static void main(String[] args){
Car myCar = new Car("검정", 3000);
// Car myCar new Car();
// 생성자가 명시적으로 선언되어 있을 경우 기본 생성자 호출이 불가능
}
}
필드 초기화
클래스로부터 객체가 생성될 때, 필드는 기본 초기 값으로 자동 설정
다른 값으로 초기화하는 2가지 방법
필드를 선언할 때 초기값을 준다.
생성자에서 초기값을 준다. (객체 생성 시점에 외부에서 제공되는 다양한 값들로 초기화될 경우)
public class Korean {
// 필드
String nation = "대한민국"; // 필드에서 초기화
String name;
String ssn;
// 생성자
// 생성자에서 초기화
public Korean(String n, String s) {
name = n;
ssn = s;
}
}
생성자의 매개 변수 이름은 필드와 동일한 이름을 갖는 매개 변수를 사용한다. 그렇게 되면 필드와 매개 변수 이름이 동일하기 때문에 생성자 내부에서 해당 필드에 접근이 불가능하다. (매개 변수가 사용 우선순위가 높기 때문)
public class Car {
// 필드
String company = "현대자동차";
String model;
String color;
int maxSpeed;
// 생성자
Car(){
}
Car(String model) {
this(model, "은색", 250); // 맨 아래 생성자 호출
}
Car(String model, String color) {
this(model, color, 250); // 맨 아래 생성자 호출
}
Car(String model, String color, int maxSpeed){
this.model = model;
this.color = color;
this.maxSpeed = maxSpeed;
}
}
메소드
메소드 : 객체의 동작에 해당하는 중괄호 블록
리턴타입, 메소드이름, 매개변수선언
시그너처(signature) : 메소드 선언부
메소드 이름은 자바 식별자 규칙에 맞게 사용한다.
소문자로 작성, 단어의 첫머리는 대문자
public class Caculator {
// 메소드
void powerOn(){
System.out.println("전원을 켭니다.");
}
int plus(int x, int y){
int result = x + y;
return result;
}
}
public class CaculratorExample {
public static void main(String[] args){
Caculator myCalc = new Caculator();
myCalc.powerOn(); // 메소드 호출
int result1 = myCalc.plus(5, 6);
System.out.println(result1);
}
}
매개 변수의 수를 모를 경우 : 매개 변수를 배열 타입으로 선언한다.
public class Computer {
// 첫번째 방법 생성자
int sum1(int[] values){
int sum = 0;
for(int i=0; i<values.length; i++){
sum += values[i];
}
return sum;
}
// 두번째 방법 생성자
int sum2(int ... values) {
int sum = 0;
for (int i = 0; i < values.length; i++) {
sum += values[i];
}
return sum;
}
}
public class ComputerExample {
public static void main(String[] args){
Computer myCom = new Computer(); // 객체 생성
int[] values1 = {1, 2, 3};
int result1 = myCom.sum1(values1);
System.out.println(result1);
int result2 = myCom.sum1(new int[] {1,2,3,4,5});
System.out.println(result2);
int result3 = myCom.sum2(1, 2, 3);
System.out.println(result3);
}
}
클래스 로더가 클래스(바이트 코드)를 로딩해서 메소드 메모리 영역에 적재할 때 클래스별로 관리된다.
클래스 이름으로 접근할 수 있다. 객체 참조 변수로도 가능하지만, 사용 시 경고 표시가 나타난다.
정적 필드는 필드 선언과 동시에 초기 값을 주는 것이 보통이지만, 계산이 필요한 경우 정적 블록을 사용한다.
public class Television {
static String company = "Samsung"; // 보통 필드에서 초기값 결정
static String model = "LCD";
static String info;
static { // 정적 블록 사용
info = company + "_" + model;
}
}
클래스 내부에서 new 연산자로 생성자 호출이 가능하기 때문에, 정적 필드도 private 접근 제한자를 붙인다.
외부에서 호출할 수 있도록, 정적 메소드인 getInstance()를 선언하고, 정적 필드에서 참조하고 있는 자신의 객체를 리턴해준다.
public class Singleton {
// private + 정적 필드
private static Singleton singleton = new Singleton();
// private + 생성자
private Singleton(){}
// private + 정적 메소드
static Singleton getInstance(){
return singleton;
}
}
// 외부에서 객체를 얻는 유일한 방법
public class SingleExample(){
public static void main(String[] args){
Singleton obj = Singleton.getInstance();
}
}
final 필드와 상수
final 필드
초기 값이 저장되면 이것이 최종적인 값이 되어서 프로그램 실행 도중에 수정할 수 없다.
final 필드 초기값 주는 2가지 방법
필드 선언 시에 준다.
생성자에서 준다.
public class Person {
final String nation = "Korea"; // 수정 불가
final String ssn;
String name;
public Person(String ssn, String name){
this.ssn = ssn;
this.name = name;
}
}
상수(static final)
변하지 않는 값
final 필드는 객체마다 저장되고, 생성자의 매개값을 통해서 여러 가지 값을 가질 수 있기 때문에 상수가 될 수 없다.
상수는 static + final
상수 이름은 모두 대문자
public class Earth {
static final double EARTH_RADIUS = 6400;
static final double EARTH_SURFACE_AREA;
static {
EARTH_SURFACE_AREA = 4 * Math.PI * EARTH_RADIUS * EARTH_RADIUS;
}
}
패키지(Package)
클래스를 체계적으로 관리하기 위해서 사용
패키지의 물리적 형태는 파일 시스템의 폴더
클래스를 식별해준다.
상위패키지.하위패키지.클래스
package 상위패키지.하위패키지;
모두 소문자로 작성
중복되지 않도록 보통 회사의 도메인 이름으로 패키지 작성
패키지 폴더를 자동으로 생성하려면 javac 명령어 다음 -d 옵션을 추가해 패키지가 생성될 경로를 지정해줘야한다.
javac -d 경로
import문
다른 패키지에 속하는 클래스를 사용할 수 있는 방법
* 은 패키지에 속하는 모든 클래스
import 문으로 지정된 패키지의 하위 패키지는 import 대상이 아니다.
접근 제한자(Access Modifier)
객체 생성을 막기 위해 생성자를 호출하지 못하게 하거나 객체의 특정 데이터를 보호하기 위해서 해당 필드에 접근하지 못하도록 막아준다.
public, protected, default, private
클래스에 적용할 수 있는 접근 제한 : public, default
[접근 제한자 종류]
Getter와 Setter 메소드
객체 지향 프로그래밍에서는 객체의 무결성을 유지하기 위해, 외부의 직접적 접근을 막는다.
메소드를 통해 데이터를 변경하는 방법을 선호한다.
Setter : 검증을 통해 유효한 값만 데이터로 저장 가능 (ex. 음수 검증)
Getter : 객체 외부에서 객체 필드값을 사용하기 부적절한 경우, 메소드에서 필드 값 가공 후 외부로 전달
private 타입 fieldName;
// Getter
public 리턴타입 getFieldName(){
return fieldName;
}
// Setter
public void setFieldName(타입 fieldName){
this.fieldName = fieldName;
}
어노테이션(Annotation)
메타데이터(metadata)라고 볼 수 있다.
애플리케이션에서 처리해야 하는 데이터가 아니라, 컴파일 과정과 실행 과정에서 코드를 어떻게 컴파일하고 처리할 것인지 알려주는 정보
어노테이션의 3가지 용도
컴파일러에게 코드 문법 에러를 체크하도록 정보 제공
대표적인 예시 : @Override (메소드가 오버라이드된 것인지 컴파일러에게 알려주고, 제대로 되지 않았으면 에러 발생)
소프트웨어 개발 툴이 빌드나 배치 시 코드를 자동으로 생성할 수 있도록 정보 제공
실행 시 특정 기능을 실행하도록 정보 제공
어노테이션 타입 정의 방법
public @interface AnnotationName {}
엘리먼트(element)를 멤버로 가질 수 있다.
타입 element() [default 값];
엘리먼트 타입 : int, double, String, 열거, Class 타입 등등
어노테이션 타입 적용 방법
@AnnotationName
어노테이션 적용 대상 : java.lang.annotation.ElementType 열거 상수로 정의