01-注解介绍(掌握)
-
概述
- Java 注解(Annotation)又称 Java 标注,是 JDK5.0 引入的一种注释机制。 Java 语言中的类、方法、变量、参数和包等都可以被标注。
-
特点
- 是JDK5.0之后引入的特性.注解是以”@注解名”在代码中存在的
-
作用
- 自定义注解就是为了替代配置文件(xml , properties) , 简化开发步骤
-
代码实现
public class Fu { public void show() { System.out.println("fu show"); } }
public class Zi extends Fu{ //重写方法 @Override public void show() { System.out.println("zi show"); } }
02-JDK内置注解(掌握)
-
①@Override
- 标记在成员方法上,用于标识当前方法是重写父类方法,编译器在对该方法进行编译时会检查是否符合 重写规则,如果不符合,编译报错
-
②@Deprecated
- 用于标记当前类、成员变量、成员方法或者构造方法过时 如果开发者调用了被标记为过时的方法,编译器在编译期进行警告
-
③@SuppressWarnings
- unchecked 未检查的转化,如集合没有指定类型还添加元素
- unused 未使用的变量
- resource 有泛型未指定类型 path 在类路径,原文件路径中有不存在的路径
- deprecation 使用了某些不赞成使用的类和方法
- fallthrough switch语句执行到底没有break关键字
- rawtypes 没有写泛型,比如: List list = new ArrayList();
- all 全部类型的警告
-
代码实现1
@Deprecated public class User { @Deprecated public String name; @Deprecated public User() { } public User(String name) { this.name = name; } public String getName() { return name; } @Deprecated public void setName(String name) { this.name = name; } @Override public String toString() { return "User{" + "name='" + name + '\'' + '}'; } }
-
代码实现2
@SuppressWarnings("unused") public class Demo02 { @SuppressWarnings("all") public static void main(String[] args) { @SuppressWarnings("unused") User user = null; User user2 = null; List list = new ArrayList(); list.add(1); list.add("a"); } public static void show() { User user3 = null; } }
03-自定义注解(掌握)
-
语法
public @interface 注解名 { 数据类型 变量名1() default 默认值1; 数据类型 变量名2() default 默认值2; ... }
-
分类
- ①标记注解 : 注解中没有任何属性 , 比如 : @Override
- ②单值注解 : 注解中只有一个属性 , 比如 : @SuppressWarnings
- ③完整注解 : 注解中有多个属性
-
①标记注解
/** * 03-自定义注解 * ①标记注解 */ public @interface MyAnnotation01 { }
-
②单值注解
public @interface MyAnnotation02 { String msg() default "hello"; }
public @interface MyAnnotation03 { String value() ; }
- 注意1 : 注解属性如果没有默认必须手动赋值, 否则编译报错.
-
③完整注解
public @interface MyAnnotation04 { String msg() default "hello"; int value() default 250; }
-
注意事项
- 如果属性名为value , 且在使用注解时 , 只对value属性进行赋值, value是可以省略不写的.
04-元注解(掌握)
-
概述
- 用于描述其他注解的注解.
-
分类
- ①@Target (掌握) , ②@Retention(掌握) , ③@Inherited (了解) , ④@Documented (没用)
-
①@Target : 描述其他注解的作用范围 , 自定义注解默认情况下可以作用所有位置
-
代码实现1
@Target({ ElementType.TYPE, ElementType.FIELD, ElementType.CONSTRUCTOR, ElementType.METHOD, ElementType.PARAMETER, ElementType.LOCAL_VARIABLE }) public @interface MyAnnotation05 { }
** * 04-元注解 * @Target */ @MyAnnotation05 public class Demo04 { @MyAnnotation05 private int num = 250; @MyAnnotation05 public Demo04(int num) { this.num = num; } @MyAnnotation05 public void show(@MyAnnotation05 int num) { @MyAnnotation05 int num2 = 500; System.out.println("show"); } }
-
②@Retention : 描述其他注解的生命周期 , 自定义注解默认情况下仅存活于编译期
@Retention(RetentionPolicy.RUNTIME) public @interface MyAnnotation06 { }
/** * 04-元注解 */ @MyAnnotation06 public class Demo05 { public static void main(String[] args) { //@MyAnnotation06默认存活于编译期, 当程序时就已经不存在了. //使用反射 , 在程序运行时 , 动态获取Demo05.class类上的@MyAnnotation06注解 Class clazz = Demo05.class; boolean present = clazz.isAnnotationPresent(MyAnnotation06.class); System.out.println("Demo05类上存在MyAnnotation06注解 = " + present); } }
-
③@Inherited : 了解 , 父类上的注解也可以作用到子类上
@Retention(RetentionPolicy.RUNTIME)
@Inherited//@MyAnnotation07虽然标记在父类上, 但是也可以作用于子类上.
public @interface MyAnnotation07 {
}
@MyAnnotation07
public class Fu {
public void show() {
System.out.println("fu show");
}
}
public class Zi extends Fu{
//重写方法
@Override
public void show() {
System.out.println("zi show");
}
}
/**
* 04-元注解
* ③@Inherited
*/
public class Demo06 {
public static void main(String[] args) {
Zi zi = new Zi();
boolean present = zi.getClass().isAnnotationPresent(MyAnnotation07.class);
System.out.println("Zi类是否有MyAnnotation07注解 = " + present);
}
}
- ④@Documented : 没用
@Documented//让MyAnnotation08生成到文档中
public @interface MyAnnotation08 {
}
@MyAnnotation08
public class Demo07 {
public static void main(String[] args) {
System.out.println("Demo07");
}
}
05-自定义注解@MyTest(掌握)
-
需求
- 自定义注解@MyTest , 用于标注方法 , 被@MyTest注解标注的方法 , 可以一键运行.
-
代码实现
/** * 05-自定义注解@MyTest * 需求 : 自定义注解@MyTest , 用于标注方法 , 被@MyTest注解标注的方法 , 可以一键运行 (执行标记有@MyTest注解的方法). */ public class Demo08 { public static void main(String[] args) throws Exception { //1.获取Demo08类中的所有方法 Class clazz = Demo08.class; Method[] methods = clazz.getMethods(); for (Method method : methods) { //2.判断每个方法是否有标记@MyTest注解 if (method.isAnnotationPresent(MyTest.class)) { //有@MyTest注解标记 , 就执行方法 method.invoke(clazz.newInstance()); } else { //没有@MyTest注解标记 , 不需要处理 } } } @MyTest public void test1() { System.out.println("Demo08 test1"); } @MyTest public void test2() { System.out.println("Demo08 test2"); } public void test3() { System.out.println("Demo08 test3"); } @MyTest public void test4() { System.out.println("Demo08 test4"); } }
-
总结
- 注解如果要有意义必须结合反射使用.
06-自定义注解@BeanInfo(掌握)
-
beaninfo.properties
className=com.atguigu.bean.User id=1 name=zhangsan
-
需求
- 使用注解替代beaninfo.properties配置文件.
-
代码实现
@Retention(RetentionPolicy.RUNTIME) @Target(ElementType.TYPE) public @interface BeanInfo { String className() ; int id(); String name(); }
/** * 06-自定义注解@BeanInfo */ @BeanInfo( className = "com.atguigu.bean.User", id = 1, name = "张三" ) public class Demo09 { public static void main(String[] args) throws Exception { //1.获取@BeanInfo注解 Class clazz = Demo09.class; boolean present = clazz.isAnnotationPresent(BeanInfo.class); if (present) { //2.Demo09类上有@BeanInfo注解 , 获取@BeanInfo注解 BeanInfo beanInfoAnnotation = (BeanInfo) clazz.getAnnotation(BeanInfo.class); String className = beanInfoAnnotation.className(); System.out.println("className = " + className); int id = beanInfoAnnotation.id(); System.out.println("id = " + id); String name = beanInfoAnnotation.name(); System.out.println("name = " + name); //3.根据@BeanInfo信息使用反射操作数据 //根据className使用反射创建User对象 Class<?> userClass = Class.forName(className); User user = (User) userClass.newInstance(); //根据id使用反射操作id属性 Field idField = userClass.getDeclaredField("id"); idField.setAccessible(true); idField.set(user, id); //根据name使用反射操作setName方法 Method setNameMethod = userClass.getMethod("setName", String.class); setNameMethod.invoke(user , name); //4.打印User对象信息 System.out.println("user = " + user); } } }
07-接口的default方法(掌握)
-
接口的成员特点(回顾)
- 接口中不能有构造器
- 成员变量只能是常量 , 默认有public static final修饰
- 成员方法只能是抽象方法 , 默认有public abstract修饰(注意 , 注意 , 注意)
-
default方法
- 如何能在丰富接口功能的同时又不对子类代码进行更改呢?允许接口中定义带有方法体的方法。
- default方法不要求子类强制重写。
-
代码实现
public interface MyInterface01 { void show(); default void show2() { System.out.println("MyInterface01 show2"); } }
public interface MyInterface02 { void show(); default void show2() { System.out.println("MyInterface02 show2"); } }
public class MyInterface01Impl implements MyInterface01 , MyInterface02{ @Override public void show() { System.out.println("MyInterface01Impl show"); } @Override public void show2() { System.out.println("MyInterface01Impl show2"); } }
public class Demo10 { public static void main(String[] args) { MyInterface01Impl myInterface01 = new MyInterface01Impl(); myInterface01.show(); myInterface01.show2(); } }
-
注意事项
- 如果子类实现了两个接口 , 该接口中有相同的default方法, 要求子类必须重写该default方法, 否则报错.
08-接口的static方法(掌握)
-
代码实现
public interface MyInterface03 { static void show() { System.out.println("MyInterface03 static show"); } }
public interface MyInterface04 { static void show() { System.out.println("MyInterface04 static show"); } }
public class MyInterface03Impl implements MyInterface03 , MyInterface04{ }
-
报错
-
注意事项
- 接口中的静态方法只能通过接口名调用, 不能通过子类对象调用.
- 1.静态方法无法重写 ; 2.子类可以实现多个接口
09-函数式接口(掌握)
-
概述
- 有且仅有一个抽象方法的接口。 适用于函数式编程场景的接口。而Java中的函数式编程的体现就是lambda
-
@FunctionalInterface
- 用于标记当前接口是一个函数式接口.
-
代码实现
@FunctionalInterface public interface MyFunctionInterface01 { void show(); }
10-lambda初体验(掌握)
-
匿名内部类对象
new 类名/接口名() { public void 方法名(形参列表) { 方法体; } };
-
概述
- 是一套关于函数定义, 输入参数, 返回值的计算方案 , 其实就是匿名内部类对象的
语法糖
- 之前, 面向对象思想, 开发人员需要考虑怎么做 ; 使用lambda , 开发人员只需要思考做什么
- 是一套关于函数定义, 输入参数, 返回值的计算方案 , 其实就是匿名内部类对象的
-
语法
(形参列表)-> { 方法体; }
-
代码实现
/** * 10-lambda初体验 */ public class Demo12 { public static void main(String[] args) { //匿名内部类对象 method(new MyFunctionInterface01() { @Override public void show() { System.out.println("匿名内部类对象"); } }); //lambda method(() -> { System.out.println("lambda"); }); method(() -> System.out.println("lambda")); } public static void method(MyFunctionInterface01 functionInterface01) { functionInterface01.show(); } }
-
注意事项
- lambda表达式使用的接口是函数式接口.
11-lambda基本使用(掌握)
-
①场景一:函数式接口作为参数,接口方法无参数无返回值
@FunctionalInterface public interface MyFunctionInterface01 { void show(); }
/** * 11-lambda基本使用 * ①场景一:函数式接口作为参数,接口方法无参数无返回值 */ public class Demo13 { public static void main(String[] args) { //匿名内部类对象 method(new MyFunctionInterface01() { @Override public void show() { System.out.println("匿名内部类对象"); } }); //lambda完整版 method(()-> { System.out.println("lambda完整版"); }); //lambda简化版 method(()-> System.out.println("lambda简化版")); } public static void method(MyFunctionInterface01 functionInterface01) { functionInterface01.show(); } }
-
②场景二:函数式接口作为参数,接口方法有参数无返回值
@FunctionalInterface public interface MyFunctionInterface02 { void show(String msg); }
/** * 11-lambda基本使用 * ②场景二:函数式接口作为参数,接口方法有参数无返回值 */ public class Demo14 { public static void main(String[] args) { //匿名内部类对象 method("hello", new MyFunctionInterface02() { @Override public void show(String msg) { System.out.println("匿名内部类对象" + msg); } }); //lambda完整版 method("hello", (String msg) -> { System.out.println("lambda完整版" + msg); }); //lambda简化版 method("hello", (String msg) -> System.out.println("lambda简化版" + msg)); //lambda超级简化版 : 可以省略形参的数据类型 method("hello", (msg) -> System.out.println("lambda超级简化版" + msg)); //lambda超级超级简化版 : 如果形参只有一个, 可以省略小括号 method("hello", msg -> System.out.println("lambda超级超级简化版" + msg)); } public static void method(String msg, MyFunctionInterface02 functionInterface02) { functionInterface02.show(msg); } }
-
③场景三:函数式接口作为返回值,接口方法无参数无返回值
/** * 11-lambda基本使用 * ③场景三:函数式接口作为返回值,接口方法无参数无返回值 */ public class Demo15 { public static void main(String[] args) { method1().show(); method2().show(); method3().show(); } //匿名内部类对象 public static MyFunctionInterface01 method1() { return new MyFunctionInterface01() { @Override public void show() { System.out.println("匿名内部类对象"); } }; } //lambda完整版 public static MyFunctionInterface01 method2() { return () -> { System.out.println("lambda完整版"); }; } //lambda简化版 public static MyFunctionInterface01 method3() { return () -> System.out.println("lambda简化版"); } }
-
④场景四:函数式接口作为返回值,接口方法有参数
/** * 11-lambda基本使用 * ④场景四:函数式接口作为返回值,接口方法有参数无返回值 */ public class Demo16 { public static void main(String[] args) { method1().show("hello"); method2().show("hello"); method3().show("hello"); method4().show("hello"); } //匿名内部类对象 public static MyFunctionInterface02 method1() { return new MyFunctionInterface02() { @Override public void show(String msg) { System.out.println("匿名内部类对象" + msg); } }; } //lambda完整版 public static MyFunctionInterface02 method2() { return (String msg) -> { System.out.println("lambda完整版" + msg); }; } //lambda简化版 public static MyFunctionInterface02 method3() { return (String msg) -> System.out.println("lambda简化版" + msg); } public static MyFunctionInterface02 method4() { return (msg) -> System.out.println("lambda超级简化版" + msg); } public static MyFunctionInterface02 method5() { return msg -> System.out.println("lambda超级超级简化版" + msg); } }
-
⑤场景五:函数式接口作为参数,接口方法无参数有返回值
/** * 11-lambda基本使用 * ⑤场景五:函数式接口作为参数,接口方法无参数有返回值 */ public class Demo17 { public static void main(String[] args) { //匿名内部类对象 int result = method1(new MyFunctionInterface03() { @Override public int show() { return 250; } }); System.out.println("匿名内部类对象 result = " + result); int result2 = method1(() -> { return 250; }); System.out.println("lambda完整版 result2 = " + result2); int result3 = method1(() -> 250); System.out.println("lambda简化版 result3 = " + result2); } public static int method1(MyFunctionInterface03 functionInterface03) { return functionInterface03.show(); } }
-
⑥场景六: 函数式接口作为返回值 , 接口方法有参数有返回值
/** * 11-lambda基本使用 * ⑥场景六: 函数式接口作为返回值 , 接口方法有参数有返回值 */ public class Demo18 { public static void main(String[] args) { //匿名内部类对象 int result = method1().show("hello"); System.out.println("匿名内部类对象 result = " + result); int result2 = method2().show("hello"); System.out.println("lambda完整版 result2 = " + result2); int result3 = method3().show("hello"); System.out.println("lambda简化版 result3 = " + result3); } public static MyFunctionInterface04 method1() { return new MyFunctionInterface04() { @Override public int show(String msg) { return 250; } }; } public static MyFunctionInterface04 method2() { return (String msg) -> { return 250; }; } public static MyFunctionInterface04 method3() { return msg -> 250; } }
-
总结
- 函数式接口可以作为方法的参数
- 函数式接口可以作为方法的返回值
-
注意事项
- ①接口方法中只有一行代码, 那么可以省略大括号.
- ②可以省略形参的数据类型
- ③如果形参只有一个, 可以省略小括号
- ④接口方法中只有一行代码 , 且是一个返回值代码 , 可以省略大括号和return
- ⑤lambda表达式不能单独使用
12-Runnable接口(掌握)
-
代码实现
/** * Runnable接口 */ public class Demo20 { public static void main(String[] args) { //匿名内部类对象 new Thread(new Runnable() { @Override public void run() { System.out.println("匿名内部类对象 线程启动"); } }).start(); //lambda new Thread(() -> System.out.println("lambda 线程启动")).start(); } }
13-Supplier接口(掌握)
-
概述
- JDK提供了大量常用的函数式接口以丰富Lambda的典型使用场景,它们主要在 java.util.function 包 中被提供。
-
Supplier接口
-
需求1
- 使用Supplier接口获取数字250
-
需求2
- 使用 Supplier 接口作为方法参数类型,通过Lambda表达式求出int数组中的最大值。
-
代码实现1
/** * 05-Supplier接口 * 需求1 : 使用Supplier接口获取数字250 */ public class Demo21 { public static void main(String[] args) { Integer num = getNum(new Supplier<Integer>() { @Override public Integer get() { return 250; } }); System.out.println("num = " + num); Integer num2 = getNum(() -> 250); System.out.println("num2 = " + num2); } public static Integer getNum(Supplier<Integer> supplier) { return supplier.get(); } }
-
代码实现2
/** * 05-Supplier接口 * 需求2 : 使用 Supplier 接口作为方法参数类型,通过Lambda表达式求出int数组中的最大值。 */ public class Demo22 { public static void main(String[] args) { Integer myMax = getMax(() -> { int[] nums = {1, 2, 3, 4, 5}; int max = nums[0];//记录数组中的最大值 for (int num : nums) { if (max < num) { max = num; } } return max; }); System.out.println("myMax = " + myMax); } /** * 获取数组中的最大值 * * @param supplier * @return */ public static Integer getMax(Supplier<Integer> supplier) { return supplier.get(); } }
14-Consumer接口(掌握)
-
概述
- Consumer接口java.util.function.Consumer接口则正好与Supplier接口相反,它不是生产一个 数据,而是消费一个数据, 其数据类型由泛型决定
-
常用方法
-
①accept方法
/** * 14-Consumer接口 * ①accept方法 */ public class Demo23 { public static void main(String[] args) { //匿名内部类对象 consumeString("helloworld", new Consumer<String>() { @Override public void accept(String msg) { System.out.println("msg = " + msg); } }); consumeString("helloworld", msg -> System.out.println("msg = " + msg)); } public static void consumeString(String msg, Consumer<String> consumer) { consumer.accept(msg); } }
-
②andThen方法
/** * 14-Consumer接口 * ①andThen方法 */ public class Demo24 { public static void main(String[] args) { consumeString( "hello", new Consumer<String>() { @Override public void accept(String msg) { System.out.println("匿名内部类对象 consumer1 : " + msg); } }, new Consumer<String>() { @Override public void accept(String msg) { System.out.println("匿名内部类对象 consumer2 : " + msg); } } ); consumeString( "hello", msg -> System.out.println("lambda1 msg : " + msg), msg -> System.out.println("lambda2 msg : " + msg) ); } public static void consumeString(String msg, Consumer<String> consumer1, Consumer<String> consumer2) { //链式编程 consumer1.andThen(consumer2).accept(msg); } }
15-Predicate接口(掌握)
-
概述
- 有时候我们需要对某种类型的数据进行判断,从而得到一个boolean值结果。这时可以使用 java.util.function.Predicate 接口
-
常用方法
-
代码实现
/** * 15-Predicate接口 */ public class Demo25 { public static void main(String[] args) { boolean flag = test("hello", msg -> msg.length() > 3); System.out.println("flag = " + flag); boolean flag2 = and( "hello", msg -> msg.length() > 3,//true msg -> msg.startsWith("a")//false ); System.out.println("flag2 = " + flag2); boolean flag3 = or( "hello", msg -> msg.length() > 3,//true msg -> msg.startsWith("a")//false ); System.out.println("flag3 = " + flag3); boolean flag4 = negate("hello", msg -> msg.length() > 3); System.out.println("flag4 = " + flag4); boolean flag5 = isEqual("a", "a"); System.out.println("flag5 = " + flag5); } public static boolean test(String msg, Predicate<String> predicate) { return predicate.test(msg); } public static boolean and(String msg, Predicate<String> predicate1, Predicate<String> predicate2) { return predicate1.and(predicate2).test(msg); } public static boolean or(String msg, Predicate<String> predicate1, Predicate<String> predicate2) { return predicate1.or(predicate2).test(msg); } public static boolean negate(String msg, Predicate<String> predicate) { return predicate.negate().test(msg); } public static boolean isEqual(String msg1 , String msg2 ) { return Predicate.isEqual(msg1).test(msg2); } }
16-Function接口(掌握)
-
概述
- java.util.function.Function 接口用来根据一个类型的数据得到另一个类型的数据,前者称为前置条 件, 后者称为后置条件。
-
常用方法
-
代码实现
/** * 16-Function接口 */ public class Demo26 { public static void main(String[] args) { Integer num = apply("250", numberStr -> Integer.parseInt(numberStr)); System.out.println("num = " + num); Integer num2 = andThen( "250", numberStr -> Integer.parseInt(numberStr),//250 number -> number + 250 ); System.out.println("num2 = " + num2); Object msg = identity("hello"); System.out.println("msg = " + msg); } public static Integer apply(String numberStr, Function<String, Integer> function) { return function.apply(numberStr); } /** * @param numberStr * @param function1 : numberStr -> number * @param function2 : number -> number + 250 * @return */ public static Integer andThen(String numberStr, Function<String, Integer> function1, Function<Integer, Integer> function2) { return function1.andThen(function2).apply(numberStr); } public static Object identity(Object obj) { return Function.identity().apply(obj); } }
据得到另一个类型的数据,前者称为前置条 件, 后者称为后置条件。
-
常用方法
- [外链图片转存中…(img-71dd2WLj-1666624628418)]
-
代码实现
/** * 16-Function接口 */ public class Demo26 { public static void main(String[] args) { Integer num = apply("250", numberStr -> Integer.parseInt(numberStr)); System.out.println("num = " + num); Integer num2 = andThen( "250", numberStr -> Integer.parseInt(numberStr),//250 number -> number + 250 ); System.out.println("num2 = " + num2); Object msg = identity("hello"); System.out.println("msg = " + msg); } public static Integer apply(String numberStr, Function<String, Integer> function) { return function.apply(numberStr); } /** * @param numberStr * @param function1 : numberStr -> number * @param function2 : number -> number + 250 * @return */ public static Integer andThen(String numberStr, Function<String, Integer> function1, Function<Integer, Integer> function2) { return function1.andThen(function2).apply(numberStr); } public static Object identity(Object obj) { return Function.identity().apply(obj); } }