자바에서 바이트배열을 수로 바꾸기, 수를 바이트배열로 바꾸기



참고사항

byte 에서 int 형변환시 lsb 커진다. 무슨 말이냐 하면

 

byte 0x80 하자. 그럼 1000 0000 이다.

 

byte 부호있는 십진수로 보면 -128이다.

 

int i= byte 라 하면  int i 값은 -128이다.

 

왜냐면 작은 크기의 형이 형으로 변환될 때는 lsb  부호 비트 값이 왼쪽 모두를 채운다.

 

1000 1000 -> 0000 0000 0000 0000 0000 0000 1000 0000 되기를 기대하지만 실제로는

1000 0000 -> 1111 1111 1111 1111 1111 1111 1000 0000 된다. unsigned 없는 자바 로써는 당연한거다.(byte signed ) 인식한다. 다시 말해 1000 0000 앞의 1 부호 비트라보고 변수형으로 커질때 왼쪽을 부호 비트로 채운다.

 

아래와 같이 해야한다.

int I = (byte & 0xff) 해주어야 한다.

 

그럼 1111 1111 1111 1111 1111 1111 1111 1111 &  0000 0000 0000 0000 0000 0000 1111 1111 =  0000 0000 0000 0000 0000 0000 1111 1111




예제소스


위의 내용을 바탕으로 자바에서 난 이런식으로 사용하였다.


바이트배열을 수로, 수를 바이트로 만들기

byte array to int, double, float, long, short And short, int, double, float, long, to byte array

import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; public class BytesValue extends Number implements BytesInOutStream { static enum ENDIAN{ BIG_ENDIAN, LIITLE_ENDIAN } private byte[] bytes; private ENDIAN endian; private int byteSize; public BytesValue(int byteSize) { this.byteSize = byteSize; this.bytes = new byte[byteSize]; this.endian = ENDIAN.BIG_ENDIAN; } public void setOrder(ENDIAN endian) { byte[] temp = this.bytes; if(this.endian!=endian) { temp=Util.reverse(this.bytes); } this.endian = endian; this.bytes = temp; } public byte[] getBytes(ENDIAN endian) { byte[] temp = this.bytes; if(this.endian!=endian) { temp=Util.reverse(this.bytes); } return temp; } public void setBytes(byte[] bytes, ENDIAN endian) { byte[] temp = bytes; if(this.endian!=endian) { temp=Util.reverse(this.bytes); } System.arraycopy(temp, 0, this.bytes,0 ,(int) this.byteSize); } public void setByte(byte value) { this.bytes[0]=value; } public void setShort(short value) { int size=Short.SIZE; byte[] temp = new byte[this.byteSize]; for(int i=0;i<this.byteSize && i<size;i++) { temp[i] = (byte)((value >> (8*i)) & 0xff); } if(this.endian == ENDIAN.BIG_ENDIAN) { temp = Util.reverse(temp); } this.bytes = temp; } public void setInt(int value) { int size=Integer.SIZE; byte[] temp = new byte[this.byteSize]; for(int i=0;i<this.byteSize && i<size;i++) { temp[i] = (byte)((value >> (8*i)) & 0xff); } if(this.endian == ENDIAN.BIG_ENDIAN) { temp = Util.reverse(temp); } this.bytes = temp; } public void setLong(long value) { int size=Long.SIZE; byte[] temp = new byte[this.byteSize]; for(int i=0;i<this.byteSize && i<size;i++) { temp[i] = (byte)((value >> (8*i)) & 0xff); } if(this.endian == ENDIAN.BIG_ENDIAN) { temp = Util.reverse(temp); } this.bytes = temp; } public void setFloat(float value) { int size=Float.SIZE; long valueTwo = Float.floatToRawIntBits(value); byte[] temp = new byte[this.byteSize]; for(int i=0;i<this.byteSize && i<size;i++) { temp[i] = (byte)((valueTwo >> (8*i)) & 0xff); } if(this.endian == ENDIAN.BIG_ENDIAN) { temp = Util.reverse(temp); } this.bytes = temp; } public void setDouble(Double value) { int size=Double.SIZE; long valueTwo = Double.doubleToRawLongBits(value); byte[] temp = new byte[this.byteSize]; for(int i=0;i<this.byteSize && i<size;i++) { temp[i] = (byte)((valueTwo >> (8*i)) & 0xff); } if(this.endian == ENDIAN.BIG_ENDIAN) { temp = Util.reverse(temp); } this.bytes = temp; } @Override public byte byteValue() { byte[] temp = this.bytes; if(this.endian==ENDIAN.BIG_ENDIAN) { temp=Util.reverse(this.bytes); } return (byte)(temp[0] & 0xff); } @Override public short shortValue() { byte[] temp = this.bytes; if(this.endian==ENDIAN.BIG_ENDIAN) { temp=Util.reverse(this.bytes); } long ret=0; for(int i=0;i<this.byteSize;i++) { ret |= ((temp[i]& 0xff)<< (8*i)); } return (short)ret; } @Override public double doubleValue() { byte[] temp = this.bytes; if(this.endian==ENDIAN.BIG_ENDIAN) { temp=Util.reverse(this.bytes); } long ret=0; for(int i=0;i<this.byteSize;i++) { ret |= ((temp[i]& 0xff)<< (8*i)); } return Double.longBitsToDouble(ret); } @Override public float floatValue() { byte[] temp = this.bytes; if(this.endian==ENDIAN.BIG_ENDIAN) { temp=Util.reverse(this.bytes); } long ret=0; for(int i=0;i<this.byteSize;i++) { ret |= ((temp[i]& 0xff)<< (8*i)); } return Float.intBitsToFloat((int)ret); } @Override public int intValue() { byte[] temp = this.bytes; if(this.endian==ENDIAN.BIG_ENDIAN) { temp=Util.reverse(this.bytes); } long ret=0; for(int i=0;i<this.byteSize;i++) { ret |= ((temp[i]& 0xff)<< (8*i)); } return (int)ret; } @Override public long longValue() { byte[] temp = this.bytes; if(this.endian==ENDIAN.BIG_ENDIAN) { temp=Util.reverse(this.bytes); } long ret=0; for(int i=0;i<this.byteSize;i++) { ret |= ((temp[i]& 0xff)<< (8*i)); } return ret; } @Override public int getByteCount() { return this.byteSize; } @Override public void writeOutputStream(OutputStream output,int offset, int lenth) throws IOException { output.write(this.bytes, offset, lenth); } @Override public int readInputStream(InputStream input,int offset, int lenth) throws IOException { int readCount = input.read(this.bytes, offset, lenth); return readCount; } }

 




byte 배열의 값 순서 reverse 하기

import java.util.ArrayList; public class Util { public static byte[] reverse(byte[] objects) { byte[] temp = new byte[objects.length]; for (int left = 0, right = objects.length - 1; left <= right; left++, right--) { temp[left]=objects[right]; temp[right]=objects[left]; } return temp; }  

} 



바이트를 문자열로 문자열을 바이트로 만들기

byte to string and string to byte

 import java.io.IOException;

