Java의 Reference 타입 자료형에 대해


자바의 자료형은 크게 기본형과 레퍼런스 타입으로 분류할 수 있다. 

레퍼런스 타입은 new 연산자를 통해서 힙(heap) 영역에 생성되는 자료형들을 의미한다. 

레퍼런스 타입으로는 클래스, 배열, 인터페이스 들이 있다.


따라서 arr1, arr2라는 2개의 배열이 있을 때 

arr1 = arr2;

를 하면 arr2에 있는 데이터를 arr1에 대입하는 것이 아니라(call-by-value가 아니라)

arr2가 가리키는 메모리 주소 값을 대입한다(call-by-reference이다). 


따라서 arr1에서 값을 변경하면arr2에서도 값이 변경된다. 

반대로 arr2에서 값을 변경하면 arr1의 값도 동시에 바뀐다.


그러나 

int arr1, int arr2;


가 있다면 이때 

arr1 = arr2;


라고 하면 이건 값(데이터)을 대입한다. 즉 call-by-value이다. 

따라서 arr1의 값을 변경해도 arr2에는 아무런 영향이 없고

arr2의 값을 변경해도 arr1에는 아무런 영향이 없다.


그런데 배열은 근본적으로 call-by-reference이다. 

따라서 아래 코드에서 

mRGBData를 chageData(byte[] rgb)로 넘기면 

mRGBData와 rgb는 동일한 기억 장소를 가리키게 된다. 

따라서 changeData()에서 mRGBData에 값을 대입하는 것이 전혀

없을지라도 mRGBData를 출력해 보면 changeData()에서 수정한 값이 잘 출력된다.


public class MainActivity extends Activity {

private TextView txt;

@Override

protected void onCreate(Bundle savedInstanceState) {

super.onCreate(savedInstanceState);

setContentView(R.layout.activity_main);

txt = (TextView)findViewById(R.id.txt);

byte[] mRGBData = null;

mRGBData = new byte[5];

changeData(mRGBData);

String str = "";

for (int i=0; i<mRGBData.length; i++) {

str += mRGBData[i] + ", ";

}

txt.setText(str);

} //onCreate

private void changeData(byte[] rgb) 

{

for(int j=0; j<rgb.length; j++) {

//여기서 mRGBData에 값을 대입하지 않고 rgb에만 값을 넣었는데도

//onCreate()에서 TextView에 mRGBData를 출력해 보면 0, 2, 4, 6, 8이 출력된다.

rgb[j] = (byte)(j*2);

}

}

}



아래와 같이 class도 reference type이다. class 참조변수(객체)에 대입을 하면 value가 대입되는 것이 아니라

reference가(해당 클래스의 기억장소 주소 값이) 대입 되게된다.

그래서 class의 두 참조 변수는 동일한 기억 장소를 가리키게 된다.


public class MainActivity extends Activity {

private TextView txt;

@Override

protected void onCreate(Bundle savedInstanceState) {

super.onCreate(savedInstanceState);

setContentView(R.layout.activity_main);

txt = (TextView)findViewById(R.id.txt);

MyClass myClass = new MyClass();


//아래 로그를 출력해 보면 다음과 같이 My2클래스에서 myc와 mc를 출력했을 때와 같이

//동일한 기억장소를 가리키게 된다.

// myClass : com.example.test.MainActivity$MyClass@411e71c0

Log.e("$$$$$$$", "myClass : "+myClass.toString());

My2 my2 = new My2(myClass);

String str = myClass.name + "\n" + myClass.age;

txt.setText(str); 

} //onCreate

class MyClass

{

private String name;

private int age;

}

class My2

{

private long kkk;

MyClass myc;

public My2(MyClass mc)

{

myc = mc;

//아래 로그를 출력해 보면

//myc : com.example.test.MainActivity$MyClass@411e71c0

Log.e("$$$$$$$", "myc : "+myc.toString());


//아래 로그를 출력해 보면

//mc : com.example.test.MainActivity$MyClass@411e71c0

Log.e("$$$$$$$", "mc : "+mc.toString());

mc.name = "홍길동";

mc.age = 29;

}

}

}




안드로이드에서 DB 작업을 하다보면 다음과 같은 에러를 만날 때가 있다.


"android.database.

       CursorIndexOutOfBoundsException: 

             Index -1 requested, with a size of ..."


이 에러는 DB에서 SELECT한 결과를 Cursor로 받는데 이때 Cursor의 위치가 첫번째 항목 바로 앞(index가 -1인) 위치에 놓이게 된다.

이때 다음 명령을 실행하면 


cursor.getString(cursor.getColumnIndex("name"));


