+6

Invoking Method

Chào các bạn, mình mới biết khái niệm này trong một project nên muốn chia sẻ một số điều mình đã tìm hiểu được, tất nhiên là chưa đươc nhiều và sâu, mong các bạn góp ý thêm.

Trong bài này mình sẽ giới thiệu 1 ví dụ nhỏ là invoking method. Như chúng ta biết khi khai báo 1 field hay method thậm chí là constructor là private thì chỉ có thể truy cập được trong class đó. Tuy nhiên thực ra vẫn có thể truy cập được từ bên ngoài class bằng cách sử dụng Java Reflection. Để cụ thể mình sẽ giới thiệu 1 ví dụ đơn giản, ở đây mình dùng luôn trên android.

Đầu tiên sẽ tạo 1 class chứa các method, chẳng hạn như dưới đây, gồm 2 method 1 public và 1 private

public class AllMethod {
    public void compare(Context context, String message) {
        Toast.makeText(context, message, Toast.LENGTH_LONG).show();
    }

    private void add(Context context) {
        Toast.makeText(context, "add", Toast.LENGTH_LONG).show();
    }
}

Bây giờ em sẽ call các method này từ MainActivity

public class MainActivity extends AppCompatActivity {
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
    }

    public void compare(View v) {
        try {
            Class<?> c = Class.forName(AllMethod.class.getName());
            Method compareMethod = c.getMethod("compare", new Class[]{Context.class, String.class});
            compareMethod.invoke(c.newInstance(), this, "compare");
        } catch (ClassNotFoundException | InvocationTargetException | IllegalAccessException | InstantiationException | NoSuchMethodException e) {
            e.printStackTrace();
        }
    }

    public void add(View v) {
        try {
            Class<?> c = Class.forName(AllMethod.class.getName());
            Method addMethod = c.getDeclaredMethod("add", new Class[]{Context.class});
            addMethod.setAccessible(true);

            addMethod.invoke(c.newInstance(), this);
        } catch (ClassNotFoundException | InvocationTargetException | IllegalAccessException | InstantiationException | NoSuchMethodException e) {
            e.printStackTrace();
        }
    }
}

Ở đây mình tạo 2 button, onClick sẽ gọi vào 2 method add và compare.

Đầu tiên là compare,vì đây là public method chúng ta có thể gọi ra các bằng hàm getMethod, các param truyền vào sẽ là (String name, Class<?>... parameterTypes), tương ứng với các param trong method được gọi tới, ví dụ ở đây là compare(Context context, String message) thì sẽ truyền vào new Class[]{Context.class, String.class}. Sau đó để gọi method này thì sẽ dùng invoke(c.newInstance(), this, "compare");. Cần chú ý ở đây là Class AllMethod ở đây không có constructor, nếu có constructor có param, chẳng hạn như public AllMethod(Context context) thì sẽ không thể invoke được bằng c.newInstance() mà cần dùng đến java.lang.reflect.Constructor để tạo newInstance thì mới gọi được.

Tiếp theo là method add, đây là private method, thông thường thì sẽ không thể truy cập được, tuy nhiên ở đây:

  • Đầu tiên chúng ta cần sử dụng getDeclaredMethod, nó sẽ có khả năng lấy ra tất cả các method, không chỉ public giống bên phần compare method
  • Bước tiếp theo, vì method đó là private nên cần có thêm một dòng addMethod.setAccessible(true);, nếu không có dòng này khi chạy sẽ báo lỗi
java.lang.IllegalAccessException: access to method denied

sau khi có dòng lệnh đó thì có thể gọi giống như phần trên.

Ở đây mình gọi trực tiếp bằng name, ngoài ra có thể sử dụng Method[] allMethods = c.getDeclaredMethods(); để lấy ra toàn bộ method, sau đó có thể find theo tên, theo params, theo kết quả return ...

  • Kết quả: Kết quả thì như đã mô tả, thì khi click vào button add thì sẽ show Toast là add, tương tự với compare

Capture.PNG

Thank you for reading


All rights reserved

Viblo
Hãy đăng ký một tài khoản Viblo để nhận được nhiều bài viết thú vị hơn.
Đăng kí