import java.io.InputStream; import java.io.OutputStream; import java.io.UnsupportedEncodingException; import java.nio.charset.Charset; import java.util.Arrays; /** * Created by shh on 2016-03-28. */ public class BytesChars implements BytesInOutStream{ private byte[] bytes; private int byteSize=-1; public BytesChars(int byteSize) { this.byteSize = byteSize; bytes = new byte[byteSize]; } public byte[] getBytes() { byte[] temp = this.bytes; return temp; } public void setBytes(byte[] bytes) { byte[] temp = bytes; if(temp.length > this.byteSize) { System.arraycopy(temp, 0, this.bytes,0 ,(int) this.byteSize); }else { System.arraycopy(temp, 0, this.bytes,0 , temp.length); } } public void setString(String str, String charsetName) throws UnsupportedEncodingException { byte[] temp = str.getBytes(charsetName); this.setBytes(temp); } public String getString(String charsetName) throws UnsupportedEncodingException { int nullIndex = this.byteArrayindexOf(this.bytes,(byte)0,0); if(nullIndex==-1) { return new String(this.bytes,0,this.bytes.length,charsetName); }else { return new String(this.bytes,0,nullIndex,charsetName); } } public int byteArrayindexOf(byte[] array, byte valueToFind, int startIndex) { if (array == null) { return -1; } if (startIndex < 0) { startIndex = 0; } for (int i = startIndex; i < array.length; i++) { if (valueToFind == array[i]) { return i; } } return -1; } @Override public int getByteCount() throws Exception { return this.byteSize; } @Override public void writeOutputStream(OutputStream output,int offset, int lenth) throws IOException { output.write(this.bytes, offset, lenth); } @Override public int readInputStream(InputStream input,int offset, int lenth) throws IOException { int readCount = input.read(this.bytes, offset, lenth); return readCount; } }




오랜만에 글쓰네요.


Letter Date or Time Component Presentation Examples
G Era designator Text AD
y Year Year 1996; 96
M Month in year Month July; Jul; 07
w Week in year Number 27
W Week in month Number 2
D Day in year Number 189
d Day in month Number 10
F Day of week in month Number 2
E Day in week Text Tuesday; Tue
a Am/pm marker Text PM
H Hour in day (0-23) Number 0
k Hour in day (1-24) Number 24
K Hour in am/pm (0-11) Number 0
h Hour in am/pm (1-12) Number 12
m Minute in hour Number 30
s Second in minute Number 55
S Millisecond Number 978
z Time zone General time zone Pacific Standard Time; PST; GMT-08:00
Z Time zone RFC 822 time zone -0800

서버의 인코딩 방식이 utf-8 이라면 클라이언트도 utf-8로 보내야한다.

그래야 서버가 디코딩하고 또다시 utf-8로 인코딩하는 번거로움도 없어지고 서로의 규약을 맞출수 있다.

예)
URL url = new URL("http://www.test.com/login.jsp?id=홍길동&pass=지리산 호랑이");

예문과 같이 하게되면 홍길동과 지리산 호랑이가 한글이고 이것의 인코딩 방식이 자바의 인코딩 방식을 따르기 때문에 서버에서는 이상한 문자로 받아들일수가 있다.

이 경우
String id=URLEncoder.encode("홍길동", "UTF-8");
String pass=URLEncoder.encode("지리산 호랑이", "UTF-8");
URL url = new URL("http://www.test.com/login.jsp?id="+id+"&pass="+pass);

이런식으로 한글을 인코딩하여 url 에 써주어야한다.
위의 GET 방식뿐만 아니라 POST 방식도 마찬가지다

필자의 경우는 서버와 클라이언트 둘다 UTF-8 로 문자 인코딩 방식을 맞추었다.
개발자에 따라 자신이 원하는 인코딩 방식을 정하고 그에 맞게 URLEncoder를 이용하여 한글을 인코딩하기 바란다.


여담이지만
"없습니다.".getBytes("UTF-8") 과 URLEncoder.encode("없습니다", "UTF-8") 의 비교를 하겠다.

"없습니다.".getBytes("UTF-8") 이경우 바이트 배열을 반환하고 이를 출력해보면 
ec9786ec8ab5eb8b88eb8ba42e

URLEncoder.encode("없습니다", "UTF-8")  이 경우 문자열을 반환하고 이를 출력해보면
%EC%97%86%EC%8A%B5%EB%8B%88%EB%8B%A4

"없습니다.".getBytes("UTF-8") 는 "없습니다" 라는 문자를 utf-8로 바이트단위로 인코딩하는 것이라면
URLEncoder.encode("없습니다", "UTF-8")  는 인코딩한 값을 문자로써 보여준다.

"없습니다.".getBytes("UTF-8") 해서 나온 바이트배열을 한 바이트단위로 %를 붙여 문자열화 시킨것이
URLEncoder.encode("없습니다", "UTF-8") 이다.



ps . 글을 발로 썼나... 글공부좀 해야지
이해하신 분들은 용자...


아래는 검색하다가 이거다 싶어서 퍼왔다.  저 자세한 내용은 출처에 있으니 참고하시길..

String url = "http://example.com";
String charset = "UTF-8";
String param1 = "value1";
String param2 = "value2";
// ...
String query = String.format("param1=%s&param2=%s",
     
URLEncoder.encode(param1, charset),
     
URLEncoder.encode(param2, charset));


출처 : http://stackoverflow.com/questions/2793150/how-to-use-java-net-urlconnection-to-fire-and-handle-http-requests





  1. 동미선 2021.02.27 08:02

    감사합니다


 String enc = new java.io.OutputStreamWriter(System.out).getEncoding();

 System.out.println("default encoding = " + enc);

출처 : http://itsoldesk.tistory.com/entry/Java-%EA%B8%B0%EB%B3%B8-encoding-type-%ED%99%95%EC%9D%B8%ED%95%98%EA%B8%B0


Window -> Preferences -> Java -> Code Style -> Code Templates -> Comments 에서

파일정보 주석 (소스 가장 위 상단을 선택)

Types -> Edit

/**
* @FileName : ${file_name}
* @Project : ${project_name}
* @Date : ${date}
* @작성자 : ${user}

* @변경이력 :
* @프로그램 설명 :
*/

메소드정보 주석 (원하는 함수를 선택)

Methods -> Edit

/**
* @Method Name : ${enclosing_method}
* @작성일 : ${date}
* @작성자 : ${user}
* @변경이력 :
* @Method 설명 :
* ${tags}
*/

${} 내용설명

data : Current date (현재 날짜)

dollar : The dollar symbol (달러문양)

enclosing_type :The type enclosing the method (선택된 메소드의 타입)

file_name : Name of the enclosing compilation (선택된 편집파일 이름)

package_name : Name of the enclosing package (선택된 패키지 이름)

project_name : Name of the enclosing project (선택된 프로젝트 이름)

tags : Generated Javadoc tags (@param, @return...) (Javedoc 태그 생성)

time : Current time (현재 시간)

todo : Todo task tag ('해야할일'태그 생성)

type_name : Name of the current type (현재 타입의 이름)

user : User name (사용자 이름)

year : Current year (현재 연도)

3.2 기준으로 주석입력 단축키는 ALT + SHIFT + J



출처 : http://blog.naver.com/rapkuma?Redirect=Log&logNo=20036011030


