[221117]研修17日目


Static
class Temp {
	static int add( int i, int j ) {  return 100; }
}
//
public class Test136 {
	public static void main( String[] args ) {
		int r = Temp.add( 10, 20 );
		System.out.println( r );
	}
}
static付きメンバー関数は?
  • インスタンスを必要とせずに클래스명.함수명を呼び出すことができます.(参照変数は不要)
  • 「Cの一般関数と同じ」
    int add( int i , int j ) {
    	return 100;
    }
    
    int main() {
    	int r;
    	r = add( 10, 20 );
    	printf("%d\n", r );
    	
    	return 0;
    }
    Cはクラス外で関数を宣言できますがjavaはできません.
    したがって,クラスで宣言する場合,メンバ関数を区別するためにstaticというキーワードを用いる.
    static initializer
    class Temp {
    	static {
    		System.out.println("static");
    	}
    	//
    	Temp() {
    		System.out.println("생성");
    	}
    }
    //
    public class Test137 {
    	public static void main( String[] args ) {
    		new Temp();
    		new Temp();
    		new Temp();		
    	}
    }
    static initializer:インスタンスを作成する前に1回のみ呼び出されます.つまり、クラスはロード時に呼び出されます.
    試験137時間第1回試験137.classのみ使用します.new Temp()に遭遇した場合、Temp.classが必要でTempclassはメモリにロードする必要があります.次に、インスタンスがロードされたクラスとして作成されます.
    このとき(クラスロード時)static initializerが呼び出されます.インスタンスの作成時にメンバーを指す関数ポインタにはメモリが割り当てられるため、クラスのロード時にメンバーを呼び出すことはできません.
    class Temp {
    	static {	// 얼마든지 OK
    		Temp t = new Temp();
    		t.print();
    	}
    	static void print2() {
    		// 에러 : print();
    	}
    	void print() {
    		print2();
    	}
    }
    /*
    인터페이스는 오버라이딩을 전제로 하는 함수를 가진다. 
    오버라이딩은 함수 포인터로 운용되어야하므로 인스턴스에 함수포인터가 있어야 한다.
    따라서 인터페이스 안에서는 non-static 한 메소드를 사용해야 한다.
    */
    interface ITemp {
    	// public static void print();	
    }
    //
    public class Test138 {
    	public static void main( String[] args ) {
    		//...
    	}
    }
    non-static method print() cannot be referenced from a static context
  • 静的に関連するメンバー変数と関数の作成時間はclassがロードされたときです.このときnon-staticメンバーはまだ現れていません.
  • staticでnon-staticメンバーは使用できません!
    Singleton Pattern
    class Temp {
    	// uniq 변수는 jvm 안에 유일하게 된다.
    	private static Temp uniq = null;
    	// static initializer 안에서 uniq 로 인스턴스를 가리키게 하라.
    	static {
    		uniq = new Temp();
    	}
    	// public static synchronized 하게 uniq 를 제공하는 getInstance 함수를 선언한다.
    	public static synchronized Temp getInstance() {
    		return uniq;
    	}
    	// Temp 밖에서는 생성자를 호출할 수 없다. 즉 인스턴스를 못 만든다.
    	private Temp() { }
    }	// 이렇게 설계하는 설계 패턴을 Singletone Pattern 이라고 한다.
    //
    public class Test139 {
    	public static void main( String[] args ) {
    		// 에러 new Temp();
    		Temp a = Temp.getInstance();
    		Temp b = Temp.getInstance();
    		System.out.println( a == b );	// 인스턴스가 재활용되고 있고 공유되고 있음.
    	}
    }
    class Temp {
    	private static Temp uniq = null;
    	//	처음 호출시에 인스턴스가 생성되고 , 그 이후에는 인스턴스는 재활용된다.
    	public static synchronized Temp getInstance() {
    		if( uniq == null ) {
    			uniq = new Temp();
    		}
    		return uniq;
    	}
    	private Temp() { }
    }
    クラスの読み込み
    package banana;
    class Temp {
    	static {
    		System.out.println("static");
    	}
    	public void print() {
    		System.out.println("print");
    	}
    }
    //
    public class Test141 {
    	public static void main( String[] args ) throws Exception {
    		Class<?> cls = Class.forName("banana.Temp");
    		Object obj = cls.newInstance();
    		System.out.println( obj.getClass().getName() );
    	}
    }
    Class.forName:文字列に指定された名前のクラスを強制的にロードします.Object obj = cls.newInstance():clsに対応するクラスインスタンスを作成します.newなしでインスタンスを作成
    getMethod
    package banana;
    import java.lang.reflect.Method;
    //
    class Temp {
    	public void print() {
    		System.out.println("print");
    	}
    }
    public class Test143 {
    	public static void main( String[] args ) throws Exception {
    		Temp t = new Temp();
    		t.print();
    		//
    		Class<?> cls = Class.forName("banana.Temp");
    		Object obj = cls.newInstance();
    		System.out.println( obj );
    		//
    		Method mtd = cls.getMethod("print");
    		mtd.invoke( obj );
    	}
    }
    関数名を文字列として呼び出すことができますgetMethod:clsはprintという名前の関数を呼び出すポインタを提供していると思います.invoke:関数を呼び出す場合は、インスタンスにポインタ(obj)を付ける必要があります.
    import java.lang.reflect.Method;
    //
    class Temp {
    	public void print( int i ) {
    		System.out.println("Hello " + i );
    	}
    	public void print() {
    		System.out.println("Apple" );
    	}
    	public void print( int i, double j ) {
    		System.out.println("Banana" + j );
    	}
    }
    //
    public class Test148 {
    	public static void main( String[] args ) throws Exception {
    		Class<?> cls = Class.forName("banana.Temp");
    		Object obj = cls.newInstance();
    		// cls 에 선언된 이름이 print 이고 매개변수가 int 로 선언된 함수 포인터를 넘긴다.
    		Method mtd = cls.getMethod("print", int.class );
    		mtd.invoke( obj, 100 );
    		// getMethod 는 가변길이 파라미터를 쓰는 형태를 지원
    		Method mtd2 = cls.getMethod("print", int.class, double.class );
    		Object rv = mtd2.invoke( obj, 100, 3.14 );
    		System.out.println( rv );
    	}
    }
    public Object invoke(Object obj, Object... args)
  • objは、各関数を呼び出す인스턴스のポインタ
  • を指す.
  • argsはパラメータ値
  • に渡す
    戻り
  • は、関数の戻り値
  • に相当する.
    Class cls
    class Temp {
    	public int print() {
    		System.out.println("Apple" );
    		return 100;
    	}
    }
    //
    public class Test149 {
    	public static void main( String[] args ) throws Exception {
    		Class<?> cls = Class.forName("banana.Temp");
    		Object obj = cls.newInstance();
    		//
    		System.out.println( Temp.class == cls );	
    		System.out.println( obj.getClass() == cls );
    		// invoke 함수의 리턴타입은 Object 니까 언박싱을 이용하여 자료형변수에 대입하려면 캐스팅 필요
    		Method mtd = cls.getMethod("print");
    		int r = (Integer)mtd.invoke( obj );
    		System.out.println( r );
    	}
    }
    Class<?> cls = ...を使用してポインタを取得
    1. Class.forName("banana.Temp");
    2.「クラス名」.class
    3.Objectで宣言したgetClass()関数を呼び出す
    強化されたfor文
    class Temp {
    	public void print( int i, int j ) {
    		System.out.println("Apple" );
    	}
    }
    //
    public class Test150 {
    	public static void main( String[] args ) throws Exception {
    		Class<?> cls = Class.forName("banana.Temp");
    		Object obj = cls.newInstance();
    		//
    		Method[] mtds = cls.getMethods();
    		for( Method mtd : mtds ) 
    		{
    			System.out.println( mtd.getName() );
    		}
    	}
    }
    配列、List、Setに使用できます.