我们于2021/07/24 的学习目标是:反射,注解和函数式接口,核心任务为:
1、学习技术:
1)、反射的概念
2)、反射操作构造器和反射创建对象
3)、反射操作属性和方法
4)、反射操作数组
5)、注解的概念
6)、元注解
7)、自定义注解
8)、注解解析器
9)、函数式接口
2、文档总结
1)、反射的概念
反射是发生在程序运行期间的动态机制或行为,Java中唯一的动态机制就是反射机制。
对于:
class Person{
void test(){
}
}
class Student extends Person{
void test(){
}
}
class Teacher extends Person{
void test(){
}
}
有:
//通过反射创建对象
Person obj = (Person) Class.forName(pro.getProperty("Student")).newInstance();
obj.test();
Java反射机制,可以实现以下功能:
- 在运行时判断任意一个对象所属的类
- 在运行时构造任意一个类的对象
- 在运行时判断任意一个类所具有的成员变量和方法
- 在运行时判断任意一个类所具有的成员变量和方法
- 在运行时调用任意一个对象的方法
- 生成动态代理
反射的源头:
Class<T> Class类型的实例可以用来表示Java运行期间的一个类型
Class对象:
Class对象在类第一次加载到内存后就已经存在的,唯一的,不变的,每一个类型只有一个Class对象可以操作这个类的所有内容(属性方法构造器…)
如何获取反射的源头:Class对象
- 类名.class
- Class.forName(权限定名)
权限定名推荐命名成 包名.类名 的格式
- 对象.getClass()
//1.类名.class
Class<String> cls1 = String.class;
System.out.println(cls1.toString());
//2.Class.forName(权限定名)
Class cls2 = Class.forName("java.lang.String");
System.out.println(cls2);
System.out.println(cls2==cls1);
//3.对象.getClass()
Class cls3 = "abc".getClass();
System.out.println(cls3);
System.out.println(cls3==cls1);
//获取当前Class对象所表示类型的父类的Class对象
Class cls4 = cls1.getSuperclass();
System.out.println(cls4);
System.out.println(cls4==Object.class);
//获取基本数据类型的Class对象
System.out.println(Integer.class);
System.out.println(int.class);
System.out.println(int.class==Integer.class);
System.out.println(Integer.TYPE);
System.out.println(Integer.TYPE==int.class);
2)、反射操作构造器和反射创建对象
反射操作构造器:
构造器<T> getConstructor(类<?>... parameterTypes)
返回一个 构造器对象,该对象反映此 类对象所表示的类的指定公共构造函数。
构造器<?>[] getConstructors()
返回一个包含构造器对象的数组, 构造器对象反映了此 类对象所表示的类的所有公共构造函数。
以上都是获取公共的,被public修饰的构造器
构造器<T> getDeclaredConstructor(类<?>... parameterTypes)
返回一个构造器对象,该对象反映此类对象所表示的类或接口的指定构造函数。
构造器<?>[] getDeclaredConstructors()
返回构造器对象的数组, 构造器对象反映由此类对象表示的类声明的所有构造函数。
反射创建对象:
Class-->T newInstance()
默认调用类型的空构造为对象初始化信息
不推荐使用,因为不能确定一个类型是否存在空构造,极有可能遇到运行时异常
Constructor---> T newInstance(Object... initargs)
创建对象的同时调用当前构造器为对象初始化信息
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
public class Class003_Reflect {
public static void main(String[] args) throws IllegalAccessException, InstantiationException, NoSuchMethodException, InvocationTargetException {
//获取构造器
Class<User> cls = User.class;
Constructor[] cons = cls.getConstructors();
for(Constructor con:cons){
System.out.println(con);
}
Constructor<User> con = cls.getDeclaredConstructor(String.class,int.class);
System.out.println(con);
//创建对象
//1)
User user = User.class.newInstance();
System.out.println(user);
//2) 私有内容需要忽略权限使用
con.setAccessible(true); //忽略权限
User user2 = con.newInstance("sample",345);
System.out.println(user2);
}
}
class User{
private String name;
private int pwd;
//公共的
public User() {
}
public User(String name) {
this.name = name;
}
//私有的
private User(String name, int pwd) {
this.name = name;
this.pwd = pwd;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getPwd() {
return pwd;
}
public void setPwd(int pwd) {
this.pwd = pwd;
}
@Override
public String toString() {
return "User{" +
"name='" + name + '\'' +
", pwd=" + pwd +
'}';
}
}
3)、反射操作属性和方法
反射操作属性:
getField(String name)
返回 字段对象,该对象反映此类对象表示的类或接口的指定公共成员字段。
[] getFields()
返回一个包含 字段对象的数组,字段对象反映此 类对象所表示的类或接口的所有可访问公共字段。
getDeclaredField(String name)
返回字段对象,该对象反映此 类对象表示的类或接口的指定声明字段。
[] getDeclaredFields()
返回 字段对象的数组,字段对象反映由此类对象表示的类或接口声明的所有字段。
void set(Object obj, Object value)
将指定对象参数上此 字段对象表示的字段设置为指定的新值。
Object get(Object obj)
返回指定对象上此 字段表示的字段的值。
反射操作方法:
getMethod(String name, 类<?>... parameterTypes)
返回方法对象,该对象反映此类对象表示的类或接口的指定公共成员方法。
getMethods()
返回一个包含 方法对象的数组,方法对象反映此类对象所表示的类或接口的所有公共方法,包括由类或接口声明的那些以及从超类和超接口继承的那些。
getDeclaredMethod(String name,类<?>... parameterTypes)
返回方法对象,该对象反映此类对象表示的类或接口的指定声明方法。
getDeclaredMethods()
返回一个包含方法对象的数组,方法对象反映此类对象表示的类或接口的所有已声明方法,包括public,protected,default(package)访问和私有方法,但不包括继承的方法。
Object invoke(Object obj, Object... args)
在具有指定参数的指定对象上调用此 方法对象表示的基础方法。
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
public class Class004_Reflect {
public static void main(String[] args) throws NoSuchFieldException, IllegalAccessException, NoSuchMethodException, InvocationTargetException {
User user = new User("zhangsan");
//User类的Class对象
Class<User> cls = User.class;
testMethod(cls,user);
}
//测试方法
public static void testMethod(Class<User> cls,User user) throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
Method[] methods = cls.getMethods();
for(Method m:methods){
System.out.println(m);
}
//私有方法
Method method = cls.getDeclaredMethod("haha",int.class);
//调用方法
method.setAccessible(true);
System.out.println(method.invoke(user,100));;
System.out.println(method.invoke(null,100));;
Method m = cls.getMethod("getName");
System.out.println(m.invoke(user));
}
//测试属性
public static void testField(Class<User> cls,User user) throws NoSuchFieldException, IllegalAccessException {
Field field = cls.getDeclaredField("name");
System.out.println(field.getName());
System.out.println(field.getType());
//忽略权限
field.setAccessible(true);
field.set(user,"zhangsanfeng");
System.out.println(field.get(user));
}
}
4)、反射操作数组
static Object newInstance(类<?> componentType, int length)
创建具有指定组件类型和长度的新数组。
static Object get(Object array, int index)
返回指定数组对象中索引组件的值。
static void set(Object array, int index, Object value)
将指定数组对象的索引组件的值设置为指定的新值。
import java.lang.reflect.Array;
import java.lang.reflect.Modifier;
import java.util.Arrays;
public class Class005_Reflect {
public static void main(String[] args) throws Exception {
testArray();
test(String.class);
}
public static void test(Class<String> cls){
//int getModifiers() 返回此类或接口的Java语言修饰符,以整数编码。
System.out.println(cls.getModifiers());
System.out.println(Modifier.toString(cls.getModifiers()));
//类<?>[] getInterfaces() 返回由此对象表示的类或接口直接实现的接口。
System.out.println(Arrays.toString(cls.getInterfaces()));
//String getName() 返回此 类对象表示的实体名称(类,接口,数组类,基本类型或void),作为 String 。
System.out.println(cls.getName());
//String getSimpleName() 返回源代码中给出的基础类的简单名称。
System.out.println(cls.getSimpleName());
}
//简单操作数组
public static void testArray(){
int[] arr = (int[]) Array.newInstance(int.class,5);
Array.set(arr,2,200);
System.out.println(Arrays.toString(arr));
System.out.println(Array.get(arr,2));
}
}
5)、注解的概念
注解:Annotation 标注,Java8引入
作用:
- 注释
- 标志|标识
- 使用注解时可以传递参数,可以在程序中通过反射操作注解,获取配置的信息在程序中使用
- 可以存在于Class文件中
- 大量的代替|简化配置文件的使用
使用:
@注解名(参数)
注解的分类:
JDK内置注解(常见):
@Override 检查重写方法
@SuppressWarnings("all")抑制警告
@Deprecated 表示已过时,不推荐使用
@FunctionalInterface 标识函数式接口
参数的个数分类:
标志|标识注解
单值注解
完整注解
元注解:给注解进行注解
自定义注解
6)、元注解
- @Target 用于描述注解的使用范围
- @Retention 规定注解类型的声明周期
- @Documented 保留在API文档中
- @Inherited 标识注解类型可以被继承
7)、自定义注解
- @interface定义注解类型
- 默认实现java.lang.annotation.Annotation接口
- 自定义的注解类型不能显示的继承其他父类,实现其他接口
- 如果注解类中的属性只有一个,建议名字为value,为value属性赋值可以直接赋值
- 为注解类型定义属性|字段:数据类型 数据名();
- 属性的数据类型要求:基本数据类型、String、枚举、注解类型以及以上类型的数组
- 属性可以通过default提供默认值
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
public class Class003_MyAnnotation {
@MyAnnotation(value=111,haha=123,hehe=321)
int apple;
}
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
@interface MyAnnotation{
int value() default 1;
int haha();
int hehe();
}
8)、注解解析器
定义:通过反射操作注解
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.reflect.Field;
import java.util.Arrays;
/*
案例: 自定义水果清单 FruitList
int apple;
int pair;
为每种水果提供一个默认的进货数量,通过注解进行配置
注解类型: FruitNum 属性: int value();
注意:
如果通过反射操作注解,注解类型的生命周期应该定义为运行期
*/
public class Class004_FruitList {
public static void main(String[] args) throws Exception {
FruitList list = new FruitList();
list.apple=200;
System.out.println(list);
testFruitList(list,FruitList.class);
System.out.println(list);
}
//注解解析器
public static FruitList testFruitList(FruitList list,Class<FruitList> cls) throws Exception {
//1.获取所有属性
Field[] arr = cls.getDeclaredFields();
//2.判断当前对象的每一个属性值
for(Field field:arr){
Object value = field.get(list);
//是否==null,如果不等于 略过 如果==null 1)获取当前成员变量上的注解对象, 2)获取到实现 3)赋值
if(value==null){
//判断当前属性上是否存在FruitNum注解修饰
if(field.isAnnotationPresent(FruitNum.class)){
//获取当前属性上的FruitNum注解实例
FruitNum fruitNum = field.getAnnotation(FruitNum.class);
System.out.println(fruitNum.value());
//为当前属性赋值,值为成员上的注解上配置的实参
field.set(list,fruitNum.value());
}
}
}
return list;
}
}
class FruitList{
@FruitNum(50)
Integer apple;
@FruitNum
Integer pair;
@Override
public String toString() {
return "FruitList{" +
"apple=" + apple +
", pair=" + pair +
'}';
}
}
//水果数量
@Retention(RetentionPolicy.RUNTIME)
@interface FruitNum{
int value() default 20;
}
9)、函数式接口
定义:接口中只与一个必须被重写的抽象方法
@FunctionalInterface
四大内置函数式接口:
- 消费性接口: Consumer<T>
void accept(T t) --> 有来无回,有参数没有返回值
- 供给型接口: Supplier<T>
T get()
- 函数型接口: Function<T,R>
R apply(T t)
- 段言型接口: Predicate<T>
boolean test(T t)
import java.util.ArrayList;
import java.util.List;
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.function.Predicate;
import java.util.function.Supplier;
public class Class001_FunctionalInterface {
public static void main(String[] args) {
testConsumer(5000, m-> System.out.println(m));
testConsumer(10000, m-> System.out.println(m));
System.out.println(getNum(5,()->(int)(Math.random()*(5-1+1)+1)));;
System.out.println(getNum(3,()->(int)(Math.random()*(15-10+1)+10)));;
System.out.println(strHandler(" haha ",s->s.trim()));;
System.out.println(strHandler(" haha ",s->s.toUpperCase()));;
List<Employee> list = new ArrayList<Employee>();
list.add(new Employee(1003,"zhangsan",19));
list.add(new Employee(1002,"lisi",17));
list.add(new Employee(1001,"wangwu",18));
System.out.println(checkEmp(list,e->e.getAge()>=18));
}
//对员工集合中的员工数据按照某种规则进行过滤,返回结果
public static List<Employee> checkEmp(List<Employee> list, Predicate<Employee> predicate){
List<Employee> newList = new ArrayList<>();
for(Employee e:list){
if(predicate.test(e)){
newList.add(e);
}
}
return newList;
}
//对字符串进行处理,返回结果
public static String strHandler(String str, Function<String,String> my){
return my.apply(str);
}
//产生指定个数的指定规则的随机数
public static List<Integer> getNum(int num, Supplier<Integer> supplier){
List<Integer> list = new ArrayList<>();
for(int i=1;i<=num;i++){
list.add(supplier.get());
}
return list;
}
//消费的功能
public static void testConsumer(int money, Consumer<Integer> con){
con.accept(money);
}
}