파일이 바뀌었는지를 확인하기 위해서 사용하였다.
아마존 클라우드랑 로컬 파일시스템이랑 데이터 자동 동기화 프로그램을 작성중인데 최근 수정 날짜로만 파일이 바뀐지를 알아보기는 아주 비효율적이라 파일의 DNA 즉 MD5 코드를 이용하여 파일이 바뀐지 분석하였다.
클라우드에 파일이 생겼는지 삭제됐는지 수정됐는지 알기 위해서 클라우드상의 파일 목록을 로컬에서 저장해두고 N초 마다 목록을 다시 가져와 과거의 목록과 비교하면서 감시하고 있는데... 클라우드상에서 이런걸 지원해주는거 없나??
시간을 보내주면 그 시간 이후에 파일이 생겼는지, 수정됐는지, 삭제됐는지 아는 방법... 생성, 수정은 최근 수정 날짜로 판단하면 되는데 삭제된 파일은.. 최근 수정 날짜로 판단이 불가하니까.. 에이..

어째든 아래의 코드가 파일이든 모든 inputStream 을 받아 MD5 코드를 만들어 주는 함수이다...

public static byte[] computeMD5Hash(InputStream is) throws NoSuchAlgorithmException, IOException {
         BufferedInputStream bis = new BufferedInputStream(is);
         try {
             MessageDigest messageDigest = MessageDigest.getInstance("MD5");
             byte[] buffer = new byte[16384];
             int bytesRead = -1;
             while ((bytesRead = bis.read(buffer, 0, buffer.length)) != -1) {
                 messageDigest.update(buffer, 0, bytesRead);
             }
             return messageDigest.digest();
         } finally {
             try {
                 bis.close();
             } catch (Exception e) {
                 System.err.println("Unable to close input stream of hash candidate: " + e);
             }
         }
     }


위 함수를 그냥 사용하면 반환형이 byte 배열이라 사용하기 힘듬
아래의 함수를 이용해서 BASE64로 인코딩해서 String 으로 만들어서 사용하세요

   public static String toBase64(byte[] data) {
         byte[] b64 = Base64.encodeBase64(data);
         return new String(b64);
     }




자바
wait(), notify(), notifyall() 을 무한 쓰레드의 cpu 점유율을 줄이기 위해 사용하게 되었다.
근데 위 함수를 사용하는 곳에서 자꾸 java.lang.IllegalMonitorStateException  예외가 떴다.

알아보니 wait(), notify(), notifyall()을 사용하는 객체가 synchronized(){} 되어야 했다.

정리
wait(), notify(), notifyall() 사용하는 객체를 synchronized(){}  하여라..

만약 thread 라는 객체가 있고 이 객체의 wait(), notify(), notifyall() 을 호출하기 위해서는
synchronized(thread)
{
    thread.wait();
}
하라는 말이다..


synchronized() 내의 객체와 wait나 notify 함수를 호출하는 객체는 같아야한다..

synchronized(A)
{
    B.wait();
}
이거 안됨

synchronized(A)
{
    A.wait();
}
이거 됨


아 그리고 자꾸 wait() 에 대해서만 synchronized 블럭 사용하는데 notify() , notifyall() 함수도 synchronized 블럭내에 있어야한다.

혹자들은 이런 생각을 할수 있다. synchronized 에 같은 객체를 블럭시키면 wait()가 의미가 없는 것이냐고.. 그렇지 않다. wait() 함수는 자신을 호출시킨 객체의 synchronized를 푼다. 이해가셨을지 모르겟다...;;; 리눅스의 pthread_cond_wait()를 참조해라.. 같은 원리다.


ps . 나만 알아보겠구만...

public class UserHomeExample
{
public static void main ( String [] args )
{

System.out.println ( "User Home Path: "
+
System.getProperty (
"user.home" )) ;
}
}





이게 사용자의 기본 홈 디렉토리 경로를 찾는 방법입니다.
System.getProperty ( "user.home" )) ;


출처 : http://www.roseindia.net/java/beginners/UserHomeExample.shtml


public class DotThis {

       

        void f() {

               System.out.println("DotThis.f()");

        }

       

        public class Inner {

               public DotThis outer() {

 

                       return DotThis.this;

                       //DotThis.this 는 외부클래스 객체(DotThis)를 나타낸다.              

                      

                       //return this;

                       //this 는 내부클래스 객체(Inner)를 나타낸다.

               }

        }

       

        public Inner inner() {

               return new Inner();

        }

       

        public static void main(String[] args) {

               DotThis dt = new DotThis();

               DotThis.Inner dti = dt.inner();

               dti.outer().f(); //outer()가 리턴하는 것이 외부클래스 객체를 리턴함

        }

}

/* 결과:

DotThis.f()

*/


클래스이름.this 는 클래스의 인스턴스를 나타내는 명시적 표현이다.



Reflection
리플렉션(Reflection)이란 객체를 통해 클래스의 정보를 분석해 내는 프로그램 기법을 말합니다. 약간 어렵죠. 영어 단어로 Reflection은 '거울에 비친 그림자' 또는 '반사' 등의 의미로 사용됩니다. 자세히 관찰하면 자바의 리플렉션은 이 의미를 그대로 따르고 있습니다. 거꾸로라는 의미죠.

▣ 리플렉션(Reflection)이란?
◈ 객체를 통해 클래스의 정보를 분석해 내는 프로그램 기법

일반적으로 여러분들은 클래스를 디자인하고, 클래스의 모든 정보를 담고있는 .class 파일을 만듭니다. 만들어진 클래스를 이용해서 새로운 객체를 선언하고, 그리고 객체의 메모리를 할당하게 됩니다. 그런데 이것을 역으로 생각해 보죠. 만약 객체의 메모리만을 알고 있고, 그리고 이 객체의 형을 모른다고 가정해 보죠. 모든 객체는 Object 클래스를 상속받으니 기본적으로 Object형의 객체로 인식될 수는 있지만, 형을 모른다면 객체 내에 포함되어 있는 메서드를 호출할 수 있을까요? 지금까지 배운 기술로는 불가능합니다. 하지만 리플렉션 기법의 프로그래밍을 이용하면 형을 모르는 상태에서 객체의 메서드를 호출할 수 있습니다.

ⓙ───────────────────────────────────────
/**
클래스의 내의 정보 출력
**/
import java.lang.reflect.*;
import java.util.Vector;
public class ShowClassInfoMain {    
    public static void main(String [] args) {        
            Class c = Integer.class;
            Class[] iface = c.getInterfaces();
            Constructor [] ctor = c.getConstructors();
            Method [] m = c.getMethods();
            Field[] f = c.getFields();
            Class temp = c;
           
            System.out.println("==========start getSuperclass() ============" );
            while( (temp=temp.getSuperclass()) != null ){
                System.out.println(temp);
            }
            System.out.println("==========end getSuperclass() ============" );
           
            System.out.println();
            System.out.println("==========start getInterfaces() ============" );
            for(int i=0; i<iface.length; i++){
                System.out.println("interface[" + i + "]:" + iface[i]);
            }
            System.out.println("==========end getInterfaces() ============" ); 
            System.out.println();
            System.out.println("==========start getConstructors() ============" );
            for(int i=0; i<ctor.length; i++){
                System.out.println("Constructor[" + i + "]:" + ctor[i]);
            }
            System.out.println("==========end getConstructors() ============" );
            System.out.println();
            System.out.println("==========start getMethods() ============" );
            for(int i=0; i<m.length; i++){
                System.out.println("Method[" + i + "]:" + m[i]);
            }
            System.out.println("==========end getMethods() ============" );
            System.out.println();
            System.out.println("==========start getFields() ============" );
            for(int i=0; i<f.length; i++){
                System.out.println("Field[" + i + "]:" + f[i]);
            }
            System.out.println("==========end getFields() ============");
           
    } //end of main
} //end of ShowClassInfoMain class

