java筑基.泛型,反射,注解-利用注解加反射练习(代码片段)

六道对穿肠 六道对穿肠     2022-12-04     230

关键词:

文章目录

泛型:

把类型明确的工作推迟到创建对象或调用方法的时候才去明确的特殊的类型

泛型类


/*
    1:把泛型定义在类上
    2:类型变量定义在类上,方法中也可以使用
 */
public class ObjectTool<T> 
    private T obj;

    public T getObj() 
        return obj;
    

    public void setObj(T obj) 
        this.obj = obj;
    

  • 测试代码:

    public static void main(String[] args) 
        //创建对象并指定元素类型
        ObjectTool<String> tool = new ObjectTool<>();

        tool.setObj(new String("字符串"));
        String s = tool.getObj();
        System.out.println(s);


        //创建对象并指定元素类型
        ObjectTool<Integer> objectTool = new ObjectTool<>();
        /**
         * 如果我在这个对象里传入的是String类型的,它在编译时期就通过不了了.
         */
        objectTool.setObj(10);
        int i = objectTool.getObj();
        System.out.println(i);
    

用户想要使用哪种类型,就在创建的时候指定类型。使用的时候,该类就会自动转换成用户想要使用的类型了。

泛型方法

定义泛型方法…泛型是先定义后使用的


    //定义泛型方法..
    public <T> void show(T t) 
        System.out.println(t);

    

  • 测试代码:

用户传递进来的是什么类型,返回值就是什么类型了

    public static void main(String[] args) 
        //创建对象
        ObjectTool tool = new ObjectTool();

        //调用方法,传入的参数是什么类型,返回值就是什么类型
        tool.show("hello");
        tool.show(12);
        tool.show(12.5);

    

泛型接口


/*
    把泛型定义在接口上
 */
public interface Inter<T> 
    public abstract void show(T t);



子类明确泛型类的类型参数变量

/**
 * 子类明确泛型类的类型参数变量:
 */

public class InterImpl implements Inter<String> 
    @Override
    public void show(String s) 
        System.out.println(s);

    


子类不明确泛型类的类型参数变量

当子类不明确泛型类的类型参数变量时,外界使用子类的时候,也需要传递类型参数变量进来,在实现类上需要定义出类型参数变量


/**
 * 子类不明确泛型类的类型参数变量:
 *      实现类也要定义出<T>类型的
 *
 */
public class InterImpl<T> implements Inter<T> 

    @Override
    public void show(T t) 
        System.out.println(t);

    


测试代码:

    public static void main(String[] args) 
        //测试第一种情况
        //Inter<String> i = new InterImpl();
        //i.show("hello");

        //第二种情况测试
        Inter<String> ii = new InterImpl<>();
        ii.show("100");

    

  • 实现类的要是重写父类的方法,返回值的类型是要和父类一样的!
  • 类上声明的泛形只对非静态成员有效

限定类型变量


public class ArrayAlg

    //表示传入两个泛型,但是需要有compareTo方法 如何实现 使用限定类型变量
    //public static <T> T min(T a,T b)
    //    if(a.compareTo(b)>0) return a : else return b;
    // 
    
    //让 T extends Comparable
    public static <T extends Comparable> T min(T a,T b)
       if(a.compareTo(b)>0) return a : else return b;
     
     
     
     //可以使用& 跟上接口  也可以extneds类  但是类有且只有一个,接口可以有很多
     public static <T extends ArrayList & Comparable> T min(T a,T b)
       if(a.compareTo(b)>0) return a : else return b;
     

通配符泛型

?是通配符,泛指所有类型

一般用于定义一个引用变量,这么做的好处是,如下所示,定义一个sup的引用变量,就可以指向多个对象。

SuperClass<?> sup = new SuperClass<String>("lisi");

sup = new SuperClass<People>(new People());

sup = new SuperClass<Animal>(new Animal());

//若不用?,用固定的类型的话,则:

SuperClass<String> sup1 = new SuperClass<String>("lisi");

SuperClass<People> sup2 = new SuperClass<People>("lisi");

SuperClass<Animal> sup3 = new SuperClass<Animal>("lisi");

//这就是?通配符的好处。

注解

注解本身没有意义,单独的注解就是一种注释,他需要结合其他如反射,插桩的时候才有作用等技术才有意义.

定义: 使用@interface 关键字声明.

例如:


@Target(ElementType.FIELD)// 属性
@Retention(RetentionPolicy.RUNTIME)// 运行时
public @interface InjectPresenter 


或者


@Target(ElementType.TYPE)
@Retention(RetentionPolicy.SOURCE)
public @interface TestClassAnnotation 
    String id();
//    String value();
    //如果这里不是value 是id那么调用的时候需要id = "22"  value比较特殊
 



  • @Target(ElementType.TYPE,ElementType.METHOD) 也可以指明多个 在类上注解,在方法上也行