android.database.CursorIndexOutOfBoundsException: Index -1 requested, with a size of 1과 같은 에러가 발생한다.

왜냐하면 cursor의 위치가 before the first entry이기 때문이다. 즉 cursor의 index가 첫 번째 데이터 바로 앞인 -1의 위치에 있기 때문이다.


이건 다음 둘 중 한 방법으로 처리 해야한다.


1) cursor.moveToFirst()를 cursor.getString() 이전에 실행해서 index가 -1인 (첫 번째 항목 바로 앞) 위치에서 첫 번째 항목으로 이동시킨 후

cursor.getString(cursor.getColumnIndex("name"));

과 같은 명령을 통해 원하는 데이터를 추출하면 된다.


2) while문을 이용해서 cursor.moveToNext()를 이용해서 하면 moveToFirst()를 안 해도 된다.

이때 movetToFirst()를 실행하면 맨 첫번째 데이터를 놓치고 넘어가게 된다.

while(cursor.moveToNext()) {...}를 하면 index -1에서 cursor.moveToNext()로 인해

첫 번째 데이터 위치로 index가 옮겨가게 되므로 굳이 moveToFirst()가 필요 없게 된다.


while(cursor.moveToNext()) {

name = cursor.getString(cursor.getColumnIndex("name"));

}


아래는 코드 조각이다.


DBHelper db_Helper = new DBHelper(mContext);

SQLiteDatabase db = db_Helper.getReadableDatabase();

String sql = "SELECT * FROM "+mContext.getString(R.string.memberTable) 

+" WHERE "+mContext.getString(R.string.pinNum)+"='"+pin_num+"';";

//A Cursor object, which is positioned before the first entry.

Cursor cursor = db.rawQuery(sql, null);

//cursor.moveToFirst(); 

if (cursor.getCount() > 0) {

while(cursor.moveToNext()) {

name = cursor.getString(cursor.getColumnIndex("name"));

}

}

db_Helper.close();





CSS에서 가상 클래스(pseudo class)를 이용하여 링크에 마우스 동작 감지하는 법


웹 사이트의 링크에 마우스를 올리면 링크에 밑줄이 그어지면서 링크의 색상이 바뀌거나 혹은 이미 방문했던 링크는 다른 색상으로 변경되어 있어 사용자로 하여금 방문했던 곳인줄 인지하게 하는 기능이 있다. 이러한 기능은 아래의 가상 클래스(pseudo class)들을 이용해서 기능을 구현할 수 있다.

아래 가상 클래스들은 링크 뿐만아니라 버튼, input 컨트롤 등에도 적용이 가능하다.


:link

⇒ 아직 방문하지 않은 링크에 대해 스타일(색상, 글자 모양, 밑줄 등)을 지정하는 기능


:visited

⇒ 이미 방문했던 링크에 대해 스타일을 지정하는 기능


:hover

⇒ 사용자가 링크에 마우스를 올릴 때 다른 형태의 스타일을 갖도록 지정하는 기능


:activity

⇒ 링크가 현재 시점에서 활성화(activated)되고 있는 상태일때 스타일 지정하는 기능.

예를 들어서 버튼의 경우 눌려져 있는 시점, 링크의 경우는 마우스가 클릭되어 있는 시점을 의미한다. 짧은 순간 마우스를 눌렀다 떼기 때문에 스타일의 변화가 순간적으로 나타나지만 마우스를 롱 클릭해 보면 알수 있다.


:focus

⇒ element가 focus을 얻었을 때 스타일을 지정할수 있다.

focus란 입력 박스(input box)에 내용을 입력하기 위해 커서가 위치해 있을 때 입력 박스가 focus를 가진 상태이다. 혹은 키보드의 탭 키를 누를 때 focus가 이동하는데 이러한 방식으로도 element들이 focus를 가질수 있다. 

이렇게 focus를 가졌을 때 스타일을 지정할 수 있다.


가상 클래스를 사용할 때는 반드시 다음과 같은 순서로 CSS를 작성해야 한다.

:link → :visited → :hover → :focus → :active


아래는 CSS 코드 조각이다.


a:link {

color: deeppink;

text-decoration: none;}


a:visited {

color: black;}


a:hover {

color: deeppink;

text-decoration: underline;}


a:active {

color: darkcyan;}




안드로이드 전화번호 입력시 자동으로 dash(-) 붙이기


전화번호를 입력할 때 01028910318과 같이 입력해도(-를 입력하지 않아도) 010-2891-0318과 같이 자동으로 자릿 수에 적당하게 -를 입력되게하는 기능이 안드로이드에서 제공된다. 

해당 클래스는 PhoneNumberFormattingTextWatcher이다.


