Reflection calls a method to get the value of a member variable

Suppose we have a class like this:

public class Hello {

    public String name = "Zhang";

    private int age = 43;

    public String getSex( String aaa) {

        return aaa;
    }

    private String getClassName() {

        return "Still in nine years of compulsory education."; }}Copy the code


Instead of creating objects to call methods and get values inside, we can use reflection to get values and call methods inside member variables:

1.1 Call public modifier method:

Class<Hello> CLZ = hello.class; Mt = clz.getMethod()"getSex", String.class); String invoke = (String) mt. Invoke (clz.newinstance (),"eeeeee"); // Prints the return value log.e ("invoke", invoke);
} catch (Exception e) {
}Copy the code

1.2 Calling the private decorated method:

Class<Hello> CLZ = hello.class; Method getClassName = clz.getDeclaredMethod()"getClassName"); / / open the modifier limit getClassName. SetAccessible (true); Invoke = (String) getClassName.invoke(clz.newinstance ()); // Prints the return value log.e ("invoke", invoke);
} catch (Exception e) {
    e.printStackTrace();
}Copy the code

1.3 Get public accessorized member variables:

Class<Hello> CLZ = hello.class; Field name = clz.getField()"name"); // Get the name of the public attribute String name1 = name.getName(); Object name2 = name.get(clz.newinstance ()); Log.e("rrrrrrrrre",name1+":"+name2);
} catch (Exception e) {
    e.printStackTrace();
} Copy the code

1.4 Get private accessorized member variables:

Class<Hello> CLZ = hello.class; Field age = clz.getDeclaredField("age"); String age1 = age.getName(); String age1 = age.getName(); // Open the permission modifier switch age.setaccessible (true); Int age2 = age.getint (clz.newinstance ()); int age2 = age.getint (clz.newinstance ()); // Print the obtained value log.e ("rrrrrrrrre",age1+":"+age2);
} catch (Exception e) {
    e.printStackTrace();
} Copy the code

Two. Annotation knowledge point

2.1 annotations

Use @interface, which is also a type, like an enumeration of interfaces:

public @interface TestAnnotation {


}Copy the code

2.2 yuan note

For custom annotations to work, you need meta-annotations. A meta-annotation is a comment that can be annotated to a custom annotation.

  • @Retention

  • @Documented

  • @Target

  • @Inherited

  • @Repeatable

2.3 @Retention Indicates the Retention period of user-defined annotations. The values are as follows:

  • The retentionPolicy.source annotation is only retained at the SOURCE stage and is discarded and ignored when the compiler compiles.
  • The retentionPolicy.class annotation is only retained until compilation and is not loaded into the JVM.
  • Retentionpolicy.runtime annotations can be retained until the application is run, and they are loaded into the JVM, so they can be retrieved while the application is running.

Documented, I don’t know what it’s for

2.5@target This section describes the scope of a custom annotation. The values are as follows:

  • Elementtype. ANNOTATION_TYPE Annotates an annotation
  • Elementtype. CONSTRUCTOR can be annotated to a CONSTRUCTOR
  • Elementtype. FIELD can be used to annotate attributes
  • Elementtype. LOCAL_VARIABLE can be used to annotate local variables
  • ElementType.METHOD can annotate methods
  • Elementtype. PACKAGE can annotate a PACKAGE
  • Elementtype. PARAMETER can be used to annotate parameters within a method
  • Elementtype. TYPE can annotate a TYPE, such as a class, interface, or enumeration

2.6 @ Inherited Inherited

Inherited, but it doesn’t mean that the annotations themselves can be Inherited but it means that if a superclass is annotated by @Inherited annotations, then if its child classes are not applied by any annotations, then that child class inherits the annotations of the superclass.

2.7@Repeatable repeat meaning

2.8 Annotation only has attributes, no methods: int id() default-1; The name is: id, the type is int, and the default value is -1, as follows:

@Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) public @interface TestAnnotation { public int id() default - 1; public String msg() default"Hi";

}Copy the code

2.9 note:

  • If an annotation contains only one attribute named value, you can apply the annotation directly to the attribute value in parentheses
  • The annotation has no attributes and the parentheses can be omitted when the annotation is applied



The acquisition of annotations

If annotations are required to be available at runtime, how do we get them? By reflection, we introduce some methods in Class:

Such as class Test and custom annotation TestAnnotation

/ / have been TestAnnotation annotation Boolean annotation = Test. Class. IsAnnotationPresent (TestAnnotation. Class);if(annotation) {// Get the annotation object TestAnnotation annotation1 = test.class.getannotation (TestAnnotation. Class); // Get the annotated value log.e ("rrrrrr"."" + annotation1.id() + "= = = = = = = = =" + annotation1.msg());
}Copy the code

What are reflections and annotations for

Write a similar function modeled after ButterKnife, but the principle is different, mainly for understanding reflection and annotation, of course reflection and annotation have many great uses, MY ability is limited, can not understand so deep, began to paste code:

Layout:

<? xml version="1.0" encoding="utf-8"? > <android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent"
    android:layout_height="match_parent">
<TextView
    android:layout_width="match_parent"
    android:id="@+id/tv"
    android:text="aaaa"
    android:layout_height="wrap_content" />
</android.support.constraint.ConstraintLayout>Copy the code

Application:

@BindRes(R.layout.activity_test)
public class TestAnnotation extends AppCompatActivity {
    @Bind(R.id.tv)
    TextView mTextView;

    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        Inject.inJect(this);
        mTextView.setText("XiFanYin");
    }
    @BindClick(R.id.tv)
    public void onClick2(View view) {
        if (view.getId() == R.id.tv) {
            Toast.makeText(this, "Click", Toast.LENGTH_SHORT).show(); }}}Copy the code