元注解

元注解顾名思义我们可以理解为注解的注解,它是作用在注解中,方便我们使用注解实现想要的功能。元注解分别有

  1. @Retention、 保留级别 只有三个数值 是只在代码中(SOURCE),还是编入class文件中(CLASS),或者是在运行时可以通过反射访问(RUNTIME) SOURCE<CLASS<RUNTIME CLASS包含了SOURCE RUNTIME包含了SOURCE和CLASS
  2. @Target、英文意思是目标,这也很容易理解,使用@Target元注解表示我们的注解作用的范围就比较具体了,可以是类,方法,方法参数变量等,同样也是通过枚举类ElementType表达作用类型
  3. @Document、 的英文意思是文档。它的作用是能够将注解中的元素包含到 Javadoc 中去。
  4. @Inherited和 英文意思是继承,但是这个继承和我们平时理解的继承大同小异,一个被@Inherited注解了的注解修饰了一个父类,如果他的子类没有被其他注解修饰,则它的子类也继承了父类的注解。
  5. @Repeatable(JDK1.8加入)五种。Repeatable使用场景:
    在需要对同一种注解多次使用时,往往需要借助@Repeatable。

Target的英文意思是目标,这也很容易理解,使用@Target元注解表示我们的注解作用的范围就比较具体了,可以是类,方法,方法参数变量等,同样也是通过枚举类ElementType表达作用类型

  • @Target(ElementType.TYPE) 作用接口、类、枚举、注解
  • @Target(ElementType.FIELD) 作用属性字段、枚举的常量
  • @Target(ElementType.METHOD) 作用方法
  • @Target(ElementType.PARAMETER) 作用方法参数
  • @Target(ElementType.CONSTRUCTOR) 作用构造函数
  • @Target(ElementType.LOCAL_VARIABLE)作用局部变量
  • @Target(ElementType.ANNOTATION_TYPE)作用于注解(@Retention注解中就使用该属性)
  • @Target(ElementType.PACKAGE) 作用于包
  • @Target(ElementType.TYPE_PARAMETER) 作用于类型泛型,即泛型方法、泛型类、泛型接口 (jdk1.8加入)
  • @Target(ElementType.TYPE_USE) 类型使用.可以用于标注任意类型除了 class (jdk1.8加入)
    一般比较常用的是ElementType.TYPE类型

注解的应用场景

根据注解的保留级别不同,对注解的使用自然存在不同的场景.

级别技术说明
SOURCE(源码)APT技术在编译器能够获取注解与注解声明的类包括勒种所有成员信息,一般用于生成额外的辅助类
CLASS(字节码)字节码增强/插桩在编译出Class后,通过修改Class数据以实现修改代码逻辑目的. 对于是否需要修改的区分活修改为不同逻辑的判断可以使用注解
RUNTIME(运行时)反射在程序运行期间,通过反射技术动态获取注解

SOURCE<CLASS<RUNTIME CLASS包含了SOURCE RUNTIME包含了SOURCE和CLASS

ide也提供了IntDef注解(元注解),提供语法检查 ide插件实现

IntDef举例:

//设置图片
public  static void setDrawable(int id)
    


public static void main(String... args)
    setDrawalbe(111)


setDrawalbe 本身应该传入资源图片但是现在传了随手写的int类型.这里可以使用ide提供的注解 @DrawableRes 资源

//设置图片
public  static void setDrawable(@DrawableRes int id)
    


public static void main(String... args)
    //setDrawalbe(111) //如果还随手写ide就会提示

@DrawableRes 是 AndroidX 定义好的语法检测规则

apt 注解处理器

反射:

JAVA反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意方法和属性;这种动态获取信息以及动态调用对象方法的功能称为java语言的反射机制。

作用: 能过做到一般做不到的事情. 使用场景: 插件式换肤,插件式开发 apk

反射练习: demo地址

注解+反射练习

通过注解+反射代替activity 通过Intent 传递参数跳转后的 getIntent的方法

比如 A Activity 携带参数

                Intent intent = new Intent();
                intent.setClass(MainActivity.this, JumpActivity.class);
                intent.putExtra("name", "testInject");
                intent.putExtra("age", 18);
                startActivity(intent);

在B Activity只需要如下做就可以自动赋值

 @Autowired("name")
    String mString;

    @Autowired("age")
    int age;
    

利用反射实现自动注入

mString = getintent.getStringExtra("name");
age = getintent.getIntExtra("age")

具体实现代码:

第一个Activity

package com.open.testc;

import android.content.Intent;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;

import androidx.appcompat.app.AppCompatActivity;