C:\tutorial>javac ShowClassInfoMain.java

C:\tutorial>java ShowClassInfoMain
==========start getSuperclass() ============
class java.lang.Number
class java.lang.Object
==========end getSuperclass() ============

==========start getInterfaces() ============
interface[0]:interface java.lang.Comparable
==========end getInterfaces() ============

==========start getConstructors() ============
Constructor[0]:public java.lang.Integer(java.lang.String) throws java.lang.NumberFormatException
Constructor[1]:public java.lang.Integer(int)
==========end getConstructors() ============

==========start getMethods() ============
Method[0]:public int java.lang.Integer.hashCode()
Method[1]:public static int java.lang.Integer.reverseBytes(int)
Method[2]:public boolean java.lang.Integer.equals(java.lang.Object)
Method[3]:public int java.lang.Integer.compareTo(java.lang.Object)
Method[4]:public int java.lang.Integer.compareTo(java.lang.Integer)
Method[5]:public static java.lang.String java.lang.Integer.toString(int,int)
Method[6]:public static java.lang.String java.lang.Integer.toString(int)
Method[7]:public java.lang.String java.lang.Integer.toString()
Method[8]:public static java.lang.String java.lang.Integer.toHexString(int)
Method[9]:public static java.lang.Integer java.lang.Integer.decode(java.lang.String) throws java.lang.NumberFormatException
Method[10]:public static java.lang.Integer java.lang.Integer.valueOf(java.lang.String,int) throws java.lang.NumberFormat
Exception
Method[11]:public static java.lang.Integer java.lang.Integer.valueOf(int)
Method[12]:public static java.lang.Integer java.lang.Integer.valueOf(java.lang.String) throws java.lang.NumberFormatException
Method[13]:public static int java.lang.Integer.reverse(int)
Method[14]:public byte java.lang.Integer.byteValue()
Method[15]:public double java.lang.Integer.doubleValue()
Method[16]:public float java.lang.Integer.floatValue()
Method[17]:public int java.lang.Integer.intValue()
Method[18]:public long java.lang.Integer.longValue()
Method[19]:public short java.lang.Integer.shortValue()
Method[20]:public static int java.lang.Integer.parseInt(java.lang.String) throws java.lang.NumberFormatException
Method[21]:public static int java.lang.Integer.parseInt(java.lang.String,int) throws java.lang.NumberFormatException
Method[22]:public static int java.lang.Integer.bitCount(int)
Method[23]:public static java.lang.Integer java.lang.Integer.getInteger(java.lang.String,java.lang.Integer)
Method[24]:public static java.lang.Integer java.lang.Integer.getInteger(java.lang.String)
Method[25]:public static java.lang.Integer java.lang.Integer.getInteger(java.lang.String,int)
Method[26]:public static int java.lang.Integer.highestOneBit(int)
Method[27]:public static int java.lang.Integer.lowestOneBit(int)
Method[28]:public static int java.lang.Integer.numberOfLeadingZeros(int)
Method[29]:public static int java.lang.Integer.numberOfTrailingZeros(int)
Method[30]:public static int java.lang.Integer.rotateLeft(int,int)
Method[31]:public static int java.lang.Integer.rotateRight(int,int)
Method[32]:public static int java.lang.Integer.signum(int)
Method[33]:public static java.lang.String java.lang.Integer.toBinaryString(int)
Method[34]:public static java.lang.String java.lang.Integer.toOctalString(int)
Method[35]:public final void java.lang.Object.wait() throws java.lang.InterruptedException
Method[36]:public final void java.lang.Object.wait(long,int) throws java.lang.InterruptedException
Method[37]:public final native void java.lang.Object.wait(long) throws java.lang.InterruptedException
Method[38]:public final native java.lang.Class java.lang.Object.getClass()
Method[39]:public final native void java.lang.Object.notify()
Method[40]:public final native void java.lang.Object.notifyAll()
==========end getMethods() ============

==========start getFields() ============
Field[0]:public static final int java.lang.Integer.MIN_VALUE
Field[1]:public static final int java.lang.Integer.MAX_VALUE
Field[2]:public static final java.lang.Class java.lang.Integer.TYPE
Field[3]:public static final int java.lang.Integer.SIZE
==========end getFields() ============

***/
───────────────────────────────────────ⓑ

▣ 정적 바인딩
가상머신이 바이트 코드로 된 .class 파일을 로딩한 후에 객체를 생성할 수 있듯이, 프로그래머가 .class 파일을 직접 로딩한 후 Class 클래스를 이용해서 객체를 생성할 수도 있습니다. 일반적인 방법으로 객체를 생성하면 가상머신이 그 다음 작업을 해주는 것입니다.
◈ 컴파일할 때 해당 .class 파일이 필요하다면, 해당 클래스를 정적 바인딩으로 사용하는 것이다.

▣ 동적 바인딩으로 클래스 로딩
클래스의 동적 바인딩은 컴파일할 때 해당 클래스가 없어도 됩니다. 말그대로 프로그램이 실행되고 난 뒤에 동적으로 위치 를 명시하고, 해당 클래스(.class)를 로딩해서 객체를 만든다든지 메서드를 호출할 수 있습니다. 일반적으로 말하는 리플렉션 의 기법은 정적 바인딩 클래스가 아니라 동적 바인딩 클래스를 의미합니다. 동적 바인딩의 기법으로 클래스를 로딩하는 방법은 다음 과 같습니다.
◈ Class c = Class.forName("클래스이름");
클래스의 이름 자체를 컴파일 타임에 사용할 수 없기 때문에 문자열 형태로 클래스의 이름을 사용합니다. 그리고 Class.forName("클래스이름")이 호출되는 바로 그 순간에 클래스를 로딩하겠다는 의미가 됩니다. 
◈ 클래스의 이름을 문자열로 사용하는 이유는 해당 클래스가 컴파일할 때 없기 때문입니다.

◈ 동적 바인딩을 활용하면, 웹서버에(URLClassLoader이용) 있는 Class를 가져올 수 도 있다.

▣ 리플렉션 기법들
◈ 생성자에 매개변수가 없는 객체 생성하기
◈ 생성자에 매개변수가 있는 객체 생성하기
◈ 매개변수가 없는 메서드 호출하기
◈ 매개변수가 있는 메서드 호출하기
◈ 특정객체에 멤버 필드 값 셋팅하기
◈ 특정객체에 멤버 필드 값 얻어내기 .

출처 : http://blog.naver.com/PostView.nhn?blogId=ypark197&logNo=90093550962&redirect=Dlog&widgetTypeCall=true


Java 리플렉션에 대한 재고(reflection)(1)

일상에서의 리플렉션(reflection)이란 거울 속에 비친 자신의 모습입니다. 프로그래밍 세상에서의 리플렉션은 프로그램이 자신의 모습을 보고 심지어 수정하기 까지 하는 것을 말합니다. Java reflection API는 바로 그런 기능을 언어의 기본 요소인 클래스, 필드, 메소드를 들여다 볼 수 있는 평범한 Java API를 통해 제공합니다. 리플렉션을 이해하는 것은 여러분이 자주 사용하는 툴을 이해하는데 도움이 됩니다. Eclipse가 어떻게 자동완성으로 메소드 이름을 만들어 줄까? Tomcat은 web.xml파일에 있는 클래스 이름을 가지고 웹의 요청을 처리할 서블릿을 실행하는 걸까? Spring은 어떻게 마술 같은 dependency injection을 하는 것일까? 여러분의 프로그램에서도 리플렉션을 사용하여 보다 동적이고 유연한 코드를 작성하실 수 있습니다. 리플렉션을 사용하면 이전에 본적 없는 클래스들을 매우 멋지게 처리할 수 있습니다.