TextView의 메소드 중 아래 메소드에 적용하면 된다.

public void addTextChangedListener (TextWatcher watcher)


EditText edPhone = 

            (EditText)findViewById(R.id.edPhone);


edPhone.addTextChangedListener(new PhoneNumberFormattingTextWatcher()); 

⇒ 이 메소드의 매개인자로 PhoneNumberFormattingTextWatcher가 올수 있는 이유는 

PhoneNumberFormattingTextWatcher가 TextWatcher 인터페이스를 구현했기 때문에 가능하다.




형상관리 시스템(프로젝트 관리 시스템) Git에 대해 배울 수 있는 좋은 곳이다.


http://learnbranch.urigit.com/


https://backlogtool.com/git-guide/kr/



BufferedReader에 대해서


BufferedReader는 인터넷에서 데이타를 읽어올 때 유용하다. 왜냐하면 인터넷은 원격에서 가져오기 때문에

속도가 늦을 수 있다. 따라서 버퍼를 이용해서 읽는 것이 필요하다.

따라서 BufferedReader의 객체를 생성하는 법을 아는 것은 요긴하다.


BufferedReader의 핵심은 이것이다.

InputStream이 입력을 위한 가장 기본인데 

BufferedReader는 InputStream으로부터 버퍼에로

읽어온다는 개념이 BufferedReader의 핵심 개념이다. 

따라서 BufferedReader의 생성자 자체가 InputStream을 매개인자로 갖는다.


BufferedReader의 생성자를 보면 아래와 같이 2종류가 있다.


BufferedReader(Reader in)

BufferedReader(Reader in, int size)


1) 생성자(다른 것은 API 참조)

BufferedReader(Reader in)


2) Reader 클래스의 Known Direct Subclasses들은 다음과 같다

BufferedReader, CharArrayReader, FilterReader, InputStreamReader, PipedReader, StringReader


3) 따라서 BufferedReader의 생성자 매개인자로 InputStreamReader의 객체가 올수 있다.


4) InputStreamReader의 생성자(다른 것은 API 참조)

public InputStreamReader (InputStream in, Charset charset)

==> Charset charset는 한글 코드에 대한 디코딩 정보이다. 보통 웹은 euc-kr(2바이트 한글)이고 자바에서는 유니코드 체계인 utf-8이다


5) InputStreamReader의 객체를 생성할 수 있는 메소드

  -. URLConnection의 getInputStream();

  -. HttpURLConnection이 URLConnection을 상속받았기 때문에 여기서도 가능하다



callback 메소드가 있는 클래스의 객체 선언 법


abstract 클래스도 아니고 interface도 아닌 

일반 클래스임에도 콜백 메소드(시스템에 의해 자동 호출되는 메소드)가 있을 경우 abstract 클래스나 interface와 유사한 방식으로 객체를 생성을 할 수 있다. 

아래 두 경우를 보면 모두 일반 클래스이다.


public class Handler extends Object

public class PhoneStateListener extends Object


그런데 이들 클래스 안에 콜백 메서드를 사용하기 위해 다음과 같이 mHandler라는 객체를 다음과 같이 생성한다.


 Handler mHandler = new Handler(){ 

     @Override

     public void handleMessage(Message msg){ //이게 콜백 메소드

         //여기서 원하는 기능 수행

     }

  };


위의 handleMessage() 메소드는 핸들러로 메시가 들어올때 즉 이 핸들러 호출이 있을 때 시스템에 의해 이 메소드 호출된다.



PhoneStateListener mPhoneState = new PhoneStateListener(){

    public void onCallStateChanged(int state, String incomingNumber){ //이게 콜백 메소드이다.

    switch(state){

    case TelephonyManager.CALL_STATE_IDLE :

    txt.append("\n☆ 전화 상태 : 대기 상태");

    break;

    case TelephonyManager.CALL_STATE_OFFHOOK :

    txt.append("\n☆ 전화 상태 : 통화 중");

    break;

    case TelephonyManager.CALL_STATE_RINGING :

    txt.append("\n☆ 전화가 왔습니다 : " + incomingNumber);

    break;

    }

    }

    };





String을 byte[] 배열로 변환하는 법

 

String 문자열을 byte[] 배열로 바꾸는데는 String 클래스에서 제공하는 getBytes() 메소드를 이용하면 된다.

이 메소드는 overloading 된 4개의 메소드가 있다.


public byte[] getBytes ()

public byte[] getBytes (String charsetName)


첫 번째 메소드는 문자열을 byte[] 바꿀때 시스템의 디폴트 charset을 이용해서 변환한다.

두 번째 메소드는 지정된 charsetName으로 인코딩된 형태로 변환한다.


