2014년 11월 27일 목요일

Cube U27GT Spec & Rooting & ...

내 책상 위의 Cube U27GT
Cube U27GT (Wifi only ver.)

• Android 4.4.2 (킷캣)
• 8-inch 1280*800 IPS screen
• MediaTek MT8127 Quad Core 1.3GHZ (Mali-450)
• 1GB RAM + 8GB ROM
• Cameras: 0.3MP & 2MP
• OTG support
• Micro SD card support
• Wifi / Bluetooth
• mini HDMI
• FM Radio








몇달전 AliExpress 를 통해 구입한 Cube U27GT 안드로이드 태블릿의 사양이다. 물건을 받았을 때는 정말 기분이 좋았는데, 이게 치명적인 단점이 있었다.


Cube U27GT의 저장소 현황


앱 설치공간이 1GB 밖에 안된다는 것... 요새 안드로이드 기기들은 OOO 16G 모델이라 하면 '내부 저장소' 자체가 16GB 인 것에 반하는 (좀 구닥다리같은) 공간구성이라는 것.

안드로이드 기기에는 문외한이라 열심히 루팅하는 법을 구글링 했었는데, 매번 실패만 하다 오늘 제대로 된 방법을 찾았다.

이 페이지에 나온 방법대로 루팅하면 끝.
(다만, Kingo Root 화면에 Waiting for Device... 라고  뜨고, 기기가 셧다운되었을 때 수동으로 전원버튼을 켜줘야된다는건 문서에 없는 것 같다. 실패했을 경우 좌절하지 말고 다시 도전해보자.)

이젠 내 기기에 루팅되었다고 나온다. SuperSU도 제대로 동작하고 말이다. 그리고 MoveToSdcard 라는 앱을 설치하였다. 이 앱이 하는 역할은 루팅전에는 '내부 저장소(1G)' 에 설치된 앱 중에서 'USB 저장소(4.98G)'로 이동되지 않던 앱들을 'USB 저장소'로 강제이동시키는 역할을 한다. (물론 루팅했으니 가능하다.)

사실, 이 기기의 'USB 저장소'라는 공간도 그리 넓은건 아니다. 요새 나오는 3D 게임의 경우 데이터만 몇 GB씩 하니 게임 몇개만 깔아도 더 이상 설치가 불가능하다. 그래서 이것도 극복하는 방법이 있다고는 하는데 (외장 SD 카드에 EXT 파티션을 만들어서 여기에 앱을 옮기는 방법) 귀찮기도 하고, 아직 쓸때가 없어서 시도해보지는 않았다. 이는 다음에 시도 및 성공하면 포스팅하겠다.

그래도, 앱설치공간을 조금이나마 더 확보할 수 있어서 행복하다. 크흑..

뱀발.
Cube U27GT 의 치명적 단점 하나 더.
바로, 국내 유수의 인터넷 뱅킹앱에서 루팅된 단말기로 인식된다는 점이다. (물론 루팅따윈 되어있지도 않지만 말이다.) 기기에 안드로이드를 포팅하는 과정에서 뭔가 흔적이 남았나? 거기까진 모르겠지만 인터넷뱅킹은 기대하지 말자. (이제 루팅했으니 언루팅하고 뱅킹해볼까??)
참고로, Cube Talk 79 나 Cube Talk 7 에도 동일한 문제였으니, 아마 Cube Talk 태블릿들은 동일하지 않을까 싶다.

2012년 10월 22일 월요일

Java 에서 Timestamp 찍어보기

new Timestamp(System.currentTimeMillis());
 
이걸 System.out.println() 으로 찍거나.. 하면 된다.
Log4J 같은 라이브러리를 많이 쓰는 요즘이지만, 아쉬울 때 쓰면 될 듯. 

2012년 8월 6일 월요일

Java 에서 객체의 초기화 (2)

>> Java에서 객체의 초기화(1) 에서 이어짐.


 
생성자 (Constructors)

객체 초기화의 중심요소는 '생성자'이다. 자바에서, 생성자는 메서드와 비슷하나, 메서드는 아니다.생성자는 메서드처럼 파라미터를 셋팅할 수 있고, 코드로 된 몸체를 가진다. 그러나 생성자는 return type 이 없어 메서드와는 다르다. 개발자는 메서드와 마찬가지로 생성자에 특정 접근권한을 줄 수 있지만, public, protected, package 접근자가 붙은 생성자는 서브클래스에 상속되지 않는다. (생성자의 access level 은 단순히 생성자 호출가능 여부가 아니라 객체의 인스턴스화를 결정한다.)


