反射笔记
java三阶段:1-源码 2-class 3-runtime
一. 获取Class对象的方式
---【获取Class.forName("全类名")】:将自己吗文件加载进内存,返回Class对象
多用于配置文件,将类名定义在配置文件中,读取文件,加载类
---【类名.class】:通过类名的属性class获取
多用于参数传递
---【对象.getClass()】:getClass()方法在 Object类中定义着
多用于对象的获取字节码的方式
结论:同一个字节码文件(*.class)在一次程序运行过程中,只会被加载一次,不论通过哪一种方式获取的Class对象都是同一个
二. Class对象功能
1. 暴力反射 Field/Constructor/Method对象.setAccessible(true)==忽略访问权限修饰符的安全检查
2.【获取成员变量/们】
Field[] getFields() 获取所有public修饰的成员变量
Field getField(String name) 获取指定名称的public修饰的成员变量
Field[] getDeclaredFields() 获取所有的成员变量,不考虑修饰符
Field getDeclaredField(String name) 获取指定名称的,不考虑修饰符
[操作]
设置值 void set(Object obj, Object value)
获取值 Object值 get(Object obj)
3.【获取构造方法/们】
Constructor<?>[] getConstructors()
Constructor<T> getConstructor(类<?>... parameterTypes)
Constructor<T> getDeclaredConstructor(类<?>... parameterTypes)
Constructor<?>[] getDeclaredConstructors()
[操作]
创建对象 T表示返回对象类型
T Construct对象.newInstance(Object... initargs)
T Class对象.newInstance()(空参数构造方法创建对象可这样简化)
4.【获取成员方法/们】
Method[] getMethods()
Method getMethod(String name, 类<?>... parameterTypes)
name==方法名称 parameterTypes==参数类型列表
Method[] getDeclaredMethods()
Method getDeclaredMethod(String name, 类<?>... parameterTypes)
[操作]
执行方法 Object invoke(Object obj, Object... args)
参数:obj==方法类的对象 args==方法参数列表
获取方法名称 String getName()
5.【获取全类名】
String getName()
函数式编程
函数式编程:
通过匿名内部类和lambda表达式完成*
匿名内部类:
定义一个接口,该接口定义一个未实现的方法,当其他类方法参数用到该接口类型时,可以直接new该接口并实现方法即可。
Lambda表达式:
当某个方法需要一个参数,这个参数类可以是一个接口并且接口只有一个方法时可用Lambda
1-一些参数
2-一个箭头
3-一段代码
格式:(参数列表)->{一些重写方法的代码};
可省略内容:
1-括号中参数列表的数据类型,可省略
2-括号中的参数如果只有一个,那么类型和括号都可以省略
3-如果{}中代码只有一行,无论是否有返回值,都可以省略({},return,分号)
注意:要省略{},return,分号必须一起省略
两者实现都是:定义一个接口,接口只定义一个方法,
直接创建接口并重写方法作为参数传入需要相应类型参数的方法中
匿名内部类需要重写方法和方法体,
区别:Lambda表达式更加简洁一些,
在Lambda表达式中不需重写方法,
Lambda引用
可以简化lambda表达式来简化代码
使用前提是对象名是已经存在的,成员方法也存在
执行过程
创建函数式接口-->lambda实现接口方法-->普通方法调用接口方法
【方法引用】
@FunctionalInterface //函数式接口
interface Printabe{
public void print(String str);
}
//普通方法
public static void printString(Printabe p) {
p.print("helloword");
//这里p调用的print("helloword")即等于调用了arg->System.out.println(arg)
//"helloword"赋值给参数arg,方法体System.out.println(arg)打印了arg(即helloword)出来
}
//-----lambda实现
printString(p->System.out.println(arg));
p即print()方法的参数str,
System.out.println(arg)即相当于该方法的方法体
//-----引用实现
printString(System.out::println);
【定义类对象引用方法】
//-----Lambda表达式实现
printString((s)->{
//创建对象
t05_1MethodRerObj_方法引用 obj = new t05_1MethodRerObj_方法引用();
obj.printUpperCaseString(s);
});
//-----引用实现
t05_1MethodRerObj_方法引用 obj = new t05_1MethodRerObj_方法引用();
printString(obj::printUpperCaseString);
【类名引用静态方法】
//函数式编程所需接口
@FunctionalInterface
interface Calcable{
public int calsABs(int number);
}
//使用方法
public static int method(int number,Calcable c) {
return c.calsABs(number);
}
//-----Lambda表达式实现
int numberabs = method(-10, (n)->{
return Math.abs(n);
});
//-----引用实现
int numberabs2 = method(-10, Math::abs);
【super引用父类方法】
super::父类方法名
【this引用本类方法】
this::本类方法名
【类引用构造方法】
//定义一个方法,参数传w递姓名和PsesonBuilder接口,方法中通过姓名创建Person对象
public static void printName(String name,PersonBuilder pb) {
Person person = pb.builPerson(name);
System.out.println(person);
}
//-----lambda表达式实现
//调用printName,传递Lambda表达式
printName("迪丽热巴", (String name)->{
return new Person(name);
});
//-----引用实现
//创建对象已知,new
printName("古力娜扎", Person::new);//使用Person类的带参构造方法,通过传递的姓名创建对象
例子2:创建数组------------------------------------------------
@FunctionalInterface//函数式编程所需接口
interface AarryBuilder{
//定义一个创建int类型数组的方法,参数传递数组场地,返回创建好的int类型数组
int[] builderAray(int length);
}
//创建方法
public static int[] CreateArray(int length,AarryBuilder ab) {
return ab.builderAray(length);//该语句相当于使用了lambda表达式内分方法体
}
//------lambda表达式
CreateArray(10, (len)->{//第二参数相当于实现接口方法便于创建方法调用该方法
return new int[len];
});
//-----引用实现
//int[]引用new 根据参数传递的长度来创建数组
CreateArray(10,int[]::new);
注解
命令:javadoc--生成文档 javap--反编译
- jdk1.5后新特性
- 说明程序的
- 定义注解--@interface 使用注解--@注解名称
注解本质就是一个接口,默认继承annotation接口
-
jdk预定义注解
- @Override :检测被该注解标注的方法是否继承自父类(接口)
- @Deprecated :表示该注解标注的内容已过时
- @SuppressWarnings :压制警告
-
自定义注解 属性:接口中的抽象方法 其返回值类型有如下:
- 基本数据类型
- String
- 枚举
- 注解
- 以上类型数组
定义属性 使用default关键字给属性赋初始值 使用注解时有默认值的属性可不赋值
使用注解时 只赋值一个属性且属性名叫value则value可省略
数组赋值 值用{}包裹,单个值{}可省
- 元注解:描述注解的注解
- @Target 描述注解能够作用位置
- ElementType.TYPE 表示只能作用到类上
- ElementType.METHOD 可以作用到方法上
- ElementType.FIELD可以作用到成员变量上
- @Retention 描述注解被保留的阶段
- RetentionPolicy.RUNTIME 被描述的注解会保留到class字节码文件中被jvm读取到
- @Documented 描述注解是否被抽取到api文档中
- @Inherited 描述注解是否被子类继承
- @Target 描述注解能够作用位置
解析注解 获取属性中定义的属性值
- 获取加了注解的类字节码class文件对象 即.class等
- 获取注解对象 ----字节码文件对象.getAnnotation(注解字节码 即注解名.class) 其实就是在内存中生成了一个该注解接口的子类实现对象
- 调用注解对象中定义的抽象方法(即注解的属性)获取属性值