15 Mayıs 2018 Salı

Method Sınıfı

Giriş
Şu satırı dahil ederiz.
import java.lang.reflect.Method;
Bu sınıf AnnotatedElement arayüzünden kalıtır.

constructor - Class.getDeclaredMethod metodu
Access modifier tipine bakmaksızın nesnenin tanımladığı - kalıtımla gelen hariç - ismi belirtilen metodu döner.

Örnek
Elimizde şöyle bir sınıf olsun. Erişmek istediğiniz metod public.
public class Foo {
  public void isFoo(Object obj) {
    ...
  }
}
Bir parametre alan metodu bulmak için şöyle yaparız.
Class c = Foo.class;
Method m = c.getDeclaredMethod("isFoo", Object.class);
Metodumuz birden çok parametre alsaydı ikinci parametreyi bir dizi olarak geçebilirdik.
String methodName = ...;
Class[] types = ...;
Method method = c.getDeclaredMethod(methodName, types);
Örnek
Elimizde şöyle bir sınıf olsun. Bu sefer erişmek istediğimiz metod protected.
public class PrivateCar {

  private String color;

  protected void drive() {
    System.out.println("this is private car! the color is:" + color);
  }
}
Şöyle yaparız.
Class clazz = loader.loadClass("javaReflect.test.PrivateCar");
Method method = clazz.getDeclaredMethod("drive");
Örnek
Elimizde Foo ata sınıfı olsun.
public class Foo {
  public void doit() {
    System.out.println("good");
  }
}
Bu sınıftan kalıtan Bar sınıfı olsun
public class Bar extends Foo {
  public void doit() {
    System.out.println("bad");
  }
}
Method nesnesine Foo.class olarak erişsek bile ve hatta çağırırken yine Foo sınıfına cast etsek bile Bar sınıfının doIt() metodu çağrılır. Çıktı olarak bad alırız.
Bar b = new Bar();
/* Using Foo.class */
Method m = Foo.class.getDeclaredMethod("doit", new Class[]{});

m.invoke((Foo)b, new Object[]{});
constructor - Class.getDeclaredMethods
Access modifier tipine bakmaksızın nesnenin tanımladığı - kalıtımla gelenler hariç - tüm metodları döner.

Örnek ver.

constructor - Class.getMethod metodu
Elimizde şöyle bir sınıf olsun.
class Foo {
  public void foo() {
  }
}
Şöyle yaparız.
Method m = c.getMethod("foo");
Eğer foo int parametresi alıyor olsaydı şöyle yapardık.
Method m = c.getMethod("foo", int.class);
constructor - Class.getMethods metodu
Sadece public metodları döner. Şöyle yaparız.
Method[] methods = c.getMethods();
getAnnotation metodu
Elimizde şöyle bir metod olsun.
@CachePut(value ="DATA1", key = "#key1")
public Object saveData1(long key1, Object obj) {
  ...
}
Bu metodun Annotation değerlerine erişmek için şöyle yaparız. Tabi CachePut sınıfının elimizde olması gerekir.
Method method = ..;
String[] value = new String[1];

CachePut cachePut = method.getAnnotation(CachePut.class);
if (cachePut != null) {
  value = cachePut.value();
}
getDeclaringClass metodu
Bir metodun override edildiğini anlamak için şöyle yaparız.
class Base {
  public void bar() {}
}
class Derived extends Base {
  @Override   
  public void bar() {}
}
...
Method mbar = Derived.class.getMethod("bar");
boolean ovrBar = mbar.getDeclaringClass() != Base.class;
System.out.println("Have override for bar: "+ovrBar);
Çıktı olarak şunu alırız.
Have override for bar: true
getName metodu
Şöyle yaparız.
Method method = ...;
String name = method.getName();  
getParameterTypes metodu
Şöyle yaparız.
Method method = ...;
Class<?>[] params = method.getParameterTypes();
Parametreleri string'e çevirmek için şöyle yaparız.
String str = "";
for (int i = 0; i < params.length; i++) {
  if (i > 0) {
    str += ", ";
  }
  str += (params[i].getSimpleName());
}
invoke metodu
invoke metodu parametrelerin bir dizi içinde verilmesini bekler.
Örnek - parametresiz
Eğer metod parametre almıyorsa, ikinci parametre null geçilebilir.
m.invoke(foo, null);
null Object[]'ye cast edilebilir ancak ben sevmiyorum. Şöyle yaparız.
m.invoke(foo, (Object[]) null);
Örnek - tek parametre
Şöyle yaparız.
Foo foo = ...;
Object obj = ...;

m.invoke(foo, o2);
Örnek - array tipinden tek parametre
Elimizde şöyle bir kod olsun.
class Sample{

  public void doSomething(String ... values) {
    //do something
  }

  public void doSomething(Integer value) {
   ...
  }

}
Şöyle yaparız.
Sample object = new Sample();
Method m = object.getClass().getMethod("doSomething", String[].class);
String[] arr = {"v1", "v2"};
m.invoke(object, new Object[] {arr});
isAnnotationPresent metodu
Elimizde şöyle bir annotation olsun
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface @MyName {
}
Bunu bir sınıfa uygulayalım.
public class MyClass {
  @MyName
  public String generateName() {
    ...
  }
}
Sınıfın metodunun bu anotasyona sahip olduğunu kontrol etmek için şöyle yaparız.
Class<?> clazz = ...;

Method[] methods = clazz.getDeclaredMethods();
if (methods.length != 1) {
    // error
}
Method method = methods[0];
if (!method.isAnnotationPresent(MyName.class)) {
    // error as well
}
isBridge metodu
Gernic kodlarda Object parametre alan metodlara bridge denir.

Örnek
Şöyle yaparız. true ve false döner.
method.isBridge();
Örnek
Elimizde generic kod olsun.
import java.util.Arrays;

interface Interface<T> {
    void doSomething(T element);
}

class StringImpl implements Interface<String> {
    @Override
    public void doSomething(String element) {
        System.out.println("StringImpl: doSomething");
    }
}

public class Main {
    public static void main(String... args) {
        System.out.println(Arrays.toString(StringImpl.class.getDeclaredMethods()));
    }
}
Çıktı olarak şunu alırız
[public void com.ra.StringImpl.doSomething(java.lang.String), 
public void com.ra.StringImpl.doSomething(java.lang.Object)]
Sadece T tipini almak istersek şöyle yaparız.
public void com.ra.StringImpl.doSomething(java.lang.String)
Method[] methods = Arrays.stream(StringImpl.class.getDeclaredMethods())
                         .filter(m -> !m.isBridge())
                         .toArray(Method[]::new);

setAccessible metodu
Public olmayan metodlara erişebilmemizi sağlar. Şöyle yaparız.
class Dummy{
  private void foo(){
    System.out.println("hello foo()");
  }
}

class Test{
  public static void main(String[] args) throws Exception {
    Dummy d = new Dummy();
    Method m = Dummy.class.getDeclaredMethod("foo");
    //m.invoke(d);// throws java.lang.IllegalAccessException
    m.setAccessible(true);// Abracadabra 
    m.invoke(d);// now its OK
  }
}



Hiç yorum yok:

Yorum Gönder