생성자의 기초 (Constructor basics)

소스파일에서 생성자는 클래스의 이름과 같은 이름을 가진 메서드 선언(declaration)처럼 보이지만, return type 이 없다. CoffeCup 클래스에서 생성자의 선언은 다음과 같다 :


// In source packet in file init/ex2/CoffeeCup.java   
 
class CoffeeCup {
    // Constructor looks like a method declaration
    // minus the return type
    public CoffeeCup() {
        // Body of constructor
    }
    // ...
}


메서드 처럼, 파라미터의 순서, 개수, 타입의 다양화를 통해 생성자를 오버로드할 수 있다. 두 개의 생성자를 가진 CoffeeCup 클래스는 다음과 같다 :

// In source packet in file init/ex3/CoffeeCup.java   
 
class CoffeeCup {
    private int innerCoffee;
    public CoffeeCup() {
        innerCoffee = 237;
    }
    public CoffeeCup(int amount) {
        innerCoffee = amount;
    }
    // ...
}


객체가 new 연산자로 초기화될 때, 생성자는 반드시 명시되어야 한다. 다음과 같이 두 개의 생성자를 가진 CoffeeCup 클래스는 두가지 방법으로 초기화될 수 있다 :

// In source packet in file init/ex3/Example3.java   
 
class Example3 {
    public static void main(String[] args) {
        // Create an empty cup
        CoffeeCup cup1 = new CoffeeCup();
        // Create a cup with 355 ml of coffee in it
        CoffeeCup cup2 = new CoffeeCup(355);
    }
}



인자가 없는 생성자 (The no-arg constructor)

자바 용어에서 파라미터를 가지지 않은(혹은 인자가 없는) 생성자는 "no-arg constructors"로 불린다. 코드에서 보여지듯, CoffeeCup 객체의 첫번째 인스턴스화는 인자가 없는 생성자에 명시되어있다. 두번째 인스턴스화는 int 형 파라미터를 요구하는 생성자에 명시되어있다.


this() 호출 (The this() invocation)

You may want to do this if you have several overloaded constructors in a class, all of which must execute much of the same code. Here's an example:

생성자로부터, this() 문을 사용함으로서 동일한 클래스에서 또다른 생성자를 명시적으로 호출할 수 있다. 클래스에서 여러 오버로드된 생성자가 있다면, 다음과 같이 모두 거의 동일한 코드를 수행해야만 한다.

// In source packet in file init/ex4/CoffeeCup.java   
 
class CoffeeCup {
    private int innerCoffee;
    public CoffeeCup() {
        this(237); // Calls other constructor
        // Could have done more construction here
    }
    public CoffeeCup(int amount) {
        innerCoffee = amount;
    }
    // ...
}


예와 같이, 인자가 없는 생성자는 int 와 같은 파라미터를 가진 또 다른 생성자를 호출한다. 237 이라는 값을 다른 생성자에 넘김으로서 innerCoffe 에 값을 할당한다.

메서드에서는 this()를 호출할 수 없다. 생성자에서 this()를 호출한다면, 반드시 그것을 생성자 내의 다른 코드 이전에 첫번째로 호출해야만 한다. 그리고, this()는 단 한번만 호출할 수 있다. this()가 호출된 후에 포함된 다른 코드들은 호출된 생성자가 완료된 후에 수행된다.


생성자는 메서드가 아니다.

메서드와 생성자사이의 다른 점은 다음 사실을 살펴보며 설명하겠다 : The name of a class is a valid name for its methods. In other words, class CoffeeCup could have methods named CoffeeCup:
클래스의 이름은 클래스에 속한 메서드의 이름에 적합한 이름이다. 달리말하면, CoffeeCup 클래스는 CoffeeCup 이란 메서드를 가질 수 있다.

// In source packet in file init/ex5/CoffeeCup.java
// THIS WORKS, BUT IT IS AN EXAMPLE OF POOR METHOD NAMING  
 
class CoffeeCup {
    private int innerCoffee;
    public CoffeeCup() {    // The constructor
        innerCoffee = 237;
    }
    public void CoffeeCup() {   // The method
        innerCoffee = 99;
    }
    // ...
}