Custom annotations:

@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface Bind {
    int value();

}Copy the code
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface BindClick {
    int[] value();

}Copy the code
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface BindRes {
    int value();
}
Copy the code


Then there’s the key class, which uses reflection to find the control to assign and set the click event:

public class Inject {
    public static void inJect(AppCompatActivity activity) {

        try {
            bindRes(activity); // Bind the layoutbindView(activity); // Find the controlbindClick(activity); } catch (Exception e) {e.printStackTrace(); } } private static voidbindClick(AppCompatActivity activity) { Class<? extends AppCompatActivity> clz = activity.getClass(); Method[] methods = clz.getMethods(); // Get all the methodsfor (Method method : methods) {
            if(method. IsAnnotationPresent (BindClick. Class)) {/ / = any BindClick annotations BindClick under an annotation method.getAnnotation(BindClick.class); int[] value = annotation.value();for (int id : value) {
                    View view = activity.findViewById(id);
                    view.setOnClickListener(new View.OnClickListener() {
                        @Override
                        public void onClick(View v) {
                            method.setAccessible(true); try { method.invoke(activity, view); } catch (IllegalAccessException e) { e.printStackTrace(); } catch (InvocationTargetException e) { e.printStackTrace(); }}}); } } } } private static voidbindRes(AppCompatActivity activity) {
        Class<? extends AppCompatActivity> clz = activity.getClass();
        BindRes annotation = clz.getAnnotation(BindRes.class);
        if(annotation ! = null) { int value = annotation.value(); activity.setContentView(value); } } public static voidbindView(AppCompatActivity activity) throws IllegalAccessException {
        Class<? extends AppCompatActivity> clz = activity.getClass();
        Field[] fields = clz.getDeclaredFields();
        for (int i = 0; i < fields.length; i++) {

            if (fields[i].isAnnotationPresent(Bind.class)) {
                Bind bind = fields[i].getAnnotation(Bind.class);
                int value = bind.value();
                View view = activity.findViewById(value);
                fields[i].setAccessible(true);

                fields[i].set(activity, view);

            } else {
                System.out.println("没有"); } // System.out.println(fields[i]); }}}Copy the code

This implements functionality similar to ButterKnife.

Dynamic proxy

Function: enhanced functionality without modifying the source code of the proxy object.

Define a business license interface that can sell things

public interface Sell {

    void maidongxi();

}Copy the code

A person who wants to buy red Flag canal cigarettes will realize the business license

public class hongqiqu implements Sell {
    @Override
    public void maidongxi() {
        Log.e("rrrrrrrrrr"."I can sell the Red Flag canal."); }}Copy the code

After a while, he wanted to make more money, like selling wine. Then we need to modify the code of hongqiqu class, if for the project, either to inherit, or to use the wrapper pattern to extend, rarely modify the original class, today we use dynamic proxy to achieve:

public class GuitaiA implements InvocationHandler {

    private Object pingpai;

    public GuitaiA(Object pingpai) {
        this.pingpai = pingpai;
    }

    @Override
    public Object invoke(Object o, Method method, Object[] objects) throws Throwable {
        Log.e("rrrrrrr"."I can sell alcohol now.");
        method.invoke(pingpai, objects);
        returnnull; }}Copy the code

This pattern looks a bit like the wrapper pattern, but with reflection calls, simple changes can make it no longer matter what method name is called.

And then in the main screen,

// Hongqiqu hongqiqu = new hongqiqu(); Jingxiao = new GuitaiA(hongqiqu); / / get to Taiwan agent interface Sell dynamicProxy = (Sell) Proxy. NewProxyInstance (hongqiqu. Class. GetClassLoader (), hongqiqu.class.getInterfaces() , jingxiao); dynamicProxy.maidongxi();Copy the code

Found that did not modify the code in hongqiqu class, he can sell red Flag canal, and can sell wine

This is the dynamic proxy, the rich function out, who passed in, I will go to have my rich this function! Perfect decoupling ~

Dependency injection and inversion of control

If you want to go on a long journey, you can choose either train or bus, using the usual code:

If the train is selected, the code should look like this

public class Person {

    private HotCar car;

    public Person() {
        car = new HotCar();
    }


    public void chumen() { car.drive(); }}Copy the code

If you select a car, change the code to this:

public class Person {
//    private HotCar hotCar;
    private Car car;

    public Person() {
        car = new Car();
//        hotCar = new HotCar();
    }


    public void chumen() { car.drive(); // hotCar.drive(); }}Copy the code

Every time you choose a different vehicle, you have to change it. Can you not change it? It can be written like this:

5.1 Abstract Interface:

Public interface Driveable {// drive void drive(); }Copy the code

5.2. Human incoming interface

public class Person {


    private Driveable driveable;

    public Person(Driveable driveable) {
        this.driveable = driveable;
    }

    public void chumen() { driveable.drive(); }}Copy the code

5.3 call

Car car = new Car();
HotCar hotCar = new HotCar();
Person p = new Person(hotCar);
p.chumen();Copy the code

Here introduced to what objects to use what method, through the interface to decoupling, rather than to change every time the person class, let’s focus and the principle of what kind of transportation, the passed object is called dependency injection, control at the same time, it has carried on the transformation, no longer let person to control, but what I passed, what do you use only, These are dependency injection and inversion of control.