public class MainActivity extends AppCompatActivity 

    // Used to load the 'native-lib' library on application startup.
    static 
        System.loadLibrary("native-lib");
    

    private TextView sampleText;
    private Button btJump;


    @Override
    protected void onCreate(Bundle savedInstanceState) 
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        sampleText = (TextView) findViewById(R.id.sample_text);
        btJump = (Button) findViewById(R.id.bt_jump);

        // Example of a call to a native method
        sampleText.setText(stringFromJNI());
        btJump.setOnClickListener(new View.OnClickListener() 
            @Override
            public void onClick(View view) 
                Intent intent = new Intent();
                intent.setClass(MainActivity.this, JumpActivity.class);
                intent.putExtra("name", "testInject");
                intent.putExtra("age", 18);
                startActivity(intent);
            
        );
    

    /**
     * A native method that is implemented by the 'native-lib' native library,
     * which is packaged with this application.
     */
    public native String stringFromJNI();

第二个Activity

package com.open.testc;

import android.os.Bundle;
import android.util.Log;
import android.widget.TextView;

import androidx.appcompat.app.AppCompatActivity;

import com.open.testc.inject.Autowired;

public class JumpActivity extends AppCompatActivity 

    private static final String TAG = "JumpActivtiy";
    @Autowired("name")
    String mString;

    @Autowired("age")
    int age;

    private TextView tvResult;

    @Override
    protected void onCreate(Bundle savedInstanceState) 
        super.onCreate(savedInstanceState);
        InjectUtil.InjectView(this);
        setContentView(R.layout.activity_jump);
//        Bundle bundleExtra = getIntent().getBundleExtra();
        Log.d(TAG, "自动装配获取 onCreate: name = " + mString);
        Log.d(TAG, "自动装配获取 onCreate: age = " + age);

        tvResult = (TextView) findViewById(R.id.tv_result);

        tvResult.setText("name = " + mString + " age = " + age);
    

注入工具类:

package com.open.testc;

import android.app.Activity;
import android.os.Bundle;
import android.os.Parcelable;
import android.text.TextUtils;

import com.open.testc.inject.Autowired;

import java.lang.reflect.Field;
import java.util.Arrays;

/**
 * Created by liuml on 2021/4/14 19:40
 */
public class InjectUtil 

    public static void InjectView(Activity activity) 
        Class<? extends Activity> aClass = activity.getClass();
        try 
            //1.遍历这个activity里面所有的GetIntentField 注解
            //getDeclaredFields  和 getFields区别  getDeclaredFields()返回Class中所有的字段,包括私有字段
//        getFields  只返回公共字段,即有public修饰的字段。
            Field[] declaredFields = aClass.getDeclaredFields();
            Bundle bundle = activity.getIntent().getExtras();
            if (bundle == null) 
                return;
            
            for (Field field : declaredFields) 
                Autowired annotation = field.getAnnotation(Autowired.class);
                //2. 找到注解后获取他的值
                if (field.isAnnotationPresent(Autowired.class)) 
                    //获得key
                    String key = TextUtils.isEmpty(annotation.value()) ? field.getName() : annotation.value();

                    if (bundle.containsKey(key)) 
                        //获取传输的值
                        Object obj = bundle.get(key);

                        //获得数组单个元素类型 下面需要用到
                        Class<?> componentType = field.getType().getComponentType();
                        //判断如果是Parcelable[] 素组
                        if (field.getType().isArray() && Parcelable.class.isAssignableFrom(componentType)) 
                            //创建对应类型并拷贝
                            Object[] objs = (Object[]) obj;//强转
                            //拷贝数据  (Class<? extends Object[]>) field.getType())   通过getType 获取真正的反射类型
                            Object[] objects = Arrays.copyOf(objs, objs.length, (Class<? extends Object[]>) field.getType());
//                            Object[] objects = Arrays.copyOf(objs, objs.length, Parcelable[].class);
                            obj = objects;//赋值
                        

                        //3. 反射设置属性的值
                        field.setAccessible(true);
//                    Class<?> type = field.getType();
                        field.set(activity, obj);
                    
                
            
         catch (IllegalAccessException e) 
            e.printStackTrace();

        
    
 

ASM插件安装 使用字节码插桩技术时这个插件很有用

狂神说java笔记--反射和注解部分笔记(代码片段)

...行时结构13.动态创建对象执行方法14.性能对比分析15.获取泛型信息16. 查看详情

day642.反射注解和泛型问题-java业务开发常见错误

反射、注解和泛型问题Hi,我是阿昌,今天记录学习分享的是一些反射、注解和泛型问题如果你从来没用过反射、注解和泛型,可以先通过官网有一个大概了解:JavaReflectionAPI&ReflectionTutorials;Annotations&Les... 查看详情

利用反射调用注解

 利用反射调用注解  packagenet.jeesite.java;importjava.lang.annotation.Retention;importjava.lang.annotation.RetentionPolicy;importjava.lang.reflect.Method;@Retention(value=RetentionPolicy.RUNTIME)@interfa 查看详情