위의 소스코드에서 CoffeeCup 클래스의 정의를 감안할 때, 다음과 같이 가능하다 :


// In source packet in file init/ex5/Example5.java 
 
class Example5 {
    public static void main(String[] args) {
        CoffeeCup cup = new CoffeeCup(); // invoke the constructor  
        cup.CoffeeCup(); // invoke the method
    }
}


비록 클래스명칭과 같은 이름의 메서드를 만들 수 있다하더라도, 실제론 다른 개발자들이 생성자와 혼동할 수도 있으며, 올바른 메서드 디자인 방식을 깨는 것이기에 결코 그렇게하면 안된다.

첫째, 클래스명은 '동사'가 아니라 '명사'이다.(적어도 '명사'여야 한다.) 메서드명칭은 동사여야 한다. 메서드가 수행하는 동작을 명칭으로 써야한다. 'CoffeeCup'은 동작이 아니다. 또한 'CoffeeCup'은 첫번째문자가 소문자여야 한다는 명명규칙 역시 따르지 않았다. 이 예제의 목적은 단지 생성자와 같은 명칭의 메서드가 생성자와 충돌하지 않는다는 것을 보여줌으로서 생성자는 메서드가 아니다라는 사실을 강조하는 것이다.


기본생성자(Default constructors)

만약 클래스에 생성자가 선언되어있지 않다면, 컴파일러는 자동으로 기본생성자(Default Constructor)를 생성한다. 기본 생성자는 파라미터가 없으며(no-arg constructor), 빈 (코드)몸체를 가진다. 개발자가 명시적으로 생성자를 선언하지 않았을 경우, 컴파일러가 자동적으로 기본생성자를 생성해주기 때문이다. 모든 클래스는 최소한 하나의 생성자가 생성된다.  예를 들어, CoffeeCup 클래스에 생성자가 선언되어있지 않은 경우는 다음과 같다. :



// In source packet in file init/ex6/CoffeeCup.java

class CoffeeCup {
    private int innerCoffee;
    public void add(int amount) {
        innerCoffee += amount;
    }
    //...
}


컴파일러는 마치 개발자가 명시적으로 빈 몸통을 가진 인자가 없는 생성자(no-arg constructor)를 명시적으로 선언한 것과 같은 클래스파일을 생성할 것이다. :


// In source packet in file init/ex7/CoffeeCup.java

class CoffeeCup {
    private int innerCoffee;
        public CoffeeCup() {
    }
    public void add(int amount) {
        innerCoffee += amount;
    }
    //...
}

컴파일러는 클래스 자체의 접근레벨과 동일한 권한을 가진 기본생성자를 제공한다. 이전 예제처럼 CoffeeCup 클래스는 public 이며, 기본생성자도 public 이다. 만약 CoffeeCup 클래스가 package 레벨의 접근권한을 가지고 있다면, 기본 생성자 역시 그러할 것이다.



>>  Java 에서 객체의 초기화 (3) 으로 이어짐.

2012년 7월 24일 화요일

Java 에서 객체의 초기화 (1)

※ 본 글의 출처는 Object initialization in Java 이며, 일종의 번역본이라 할 수 있다. 저작물번역에 대한 허가는 받지 않았으므로, 문제가 될 경우 삭제될 수 있다.

객체는 메모리를 조작하는 코드로 묶여진 메모리 덩어리다. 메모리에서, 객체는 생존시간(lifetime) 동안 객체가 변화하는 등의 상태(인스턴스 변수들의 값)를 유지한다. 정상적으로 새롭게 생성된 객체를 얻으려면, 객체에 새롭게 할당된 메모리는 반드시 적절한 초기상태로 초기화되어야 한다.이 문서는 적절한 초기화를 위한 클래스의 설계에 중점을 두었다. 이제 우리는 객체 초기화관리에 사용되는 메커니즘을 심층적으로 실펴볼 것이다.


자바의 초기화 기법 이면의 동기(motivation)

객체생명의 시작에서 자바가상머신(이하 JVM)은 객체의 인스턴스 변수들에게 제공된 힙에 충분한 메모리를 할당한다. 메모리가 최초 할당될 때, 그것이 데이터를 포함하였는지 예측할 수 없다. 만약 메모리가 그대로 사용된다면, 객체의 행동 또한 예측할 수 없다. 따라서 객체가 다른 코드들에 의해 사용되기 전에 이러한 시나리오를 방지하기 위해 자바는 최소한의 예측가능한 초기화 값으로 메모리를 초기화 한다.