클래스 만들기

이미 말했듯이 리플렉션의 기본 아이디어는 프로그램이 동작하는 내부에 집어 넣을 API를 제공하는 것입니다. Java에서 가장 기본이 되는 사상이 바로 클래스기 때문에(클래스 없이 자바 프로그램을 만들어 보세요) Class 클래스부터 살펴보는 것이 좋겠습니다. 이것의 객체는 Class 타입일 것입니다. 일단 Class객체를 가지게 되면 그것으로부터 클래스에 관련된 모든 정보를 뽑아낼 수 있습니다. 클래스의 이름, 그것이 public 인지 abstract 인지 final 인지 그리고 심지어 상위 클래스까지 말이죠.

이 정도면 이론은 충분합니다. 자, 이제 리플렉션 현미경을 가지고 아래에 있는 매우 간단한 Employee 클래스를 살펴봅시다.
package com.russolsen.reflect;

public class Employee
{
   public String _firstName;
   public String _lastName;
   private int _salary;

      public Employee()
   {
      this( "John", "Smith", 50000);
   }
 
   public Employee(String fn, String ln, int salary)
   {
      _firstName = fn;
      _lastName = ln;
      _salary = salary;
   }
   
      public int getSalary()
   {
      return _salary;
   }
   
   public void setSalary(int salary)
   {
      _salary = salary;
   }
   
   public String toString() 
   {
      return "Employee: " + _firstName +  " "
             + _lastName + " " + _salary;
   }

}
Class 객체를 만드는 가장 쉬운 방법은 해당 클래스 객체의 getClass 메소드를 호출하는 것입니다. 아래에 있는 코드는 Employee 객체를 만들고 그것의 Class 객체를 만들어서 클래스에 대한 다양한 정보들을 출력합니다.
package com.russolsen.reflect;

import java.lang.reflect.Modifier;

public class GetClassExample
{
   public static void main(String[] args)
   {
 
      Employee employee = new Employee();
      
      Class klass = employee.getClass();
      
      System.out.println( "Class name: " + klass.getName());
      System.out.println( 
            "Class super class: " + klass.getSuperclass());
      
      int mods = klass.getModifiers();
      System.out.println( 
            "Class is public: " + Modifier.isPublic(mods));
      System.out.println( 
            "Class is final: " +  Modifier.isFinal(mods));
      System.out.println( 
            "Class is abstract: " + Modifier.isAbstract(mods)); 

   }

}
코드를 실행하면 다음과 같은 결과를 확인할 수 있습니다.
Class name: com.russolsen.reflect.Employee
Class super class: class java.lang.Object
Class is public: true
Class is final: false
Class is abstract: false
예제에서 보이듯이 클래스의 이름과 상위 클래스를 알아내는 것은 다른 접근 메소드들(Getters or Accessors)을 호출하는 것처럼 쉬운 일입니다. 만약 해당 클래스가 public 인지 abstract 인지 final 인지 알고 싶다면 약간 복잡해 집니다. 이 모든 정보가 getModifires에 의해 하나의 int 값으로 패키징되어 넘어오기 옵니다. 다행히 Java는 Modifier 클래스를 통해 getModifiers에서 넘어온 숫자를 가지고 여러 일을 할 수 있는 static 메소드들을 제공해 줍니다.

객체에 getClass를 호출하는 것 만이 Class 객체를 얻을 수 있는 유일한 방법은 아닙니다. 클래스 이름을 사용하여 직접 얻을 수도 있습니다.
Class klass = Employee.class;
세 번째 방법은 좀 더 흥미로운 방법입니다. 문자열을 통해서 Class 객체를 생성할 수 있습니다. 물론 그 문자열이 클래스 이름을 포함하고 있을 때 말이죠. 다음과 같이 Class 클래스에 있는 forName 을 호출하여 얻을 수 있습니다.
      Class klass = Class.forName("com.russolsen.reflect.Employee");
      
      System.out.println( "Class name: " + klass.getName());
      System.out.println( 
            "Class super class: " + klass.getSuperclass());
      
      // Print out the rest...
forName을 사용할 때 한 가지 주의할 것은 클래스 이름 앞에 완전한 패키지 경로를 붙여줘야 한다는 것입니다. 평범하고 늙은 “Employee” 말고 “com.russolsen.reflect.Employee" 여야만 합니다. forName을 통해 리플렉션 API의 기본적인 강력함(그리고 멋진 것)을 살펴봤습니다. 클래스 이름을 포함한 문자열로 시작할 수도 있고 class로 끝낼 수도 있습니다.

바로 인스턴스 만들기

class 객체를 가져오고 그것에 관한 정보를 찾는 것은 그것 자체로도 흥미롭고 유용합니다. 하지만 진짜 재미있는 것은 리플렉션을 사용하여 무언가를 실제 해보는 것입니다. Class 객체를 가지고 할 수 있는 가장 눈에 띄는 작업은 그 클래스의 새로운 객체를 만드는 것입니다. newInstance 메소드를 사용하여 간단하게 만들 수 있습니다. 실제 사용하는 것을 보여 주기 위하여 아래에 있는 간단한 프로그램은 커맨드 라인 인자(command line argument)로 Class 객체를 만들고 그 클래스 타입의 객체를 만드는 프로그램을 보여줍니다.
package com.russolsen.reflect;

public class NewInstanceExample
{
   public static void main(String[] args)
      throws ClassNotFoundException,
      InstantiationException, IllegalAccessException
   {

      Class klass = Class.forName(args[0]);
      Object theNewObject = klass.newInstance();
      System.out.println("Just made: " + theNewObject);
   }
}
위 코드를 "com.russolsen.reflect.Employee" 인자와 함께 실행하면 새로운 Employee 객체를 만들게 됩니다.
Just made: Employee: John Smith 50000

Run it again, but this time feed it "java.util.Date" and you will get:

Just made: Tue Feb 27 20:25:20 EST 2007
간단한 코드 몇 줄로 얼마나 많은 유연성을 얻게 되었는지 생각해보세요. 위에 있는 프로그램은 실제 Employee 나 Date 클래스에 관해 아는 것이 하나도 없지만 각각의 새로운 객체들을 만들 수 있습니다. 이것이야 말로 Java 프로그래밍을 하는 또 다른 방법입니다.

인자 없는 생성자 너머에

Class.newInstance 메소드를 호출하는 것은 인자 없이 new를 사용하는 것과 동일합니다. 그러나 만약 인자가 없는 생성자 즉 default 생성자가 없는 클래스에 newInstance를 호출하면 어떻게 될까요? 좋을 일 없습니다. 별로 맘에 안 드는 InstantiationException을 받게 됩니다.

