* 레퍼런스와 인스턴스
Java에서 레퍼런스(reference)는 객체를 가리키는 변수를 의미하며,
인스턴스(instance)는 클래스로부터 생성된 실제 객체를 의미한다.
레퍼런스를 통해 인스턴스에 접근하고 해당 인스턴스의 상태를 변경하거나 메소드를 호출할 수 있다.
이러한 개념은 객체 지향 프로그래밍에서 중요하며,
Java에서는 이를 활용하여 유연하고 모듈화된 코드를 작성할 수 있다.
* 레퍼런스와 인스턴스 - 예시
public class Person {
private String name;
private int age;
public Person(String name, int age) {
this.name = name;
this.age = age;
}
public void introduce() {
System.out.println("안녕하세요, 저는 " + name + "이고, " + age + "살입니다.");
}
}
public class Main {
public static void main(String[] args) {
// Person 클래스의 인스턴스 생성
Person person1 = new Person("Alice", 25);
// 레퍼런스를 통해 인스턴스에 접근하여 메소드 호출
person1.introduce(); // Output: 안녕하세요, 저는 Alice이고, 25살입니다.
// 또 다른 Person 클래스의 인스턴스 생성
Person person2 = new Person("Bob", 30);
// 레퍼런스를 통해 다른 인스턴스에도 접근 가능
person2.introduce(); // Output: 안녕하세요, 저는 Bob이고, 30살입니다.
}
}
클래스, 인스턴스 변수, 메소드에 대한 정리:
클래스: 클래스는 객체 지향 프로그래밍에서 객체를 생성하기 위한 템플릿이며, 객체의 속성과 동작을 정의합니다.
Person 클래스: 사람을 나타내는 클래스
인스턴스 변수: 인스턴스 변수는 클래스 내에서 선언된 변수로서, 각각의 인스턴스에 고유한 값을 가지며 객체의 상태를 나타냅니다.
name: 문자열 타입의 변수로, 사람의 이름을 저장합니다.
age: 정수 타입의 변수로, 사람의 나이를 저장합니다.
메소드: 메소드는 클래스 내에서 정의된 동작을 수행하는 코드 블록으로서, 객체의 동작을 나타냅니다.
Person 클래스의 생성자: name과 age를 매개변수로 받아 인스턴스를 초기화하는 생성자입니다.
introduce() 메소드: "안녕하세요, 저는 [name]이고, [age]살입니다."와 같은 인사말을 출력하는 메소드입니다.
위의 예시 코드에서 Person 클래스는 사람을 나타내는 클래스이다.
Person 클래스는 name과 age라는 인스턴스 변수를 가지고 있으며, introduce()라는 메소드를 가지고 있다.
Main 클래스의 main 메소드에서는 Person 클래스의 인스턴스를 생성하고,
레퍼런스를 통해 해당 인스턴스에 접근하여 메소드를 호출한다.
이를 통해 레퍼런스를 통해 인스턴스에 접근하고 해당 인스턴스의 상태를 변경하거나
메소드를 호출할 수 있음을 확인할 수 있다.
실행 결과로는 각 인스턴스의 introduce() 메소드가 호출되어 해당 인스턴스의 정보가 출력된다.
* Garbage
인스턴스 주소를 잃어버리면 접근할 수 없으며 사용할 수 없고 용량만 차지한다.
즉 이것을 Garbage 라고 부른다.
가비지는 JVM의 보조 프로세스(스레드)인 가비지 컬렉처가 해제시킨다.
Garbage Collector가 언제 Garbage를 해제시키는가 ?
① Heap 메모리가 부족할 때 Gargage 를 찾아서Heap 영역에서 제거시킨다.
② 또는 JVM이 한가할 때도 제거시킨다.
이는 자바의 주요 장점 중 하나이다.
가비지 컬렉터는 자원 관리의 부담을 덜어주고, 메모리 누수(memory leak)와 같은 문제를 방지하여
안정적인 애플리케이션 실행 환경을 제공해준다.
* dangling pointer (C언어)
C언어는 즉시 Garbage를 제거하는 명령어가 있다.
Java에서 gc()가 있지만 이것은 가비지 콜렉터에게 사용되지 않은 오브젝트를 recycling 하는데
더 노력하게 만드는 ge method를 JVM에 제안하는 것이다.
이것은 반드시 recycling 하는 결과를 보장하지는 않는다.
* 변수의 종류
* Wrapper 클래스
primitive 타입의 값을 더 정교하게 다룰 수 있는 도구
클래스 = function 묶음 = method 묶음
* 리터럴의 연산결과와 값 할당
byte b = 4 + 5
가능하다.
int a = 4
int c = 5
byte b = a + c
불가능하다.
컴파일러는 실행을 하는 것이 아니기때문에
연산과정만을 살펴보고 byte에 int 값 연산결과를 출력하려하기 때문에 불가능하다.
byte = 1 byte , int = 4 byte
* 형변환 type type casing
* 같은 타입끼리만 연산이 가능하다 !
* 또한 명시적 형병환을 해주면 나머지 대상에는 암시적 형변환이 된다.
r = i / (float) j ;
=> (float) r = (float) i / (float) j
int i = 5;
int j = 2;
float r = i/j; → 2.0 (int 의 연산이기때문에 2.5에서 정수로 변환되어 2가 출력된다.)
r = (float)i/(float)j; → 2.5
* 암시적 형변환 규칙
byte (1byte)
short (2byte) → int → long → float → double → boolean
char (2byte) (4byte) (8byte) (4byte) (8byte) (1byte)
연산 우선순위에 따라 암시적 형변환을 해야한다.
* 증감 연산자
int i = 100;
① i = i + 1;
② i += 1; 컴파일 → i = i+1;
③ i ++; 컴파일 → i = i+1;
int a = 100;
System.out.println(a);
https://dev-with-gpt.tistory.com/96
* 산술 연산자
Exam0120 - 산술연산자 : 우선순위
//산술 연산자 : 우선 순위
// 괄호를 먼저하고, 곱셉,나눕셈을 우선순위로. 더하기 빼기는 그 다음 우선순위이다.
// 같은 우선순위끼리는 실행 순서를 따른다.
package bitcamp.ex05;
//# 산술 연산자 : 우선 순위
// 괄호를 먼저하고, 곱셉,나눕셈을 우선순위로. 더하기 빼기는 그 다음 우선순위이다.
// 같은 우선순위끼리는 실행 순서를 따른다.
public class Exam0120 {
public static void main(String[] args) {
// *, /, % 는 +, - 보다 먼저 계산된다.
System.out.println(2 + 3 * 7); // 3 * 7을 먼저 수행한다.
System.out.println(3 * 7 + 2); // 3 * 7을 먼저 수행한다.
// 같은 우선순위에서는 먼저 나온 것을 먼저 계산한다.
System.out.println(3 * 8 / 2); // 3 * 8을 먼저 계산
System.out.println(8 / 2 * 3); // 8 / 2를 먼저 계산
// 같은 우선순위의 연산자는 실행 순서가 바뀌더라도 상관없다.
// 강제로 실행 순서를 바꾸고 싶다면
// 괄호()를 묶어라!
System.out.println((2 + 3) * 7); // = 35
}
}
/*
# 연산자 우선 순위
괄호: ()
후위 연산자: a++, a--
전위 연산자: ++a, --a, 단항 연산자(+, -)
*, /, %
+, -
비트이동 연산자: <<, >>, >>>
관계 연산자: <, >, <=, >=, instanceof
등위 연산자: ==, !=
&
^
|
논리 연산자 AND: &&
논리 연산자 OR: ||
삼항 연산자: (조건) ? 값 : 값
할당 연산자: =, +=, -=, *=, /=, %=, &=, ^=, |=, <<=, >>=, >>>=
*/
Exam0130 - 산술연산자 : 기본 연산 단위
//산술 연산자 : 기본 연산 단위
// byte b; 일때, b = 5+6은 된다.
// byte x = 5, byte y = 6 일때.
// b = x+y는 안된다. 왜냐하면 컴파일 단계에서 임시 4바이트 정수 메모리를 만들어
// 값을 담으려하기 때문이다. 때문에 정수를 다룰 때는 그냥 int를 사용하자 !
package bitcamp.ex05;
//# 산술 연산자 : 기본 연산 단위
//
public class Exam0130 {
public static void main(String[] args) {
byte b;
b = 5; // OK!
b = 6; // OK!
// - 리터럴 5, 6은 4바이트 정수 값이다.
// - 정수 리터럴은 기본이 4바이트 크기이지만,
// - byte 변수에 저장할 수 있다면 허락한다!
b = 5 + 6; // OK!
// - 리터럴끼리 산술 연산한 결과도 리터럴로 간주한다.
// - 그 결과 값이 변수의 범위 내의 값이면 허락한다.
System.out.println(b);
// - 이유? 리터럴 값은 컴파일 단계에서 그 값이 얼마인지 확인할 수 있기 때문이다.
// - 변수의 경우는 컴파일 단계에서 값을 확인할 수 없다.
byte x = 5, y = 6, z;
z = x; // OK!
z = y; // OK!
// z = x + y; // 컴파일 오류!
//
// "자바의 정수 연산은 최소 단위가 4바이트이다."
// "그래서 byte나 short의 연산 단위가 기본으로 4바이트이다."
//
// - 자바는 정수 변수에 대해 산술 연산을 수행할 때,
// 그 변수의 값이 4바이트 보다 작다면(byte나 short 라면),
// 4바이트로 만들어 연산을 수행한다.
// - 즉 임시 4바이트 정수 메모리를 만든 다음에
// 그 메모리에 값을 담은 후에 연산을 수행한다.
// - 따라서 x + y는 바로 실행하지 않고
// 임의의 4바이트 정수 메모리를 만든 다음에
// 그 메모리에 x와 y 값을 넣고 연산을 수행한다.
// - 연산 결과도 당연히 4바이트이다.
// 그래서 4바이트 값을 1바이트 메모리에 넣지 못하기 때문에
// 컴파일 오류가 발생하는 것이다!
// short도 마찬가지이다.
short s1 = 5;
short s2 = 6;
short s3;
s3 = s1; // OK!
s3 = s2; // OK!
// s3 = s1 + s2; // 컴파일 오류!
int s4 = s1 + s2;
System.out.println(s4);
// 이유?
// - byte 경우와 마찬가지고 short 메모리의 값을 직접 연산할 수 없다.
// - 임시 4바이트 메모리를 만든 다음에 그 메모리에 값을 저장한 후
// 연산을 수행한다.
// - 당연히 그 연산 결과를 담은 메모리도 4바이트이기 때문에
// short(2byte) 메모리에 저장할 수 없는 것이다.
}
}
// 결론!
// - 숫자의 크기에 상관없이 작은 숫자를 다루더라도
// 정수를 다룰 때는 그냥 int를 사용하라!
// - byte는 보통 파일의 데이터를 읽어 들일 때 사용한다.
Exam0143 - 산술연산자 : 연산의 결과 타입
//산술 연산자 : 연산의 결과 타입
// flaot 의 값을 연산하는 경우 기존 값이 유효자릿수라 하더라도 연산 결과가
// 유효자릿수가 아니라면 값이 잘리거나 반올림이 된다.
// 또한 연산결과를 double로 주어도 연산결과 자체가 이미 float이미 때문에
// 값이 변동된다. 때문에 기존 연산 과정에서부터 double을 주어야 한다.
// double d1 = 987.6543;
double d2 = 1.111111;
double r5 = d1 + d2; // = 988.765411
package bitcamp.ex05;
//# 산술 연산자 : 연산의 결과 타입
//
public class Exam0143 {
public static void main(String[] args) {
float f1 = 987.6543f;
float f2 = 1.111111f;
System.out.println(f1);
System.out.println(f2);
float r1 = f1 + f2;
// f1과 f2에 들어 있는 값이 유효자릿수라 하더라도
// 연산 결과가 유효자릿수가 아니라면 값이 잘리거나 반올림 된다.
// => float과 float의 연산 결과는 float이기 때문이다.
// 987.6543
// + 1.111111
// ---------------
// 988.765411 <=== float의 유효자릿수인 7자리를 넘어간다.
// 988.7654 <=== 유효자릿수를 넘어가는 수는 짤린다.
System.out.println(r1);
// 기대값: 987.6543 + 1.111111 = 988.765411
// 결과값: 988.7654
// 결과가 옳지 않게 나온 이유?
// => float과 float의 연산 결과는 float이다.
// => 그래서 메모리 크기를 넘어가는 뒤의 11은 짤린다.
// 그럼 결과를 담을 변수의 크기를 늘리면 되는가?
double r2 = f1 + f2;
System.out.println(r2);
// 기대값: 988.765411
// 결과값: 988.765380859375
// 기대한 결과가 나오지 않은 이유?
// => float과 float의 연산 결과는 float이다.
// => double 변수에 저장하기 전에 이미 float 값이 되면서 일부 값이 왜곡되었다.
// 그런데 r1 변수와 달리 뒤에 이상한 숫자가 많이 붙는 이유는 무엇인가?
// => IEEE 754의 이진수 변환 문제때문이다.
// => 4바이트 float 부동소수점을 8바이트 double 부동소수점 변수에 저장할 때
// 왜곡된 값이 들어 갈 수 있다.
// => float을 double 변수에 넣을 때 왜곡이 발생하기 때문에
// 가능한 double 변수로 값을 바꾼 다음에 연산을 수행하라.
// 더 좋은 것은 처음부터 double 변수를 사용하라!
// 다음과 같이 처음부터 double 변수를 사용하라!
double d1 = 987.6543;
double d2 = 1.111111;
double r5 = d1 + d2; // = 988.765411
System.out.println(r5);
// 그럼에도 실제 출력해보면 맨 뒤에 극한의 작은 수가 붙는다.
// 이유? IEEE 754 이진수 변환 문제이다. 고민하지 말라!
// 어떻게 처리할 건데? 맨 뒤에 붙은 극한의 작은 수는 그냥 잘라 버린다.
}
}
// 정리!
// - int와 int의 연산 결과는 int이다.
// - float과 float의 연산 결과는 float이다.
// - 즉 연산 결과는 피연산자의 타입과 같다.
// - 그래서 두 값을 계산했을 때 결과 메모리를 초과할 경우
// 값이 짤릴 수 있다.
// 주의하라!
// - 코드를 작성할 때 피연산자의 계산 결과가 피연산자의 메모리 크기를
// 벗어날 가능성이 있다면,
// 처음부터 피연산자의 값을 더 큰 메모리에 담아서 연산을 수행하라!
//
//
// 형변환(type casting=type conversion)?
// - 변수나 리터럴을 다른 타입의 값을 바꾸는 것이다.
// - 주의!
// 원래 변수의 타입을 바꾸는 것이 아니다.
// 내부적으로는 변수에 들어 있는 값을 꺼내
// 지정된 타입의 임시 메모리를 만들어 저장한다.
//
// 결론!
// 1) 자바의 최소 연산 단위는 int이다.
// 따라서 int 보다 작은 크기의 메모리 값을 다룰 때는
// 내부적으로 int로 자동 형변환을 수행한 다음에 연산을 수행한다.
// 내부적으로 자동 형변환하는 것을
// "암시적 형변환(implicit type conversion)"이라 부른다.
// => byte + byte = int
// => short + short = int
// => byte + short = int
//
// 2) 연산 결과는 항상 피연산자의 타입과 같다.
// => int + int = int
// => long + long = long
// => float + float = float
// => double + double = double
//
// 3) 다른 타입과 연산을 수행할 때는
// 내부적으로 같은 타입으로 맞춘 다음에 실행한다.
Exam0150 - 산술연산자 : 암시적 형변환
// 산술연산자 : 암시적 형변환
// - 연산은 항상 같은 타입끼리만 가능하다.
// - 다른 타입끼리 연산을 할 때는 둘 중 한개의 타입을 다른 타입을
// 바꿔야 한다.
// - 타입을 바꾸는 것을 내부적인 규칙에 따라 자동으로 처리한다고 해서
// "암시적 형변환(implicit type conversion)"이라 부른다.
// - 암시적 형변환 규칙
// 다음과 같이 오른쪽 타입의 값으로 자동 변환시킨다.
// byte,short,char => int => long => float => double
package bitcamp.ex05;
//# 산술 연산자 : 연산의 결과 타입
//
public class Exam0143 {
public static void main(String[] args) {
float f1 = 987.6543f;
float f2 = 1.111111f;
System.out.println(f1);
System.out.println(f2);
float r1 = f1 + f2;
// f1과 f2에 들어 있는 값이 유효자릿수라 하더라도
// 연산 결과가 유효자릿수가 아니라면 값이 잘리거나 반올림 된다.
// => float과 float의 연산 결과는 float이기 때문이다.
// 987.6543
// + 1.111111
// ---------------
// 988.765411 <=== float의 유효자릿수인 7자리를 넘어간다.
// 988.7654 <=== 유효자릿수를 넘어가는 수는 짤린다.
System.out.println(r1);
// 기대값: 987.6543 + 1.111111 = 988.765411
// 결과값: 988.7654
// 결과가 옳지 않게 나온 이유?
// => float과 float의 연산 결과는 float이다.
// => 그래서 메모리 크기를 넘어가는 뒤의 11은 짤린다.
// 그럼 결과를 담을 변수의 크기를 늘리면 되는가?
double r2 = f1 + f2;
System.out.println(r2);
// 기대값: 988.765411
// 결과값: 988.765380859375
// 기대한 결과가 나오지 않은 이유?
// => float과 float의 연산 결과는 float이다.
// => double 변수에 저장하기 전에 이미 float 값이 되면서 일부 값이 왜곡되었다.
// 그런데 r1 변수와 달리 뒤에 이상한 숫자가 많이 붙는 이유는 무엇인가?
// => IEEE 754의 이진수 변환 문제때문이다.
// => 4바이트 float 부동소수점을 8바이트 double 부동소수점 변수에 저장할 때
// 왜곡된 값이 들어 갈 수 있다.
// => float을 double 변수에 넣을 때 왜곡이 발생하기 때문에
// 가능한 double 변수로 값을 바꾼 다음에 연산을 수행하라.
// 더 좋은 것은 처음부터 double 변수를 사용하라!
// 다음과 같이 처음부터 double 변수를 사용하라!
double d1 = 987.6543;
double d2 = 1.111111;
double r5 = d1 + d2; // = 988.765411
System.out.println(r5);
// 그럼에도 실제 출력해보면 맨 뒤에 극한의 작은 수가 붙는다.
// 이유? IEEE 754 이진수 변환 문제이다. 고민하지 말라!
// 어떻게 처리할 건데? 맨 뒤에 붙은 극한의 작은 수는 그냥 잘라 버린다.
}
}
// 정리!
// - int와 int의 연산 결과는 int이다.
// - float과 float의 연산 결과는 float이다.
// - 즉 연산 결과는 피연산자의 타입과 같다.
// - 그래서 두 값을 계산했을 때 결과 메모리를 초과할 경우
// 값이 짤릴 수 있다.
// 주의하라!
// - 코드를 작성할 때 피연산자의 계산 결과가 피연산자의 메모리 크기를
// 벗어날 가능성이 있다면,
// 처음부터 피연산자의 값을 더 큰 메모리에 담아서 연산을 수행하라!
//
//
// 형변환(type casting=type conversion)?
// - 변수나 리터럴을 다른 타입의 값을 바꾸는 것이다.
// - 주의!
// 원래 변수의 타입을 바꾸는 것이 아니다.
// 내부적으로는 변수에 들어 있는 값을 꺼내
// 지정된 타입의 임시 메모리를 만들어 저장한다.
//
// 결론!
// 1) 자바의 최소 연산 단위는 int이다.
// 따라서 int 보다 작은 크기의 메모리 값을 다룰 때는
// 내부적으로 int로 자동 형변환을 수행한 다음에 연산을 수행한다.
// 내부적으로 자동 형변환하는 것을
// "암시적 형변환(implicit type conversion)"이라 부른다.
// => byte + byte = int
// => short + short = int
// => byte + short = int
//
// 2) 연산 결과는 항상 피연산자의 타입과 같다.
// => int + int = int
// => long + long = long
// => float + float = float
// => double + double = double
//
// 3) 다른 타입과 연산을 수행할 때는
// 내부적으로 같은 타입으로 맞춘 다음에 실행한다.
Exam0150 - 산술연산자 : 명시적 형변환
// 산술연산자 : 명시적 형변환
// => 큰 메모리의 값을 작은 메모리에 넣으려고 형변환을 사용하기도 하는데
// 다만 형변환하더라도(즉 작은 메모리에 넣더라도) 값이 잘리지 않을 때만 하라!
// => 형변환하더라도 값이 소실되지 않을 때만 "명시적 형변환"을 지시하라!
package bitcamp.ex05;
//# 산술 연산자 : 명시적 형변환
//
public class Exam0170 {
public static void main(String[] args) {
byte b;
// 4바이트 크기를 갖는 정수 리터럴을 byte 변수에 저장할 수 없다.
// b = 259; // 컴파일 오류!
// 저장하고 싶다면 형변환(type casting)을 명시적으로 지정하라!
// => 단 메모리에 들어가기에 큰 값이라면 형변환할 때 값이 잘린다.
b = (byte)259;
// int(4 byte) => 0000 0000 0000 0000 0000 0001 0000 0011
// byte(1 byte) => ---- ---- ---- ---- ---- ---- 0000 0011
//
// => 4바이트 중에서 앞의 3바이트가 잘리고 뒤의 1바이트만 b에 저장된다.
//
System.out.println(b); // 3
// 결론!
// => 큰 메모리의 값을 작은 메모리에 넣으려고 형변환을 사용하기도 하는데
// 다만 형변환하더라도(즉 작은 메모리에 넣더라도) 값이 잘리지 않을 때만 하라!
// => 형변환하더라도 값이 소실되지 않을 때만 "명시적 형변환"을 지시하라!
}
}
Exam0330 - 논리연산자 : && vs & (중요!)
// 산술연산자 : 명시적 형변환
// &&, ||
// - 앞의 피연산자의 값으로 결과를 알 수 있다면 뒤의 명령은 실행하지 않는다.
//
// &, |
// - 앞의 피연산자로 결과를 알 수 있을 지라도,
// 뒤에 놓은 명령까지 모두 실행한다.
package bitcamp.ex05;
//# 논리 연산자 : && vs &
//
public class Exam0330 {
public static void main(String[] args) {
boolean a = false;
boolean b = false;
boolean r = a && (b = true);
// 계산 순서
// r = a && (b = true)
// r = false && (b = true)
// => && 연산에서 왼쪽 값이 이미 false이기 때문에 결과는 확정되었다.
// => 이렇게 && 연산의 오른쪽을 실행하기 전에 결과를 알 수 있다면
// JVM은 실행의 효율을 위해 && 연산의 오른쪽을 실행하지 않는다.
// => 그래서 (b = true) 문장은 실행되지 않는다.
// r = false
System.out.printf("a=%b, b=%b, r=%b\n", a, b, r);
a = false;
b = false;
r = a & (b = true);
// 계산 순서
// r = a & (b = true)
// r = false & (b = true)
// => & 연산자의 경우 왼쪽 값으로 결과를 예측할 수 있다 하더라도,
// 결과에 상관없이 & 오른쪽 문장을 무조건 실행한다.
// r = false & (b 변수의 값을 true 바꾸고, b 변수의 값을 이 자리에 놓는다.)
// r = false & true
// r = false
System.out.printf("a=%b, b=%b, r=%b\n", a, b, r);
}
}
// &&, ||
// - 앞의 피연산자의 값으로 결과를 알 수 있다면 뒤의 명령은 실행하지 않는다.
//
// &, |
// - 앞의 피연산자로 결과를 알 수 있을 지라도,
// 뒤에 놓은 명령까지 모두 실행한다.
Exam0352 - 비트연산자 : & 이용하여 홀수/짝수 찾기
// 어떠한 값을 2로 나누어 떨어지면 짝수이다.
// 이를 통해 % 연산으로 쉽게 홀수/짝수를 찾을 수 있다.
package bitcamp.ex05;
//# 비트 연산자 & 를 이용하여 % 연산 구현하기 응용 I
//
public class Exam0352 {
public static void main(String[] args) {
// % 연산자를 이용하여 짝수/홀수 알아내기
System.out.println(57 % 2 == 0 ? "짝수" : "홀수");
// & 연산자를 이용하여 짝수/홀수 알아내기
System.out.println((57 & 1) == 0 ? "짝수" : "홀수");
}
}
Exam0353 - 비트연산자 : 특정 값을 차단하고 특정 값만 통과시킬 때
// 어떠한 Data를 & 연산을 통해서 "0000_1111_1100_0000"
// 2진수의 값을 지정해서 and 연산을 통해 지정된 값을 제외하고 차단시킬 수 있다.
package bitcamp.ex05;
//# 비트 연산자 & 활용: 특정 값을 차단하고 특정 값만 통과시킬 때
//=> 특정 비트의 값만 추출하고 싶을 때 사용할 수 있다.
//
public class Exam0353 {
public static void main(String[] args) {
int data = 0b1111_1001_0111_1111;
System.out.println(Integer.toBinaryString(data & 0b0000_1111_1100_0000));
// 1111_1001_0111_1111
// & 0000_1111_1100_0000
//-----------------------
// 0000_1001_0100_0000
}
}
Exam0354 - 비트연산자 : 특정 값을 차단하고 특정 값만 통과시킬 때
// 비트 연산자 & 활용: 그림의 한 픽셀에서 빨강 색을 제거하고 싶다.
// 2진수의 값을 지정해서 and 연산을 통해 지정된 색을 제외할 수 있다. (RR=00 and연산이라서 0으로 처리)
package bitcamp.ex05;
//# 비트 연산자 & 활용: 그림의 한 픽셀에서 빨강 색을 제거하고 싶다.
//
public class Exam0354 {
public static void main(String[] args) {
int pixel = 0x003f4478; // 각 바이트의 값이 '00RRGGBB' 이라 가정하다.
System.out.println(pixel & 0x0000ffff);
// pixel = 00000000_00111111_01000100_01111000
// & 00000000_00000000_11111111_11111111
// 00000000_00000000_01000100_01111000
}
}
Exam0410 - 비트연산자 : 특정 값을 차단하고 특정 값만 통과시킬 때
// 왼쪽 이동
// - 1비트 이동은 곱하기 2 한 것과 같은 효과를 준다.
// - 값을 배수로 증가시킬 때 곱하기 연산을 하는 것 보다
// 왼쪽 비트 이동 연산을 하는 것이 빠르기 때문에
// 실무에서는 이 비트 이동 연산을 자주 사용한다.
// - 비트 이동 => '2**이동비트'를 곱한 것과 같은 결과를 만든다.
package bitcamp.ex05;
//# 비트 이동 연산자 : >>, >>>, <<
//
public class Exam0410 {
public static void main(String[] args) {
// << 비트 이동 연산자 사용법
// - 왼쪽으로 비트를 이동시킨다.
// - 오른 쪽 빈자리는 0으로 채운다.
// - 왼쪽 경계를 넘어간 비트는 자른다.
//
int i = 1;
// [00000000000000000000000000000001] = 1
System.out.println(i << 1);
// 0[0000000000000000000000000000001 ]
// [00000000000000000000000000000010] = 2
System.out.println(i << 2);
// 00[000000000000000000000000000001 ]
// [00000000000000000000000000000100] = 4
System.out.println(i << 3);
// 000[00000000000000000000000000001 ]
// [00000000000000000000000000001000] = 8
System.out.println(i << 4);
// 0000[0000000000000000000000000001 ]
// [00000000000000000000000000010000] = 16
i = 11; // [00000000000000000000000000001011]
System.out.println(i << 1); // 0[00000000000000000000000000010110] => 22
System.out.println(i << 2); // 00[00000000000000000000000000101100] => 44
System.out.println(i << 3); // 000[00000000000000000000000001011000] => 88
// 왼쪽 이동
// - 1비트 이동은 곱하기 2 한 것과 같은 효과를 준다.
// - 값을 배수로 증가시킬 때 곱하기 연산을 하는 것 보다
// 왼쪽 비트 이동 연산을 하는 것이 빠르기 때문에
// 실무에서는 이 비트 이동 연산을 자주 사용한다.
// - 비트 이동 => '2**이동비트'를 곱한 것과 같은 결과를 만든다.
}
}
Exam0420 - 비트 이동 연산자 : 곱셉을 사용하지 않고 2배로 만들기
// 왼쪽 이동
// - 1비트 이동은 곱하기 2 한 것과 같은 효과를 준다.
// - 값을 배수로 증가시킬 때 곱하기 연산을 하는 것 보다
// 왼쪽 비트 이동 연산을 하는 것이 빠르기 때문에
// 실무에서는 이 비트 이동 연산을 자주 사용한다.
// - 비트 이동 => '2**이동비트'를 곱한 것과 같은 결과를 만든다.
package bitcamp.ex05;
//# 비트 이동 연산자 : >>, >>>, <<
//
public class Exam0410 {
public static void main(String[] args) {
// << 비트 이동 연산자 사용법
// - 왼쪽으로 비트를 이동시킨다.
// - 오른 쪽 빈자리는 0으로 채운다.
// - 왼쪽 경계를 넘어간 비트는 자른다.
//
int i = 1;
// [00000000000000000000000000000001] = 1
System.out.println(i << 1);
// 0[0000000000000000000000000000001 ]
// [00000000000000000000000000000010] = 2
System.out.println(i << 2);
// 00[000000000000000000000000000001 ]
// [00000000000000000000000000000100] = 4
System.out.println(i << 3);
// 000[00000000000000000000000000001 ]
// [00000000000000000000000000001000] = 8
System.out.println(i << 4);
// 0000[0000000000000000000000000001 ]
// [00000000000000000000000000010000] = 16
i = 11; // [00000000000000000000000000001011]
System.out.println(i << 1); // 0[00000000000000000000000000010110] => 22
System.out.println(i << 2); // 00[00000000000000000000000000101100] => 44
System.out.println(i << 3); // 000[00000000000000000000000001011000] => 88
// 왼쪽 이동
// - 1비트 이동은 곱하기 2 한 것과 같은 효과를 준다.
// - 값을 배수로 증가시킬 때 곱하기 연산을 하는 것 보다
// 왼쪽 비트 이동 연산을 하는 것이 빠르기 때문에
// 실무에서는 이 비트 이동 연산을 자주 사용한다.
// - 비트 이동 => '2**이동비트'를 곱한 것과 같은 결과를 만든다.
}
}
Exam0420 - 비트 이동 연산자 : 나눗셈을 사용하지 않고 2로 나누기
// 오른쪽 이동
// - 1비트 이동은 나누기 2 한 것과 같은 효과를 준다.
// - 예) n에 대해 x비트를 오른쪽으로 이동 = n / 2**x
// - 소수점이 있는 경우 그 수 보다 작은 바로 밑 정수 값이 된다.
// - 나누기 연산을 수행하는 것 보다 계산 속도가 빠르다.
// 실무에서는 나눗셈 연산이 비용(시간과 CPU 사용량)이 많이 들기 때문에
// 소수점 이하까지 정확하게 계산할 게 아니라면
// 오른쪽 비트 이동 연산자를 사용하여 주로 처리한다.
package com.eomcs.lang.ex05;
//# 비트 이동 연산자 : >>, >>>, <<
//
public class Exam0420 {
public static void main(String[] args) {
// >> 비트 이동 연산자 사용법
// - 왼쪽 쪽 빈자리를 원래 숫자와 같은 부호 값으로 채운다.
// - 양수라면 0, 음수라면 1을 채운다.
// - 오른쪽 경계를 넘어간 비트는 자른다.
//
int i = 105; // [00000000000000000000000001101001]
System.out.println(i); // => 105
System.out.println(i >> 1);
// [ 0000000000000000000000000110100]1
// [00000000000000000000000000110100] => 52
System.out.println(i >> 2);
// [ 000000000000000000000000011010]01
// [00000000000000000000000000011010] => 26
System.out.println(i >> 3);
// [ 00000000000000000000000001101]001
// [00000000000000000000000000001101] => 13
System.out.println(i >> 4);
// [ 0000000000000000000000000110]1001
// [00000000000000000000000000000110] => 6
// 오른쪽 이동
// - 1비트 이동은 나누기 2 한 것과 같은 효과를 준다.
// - 예) n에 대해 x비트를 오른쪽으로 이동 = n / 2**x
// - 소수점이 있는 경우 그 수 보다 작은 바로 밑 정수 값이 된다.
// - 나누기 연산을 수행하는 것 보다 계산 속도가 빠르다.
// 실무에서는 나눗셈 연산이 비용(시간과 CPU 사용량)이 많이 들기 때문에
// 소수점 이하까지 정확하게 계산할 게 아니라면
// 오른쪽 비트 이동 연산자를 사용하여 주로 처리한다.
//
}
}
Exam0631 - 증감 연산자 : 후위 연산자
// 후위연산자는 할당 이후에 연산을 하게 되므로 바뀌기 전의 값이 다른 변수에 할당된다.
// 즉, 증감 연산자가 변수 뒤에 쓰이면 연산을 나중에 처리한다는 뜻이 된다.
package com.eomcs.lang.ex05;
//# 증감 연산자 : 후위(post-fix) 증감 연산자 응용 I
//
public class Exam0631 {
public static void main(String[] args) {
int i = 7;
i = i++;
// 위 문장은 다음과 같이 실행된다.
//int temp = i;
//i = i + 1;
//i = temp;
//
// 1) i 값을 그자리에 놓는다.
// => i = 7;
// => 7 값을 i에 저장할 수 없다.
// => 왜? 아직 = 연산자 오른쪽의 모든 식이 수행되지 않는다.
// 2) ++ 연산 실행
// => 즉 i = i + 1 실행
// => i = 8 이 되었다.
// 3) 할당 연산자 실행
// => i <===== 7 실행
// => 다시 i는 8에서 7로 바뀌었다.
System.out.println(i);
}
}
Exam0710 - 할당 연산자 : 후위 연산자
// 할당 연산자(assignment operator)는 변수에 값을 할당하는 데 사용되는 연산자이다.
// 할당 연산자는 등호(=) 기호로 표현되며, 변수에 우측 피연산자의 값을 할당한다.
package com.eomcs.lang.ex05;
//# 할당(배정,대입) 연산자 : += -= *= /= %= &= |= ^= <<= >>= >>>=
//
public class Exam0710 {
public static void main(String[] args) {
int i = 2;
i = i + 20;
i += 20; // += 연산자를 사용하면 위의 코드를 축약할 수 있다.
System.out.println(i);
i = 2;
i *= 5;
System.out.println(i);
}
}