초기화되지 않은 데이터는 일반적인 버그의 원인이 때문에, 초기화는 중요하다. 예를 들어, 데이터의 적절한 초기화를 강요하는 기법이 적용되지 않은 C의 경우에는 초기화되지 않은 데이터로 인한 버그가 정기적으로 발생한다. C 프로그래머는 항상 반드시 데이터가 메모리에 할당되고, 사용되기 이전에 데이터의 초기화를 기억해야만 한다. 이와 대비되어 자바는 새롭게 객체가 생성되며 차지하는 메모리의 적절한 초기화가 보장되도록 개발자에게 도움을 주는 기법을 내장하고 있다. 이들 기법의 적절한 사용은 개발자가 설계한 객체가 부적합한 초기상태를 가지고 생성되는 것을 방지한다.

자바는 객체의 적절한 초기화를 보장하기 위한 다음과 같은 세가지 기법을 가진다 :
instance initializers (인스턴스 초기화 블록으로 부르기도 한다.)
instance variable initializers
constructors. (Instance initializers 와 instance variable initializers 를 통틀어 "initializers" 라고도 한다.)
(Note. "Intializers"는 초기화 장치 쯤으로 해석하면 되지 않을까 했지만, 정확한 우리말이 어려워 번역하지 않았음.)
 이 모든 기법은 객체가 생성될 때 자동으로 수행되는 자바코드라 할 수 있다. 개발자가 new 연산자나 Class 클래스의 newInstance() 메서드를 써서 새로운 객체를 위한 메모리를 할당할 때, JVM은 개발자가 새롭게 할당된 메모리를 사용할 수 있게되는 시점 전에 초기화 코드의 수행을 보장한다. 만약 클래스들이 새롭게 생성된 객체를 위한 적절한 상태를 제공하는 initializer 나 생성자를 언제나 가지도록 설계된다면, 적절하게 초기화되지 못한 객체를 생성하거나 사용할 방법이 없을 것이다.


기본 초기값들(Default Initial Values)

만약 개발자가 인스턴스 변수들을 명확하게 초기화하지 않는다면, 해당 변수의 타입에 근거하여 변수들에 예측가능한 기본 초기값들이 부여될 것이다. 표1 은 각 변수형에 따른 기본 초기값을 보여준다. (기본 초기값들은 인스턴스 및 클래스 변수들 둘 다를 위한 것이다. 지역변수에는 기본초기값이 주어지지 않는다. 지역변수들은 사용하기 전에 반드시 명확한 초기화를 해야만 한다.)

Type
Default Value
booleanfalse
byte(byte) 0
short(short) 0
int0
long0L
char\u0000
float0.0f
double0.0d
object referencenull
표1. Default value for fields

만약 개발자가 인스턴스 변수를 명시적으로 초기화하지 않았다면, new 연산자가 객체의 참조를 반환할 때 변수는 기본 초기값을 가질 것이다. 예를 들어, 여기 innerCoffee 라는 명시적으로 초기화되지 않은 필드를 가진 CoffeeCup 이라는 클래스가 있다. (클래스의 생성자나 initializer 도 없다.) :

// In source packet in file init/ex1/CoffeeCup.java           
// This class has no constructors or initializers

class CoffeeCup {

    private int innerCoffee;
    //... 
}


결과적으로 새로운 CoffeeCup 객체의 참조가 new 연산자에 의해 최초로 리턴되었을 때, innerCoffee 필드는 기본 초기값을 가지고 있을 것이다.

개발자가 명시적으로 100 이란 값으로 innerCoffee 필드를 초기화하는 것의 의미는, CoffeeCup 객체가 생성될 때 innerCoffe 에는 두 번의 효과, 두 번의 초기화가 일어날 것이란 이야기다. 첫번째로 innerCoffee 는 기본 초기값인 0 이 주어질 것이며, 다음으로 0 에 적절한 초기값인 100 으로 덮여씌여질 것이다. 이 모든 일은 JVM 이 새로운 객체를 생성하는 동안 일어난다. (새로운 객체의 참조를 리턴하기 전에...) new 연산자로부터 반환된 새로운 CoffeeCup 객체가 참조되는 시점에 innerCoffee 필드는 100 으로 셋팅될 것이다.



>>  Java 에서 객체의 초기화 (2) 로 이어짐.