java注解和反射制作dao基类的练习

首先是三个注解主键注解 packagecomments;importjava.lang.annotation.Documented;importjava.lang.annotation.ElementType;importjava.lang.annotation.Inherited;importjava.lang.annotation.Retention;importjava.lang. 查看详情

java利用反射实现注解简单功能

//自定义一个简单的注解@Retention(RetentionPolicy.RUNTIME)@Target({ElementType.TYPE,ElementType.METHOD,ElementType.FIELD,ElementType.PARAMETER,ElementType.LOCAL_VARIABLE})public@interfaceDougest{Stringvalue()def 查看详情

反射操作注解获得注解信息(代码片段)

反射操作注解获得注解信息练习:ORM代码练习importjava.lang.annotation.*;importjava.lang.reflect.Field;//练习反射操作注解publicclassTest12publicstaticvoidmain(String[]args)throwsClassNotFoundException,NoSuchFieldExceptionClassc1 查看详情

java利用java的注解和反射实现一个"低配版"的依赖注入(代码片段)

...到底发生了什么呢,这篇文章将讲述如何用Java的注解和反射实现一个“低配版”的依赖注入。下面是我们要做的一些事情:通过@interface的方式定义一个注解为某个希望杯被注入的方法添加这个注解编写测试代码,通过反... 查看详情

注解与反射-复习(代码片段)

...构造)通过反射调用成员:methodfield测试:性能分析反射获取泛型数据反射获取注解数据基于B站秦疆老师的课.感谢!注解@sinceJDK1.5不是程序本身,可以对程序做出解释,可以被其他程序读取(如编译器)内置注解@Override@SuppressWarnings(value=&qu... 查看详情

利用反射——查看类的声明

...ted、private、abstract、statc、final等)、 *类的名称、类的泛型参数、类的集成类(实现的接口)和类的注解等 *Class类的实例表示正在运行的Java应用程序中的类和接口。 *枚举是一种类,注解是一种接口 *每个数组属于被... 查看详情

熬夜刚完的注解与反射(代码片段)

...法4.使用反射读取配置文件,调用方法5.使用反射跳过泛型机制检测6.注解1.注解概念2.jdk自带注解常用3.自定义开发注解4.元注解5.注解+反射案例1.模仿Spring的自动装配功能2.获取字段上注解的属性值7.枚举用 查看详情

java注解

...。源代码编译成字节码文件,字节码加载到方法区。利用反射API解析注解。注解的用处很多,JUnit就是一个注解的用处。面试的时候会问注解。遇到反射的面试都可以过。Class.forName();newInstance();invoke();是反射最必须记住的方法... 查看详情

b站狂神说java笔记-注解和反射(代码片段)

...类的初始化10.类加载器的作用11.调用指定方法12.反射操作泛型13.获取注解信息狂神视频地址https://www.bilibili.com/video/BV1p4411P7V3?p= 查看详情

java反射反射与注解

...性和扩展性,注解可以修饰接口、类、方法、属性等。1.反射获取注解能够通过反射获取类上的注解,主要依赖于核心类AccessibleObject(如下图,Java10的DOC),其实现了AnnotatedElement类。另外其子类包含Field、Executable(Method和Construc... 查看详情

注解与反射(代码片段)

注解为什么要学注解与反射? 所有的框架底层实现机制都是注解与反射,框架中有许多的注解,通过反射读取注解的值,来简化操作.? 比如利用反射读取注解的值,通过值拼成SQL语句,就可以动态地生成表,或者其他高级的功能.什... 查看详情

反射机制读取注解

一下面的demo来介绍利用反射机制来读取注解先自定义注解,一个用来注解类,另一个注解属性,如下面的demopackage注解;importjava.lang.annotation.ElementType;importjava.lang.annotation.Retention;importjava.lang.annotation.RetentionPolicy;importjava.lang.an 查看详情

java基础:注解与反射的使用方法与场景(代码片段)

注解与反射的使用方法与场景注解注解定义使用场景内置注解元注解自定义注解反射类加载器加载配置文件反射获取Class反射获取Constructor反射获取Method反射获取Field通过反射获取注解信息内省Introspector获取Bean类信息获取bean类的g... 查看详情

java注解和反射以及mybatis使用注解开发

1、内置注解2、元注解3、注解格式较为复杂的注解4、反射Reflection5、myBatis使用注解开发 查看详情

java---注解与反射

...言近期在学习SSM框架的过程中发现在SSM框架中大量用到了反射与注解的知识,要想学好SSM框架,必须将注解与反射熟记于心,尤其是对Java反射机制的理解。对于我这种记性不好的人来说“基础不牢,地动山摇”的情况经常发生... 查看详情