int,double,boolean과 같은 타입은 기본형 타입이다.
기본형은
int는 기본형 타입으로 데이터 쪼가리지반, int값을 가지고 클래스를 만들면된다.
마치 int를 클래스로 감싸서 만드는것 처럼 보이는데 이렇게 특정 기본형을 감싸서(Wrap)만드는 클래스를 래퍼 클래스라고 한다.
public class MyInteger {
private final int value;
public MyInteger(int value) {
this.value = value;
}
public int getValue(){
return value;
}
public int compareTo(int target){
if(value < target){
return -1;
}else if(value > target){
return 1;
}else{
return 0;
}
}
@Override
public String toString() {
return String.valueOf(value);
}
}
public class MyIntegerMethodMain1 {
public static void main(String[] args) {
MyInteger myInteger = new MyInteger(10);
int i1 = myInteger.compareTo(5);
int i2 = myInteger.compareTo(10);
int i3 = myInteger.compareTo(20);
System.out.println(i1);
System.out.println(i2);
System.out.println(i3);
}
}
MyInteger는 필드로 int value라는 기본형 변수를 가지고 있다.
그러나 이것은 기본형이 아니므로 class에서 다양한 메서드를 제공한다.
value와 값을 비교하는 compareTo메서드나, toString을 오버라이딩 하여서 원하는대로 출력도 가능하다.
또한,
기본형은 항상 값을 가져야한다. 따로는 데이터가 없음이라는 상태가 필요할 수 있다.
객체의 경우 데이터가 없다는 null이라는 명확한 값이 존재한다.
public class MyIntegerNullMain1 {
public static void main(String[] args) {
MyInteger[] intArr = {new MyInteger(-1),new MyInteger(0),new MyInteger(1)};
System.out.println(findValue(intArr,-1));
System.out.println(findValue(intArr,0));
System.out.println(findValue(intArr,1));
System.out.println(findValue(intArr,100));
}
private static MyInteger findValue(MyInteger[] intArr,int target){
for (MyInteger myInteger : intArr) {
if(myInteger.getValue()==target){
return myInteger;
}
}
return null;
}
}
기본형은 항상 값이 존재해야한다. 숫자의 경우 0,-1 같은 값이라도 항상 존재해야한다.
반면 객체인 참조형은 값이 없다는 null을 사용할 수 있다.
자바는 기본형에 대응하는 래퍼 클래스를 기본으로 제공한다.
등등.
그리고 자바가 기본으로 제공하는 래퍼클래스는, 불변이다. equals로 비교해야한다 는 특징이있다.
public class WrapperClassMain {
public static void main(String[] args) {
Integer newInteger = new Integer(10);
Integer integerObj = Integer.valueOf(10);
Integer integerObj2 = Integer.valueOf(10);
Long longObj = Long.valueOf(100);
Double doubleObj = Double.valueOf(10.5);
int intValue = integerObj.intValue();
long ll = longObj.longValue();
System.out.println(newInteger==integerObj);
System.out.println(integerObj2==integerObj);
}
}
기본형을 래퍼클래스로 변경하는것을 Boxing이라고 한다.
new Integer(10)은 작동은하지만, 이제 곧 제거될 예정이다.
대신에 Integer.valueOf()를 사용하면 된다.
특징은 Integer.vlaueOf()는 성능 최적화 기능이 있다. -128~127까지 범위의 Integer클래스를 미리 생성하고 반환하다.
범위가 넘어간 숫자는 그때 new Integer()호출로 생성한다.
그래서 newInteger와 integerObj는 인스턴스 생성 방식이 다르므로, false가 나오지만,
intgerObj와 interObj2는 둘다 자바가 문자열 풀과 비슷하게 해당 숫자에 대응하는 인스턴스를 미리 생성해둔것을 가져다 쓴것이므로, 동일성을 비교해도 true가 나온다.
public class AutoboxingMain1 {
public static void main(String[] args) {
//Primitive -> Wrapper
int value = 7;
Integer boxedValue = Integer.valueOf(value);
//Wrapper -> Primitive
int unboxedValue = boxedValue.intValue();
//이제는 valueOf,intValue쓰지 않고 그냥 Auto로
Integer boxedValue1 = value;
int unboxedValue2 = boxedValue;
}
}
원래 기본형을 래퍼형, 래퍼형을 기본형으로 변환할때는 .valueOf(), xxxValue()를 사용해야만 한다.
그러나 이런과정은 너무 빈번히 일어나서 JAVA가 기본적으로 Auto로 바꿔서 넣어준다.
Integer i1 = Integer.valueof("10");//문자열,래퍼 객체 변환
int i2 = Integer.parseInt("10");//문자열 전용, 기본형 반환
int compareResult = i1.compareTo(20);
sout(Integer.sum(10,20));
Integer.min(10,20);
Integer.max(10,20);
만약에 for문에서 long +=10, Long +=10(이경우 자동으로 auto boxing해줌) 이 루프를 10억번 돌린다 치자.
그러면 성능차이가 한 5배 난다.
기본형은 메모리에서 단순히 그 크기만큼 공간을 차지하지만, 래퍼클래스의 인스턴스는 내부에 필드를 가지고 자바가 객체를 다루는데 필요한 메타데이터가 있으므로 메모리를 더사용하기 때문에 성능차이가 난다.
그러나 이 경우는 10억번 가량을 돌렸을때 이야기 이다.
1회로 환산하면 애플리케이션 관점에서 성능차이는 사막의 모래알 하나 정도 차이이다.
고로, 성능 최적화보다는 유지보수 관점에서 더 효율적인것을 선택하는것이 좋다.
Class클래스를 통해 클래스의 메타정보를 확인할 수 있고, 이를통해 객체 인스턴스를 생성하거나 메서드를 호출하는 작업을 할 수 있다.
클래스의 메타정보확인
public class ClassMetaMain {
public static void main(String[] args) {
Class clazz = String.class;
//Class clazz = new String().getClass();
//Class clazz = Class.forName("java.lang.String");
//모든 필드 출력
Field[] fields = clazz.getFields();
for (Field field : fields) {
System.out.println("Field: " + field.getType() + " "+ field.getName());
}
//모든 메서드 출력
Method[] methods = clazz.getDeclaredMethods();
for (Method method : methods) {
System.out.println("method = " + method);
}
//상위 클래스 정보 출력
System.out.println("Superclass: "+ clazz.getSuperclass().getName());
//인터페이스 정보 출력
Class[] interfaces = clazz.getInterfaces();
for (Class anInterface : interfaces) {
System.out.println("anInterface = " + anInterface);
}
}
}
Class 클래스는 3가지 방법으로 조회가 가능하다.
Class clazz = String.class;
Class clazz = new String().getClass()
Class clazz = Class.forName("java.lang.String");
Class를 통해 String 클래스의 다양한 메타 정보를 확인 할 수 있다.
Class를 통해 객체 인스턴스를 생성하거나 메서드를 호출하기
public class Hello {
public String hello()
{
return "hello";
}
}
public class ClassCreateMain {
public static void main(String[] args) throws NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException {
Class helloclass = Hello.class;
Hello hello = (Hello) helloclass.getDeclaredConstructor().newInstance();
String result = hello.hello();
System.out.println("result = " + result);
}
}
Class에 Hello.class를 받고
getDeclaredConstructor().newInstance()호출을 통해 인스턴스를 생성하였다.
이렇게 Class를 통해 해당 클래스의 객체 인스턴스를 생성하거나 메서드를 호출하는 작업을 할 수 있는데, 이런 작업을 리플랙션이라 한다.
리플랙션에 대한 자세한 내용은 뒤에서 다룰것이다.
System 클래스는 시스템과 관련된 기본기능들을 제공한다.
public class SystemMain {
public static void main(String[] args) {
//현재시간을 밀리초로 가져온다.
long currentTimeMillis = System.currentTimeMillis();
System.out.println("currentTimeMillis = " + currentTimeMillis);
//현재시간을 나노초로 가져온다.
long currentTimeNano = System.nanoTime();
System.out.println("currentTimeNano = " + currentTimeNano);
//환경변수를 읽는다.
System.out.println(System.getenv());
//시스템 속성을 읽는다.
System.out.println("propertis = " + System.getProperties());
//배열 고속 복사
char[] originalArray = new char[]{'h','e','l','l','o'};
char[] copiedArray = new char[5];
System.arraycopy(originalArray,0,copiedArray,0,originalArray.length);
//배열 출력
System.out.println(copiedArray);
}
}
public class MathMain {
public static void main(String[] args) {
int max = Math.max(10, 20);
int min = Math.min(10, 20);
int abs = Math.abs(-10);
double ceil = Math.ceil(2.1);//올림
double floor = Math.floor(2.8);//내림
long round = Math.round(2.5);//반올림
double sqrt = Math.sqrt(4);//제곱근
double random = Math.random();//0.0~1.0사이의 double 값
}
}
public class RandomMain {
public static void main(String[] args) {
Random random = new Random();
int i = random.nextInt();
double v = random.nextDouble();
boolean b = random.nextBoolean();
int i1 = random.nextInt(10);//0부터9까지 출력
int i2 = random.nextInt(10) + 1;//1부터 10까지 출력
}
}
nextInt메서드는 랜덤 int값을 반환한다.
메서드에 파라미터를 넣으면 0~bound미만의 숫자를 랜덤으로 반환한다.
Random random = new Random(1);
이렇게 생성자에 seed를 넣어서 사용할 수 있는데 해당 seed가 같으면 항상 Random의 결과가 같다.
즉 random메서드를 반복수행해도 항상 같은 결과가 나온다.