String str = "Hello world";

byte[] info = str.getBytes("utf-8");





한 프로그램에 여러 Activity가 있을 때 처음 실행되는 Activity 지정하는 법


보통 한 프로그램 안에 여러 개의 Activity가 돌아간다. 

이때 어느 것을 Main으로 설정하는지 다음과 같이 Menifest 파일에 등록해 주면 된다.


아래 적색 부분을 포함하고 있는 Activity가 프로그램 실행 시 화면에 맨 처음 뜨게 된다.

여기서 AndExam.java가 Main으로 등록되어 있다.



        <activity android:name=".AndExam"

                  android:label="@string/app_name">

            <intent-filter>

                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />

            </intent-filter>

        </activity>





안드로이드와 서버와의 통신에서 연결하는 절차


-. URL로 연결할 지점에(접속할 주소) 대한 객체를 만든다. 


URL url = new URL("http://www.google.com");


※ URL이란 A Uniform Resource Locator that identifies the location of an Internet resource 

as specified by RFC 1738.


-. HttpURLConnection 클래스의 openConnection() 메소드로 해당 주소에 접속한다. 

이때 반환되는 객체가 URLConnection 클래스의 객체이다. 이때 프로토콜이 뭐냐에 따라 

HttpURLConnection, FtpURLConnection... 등이 반환된다. 따라서 해당 프로토콜에 맞게 다운캐스팅해서 사용하면된다.


HttpURLConnection httpURL = (HttpURLConnection)url.openConnection();


-. 해당 프로토콜에 필요한 각종 속성을 설정한다. API문서를 참조


httpURLCon.setConnectTimeout(10000);

httpURLCon.setUseCaches(false);


-. Http 연결일 경우는 요청방법을 지정해야 한다. 


httpURLCon.setRequestMethod("GET"); //이게 디폴트

httpURLCon.setRequestMethod("POST");


-. 모든 속성이 완료되면 서버에 요청을 보낸다. 요청이 무사히 전달됐으면 HTTP_OK(200)가 리턴된다. 반환되는 값에 대한 정보는 HttpURLConnection 클래스에 Constants로 잘 정의되어 있다.


httpURLCon.getResponseCode(); //public int getResponseCode ()


-. 다음과 같이 BufferedReader를 이용해서 서버에서 보내온 데이타를 읽는다.

BufferedReader 클래스는 생성자의 매개인자로 Reader 클래스의 객체가 와야 한다.

public BufferedReader (Reader in)

여기서 Reader클래스를 상속받은 클래스들이 BufferedReader, CharArrayReader, FilterReader, 

InputStreamReader, PipedReader, StringReader이다.

따라서 생성의 매개인자로 Reader클래스를 상속받은 하위 클래스의 객체가 올수있다. 

따라서 InputStreamReader 객체가 올 수 있다. 

InputStreamReader의 객체 생성은 생성자가 아래와 같이 되어 있다.


InputStreamReader(InputStream in) ==> InputStreamReader의 생성자. 매개인자로는 InputStream 객체가 올수 있다.

매개인자로 들어갈 InputStream 객체를 얻는 방법은 URLConnection의 메소드인 getInputStream()을 통해서 얻을 수 있다.


public InputStream getInputStream() ==> 이 메소드는 HttpURLConnection이 상속받은 상위 클래스인 URLConnection의 메소드인데 상속 


BufferedReader br = new BufferedReader(new InputStreamReader(httpURLCon.getInputStream()));

String temp = ""; //서버에서 보내온 데이터를 받을 공간


BufferedReader클래스의 메소드 가운데 이런 편리한 메소드가 있다. 


public String readLine () 

      ⇒ Returns the next line of text available from this reader. 

          A line is represented by zero or more characters followed 

          by '\n', '\r', "\r\n" or the end of the reader. 

          The string does not include the newline sequence.

      ⇒ Returns : the contents of the line or null if no characters were read before the end of the reader has been reached.

      ⇒ 한 마디로 readLine() 메소드는 캐리지 리턴을 기준으로 한 라인씩 읽어서 String으로 반환한다.


다음과 같이 서버로 부터 보내온 데이터를 읽으면 된다.


String addr = "";

for(;;){

      temp = br.readLine();

      if (temp == null) 

         break;

      addr += temp;

}

       

br.close(); //다 읽었으면 닫아 준다.

httpURLCon.disconnect(); //연결을 끊어 준다.


네트워크에 연결하는 경우는 다양한 이유로 연결에 실패할 수 있기 때문에 각종 Exception이 발생할 수 있다. 이에 대해서는 API문서를 참조할 것.




+ Recent posts