좋은 소식이 있습니다. 생성자 인자를 필요로 하는 클래스의 객체를 동적으로 만들 수 있습니다. 하지만 약간 더 힘든 작업을 해야 합니다. 그건 바로 클래스에서 해당 생성자를 찾고 적당한 인자를 사용하여 그것을 호출하는 일입니다. 적당한 생성자를 찾는 일은 여러분이 찾고자 하는 생성자에 대한 정보를 가지고 getConstrucor 메소드를 사용하면 됩니다. 그럼 Constuctor 객체를 얻게 되고 그것을 사용하여 새로운 객체를 만들 수 있습니다.
Let's see how this all works in code:
      Class klass = Class.forName("com.russolsen.reflect.Employee");

      Class[] paramTypes = {
            String.class, 
            String.class, 
            Integer.TYPE };
      
      Constructor cons = klass.getConstructor(paramTypes);
      
      System.out.println( "Found the constructor: " + cons);

      
      Object[] args = { 
            "Fred", 
            "Fintstone", 
            new Integer(90000) };
      
      Object theObject = cons.newInstance(args);
      System.out.println( "New object: " + theObject);
생성자들 사이의 차이점은 오직 그것들이 가지고 있는 매개 변수들입니다. 따라서 getConstructor 메소드에 찾고자 하는 생성자에 들어갈 매개변수 각각의 Class들 객체의 배열을 넘겨줍니다. 위에 있는 예제에서는 두 개의 String 그리고 하나의 int를 받는 생성자를 찾게 됩니다. Constructor 객체를 얻은 뒤 새로운 객체를 생성하는 일은 간단합니다. 실제 인자로 들어갈 객체의 배열을 newInstance 메소드를 호출하면서 넘겨주면 됩니다







Java 리플렉션에 대한 재고(reflection)(2)


클래스를 좀 더 자세히 살펴보기

첫 번째 예제에서 봤듯이 Class 객체는 그것의 이름이나 상위 클래스 같은 정보를 제공합니다. 이 이름을 사용하여 좀 더 자세히 rank 와 시리얼 넘버(serial number) 차원의 정보까지 알 수 있습니다. 예를 들어 getMethods 메소드를 사용하여 클래스가 가진 모든 public 메소드를 찾을 수 있습니다.

      Class klass = Class.forName("com.russolsen.reflect.Employee");
           
      Method[] methods = klass.getMethods();
      
      for(Method m : methods )
      {
         System.out.println( "Found a method: " + m );
      }
getMethods 는 클래스가 가지고 있는 public 메소드 각각에 해당하는 Method 객체의 배열을 반환합니다.
Found a method: public java.lang.String com.russolsen.reflect.Employee.toString()
Found a method: public int com.russolsen.reflect.Employee.getSalary()
Found a method: public void com.russolsen.reflect.Employee.setSalary(int)
Found a method: public native int java.lang.Object.hashCode()
Found a method: public final native java.lang.Class java.lang.Object.getClass()
Found a method: public final native void java.lang.Object.wait(long) throws java.lang.InterruptedException
Found a method: public final void java.lang.Object.wait(long,int) throws java.lang.InterruptedException
Found a method: public final void java.lang.Object.wait() throws java.lang.InterruptedException
Found a method: public boolean java.lang.Object.equals(java.lang.Object)
Found a method: public java.lang.String java.lang.Object.toString()
Found a method: public final native void java.lang.Object.notify()
Found a method: public final native void java.lang.Object.notifyAll()
getMethods는 클래스의 사용자(client) 입장이기 때문에, 배열에는 자신이 가지고 있는 모든 public 메소드 (Object 까지 달하는 모든 상속 계층의 상위 클래스들에 있는 public 메소드까지 포함하여)를 배열에 담아 줍니다.

만약 하나의 메소드에만 관심이 있다면, getMethod(단수 형태 입니다.)를 사용할 수 있습니다. getConstructor와 비슷하게 동작하지만 파라미터 타입들 뿐만 아니라 메소드의 이름도 넘겨 줘야 합니다. 아래에 있는 코드는 하나의 int 파라미터를 가지는 setSalary 라는 메소드를 찾습니다.
      Class klass = Class.forName("com.russolsen.reflect.Employee");
      Class[] paramTypes = {Integer.TYPE };
      Method setSalaryMethod = 
         klass.getMethod("setSalary", paramTypes);
           
      System.out.println( "Found method: " + setSalaryMethod);
리플렉션을 사용하여 메소드를 호출하는 것은 constuctor를 호출하는 것과 매우 유사합니다. 앞서 살펴봤던 Method 객체만 있으면 되고 메소드에 인자로 넘겨 줄 배열과 메소드를 호출할 객체가 필요합니다. 아래에 있는 코드는 우리 직원에게 월급을 올려주기 위해서 Employee 객체에 있는 setSalary 메소드를 호출합니다.
      Class klass = Class.forName("com.russolsen.reflect.Employee");

      Class[] paramTypes = {Integer.TYPE };
      Method setSalaryMethod = 
         klass.getMethod("setSalary", paramTypes);
      
      Object theObject = klass.newInstance();
      Object[] parameters = { new Integer(90000) };
      
      setSalaryMethod.invoke(theObject, parameters);
그냥 theObject.setSalary(9000)를 호출하지 않고 왜 그렇게 귀찮게 했을까요? 위에 있는 코드를 자세히 살펴보시길 바랍니다. 코드의 첫 번째 줄을 빼면 위에 있는 프로그램은 완전히 일반적입니다. 어떤 클래스의 어떤 객체든 상관없이 setSalary 메소드를 호출할 것입니다. 약간만 수정하면 어떤 클래스의 어떤 객체든 거기에 있는 모든 메소드를 호출하는 코드로 사용할 수 있습니다.

필드 가지고 놀기

리플렉션을 사용하여 메소드를 호출하는 데에서 그치지 않습니다. 필드에 대한 모든 권한 역시 가지고 있습니다. getMethods 처럼 getFields는 해당 클래스 또는 그것의 상위 클래스에 있는 모든 public 필드 각각에 대한 Fileld 객체의 배열을 반환합니다.
      Class klass = Class.forName("com.russolsen.reflect.Employee");
      
      System.out.println( "Class name: " + klass.getName());
      
      Field[] fields = klass.getFields();
      
      for(Field f : fields )
      {
         System.out.println( "Found field: " + f);
      }
Employee 가 두 개의 public 필드를 가지고 있기 때문에 두 개의 멤버를 가진 배열을 얻게 됩니다.
Class name: com.russolsen.reflect.Employee
Found field: public java.lang.String com.russolsen.reflect.Employee._firstName
Found field: public java.lang.String com.russolsen.reflect.Employee._lastName
getField메소드를 사용하여 특정 필드 하나만 가져올 수도 있습니다.
      Field field = klass.getField("_firstName");
      System.out.println("Found field: " + field);
Field 객체를 가지고 get 메소드를 호출하면 필드가 가진 값을 가져올 수 있고 set을 사용하여 값을 설정할 수 있습니다.
      Object theObject = new Employee("Tom", "Smith", 25);
      
      Class klass = Class.forName("com.russolsen.reflect.Employee");
      
      Field field = klass.getField("_firstName");
      
      Object oldValue = field.get(theObject);
      System.out.println( "Old first name is: " + oldValue);
      
      field.set( theObject, "Harry");
      Object newValue = field.get(theObject);
      System.out.println( "New first name is: " + newValue);
위에 있는 코드를 실행하고 _firstName 필드가 변하는 것을 주의 깊게 살펴보시기 바랍니다.
Old first name is: Tom
New first name is: Harry
규칙 깨기

