文章目录
- 泛型:
- 泛型类
- 泛型方法
- 泛型接口
- 子类明确泛型类的类型参数变量
- 子类不明确泛型类的类型参数变量
- 限定类型变量
- 通配符泛型
- 注解
-
- 反射:
- 注解+反射练习
泛型:
把类型明确的工作推迟到创建对象或调用方法的时候才去明确的特殊的类型
泛型类
/*
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{
public static <T extends Comparable> T min(T a,T b){
if(a.compareTo(b)>0) return a : else return b;
}
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) 也可以指明多个 在类上注解,在方法上也行
元注解
元注解顾名思义我们可以理解为注解的注解,它是作用在注解中,方便我们使用注解实现想要的功能。元注解分别有
- @Retention、 保留级别 只有三个数值 是只在代码中(SOURCE),还是编入class文件中(CLASS),或者是在运行时可以通过反射访问(RUNTIME) SOURCE<CLASS<RUNTIME CLASS包含了SOURCE RUNTIME包含了SOURCE和CLASS
- @Target、英文意思是目标,这也很容易理解,使用@Target元注解表示我们的注解作用的范围就比较具体了,可以是类,方法,方法参数变量等,同样也是通过枚举类ElementType表达作用类型
- @Document、 的英文意思是文档。它的作用是能够将注解中的元素包含到 Javadoc 中去。
- @Inherited和 英文意思是继承,但是这个继承和我们平时理解的继承大同小异,一个被@Inherited注解了的注解修饰了一个父类,如果他的子类没有被其他注解修饰,则它的子类也继承了父类的注解。
- @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){
}
@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 {
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);
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);
}
});
}
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;
public class InjectUtil {
public static void InjectView(Activity activity) {
Class<? extends Activity> aClass = activity.getClass();
try {
Field[] declaredFields = aClass.getDeclaredFields();
Bundle bundle = activity.getIntent().getExtras();
if (bundle == null) {
return;
}
for (Field field : declaredFields) {
Autowired annotation = field.getAnnotation(Autowired.class);
if (field.isAnnotationPresent(Autowired.class)) {
String key = TextUtils.isEmpty(annotation.value()) ? field.getName() : annotation.value();
if (bundle.containsKey(key)) {
Object obj = bundle.get(key);
Class<?> componentType = field.getType().getComponentType();
if (field.getType().isArray() && Parcelable.class.isAssignableFrom(componentType)) {
Object[] objs = (Object[]) obj;
Object[] objects = Arrays.copyOf(objs, objs.length, (Class<? extends Object[]>) field.getType());
obj = objects;
}
field.setAccessible(true);
field.set(activity, obj);
}
}
}
} catch (IllegalAccessException e) {
e.printStackTrace();
}
}
}
ASM插件安装 使用字节码插桩技术时这个插件很有用
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)