Dipa's document :: '분류 전체보기' 카테고리의 글 목록 (2 Page)

오늘은 wrapper(포장)클레스에 대해서 살펴보도록 하자.

Wrapper클레스란 기본타임(byte,char,short,int,long,float,double,boolean)을 객체로 생성하는 클레스를 말한다. 그리고 이러한 wrapper클레스는 불변객체로써 값을 변경할 수가 없다.

예를 들어, 즉 포장이란 무엇인가? 어떠한 내용물을 담는 상자? 라고 생각하면 쉬울 것이다.

그럼 안의 내용물을 변경하려면 그 포장지를 뜯어야하지 않는가? 포장을 한다는 거 자체가 선물의 의미인데..이것을 바꾸려고 하는것은..(약간..억지의 감이 있지만)

따라서 값을 변경을 하지못하고, 값을 변경하고 싶으면 포장 객체를 생성을 하여야 한다.

 기본타입

포장 클레스

byte

Byte

char

Character

short

Short

int

Integer

long 

Long

float

Float

double

Double

boolean

Boolean

기본 타입 -> 포장 객체 : Boxint(박싱)

포장객체 -> 기본 타입 : Unboxing(언박싱)

package wrapper;

public class BoxingUnboxing {

	public static void main(String[] args) {
		Integer obj1 = new Integer(100);
		Integer obj2 = new Integer("100");
		Integer obj3 = Integer.valueOf(100);
		
		int value1 = obj1.intValue();
		int value2 = obj2.intValue();
		int value3 = obj3.intValue();
		
		System.out.println(value1);
		System.out.println(value2);
		System.out.println(value3);

//결과값 //100 //100 //100 } }

* 자동 박싱, 언박싱

박싱에도 자동 형변환처럼 자동적으로 변환을 하는 기능이 있다. 이 기능은 자바5부터 추가된 기능이다.

package wrapper;

public class AutoBoxingAutoUnboxing {

	public static void main(String[] args) {
		Integer obj1 = 100; //자동 박싱

int value = obj1; //자동 언박싱 System.out.println(obj1.intValue());

System.out.println(value);

//결과값 //100 //100 } }

마지막으로 ==,!=의 연산자이다. Wrapper클레스는 객체이기 떄문에 결국 ==,!=연산자는 포장객체의 내부의 값을 비교를 하는것이 아닌 객체의 참조를 비교를 하는것이다. 내부의 값을 비교를 하기위해서는 언박싱을 하여 비교를 하여야 하는데, 예외 적으로 내부의 값을 비교를 하는 짓도 한다..^^

타입 

값의 범위 

boolean 

true,false 

char 

\u0000 ~ \u0071 

 byte,short,int

-128~127 

왜 이런 현상이 나오는 것일까? 바로 위에 3가지의 기본 타입의 포장클레스의 캐쉬 떄문이다.

각각의 캐쉬를 소스코드로 확인을 해보자.

 private static class IntegerCache {
        static final int low = -128;
        static final int high;
        static final Integer cache[];

        static {
            // high value may be configured by property
            int h = 127;
            String integerCacheHighPropValue =
                sun.misc.VM.getSavedProperty("java.lang.Integer.IntegerCache.high");
            if (integerCacheHighPropValue != null) {
                try {
                    int i = parseInt(integerCacheHighPropValue);
                    i = Math.max(i, 127);
                    // Maximum array size is Integer.MAX_VALUE
                    h = Math.min(i, Integer.MAX_VALUE - (-low) -1);
                } catch( NumberFormatException nfe) {
                    // If the property cannot be parsed into an int, ignore it.
                }
            }
            high = h;

            cache = new Integer[(high - low) + 1];
            int j = low;
            for(int k = 0; k < cache.length; k++)
                cache[k] = new Integer(j++);

            // range [-128, 127] must be interned (JLS7 5.1.7)
            assert IntegerCache.high >= 127;
        }

        private IntegerCache() {}
    }
private static class CharacterCache {
        private CharacterCache(){}

        static final Character cache[] = new Character[127 + 1];

        static {
            for (int i = 0; i < cache.length; i++)
                cache[i] = new Character((char)i);
        }
    }


Posted by SH후니
,

오늘은 String클레스에 대해서 다뤄볼까 한다.

전에 Object클레스의 equals()를 설명을 하면서 String클레스에 대해서 다시 한번 언급을 하려고 했던 부분이 있다. 바로 객체를 선언을 할떄의 차이다.

public class internMethod {

	public static void main(String[] args) {
		String input01 = "홍길동";
		String input02 = new String("홍길동");
		
		System.out.println(input01.equals(input02));
	}
}

이것의 결과는 당연히 true가 나온다. 객체안에 있는 데이터를 비교를 하기 때문이다.

하지만.. 이렇게 되면 어떻게 될까?

public class internMethod {

	public static void main(String[] args) {
		String input01 = new String("홍길동");
		String input02 = new String("홍길동");
		
		System.out.println(input01.equals(input02));
	}
}

당연히 객체의 번지 주소를 비교를 하기 떄문에 false가 나오게 된다.

이러한 이유는 과연 무엇일까?? 

첫번쨰 소스코드의 차이의 이유는 바로 JVM에서 String 객체를 생성을 하였을 경우, 어떤 메모리 영역에 저장이 되는지에 대한 이유이다.

new 생성자를 이용해서 인스턴스를 만들고, heap 메모리에서 관리한다는 사실은 공통적이지만, String 객체는 불변객체로 한번 생성이 되면 값은 변하지가 않는다. 이런식으로 다른객체지만 객체 안의 데이터가 같은것을 무한히 생성을 하다보면 결국 메모리 관리 측명에서 비효율적이라는 판단을 한다.

이래서 만들어진 메모리 영역이 String Constant Pool이다.

또한 문자열을 변경하는 작업을 많이 할경우에는 StringBuffer와 StringBuilder클레스를 사용하면된다.

이 두 클레스는 내부 버퍼에 문자열을 저장해 두고 그안에서 추가, 수정 삭제 작업을 할 수 있도록 설계 되어 있다. 두가지를 사용하는 방법은 동일하나.. 하나의 차이가 있다면,

StringBuffer는 멀티 스레드 환경에서 사용할 수 있도록 동기화가 적용되어 있어 스레드에 안전하고,

StringBuilder는 단일 스레드 환경에서만 사용하도록 설계 되어 있다.


Posted by SH후니
,

Class클레스란?

자바의 클레스와 인터페이스의 메타데이터(클레스의 이름, 생성자의 정보, 필드 정보, 메소드 정보)등등을 관리 하는 클레스이다.

즉, 클레스 안의 멤버 변수와 메소드 등등의 리턴 타입이라던지...파라메터값 등등을 알 수 있다는 뜻이다.

그 중에서 오늘은 getClass(), forName()를 살펴보고자 한다. 


저 두개의 메소드의 공통점은 무엇일까? 일단 힌트는 둘다 Class의 정보를 받아볼수 있는 메소드이다.

코드를 통해 살펴보자..

 
  
public final native Class<?> getClass();
 
public static Class<?> forName(String className)
                throws ClassNotFoundException {
        Class<?> caller = Reflection.getCallerClass();
        return forName0(className, true, ClassLoader.getClassLoader(caller), caller);
    }

일단 둘다 공통점은 Class를 return한다는 것이다. 

차이점은? 

getClass() 같은경우는 Object클레스에 있는 메소드로써 객체를 생성을 한뒤 호출 할 수 있는 메소드이다.

forName() 같은경우는 객체를 생성하기 전에 직접 객체를 얻을 수 있다.

package api_class._class;
 
public class Car {
	private String model;
	private String owner;
	
	public Car(){
		
	}
	
	public Car(String model){
		this.model = model;
	}
	public String getModel() {
		return model;
	}
	public void setModel(String model) {
		this.model = model;
	}
	public String getOwner() {
		return owner;
	}
	private void setOwner(String owner) {
		this.owner = owner;
	}
}
package api_class._class;
 
public class ClassExample {

	public static void main(String[] args) {
		Car car = new Car();
		Class clazz1 = car.getClass();
		System.out.println(clazz1.getName());
		System.out.println(clazz1.getSimpleName());
		System.out.println(clazz1.getPackage().getName());
		
		System.out.println();
		
		try {
			Class clazz2 = Class.forName("api_class._class.Car");
			System.out.println(clazz2.getName());
			System.out.println(clazz2.getSimpleName());
			System.out.println(clazz2.getPackage().getName());
		} catch (ClassNotFoundException e) {
			System.out.println("존재하지 않은 클레스");
		}
		
	}

}

위의 소스는 단지 클레스의 이름에 대한 정보만 나와있다.. 하지만 생성자, 필드 메소드의 정보도 얻을수 있다고 하였는데?

당연 정보를 얻어 올수 있다!! 이것이 바로 Reflection(리플렉션)이다.

각각의 정보를 얻어 올수 있는 메소드 (생성자 - getDeclaredConstructors(), 필드 - getDeclareFields(), 메소드 - getDeclaredMethods() ) 이다. 

이들의 리턴값은 각각의 타입에 대한 배열이다. (왜냐하면,, 여러개 있을수 있으니까?)

하지만 저들의 메소드는 그 클레스에 선언된 것만 가져온다. 만약 상속된 멤버 까지 가져오고 싶다면.. 중간에 Declare를 뺴면된다..? 쉽죠? ㅋㅋ

이제 각각의 정보를 가져오는 소스를 보도록 하자

package api_class._class;

import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;

public class ReflectionExample {

	public static void main(String[] args) throws ClassNotFoundException {
		try {
			Class clazz = Class.forName("_class.Car");
			System.out.println("[생성자 정보]");
			Constructor[] constructors = clazz.getDeclaredConstructors();
			for(Constructor constructor : constructors){
				System.out.print(constructor.getName() + "(");
				Class[] parameters = constructor.getParameterTypes();
				printParameters(parameters);
				System.out.println(")");
			}
			
			System.out.println();
			
			System.out.println("[필드 정보]");
			Field[] fields = clazz.getDeclaredFields();
			
			for(Field field : fields){
				System.out.println(field.getType().getSimpleName() + " " + field.getName());
			}
			System.out.println();

			System.out.println("[메소드 정보]");
			Method[] methods = clazz.getDeclaredMethods();
			for(Method method : methods){
				System.out.print(method.getReturnType().getSimpleName() + " " + method.getName() + "(");
				Class[] parameters = method.getParameterTypes();
				printParameters(parameters);
				System.out.println(")");
			}
			
		} catch (ClassNotFoundException e) {
			System.out.println("클레스가 없음");
		}
		
	}
	
	static void printParameters(Class[] parameters){
		for(int i=0;i<parameters.length;i++){
			System.out.print(parameters[i].getName());
			if(i<(parameters.length-1)){
				System.out.print(",");
			}
		}
	}

}

이제 마지막으로 그렇다면.. 이들을 정보만 알지말고 객체를 new연산자를 이용해서 생성하지 않고, 메소드를 호출하여 사용할 수 있을까?

그것이 바로 newInstance()를 이용하여 사용할 수있다. newInstance()는 new연산자를 이용하여 객체를 생성을 하지않고, 동적으로 객체를 생성하여, runtime시에 발생을 하게 된다.

package api_class._class;

public interface Action {
	public void execute();
}


package api_class._class;

public class ReceiveAction implements Action{

	@Override
	public void execute() {
		System.out.println("데이터를 받습니다.");
	}
	
}


package api_class._class;

public class SendAction implements Action{

	@Override
	public void execute() {
		System.out.println("데이터를 보냅니다.");
	}
	
}


package api_class._class;

public class NewInstanceExample {

	public static void main(String[] args) {
		try {
			Class clazz = Class.forName("_class.ReceiveAction");
			Action action = (Action) clazz.newInstance();
			action.execute();
		} catch (ClassNotFoundException e) {
			e.printStackTrace();
		} catch (InstantiationException e) {
			e.printStackTrace();
		} catch (IllegalAccessException e) {
			e.printStackTrace();
		}
	}

}


'SH.Language > Java' 카테고리의 다른 글

[JAVA] Wrapper 클레스  (0) 2018.01.04
[JAVA] String, StringBuffer, StringBuilder 클레스  (0) 2018.01.02
[JAVA] Object클레스 - clone()  (0) 2017.12.14
[JAVA] Object클레스 - toString()  (0) 2017.12.11
[JAVA] Object클레스 - hashCode()  (0) 2017.12.06
Posted by SH후니
,

Object클레스의 clone()메소드는 복제를 의미한다. 따로 설명을 하기가 어려운데..그냥 정말 복제다.

복제를 하는 이유는 무엇일까? 원본 객체를 유지를 하기위한 방패막이라고나 할까?ㅋㅋㅋ

하지만 복재는 두가지 분류로 나뉜다. 얕은복제, 깊은복제

1) 얕은 복제 : 객체의 기본 타입만 복제(참조 타입의경우 객체의 번지가 복사 -> 참조를 바꾸면? 같이 바뀐다..)

2) 깊은 복제 : 객체의 기본 타입, 참조 타입 모두가 바뀐다.

그럼, 이제 코드를 한번 확인을 해보자.

package object;

public class Member implements Cloneable{
	public String id;
	public String name;
	public String password;
	public int age;
	public boolean adult;
	
	public Member(String id, String name, String password, int age, boolean adult){
		this.id = id;
		this.name = name;
		this.password = password;
		this.age = age;
		this.adult = adult;
	}
	
	public Member getMember(){
		Member cloned = null;
		try {
			cloned = (Member)this.clone();
		} catch (CloneNotSupportedException e) {
			e.printStackTrace();
		}
		return cloned;
	}
}

Clone()메소드를 작성시에 유의사항은 복사할 객체를 Cloneable 인터페이스를 구현을 해야하고, Clone()메소드에 대한 예외 처리를 해야 한다는 것이다.

getMember()드에서 object클레스의 clone()을 override를 해야하지만 default로는 얕은복제를 하기떄문에 얕은 복제를 먼저 구현을 하고 실험을 해보자.


package object;

public class MemberExample {
	public static void main(String[] args){
		Member original = new Member("blue","홍길동","12345",25,true);
		
		Member cloned = original.getMember();
		original.age = 30;
		
		System.out.println("[원본 객체의 필드값]");
		System.out.println("id: " + original.id);
		System.out.println("name: " + original.name);
		System.out.println("password: " + original.password);
		System.out.println("age: " + original.age);
		System.out.println("adult: " + original.adult);
		
		System.out.println();
		
		System.out.println("[복제 객체의 필드값]");
		System.out.println("id: " + cloned.id);
		System.out.println("name: " + cloned.name);
		System.out.println("password: " + cloned.password);
		System.out.println("age: " + cloned.age);
		System.out.println("adult: " + cloned.adult);
	}
}

결과에서 나왔듯이 원본객체를 바꿔도 복제한 객체에는 바뀌지 않는것을 볼수가 있다.

그런데 여기서 의문을 가지는 개발자가 있을것이다. 처음에는 얕은 복제는 기본타입만 복제가 된다고 했는데 String을 바꿨는데 원본과 복제된 객체의 값이 다르다? 그러면 참조타입도 복제가 되었다는 말아닌가???? ㅡㅡ 여기서.. 여기서 나의대답은!! String은 참조 타입이다. 하지만 String같은경우는 값이 바뀌는 것이 아니라 오히려 그 데이터의 객체를 하나 생성을 한다...

말이 어려울수 있으니..이부분에 대해서는 String 클레스에서 다시한번 설명하도록 하겠다.


package object;

import java.util.Arrays;

public class Member2 implements Cloneable{
	public String name;
	public int age;
	public int[] scores;
	public Car car;
	
	public Member2(String name, int age, int[] scores, Car car) {
		this.name = name;
		this.age = age;
		this.scores = scores;
		this.car = car;
	}
	
	@Override
	protected Object clone() throws CloneNotSupportedException {
		Member2 cloned = (Member2)super.clone();
		cloned.scores = Arrays.copyOf(this.scores, this.scores.length);
		cloned.car = new Car(this.car.model);
		
		return cloned;
	}
	
	public Member2 getMember(){
		Member2 cloned = null;
		try {
			cloned = (Member2)this.clone();
		} catch (CloneNotSupportedException e) {}
		
		return cloned;
	}
}

깊은 복제를 하기위해서는 override를 해야하는데, 일단 기본타입을 위해서 먼저 object클레스의 clone()을 한번 호출을한뒤, 남은 클레스타입과 배열타입을 복사를 한다.

package object;

public class Member2Example {
	public static void main(String[] args){
		Member2 original = new Member2("홍길동",25,new int[]{90,90},new Car("소나타"));
		
		Member2 cloned = original.getMember();
		cloned.scores[0] = 50;
		cloned.scores[1] = 50;
		
		System.out.println("[원본 객체의 필드값]");
		System.out.println("name : " + original.name );
		System.out.println("age : " + original.age );
		for(int i =0;i<original.scores.length;i++){
			System.out.print(original.scores[i] + " ");
		}
		
		System.out.println();
		
		System.out.println("[복제 객체의 필드값]");
		System.out.println("name : " + cloned.name );
		System.out.println("age : " + cloned.age );
		for(int i =0;i<cloned.scores.length;i++){
			System.out.print(cloned.scores[i] + " ");
		}
	}
}


Posted by SH후니
,

Object클레스의 toString()메소드느 객체의 문자 정보를 리턴을 한다. 그리하여 Object 클레스의 toString()메소드를 Override를 하여 사용자의 입맛에 맡게 사용하면된다.


먼저, Object클레스의 toString()메소드이다.

public class ObjectToStringMethod {

	public static void main(String[] args) {
		Object tmp = new Object();
		String output = tmp.toString();
		System.out.println(output);

	}
}

Object클레스의 toString()"클레스명@16진수헤쉬코드" 를 반환을 한다.


다음은 toString()를 Override를 한 클레스와 실행부분이다.



class SmartPhone{
	private String company;
	private String os;
	
	public SmartPhone(String company, String os){
		this.company = company;
		this.os = os;
	}
	
	@Override
	public String toString() {
		return company + " - " + os;
	}
}
public class OverrideToStringMethod {
	public static void main(String[] args) {
		SmartPhone smartPhone = new SmartPhone("구글","안드로이드");
		String output = smartPhone.toString();
		System.out.println(output);
		System.out.println(smartPhone);
	}
}

여기서 System.out.println()메소드의 경우에 객체를 집어 넣으면 어떻게 될까? 매개값으로 객체를 넣을경우,

Override를 통해 구현한 toString()를 호출해서 리턴값을 받아 출력하도록 되어 있다.

Posted by SH후니
,


이 메소드는 해싱(hashing)기법에 사용되는 '해쉬함수(hash function)'를 구현 한 것이다. 해싱은 데이터 관리기법 중의 하나인데 다량의 데이터를 저장하고 검색하는데 유용하다. (자료구조 - 해쉬참고바람)


일반적으로 해시코드가 같은 두 객체가 존재하는 것이 가능하지만, Object클레스의 hashCode() 메소드는 객체의 메모리 번지를 이용해서 해시코드를 만들어 리턴하기 떄문에 객체마다 다른 값을 가지고 있다.


컬렉션부분에서의 HashSet, HashMap, Hashtable과 같은경우에서 논리적 동등 비교(데이터 비교)시 hashCode()를 overriding을 할 필요성이 있다. 

Key 객체의 주소가 달라도 같은 내용의 객체이면, hashCode()는 같은 hashCode를 리턴 해야 할 것이다. 

이유는 Key객체의 내용이 같을 떄, 같은 값의 hashCode를 리턴해야 HashTable, HashMap과 같은 것을 사용할 떄, 제대로 된 key로써의 역할을 하기 떄문이다.


먼저 equals()를 호출하기전에 hashCode()를 통한 해쉬코드의 값을 호출을 하고 비교를 하고 같으면, 다시 한번 equals()메소드를 통해 두 객체의 내부 데이터가 동등한지 확인 작업을 하고 동등객체 인지의 유무를 결정을 한다.

따라서, 사용자가 직접 만든 클래스를 Key로 사용하기 싶으면, 반드시 hashCode()를 overridung를 해야한다.


아래의 소스 코드를 보면

public class ObjectEqualsMethod {

public class Key {
	private int number;
	
	public Key(int number) {
		this.number = number;
	}

	public int getNumber() {
		return number;
	}

	public void setNumber(int number) {
		this.number = number;
	}
	
	@Override
	public boolean equals(Object obj) {
		if(obj instanceof Key) {
			Key compareKey = (Key)obj;
			if(this.number == compareKey.number) {
				return true;
			}
		}
		return false;
	}
	
    }
}
import java.util.HashMap;

public class KeyExample {
	public static void main(String[] args) {
		
		//Key객체를 식별키로 사용해서 String 값을 저장하는 HashMap 객체를 생성 
		HashMap<Key,String> hashMap = new HashMap<Key,String>();
		
		hashMap.put(new Key(1), "홍길동");

		System.out.println((hashMap.get(new Key(1))));
	}
}

Key값으로 Key객체를 사용하였는데도, 결과는 null이라는 충격적인 결말이 나온다. 이는 hashCode()를 재정의를 하지를 않아, Object클래스의 

hashCode()를 사용을 하기 떄문에 저장하고, 불러오는 과정의 Key객체는 서로 다른 객체로 판별이 되어 null값으로 처리가 된다. 


결국 Object클레스의 hashCode()를 재정의를 하여여 한다는 결론이 나온다.


HashSet, HashMap, Hashtable은 해시코드 값이 다르면 다른 객체로 판단하고, 해시코드 값이 같으면 equals()메소드를 다시 비교한다. 그렇기 떄문에 hashCode() 메소드가 true가 나와도 equals()의 리턴값이 다르면 다른 객체가 된다. 

Posted by SH후니
,

블로그에 빨리올려야지 했는데..벌써 한달이 가까운시간을 안하고 이제서야 올린다,,,ㅡㅡ 반성중(_ _)

이번에는 Object클레스에 대해서 공부해보고자 한다.

Object클래스는 Java.lang패키지에 있는 클래스로 Java.lang패키지는 자바 프로그램의 기본적인 클래스를 담고있는 패키지 이다. 그중에서도 Object클래스 자바 클래스의 최상이 클래스 이기떄문에 중요한 클래스라고 생각을 한다.

따라서, 클래스를 선언을 하고 extends를 통해서 다른 클래스를 상속을 받지 않으면, 암시적으로 java.lang패키지의 Object클래스를 상속을 받게 된다. 

자바의 모든 클래스는 Object클래스의 자식클래스이자 자손 클래스이다. Object클래스는 메소드들로만 구성이 되어 있는데 이 메소드들은 모든 클래스가 Object클래스를 상속을 받고 있으므로 모든 클래스에 사용이 가능하다.

Object 클래스의 메소드에는 equals(), hashCode(), toString() 등등이 있다.


* equals()

 결론부터 예기를 하면 Object 클래스의 equals()는 '==' 연산자와 동일한 기능을 한다. 같은 객체일 경우에는 true를 리턴을 하고, 객체가 다를경우에는 false를 리턴을 한다. 그렇다면 여기서 의문을 가지는게,,, 왜 String의 문자 비교를 할떄는 equals()를 쓰는지가 의문일 것이다.

그것은 String클래스가 Object클래스의 equals()메소드를 Override(재정의)를 하였기 떄문이다. String클래스의 equals()는 Override를 통해서 논리적 동등 비교를 하는 것이다.(논리적 동등 비교란? 객체가 같은지 다른지를 비교를 하는 것이 아닌 객체가 저장하고 있는 데이터를 비교를 하는 것)

public class ObjectEqualsMethod {

	public static void main(String[] args) {
		Object object01 = new Object();
		Object object02 = new Object();

		System.out.println(object01 == object02);
		
		System.out.println(object01.equals(object02));
	}

}

위에 코드를 보면 Object의 equals()메소드는 '=='연산자와 같다는 것을 알수가 있다. 

그렇다면 String클래스를 한번 살펴 보자.

   public boolean equals(Object anObject) {
        if (this == anObject) {
            return true;
        }
        if (anObject instanceof String) {
            String anotherString = (String)anObject;
            int n = value.length;
            if (n == anotherString.value.length) {
                char v1[] = value;
                char v2[] = anotherString.value;
                int i = 0;
                while (n-- != 0) {
                    if (v1[i] != v2[i])
                        return false;
                    i++;
                }
                return true;
            }
        }
        return false;
    }

위의 코드는 Object클래스의 equals()메소드를 Override를 한 것이다. 처음 조건문에서는 객체를 비교를 하는 조건문이고 두번째 조건문에서는 String클래스가 맞으면 객체 안의 데이터. 즉, 문자를 비교를 하는 소스 코드이다.  첫번쨰 조건문이 왜 있는것일까? 단순희 문자만 비교를 하면 두번째 조건문마 있므면 되지 않나? 라는 의구심을 품는 개발자도 있을것이다. 

이 부분에 대해서는 String클래스 부분에서 다시한번 포스팅을 할 것이다. 결론부터 얘기를 하면 이 두소스의 차이이다. 

public class internMethod {

	public static void main(String[] args) {
		String input01 = "홍길동";
		String input02 = new String("홍길동");
		
		System.out.println(input01.equals(input02));

	}

}


Posted by SH후니
,

자바 프로그램을 개발하고(*.java) 개발한 자바소스 파일을 컴파일(javac.exe)을 하여 컴파일이 성공을 하면 바이트 코드(*.class)파일이 생성이 된다. 

응용 프로그램을 실행을 시키기 위해서, JVM 구동 명령어(java.exe)를 통해서 JVM을 구동 시키면 JVM은 운영체제로 부터 필요한 메모리를 할당을 받는데 이를 메모리 영역(Runtime Data Area)이라고 한다.

메모리 영역에는 3가지의 주요영역 (메소드 영역 - method area 또는 Class area 또는 Static area, 힙 영역 - heap area. 스택영역 - call stack 또는 execution stack)이 있다.

* 메소드 영역 : 클래스파일의 바이트 코드가 로드 되는 곳이다.

 프로그램 실행 중 어떤 클래스가 사용이 되면, JVM은 해당 클래스들을 클래스 로더로 읽어서 클래스별로 런타일 상수풀(runtime constant pool), 필드(field), 데이터, 메소드(method) 데이터, 메소드 코드 생성자 코드 등을 분류해서 저장하고,(왜냐? 우리가 집을 정리할떄도 어떤건 어디에두고 그러지 않나? 그거랑 똑같다고 생각하면 된다) 

이 영역은 JVM이 사작할 때 생성되고 모든 스레드가 공유 하는 영역이다.

*cf : 열거상수(enum 클래스의 상수)도 메소드 영역에 저장이 되고, 메소드 영역에 생성된 열거 상수가 해당 enum의 객체를 참조하게 된다.

* 힙 영역 : 인스턴스(객체) 가 생성되는 공간으로, 프로그램 실행중 생성되는 인스턴스는 모두 이 곳에 생성이 된다. 스택 영역의 변수나 다른 객체의 필드에서 참조를하며, 참조하는 변수나 필드가 없는 객체는 의미없는 객체가 되기 떄문에 JVM은 Garbage Collector에 의해서 자동으로 자동으로 힙 영역의 객체를 제거 한다.

* 스택 영역 : 한마디로 말하면 지역변수와 매개변수가 저장이 된다고 생각을 하면된다.

각 스레드 마다 하나씩 존재하며 스레드가 시작될떄 할당이 되고, java에서 추가적으로 스레드를 생성하지 않았다면 main 스래드만 존재하므로 스택도 하나이다. 메소드의 작업에 필요한 메모리 공간(Frame)을 제공을 하고, 메소드가 호출이 되면, 호출스택에 호출된 메소드를 위한 메모리가 할당되며, 이 메모리는 메소드가 작업을 수행하는 동안 지역변수(매개변수 포함)들과 연산의 중간결과 등을 저장하는데 사용이 되고. 메소드의 작업을 마치면 할당되었던 메모리 공간은 반환된다.

스택영역의 메모리 사용에 대해서 소스로 알아보자.

 public class StackMemory {

	public static void main(String[] args) {
		System.out.println("main(String[] args) 메소드 실행 시작 - stack 쌓임(push)");
		int sum = 0;
		int v1 = 10;
		int v2 = 20;
		System.out.println("main(String[] args) 메소드 영역 지역 변수 할당 및 초기화 (v1 = 10, v2 = 20, sum = 0)");
		sum = firstMethod(v1,v2);
		System.out.println("main(String[] args) 메소드 실행 종료 - memory 반환(pop)");
	}
	static int firstMethod(int a, int b){
		System.out.println("firstMethod() 메소드 실행 - stack 쌓임(push)");
		System.out.println("firstMethod() 메소드 영역 지역 변수 할당 및 초기화 (a = 10, b = 20)");
		secondMethod();
		System.out.println("firstMethod() 메소드 실행 종료 - memory 반환(pop)");
		return a + b;
	}
	static void secondMethod(){
		System.out.println("secondMethod() 메소드 실행 - stack 쌓임(push)");
		System.out.println("secondMethod() 메소드 실행 종료 - memory 반환(pop)");
	}

 }

stack 구조는 쌓는 방식으로써 순차적으로 실행을 할떄 main()프레임 영역이 쌓이고, 변수 선언 및 초기화를 하였을시에 main()영역 안에서 초기화가 이루어 진다. 

그러다가 firstMethod()가 실행이 되면 main()프레임의 작업을 잠시 맘추고 secondMethod()를 호출을 하여 stack에 main() 프레임 위에 쌓이게된다. 작업이 완료가 되면 메모리를 반환을 하고(pop)모든 호출을 통한 처리가 끝나게 된다.

Posted by SH후니
,



자바 프로그램을 개발하기 위해서는 Java SE(Standard Edition)의 구현체인 'JDK'를 설치를 하여야 합니다.

Java SE는 JDK(Java Development Kit)와 JRE(Java Runtime Environment) 두가지 버전이 있는데 둘의 차이점을 보면 간단히 이렇습니다.

JDK = JVM(JAVA Virtural Mashine) + 라이브러리 API + 컴파일러 등등

JRE = JVM(JAVA Virtural Mashine) + 라이브러리 API -> 자바 프로그램을 개발목적 X, 개발된 프로그램 실행 O


1. JAVA 다운 + 설치 방법

먼저 Oracle 사이트에 접속을하여 Jdk를 다운을 받아야 한다.

Oracle 홈페이지가 예전에 비해 구조가 조금 달라셔서 jdk를 다운로드 하려고 고생하시는 분들이 많은것 같아서 해당 URL을 제공 하겠다. http://www.oracle.com/technetwork/java/javase/downloads/index.html


아래 그림에서는 JDK 9가 있지만, 스크롤 내리면 JDK 8버전이 있습니다. 이번년도에 JDK 9가 출시가 되었지만..저는 JDK 8버전을 사용하도록 하겠습니다. JDK 다운 버튼을 누르시고

JDK를 설치를 하기위해서는 반드시 Accept License Agreement를 체크를 해주여야 하며, 자신의 운영체제에 맞게 클릭을 해주시면 됩니다.

JDK를 설치를 하면 설치 안내창이 뜨면서 설치를 합니다. 해당부분은 jdk의 설치 경로가 되겠고, next를 합니다. 설치 경로를 변경하고 싶으시면 change를 눌러서 변경을 하시기 바랍니다.

그리고 설치를 완료를 하였으면, 설치가 제대로 되었는지 확인을 해주시면 됩니다. CMD창을 열어서 

명령어를 java -version을 입력을 하고 enter를 치시면 아래와 같은 화면이 나오고 정상적으로 설치가 된것을 알 수 있습니다.


2. Path설정 하기

보통 많은 개발자 분들이 Java를 설치를 하고, Path를 설정을 하는데 Path를 왜 설정을 하는지 이유를 모르고 설정을 하시는 분들이 많은 거 같아서 간단히 말합니다.(저도 몰라서 찾아봣어요..ㅎㅎ)

JDK 내부의 bin 디렉토리에는 컴파일러인 javac.exe와 JVM 구동명령어인 java.exe가 포함이 되어 있는데 이 명령어들은 자바 프로그램 개발 시 아주 빈번히 사용이 됩니다. 이 명령어들을 다른 디렉토리에서도 쉽게 실행할 수 있도록 하기 위해 Path 환경 변수에 bin 위치를 등록할 필요가 있어서 하는 것입니다. 



제어판에서 고급 시스템 설정을 들어가주세요.

그리고 [고급]탭에서 환경 변수버튼을 클릭


[환경변수]에서 [시스템 변수]에 새로 만들기를 한다음 

변수이름 :  JAVA_HOME

변수 값 : JDK설치 경로 (bin전까지) 넣어주시면됩니다.


마지막으로 시스템 변수의 Path를 편집 버튼을 누르시고

제일 뒷부분에 ";%JAVA_HOME%\bin;" (큰따옴표는 아닙니다^^)를 넣어주세요


이러면 끝입니다. 이제 마지막으로 잘 설정되어 있는지 확인 하기위해 cmd 창에 명령어로 javac를 입력을 하여서 아래와 같이 나오면 설정이 다 된것입니다.



3. 이클립스 설치

URL : https://www.eclipse.org/downloads/

이클립스는 자바 언어로 개발된 툴이기 떄문에 이클립스를 실행하려면 JVM이 필요하다. 이미 JDK를 설치를 하였고 설정까지 하였으니, 이클립스를 다운받아서 압축풀고 쓰면 된다.

순수한 자바를 학습하기 위해서는 Eclipse IDE for Java Developer를 받으면 되지만, 웹 어플리케이션 등의 엔터프라지으(네트워크) 환경에서 실행되는 자바 애플리케이션을 개발하기 위해서는 Eclopse IDE for Java EE Developers를 다운을 받는게 좋을꺼 같습니다.


이클립스 + jdk 설치 방법을 마치도록 하겠습니다~ 감사합니다^^



'SH.Language > Java' 카테고리의 다른 글

[JAVA] Object클레스 - clone()  (0) 2017.12.14
[JAVA] Object클레스 - toString()  (0) 2017.12.11
[JAVA] Object클레스 - hashCode()  (0) 2017.12.06
[JAVA] Object클래스 - equals()  (0) 2017.12.04
[JAVA] JVM 의 메모리 구조  (0) 2017.11.13
Posted by SH후니
,