太懒了之前写了几篇就不想写了,慢慢更吧
反射的作用介绍略过。。。。。。。
获得类
// 运行时 Class.forName 根据全类名(全路径加类名) 动态获取类
Class aClass = Class.forName("Reflection.model.UserBean");
// 获取实例
UserBean userBean = (UserBean) aClass.newInstance() ;
System.out.println("动态实例 user 全路径类名 "+ aClass.getName() );
System.out.println("动态实例 user 类名 " + aClass.getSimpleName());
获得类修饰符
//modifiers
/** PUBLIC: 1
PRIVATE: 2
PROTECTED: 4
STATIC: 8
FINAL: 16
SYNCHRONIZED: 32
VOLATILE: 64
TRANSIENT: 128
NATIVE: 256
INTERFACE: 512
ABSTRACT: 1024
STRICT: 2048**/
//getModifiers() 获得的是修饰符对应的数字
int modifiers = aClass.getModifiers() ;
System.out.println( "类的修饰符" + modifiers );
Package aPackage =aClass.getPackage();
System.out.println("获取类的package info " + aPackage.getName() );
获得方法
//获得对象里方法 并分别打印 get set 方法名称
// invoke 动态修改对象
Method [] methods = aClass.getMethods();
for (Method method : methods) {
if(isSetter(method)) {
// 检测到setname 方法 invoke动态setname
if(method.getName().equals("setName") ){
method.invoke(userBean,"zhangsan");
// invoke(obj 目标类的实例 ,args // 传入参数)
}
System.out.println("Setter " + method.getName());
}
if(isGetter(method)) {
System.out.println("Getter "+ method.getName());
}
}
public static boolean isGetter(Method method){
if(!method.getName().startsWith("get")) return false;
if(method.getParameterTypes().length != 0) return false;
if(void.class.equals(method.getReturnType()))return false;
return true;
}
public static boolean isSetter(Method method){
if(!method.getName().startsWith("set")) return false;
if(method.getParameterTypes().length != 1) return false;
return true;
}
获得字段
// getDeclaredField 私有字段与方法
privateBean privatebean = new privateBean("defaultvalue");
Class pbclazz = Class.forName("Reflection.model.privateBean");
Field privateFiled = privatebean.getClass().getDeclaredField("stringdefaultvalue");
/* 将此对象的 accessible 标志设置为指示的布尔值。值为 true 则指示反射的对象在使用时应该取消 Java 语言访问检查。
值为 false 则指示反射的对象应该实施 Java 语言访问检查;实际上setAccessible是启用和禁用访问安全检查的开关,
并不是为true就能访问为false就不能访问 ;https://blog.csdn.net/buyaoshuohua1/article/details/104175188
由于JDK的安全检查耗时较多.所以通过setAccessible(true)的方式关闭安全检查就可以达到提升反射速度的目的*/
privateFiled.setAccessible(true);
String fieldValue = (String) privateFiled.get(privatebean);
System.out.println("filedValue = " + fieldValue);
//获取私有字段数组
Field [] fields = privatebean.getClass().getDeclaredFields();
for (int i = 0; i < fields.length; i++) {
fields[i].setAccessible(true);
// 注意调用 pbclazz.newInstance() 调用的是无参构造方法
// 使用有参构造需要使用 getDeclaredConstructor 先获取对应参数的有参构造方
法才能Instance 使用
Object name =
fields[i].get(pbclazz.getDeclaredConstructor(String.class).newInstance("defaultvalue"));
System.out.println("stringdefaultvalue : " + name );
}
获取字段时注意方法区别
/* * getFields()与getDeclaredFields()区别:getFields()只能访问类中声明为公有的字段,私有的字段它无法访问, * 能访问从其它类继承来的公有方法.getDeclaredFields()能访问类中所有的字段,与public,private,protect无关, * 不能访问从其它类继承来的方法 * getMethods()与getDeclaredMethods()区别:getMethods()只能访问类中声明为公有的方法, * 私有的方法它无法访问,能访问从其它类继承来的公有方法.getDeclaredFields()能访问类中所有的字段, * 与public,private,protect无关,不能访问从其它类继承来的方法 * getConstructors()与getDeclaredConstructors()区别:getConstructors()只能访问类中声明为public的构造函数. * getDeclaredConstructors()能访问类中所有的构造函数,与public,private,protect无关 * */
泛型反射 修改泛型类型
// The Generics Reflection Rule of Thumb 泛型反射法则
// 获得 泛型返回类型 List<String> class java.lang.String
Method method = MySt.class.getMethod("getStringList",null); // 反射获得方法
Type returnType = method.getGenericReturnType();// 此Method对象表示的方法的正式返回类型
/ *List< ? extends BaseBean> list = new ArrayList<>();
list.get(1);*/
Type newtype = Long.class;
Type oldtype = java.lang.String.class;
if(returnType instanceof ParameterizedType){
//Method method = MySt.class.getMethod("getStringList",null); // 反射获得方法
Type returnType = method.getGenericReturnType();// 此Method对象表示的方法的正式返回类型
// returnType 是自己去主动获得的 ??
// ParameterizedType 是怎么获得或者说找到这个returnType的来源的method对象的泛型呢??
// ParameterizedType 参数化类型
ParameterizedType type = (ParameterizedType) returnType;
Type [] typeArguments = type.getActualTypeArguments();
for(Type typeArgument : typeArguments) {
Class typeArgClass = (Class) typeArgument;
System.out.println("修改前type = " + typeArgClass);
}
//利用ParameterizedType实现type修改
for (int i = 0; i < typeArguments.length; ++i) {
if(typeArguments[i] == oldtype){
System.out.println("替换type String --> Long");
typeArguments[i] = newtype;
}
}
for(Type typeArgument : typeArguments) {
Class typeArgClass = (Class) typeArgument;
System.out.println("修改后 type = " + typeArgClass);
}
}
看到泛型反射我就想到5月份找工作碰到的面试题,现在还记忆犹新
/*
List<? extend String>
当初的问题
虽然有了解答其实还是半知半解
https://tieba.baidu.com/p/6711807461
*/
public static void main(String[] args) {
//上界
List<? extends Fruit> flistTop = new ArrayList<Apple>();
flistTop.add(null);
//add Fruit对象会报错
//flistTop.add(new Fruit());
Fruit fruit1 = flistTop.get(0);
//下界
List<? super Apple> flistBottem = new ArrayList<Apple>();
// flistBottem.add(new Fruit()); 不能add apple 的父类 只能add apple及其子类
flistBottem.add(new Apple());
flistBottem.add(new Jonathan());
//get Apple对象会报错
//Apple apple = flistBottem.get(0);
/*
* 记住泛型只能向上转型
* ? extend Fruit 泛型上界 ? extend ,只能作为生产者
* 表示泛型 fruit类 和所有继承fruit类的子类
* 这种泛型 可以从容器中取出东西 但是却不能放东西
* 因为当你取出东西时 不论什么情况 都能知道 这个容器中放的必定是一个fruit
* 因此当取出时未知的子类时都可以向上转型为fruit承接
* 但是当你放入一个子类时虽然知道放入的一个水果,但是不知道具体到底是什么
* 在容器里找不到对应的类承接 , ( 泛型类型擦除 ?? )
* 拓展java泛型实现
* (Java中的泛型基本上都是在编译器这个层次来实现的。
* 在生成的Java字节码中是不包含泛型中的类型信息的。使用泛型的时候加上的类型参数,会在编译器在编译的时候去掉。这个过程就称为类型擦除。)
* example ? super 只能作为消费者
* List<Integer> l1 = new ArrayList<Integer>()
* List<String> l2 = new ArrayList<String>()
* System.out.println(l1.getClass() == l2.getClass()); // true
* 这是因为在实际编译过程中 Integer 和 String已经被擦出 所以 l1 l2 getClass() 都是 list.class
* ? extend base ? 泛型占位符
* ? super Apple 泛型下界
* 表示泛型 以Apple 为下类以及Apple的所有父类 一直可追溯到 Object 类
* 可以放东西却不能取出东西
* 你不能add Apple的父类,因为不能确定List里面存放的到底是哪个父类。
* 但是可以add Apple及其子类。因为不管我的子类是什么类型,它都可以向上转型为Apple及其所有的
* 父类甚至转型为Object 用来承接 ,但是当我get的时候,Apple的父类这么多,我用什么接着呢,除了Object,
* 其他的都接不住。所以,归根结底可以用一句话表示,那就是编译器可以支持向上转型
* */
最后用反射搞一个注解
自定义一个注解类
/*元注解:
元注解的作用就是负责注解其他注解。Java5.0定义了4个标准的meta-annotation类型,它们被用来提供对其它 annotation类型作说明。Java5.0定义的元注解:
1.@Target,
2.@Retention,
3.@Documented,
4.@Inherited
这些类型和它们所支持的类在java.lang.annotation包中可以找到。下面我们看一下每个元注解的作用和相应分参数的使用说明。
@Target:
@Target说明了Annotation所修饰的对象范围:Annotation可被用于 packages、types(类、接口、枚举、Annotation类型)、类型成员(方法、构造方法、成员变量、枚举值)、方法参数和本地变量(如循环变量、catch参数)。在Annotation类型的声明中使用了target可更加明晰其修饰的目标。
作用:用于描述注解的使用范围(即:被描述的注解可以用在什么地方)
取值(ElementType)有:
1.CONSTRUCTOR:用于描述构造器
2.FIELD:用于描述域
3.LOCAL_VARIABLE:用于描述局部变量
4.METHOD:用于描述方法
5.PACKAGE:用于描述包
6.PARAMETER:用于描述参数
7.TYPE:用于描述类、接口(包括注解类型) 或enum声明*/
// https://www.cnblogs.com/peida/archive/2013/04/24/3036689.html
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
public @interface MyAnnotation {
//可以什么都不定义
public String name();
public String value();
}
OK 当初学注解天真以为只要定义万就可以了,不过确实也没有问题,但是想要注解真正的生效达到想要的功能肯还需要对应的实现
注解功能实现
public class MyAnnotationimpl {
public void myanno() throws ClassNotFoundException {
ClassLoader cl = this.getClass().getClassLoader();
Class clazz = cl.loadClass("Reflection.Annotation.AnnotationTest");//注解类路径
Annotation [] annotations = clazz.getAnnotations();
try {
for (Annotation annotation : annotations) {
if (clazz.isAnnotationPresent(MyAnnotation.class)) {
MyAnnotation myAnnotation = (MyAnnotation) annotation;
System.out.println("name : " + myAnnotation.name());
System.out.println("value :" + myAnnotation.value());
Method[] methods = clazz.getMethods();
AnnotationTest annotationTest = (AnnotationTest) clazz.newInstance();
for (Method method : methods
) {
if (method.getName().contains("setAnnotationname")) {
method.invoke(annotationTest, "动态修改name");
}
if(method.getName().contains("setAnnotationdes")){
method.invoke(annotationTest,"动态描述");
}
if(method.getName().contains("setAnnotationvalue")){
method.invoke(annotationTest,"18");
}
}
System.out.println(annotationTest.toString());
}
}
}catch (Exception e){
e.printStackTrace();
}
}
}
注解类
@MyAnnotation(name= "zhangsan",value = "18")
public class AnnotationTest {
private String annotationname;
private String annotationdes;
private String annotationvalue;
//get set ....
}
测试注解功能
AnnotationTest annotationTest = new AnnotationTest();
MyAnnotationimpl myAnnotationimpl = new MyAnnotationimpl();
myAnnotationimpl.myanno();
代码
https://share.weiyun.com/13qDdAE6