Java의 가장 신성한 규칙 중 하나를 깨는 방법을 얘기하지 않고서는 리플렉션을 마무리할 수 없습니다. 여러분 모두 잘 알다시피 해당 클래스 밖에서는 private 메소드를 호출 할 수 없습니다. 그렇죠? 아마 평범한 기술을 사용하는데 그친다면 하지 못할 것입니다. 하지만 리플렉션을 사용하면 거의 모든 걸 할 수 있습니다.

private 메소드를 호출하기 위해서 가장 먼저 해야 할 일은 호출하고 싶어 하는 메소드를 나타내는Method객체를 얻는 것입니다. getMethod로는 얻을 수 없습니다. 그건 오직 public 메소드만 반환합니다. private(또는 protected)메소드를 가져오는 방법은 getDeclaredMethod를 사용하는 것입니다. getMethod는 해당 클래스의 사용자 관점(client’s view)에서 public 메소드만 가져오지만, getDeclaredMethod는 클래스에 선언한 모든 메소드를 반환합니다. 아래에 있는 예제에서 java.util.ArrayList 클래스에 있는 private 메소드인 removeRange 를 가져옵니다.
      ArrayList list = new ArrayList();
      list.add("Larry");
      list.add("Moe");
      list.add("Curley");

      System.out.println("The list is: " + list);

      Class klass = list.getClass();

      Class[] paramTypes = { Integer.TYPE, Integer.TYPE };
      Method m = klass.getDeclaredMethod("removeRange", paramTypes);

      Object[] arguments = { new Integer(0), new Integer(2) };
      m.setAccessible(true);
      m.invoke(list, arguments);
      System.out.println("The new list is: " + list);
private 메소드를 받은 뒤에 간단히 setAccessable 안전장치를 제거하고 호출하면 됩니다.
The list is: [Larry, Moe, Curley]
The new list is: [Curley]
removeRange 메소드는 리스트에서 주어진 범위의 아이템을 제거하는 것처럼 보입니다. 이것은 매우 강력한 마술입니다. java.util 에 있는 클래스에 접근하여 그 안에 있는 private 메소드를 호출할 수 있습니다. 이것을 사용하여 코드의 의도를 우회하여 private 메소드를 호출하는 취미를 즐기실 건가요? 아니죠! 그러나 저런 것들이 약간은 유용할 때가 있습니다.

결론

리플렉션을 사용하여 Java의 규칙을 무시하는 것처럼 보이는 것들을 하는 프로그램을 작성할 수 있습니다. 일반적으로는 알 수 없는 클래스에 관한 정보를 모두 알아내는 코드를 작성할 수 있습니다. 그리고 동적으로 알아낸 정보에 어떤 행위를 할 수도 있습니다. 즉 새로운 객체를 만들고 메소드를 호출하고 필드에 값을 설정하거나 가져올 수 있습니다. 극단적인 경우에서는 클래스의 private 멤버들에 접근할 수 있습니다. 점점 복잡해져가는 Java 개발 툴의 동작을 이해하기 위해서는 리플렉션에 대한 이해가 필요합니다. 또한 “평범한” Java 프로그램이 할 수 있는 것 이상의 프로그램을 작성해야 할 때도 필요합니다.










제공 : 한빛 네트워크
저자 : Russ Olsen
역자 : 백기선
원문 : Reflections on Java Reflection


출처 : http://www.hanb.co.kr/network/view.html?bi_id=1369
출처 : http://www.hanb.co.kr/network/view.html?bi_id=1370

Generics

제너릭 타입(Generic Types)은 주로 자바 컬렉션에서 많이 사용되고 있다. 컬렉션은 자료구조이다. 컬렉션에는 어떤 자료를 담을지 알 수 없으므로 최상위 객체인 Object형태로 저장되고 관리되도록 설계되어 있다. 하지만, 의도하지 않은 자료형이 담기는 경우도 발생하게 된다. 이 때의 오류는 컴파일시에는 알 수가 없고 실행을 시켜보아야만 알 수 있다는 것이 문제점이었다. 제너릭 타입을 사용하면 프로그래머가 원하는 객체의 타입을 명시해서 의도하지 않은 객체는 저장될 수 없도록 컴파일시에 오류를 확인할 수있게 된다.

제너릭클래스 정의하기

제네릭 클래스를 정의하는 방법은 일반적인 클래스를 정의하는 것과 동일하다. 다만, 클래스명 뒤에 <제너릭타입, ...>이라고 덧붙여 준다.

public class Box<T> {
    private T t; // T stands for "Type"
    public void add(T t) {
        this.t = t;
    }
    public T get() {
        return t;
    }
}

제너릭 클래스 선언 / 생성

일반적인 클래스와 동일하게 선언하고 생성할 수 있다. 다만, 클래스명 뒤에 <제너릭타입>을 덧붙여주면 된다.

Box<Integer> integerBox;
integerBox = new Box<Integer>();

제너릭 타입에 사용되는 파라미터

타입 매개변수는 하나의 대문자를 사용한다. 이들은 파일시스템에 실재로 존재하는 것은 아니다. 즉, T.java 라던지 T.class라는 파일은 없다. 타입매개변수를 여러개 사용할 수도 있지만 하나의 선언문에서 두 번 사용될 수는 없다. 즉, Box<T, U>는 가능하지만 Box<T, T>는 안된다.

  • E - Element (자바의 컬렉션에서 널리 사용되고 있다.)
  • K - Key
  • N - Number
  • T - Type
  • V - Value
  • S,U,V etc. - 2nd, 3rd, 4th types

제너릭 메서드 / 제너릭 생성자

타입 매개변수가 메서드의 선언 등에 사용될 수도 있다. 단, 매개변수의 범위가 메서드의 블록 이내로 한정된다.

public class Box<T> {
    private T t;
    public void add(T t) {
        this.t = t;
    }
    public T get() {
        return t;
    }
    public <U> void inspect(U u){
        System.out.println("T: " + t.getClass().getName());
        System.out.println("U: " + u.getClass().getName());
    }
    public static void main(String[] args) {
        Box<Integer> integerBox = new Box<Integer>();
        integerBox.add(new Integer(10));
        integerBox.inspect("some text");
    }
}

타입 파라미터 제한하기

타입매개변수를 적당히 제한해야 할 경우에는 extends ...를 사용한다. extends 뒤에는 클래스명일 수도 있고 인터페이스명일 수도 있다. 아래의 예에서는 U가 Number의 하위 클래스이어야 한다.

public <U extends Number> void inspect(U u){
    System.out.println("T: " + t.getClass().getName());
    System.out.println("U: " + u.getClass().getName());
}

여러 조건을 만족시켜야 할 경우에는 &를 사용할 수도 있다.

<U extends Number & MyInterface>

하위타입

이제, 객체지향의 '이다 (is a)'관계를 생각해 볼 때다. Integer는 Object에 할당할 수 있다. '이다'관계에 있기 때문이다. 마찬가지로 Number에 Integer를 할당할 수도 있고, Double을 할당할 수도 있다. 이러한 관계는 제너릭에서도 마찬가지이다.

Box<Number> box = new Box<Number>();
box.add(new Integer(10)); // OK
box.add(new Double(10.1)); // OK

그러나,

public void boxTest(Box<Number> n){
    // method body omitted 
}

이 경우에 Box<Integer>와 Box<Double>는 매개변수로 전달되지 않는다. 이것들은 Box<Number>의 하위타입이 아니기 때문이다. 꽤나 논리적인 내용 전개가 필요하지만 뭔말인지 헷갈리므로 그냥 패스~

