反射笔记
java三阶段:
- 1-源码
- 2-class
- 3-runtime
获取Class对象的方式
方式 | |
---|---|
Class.forName(“全类名”) | 将自己吗文件加载进内存,返回Class对象 多用于配置文件,将类名定义在配置文件中,读取文件,加载类 |
类名.class | 通过类名的属性class获取 多用于参数传递 |
对象.getClass() | getClass()方法在 Object类中定义着 多用于对象的获取字节码的方式 |
结论:同一个字节码文件(*.class)在一次程序运行过程中,只会被加载一次,不论通过哪一种方式获取的Class对象都是同一个
Class对象功能
暴力反射
// 忽略访问权限修饰符的安全检查
Field/Constructor/Method对象.setAccessible(true)
Declared 不考虑修饰符
获取构造方法/们
方法 | |
---|---|
Constructor<?>[] getConstructors() | 获取构造方法 |
Constructor getConstructor(类<?>… parameterTypes) | 获取指定参数的构造方法 |
Constructor getDeclaredConstructor(类<?>… parameterTypes) | |
Constructor<?>[] getDeclaredConstructors() | |
[操作] | |
T Construct对象.newInstance(Object… initargs) | |
T Class对象.newInstance() | 空参数构造方法创建对象可这样简化 |
T表示返回对象类型
获取成员变量/们
方法 | |
---|---|
Field[] getFields() | 获取所有public修饰的成员变量 |
Field getField(String name) | 获取指定名称的public修饰的成员变量 |
Field[] getDeclaredFields() | 获取所有的成员变量,不考虑修饰符 |
Field getDeclaredField(String name) | 获取指定名称的,不考虑修饰符 |
[操作] | |
void set(Object obj, Object value) | 设置值 |
Object get(Object obj) | 获取值 |
获取成员方法/们
方法 | |
---|---|
Method[] getMethods() | 获取public修饰的所有方法 |
Method getMethod(String name, 类<?>… parameterTypes) | name 方法名称 parameterTypes 参数类型列表 |
Method[] getDeclaredMethods() | |
Method getDeclaredMethod(String name, 类<?>… parameterTypes) | |
[操作] | |
Object invoke(Object obj, Object… args) | 执行方法 参数obj:方法类的对 参数args:方法参数列表 |
String getName() | 获取方法名称 |
获取全类名
String getName()
函数式编程
通过匿名内部类和lambda表达式完成
匿名内部类:
定义一个接口,该接口定义一个未实现的方法,当其他类方法参数用到该接口类型时,可以直接new该接口并实现方法即可。
Lambda表达式:
当某个方法需要一个参数,这个参数类可以是一个接口并且接口只有一个方法时可用Lambda。
- 一些参数
- 一个箭头
- 一段代码
格式:(参数列表)->{一些重写方法的代码};
可省略内容:
- 括号中参数列表的数据类型,可省略
- 括号中的参数如果只有一个,那么类型和括号都可以省略
- 如果{}中代码只有一行,无论是否有返回值,都可以省略({},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)出来
}
public static void main(String arg[]){
// Lambda表达式实现
// p即print()方法的参数str,System.out.println(arg)即相当于该方法的方法体
printString(p->System.out.println(arg));
// 引用实现
printString(System.out::println);
}
【定义类对象引用方法】
public static void main(String arg[]){
// 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);
}
public static void main(String arg[]){
// Lambda表达式实现
int numberabs = method(-10, (n)->{
return Math.abs(n); // 这里相当于calsABs的方法体
});
// 引用实现
int numberabs2 = method(-10, Math::abs);
}
【super引用父类方法】
super::父类方法名
【this引用本类方法】
this::本类方法名
【类引用构造方法】
// 函数式编程所需接口
@FunctionalInterface
interface PersonBuilder{
builPerson(String name);
}
//定义一个方法,参数传w递姓名和PsesonBuilder接口,方法中通过姓名创建Person对象
public static void printName(String name,PersonBuilder pb) {
Person person = pb.builPerson(name);
System.out.println(person);
}
// lambda表达式实现
printName("迪丽热巴", (String name)->{
return new Person(name); //这里相当 于builPerson的方法体
}
);
// 引用实现
//创建对象已知,new
//使用Person类的带参构造方法,通过传递的姓名创建对象
printName("古力娜扎", Person::new);
// 例子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 描述注解是否被子类继承
解析注解 获取属性中定义的属性值
-
获取加了注解的类字节码class文件对象 即.class等
-
获取注解对象
// 其实就是在内存中生成了一个该注解接口的子类实现对象 字节码文件对象.getAnnotation(注解字节码 即注解名.class)
-
调用注解对象中定义的抽象方法(即注解的属性)获取属性值