와일드카드

?는 알 수 없는 타입을 뜻한다.

  • <?> - 모든 객체 자료형, 내부적으로는 Object로 인식한다.
  • <? super 객체자료형> - 명시된 객체자료형과 그 상위 객체, 내부적으로는 Object로 인식한다.
  • <? extends 객체자료형> - 명시된 객체 자료형과 이를 상속한 하위객체, 내부적으로는 명시된 객체 자료형으로 인식한다.

타입제거

제너릭 타입이 인스턴스화 될 때, 컴파일러는 타입파라미터와 관련된 정보를 제거한다. 제너릭을 사용하기 이전의 라이브러리 등과의 호환성을 유지하기 위해서이다.

출처 : http://shonm.tistory.com/category/JAVA/%EC%A0%9C%EB%84%A4%EB%A6%AD%20%EA%B4%80%EB%A0%A8%20%EC%A0%95%EB%A6%AC


private static final String HMAC_SHA1_ALGORITHM = "HmacSHA1";

 

 

String data = "fadafadsfasdfad";

String key = "asdfasd"

 

String sol = null;
          
try {
     byte[] rel = Base64_HMACSHA1(data, key);
      sol = new String(rel);
     } catch (SignatureException e) {
     // TODO Auto-generated catch block
     e.printStackTrace();
     }
et4.setText(sol);

 

 

 

public static byte[] Base64_HMACSHA1(String data, String key)
   throws java.security.SignatureException
  {
   byte[] rawHmac = null;
   
   try {
  
    // get an hmac_sha1 key from the raw key bytes
    SecretKeySpec signingKey = new SecretKeySpec(key.getBytes(), HMAC_SHA1_ALGORITHM);
   
    // get an hmac_sha1 Mac instance and initialize with the signing key
    Mac mac = Mac.getInstance(HMAC_SHA1_ALGORITHM);
    mac.init(signingKey);
   
    // compute the hmac on input data bytes
    rawHmac = mac.doFinal(data.getBytes());
    
   } catch (Exception e) {
      throw new SignatureException("Failed to generate HMAC : " + e.getMessage());
   }
   
   //return rawHmac;
     
    
   byte [] buf = null;
       
      try {
        
       Class Base64 = Class.forName("org.apache.commons.codec.binary.Base64");
          Class[] parameterTypes = new Class[] { byte[].class };  
          Method encodeBase64 = Base64.getMethod("encodeBase64", parameterTypes);
          buf = (byte[])encodeBase64.invoke(Base64, rawHmac);
           
      } catch (Exception e) {
          e.printStackTrace();
      }            
       
      return buf;
  
  }



Java 뿐 아니라 개발자라면 한번쯤은 접해봤을법한 Base64 인코딩...
Base64의 인코딩 원리는 아래의 글을 확인해 주시고...

2009/02/23 - [정보보안/암호학] - Base64 인코딩 원리

Java 에서 Base64 인코딩을 하기 위해서는 기본적으로 Java에서 제공하는 클래스를 이용하는 방법과
Apache Commons Codec 의 Base64 클래스를 사용하는 방법이 있다.

먼저 자바에서 기본적으로 제공하는 Base64 인코딩...
static 메서드가 아니기 때문에 객체 생성후 호출을 해야하고
decoding의 경우 예외처리까지 해야하는 불편함이 있다.

import java.io.IOException;

import sun.misc.BASE64Decoder;
import sun.misc.BASE64Encoder;

public class TestBase64Encoder {
	public static void main(String[] args) {
		BASE64Encoder encoder = new BASE64Encoder();
		BASE64Decoder decoder = new BASE64Decoder();

		String txtPlain = "베이스64 인코딩, 디코딩 테스트입니다.";
		String txtCipher = "";
		System.out.println("Source String : " + txtPlain);

		txtCipher = encoder.encode(txtPlain.getBytes());
		System.out.println("Encode Base64 : " + txtCipher);

		try {
			txtPlain = new String(decoder.decodeBuffer(txtCipher));
		} catch (IOException ioe) {
			ioe.printStackTrace();
		}
		System.out.println("Decode Base64 : " + txtPlain);
	}
}

다음은 Apache Commons Codec  의 Base64 클래스를 이용하는 방법이다.
이전 소스코드보다 상대적으로 많이 길이가 줄어들었으며 static 메서드라서 바로 호출이 가능하다.
물론 이전 소스코드보다 가독성 또한 뛰어나다.

import com.sun.org.apache.xerces.internal.impl.dv.util.Base64;

public class TestCodecBase64 {
	public static void main(String[] args) {
		String txtPlain = "베이스64 인코딩, 디코딩 테스트입니다.";
		String txtCipher = "";
		System.out.println("Source String : " + txtPlain);

		txtCipher = Base64.encode(txtPlain.getBytes());
		System.out.println("Encode Base64 : " + txtCipher);

		txtPlain = new String(Base64.decode(txtCipher));
		System.out.println("Decode Base64 : " + txtPlain);
	}
}

위 두개 소스의 결과는 동일하며 아래와 같다.

Source String : 베이스64 인코딩, 디코딩 테스트입니다.
Encode Base64 : uqPAzL26NjQgwM7E2rX5LCC18MTatfkgxde9usauwNS0z7TZLg==
Decode Base64 : 베이스64 인코딩, 디코딩 테스트입니다.

출처 : http://huikyun.tistory.com/234

new String(바이트 배열,인코딩방식);
예)
byte b[]={12,45,12,45,78};
new String(b,"utf-8");

b에 있는 바이트 값들이 utf-8로 되있다는 것을 알려주는 것이다.
즉 utf-8 을 unicode로 변환시켜준다.



예)
String str = "테스트";
byte b[]=str.getbytes("utf-8");

str.getbytes() 함수는 문자열을 바이트 배열로 반환시키는 함수이다.
getbytes 함수안에 문자 형식을 지정하면 지정된 문자 형식으로 바꾸어 바이트 배열로 반환시킨다.
즉 자바가 사용하는 unicode 문자열을 utf-8로 바꾸어 바이트배열로 반환한다.


(리눅스 서버와 자바 클라이언트 프로그래밍시 문자 인코딩 방식이 달라서 사용했던 방법이다. 문자 통일좀 합시다.)

 public  byte[] inttobyte(int a)
 {
  byte b[]=new byte[4];
  
  b[0]=(byte)(a & 0x000000ff);
  b[1]=(byte)((a & 0x0000ff00)>>8);
  b[2]=(byte)((a & 0x00ff0000)>>16);
  b[3]=(byte)((a & 0xff000000)>>24);
  return b;
 }

 public  int bytetoint(byte b[])
 {
  return ((b[3]&0xff)<<24) |((b[2]&0xff)<<16) | ((b[1]&0xff)<<8) | ((b[0]&0xff)) ;
 }



서버는 리눅스로 클라이언트는 자바로 프로그래밍 중에 기본형 데이터를 서버에서 클라이언트로 혹은 클라이언트에서 서버로 전송할때 문제가 있어서 작성하였다.

리눅스에서 int를 바이트 단위로 보내고 자바의 DataOuputStream의 readInt 함수를 사용해서 읽었는데 값이 다르게 나왔었다.

왠지 자바에서 기본형을 보내거나 받을때 기본형과 매칭되는 클래스를 사용해서 직렬화를 하는것 같다. 그래서 값이 달라졌을 것이라 예상한다;;;

+ Recent posts