文章目录
-
- [📕1. 反射](#📕1. 反射)
-
-
- [✏️1.1 反射相关的类](#✏️1.1 反射相关的类)
- [✏️1.2 Class类中的相关方法](#✏️1.2 Class类中的相关方法)
- [✏️1.3 Field类中的相关方法](#✏️1.3 Field类中的相关方法)
- [✏️1.4 Method类中的相关方法](#✏️1.4 Method类中的相关方法)
- [✏️1.5 Constructor类中的相关方法](#✏️1.5 Constructor类中的相关方法)
- [✏️1.6 获取Class对象的三种方式](#✏️1.6 获取Class对象的三种方式)
- [✏️1.7 反射的使用](#✏️1.7 反射的使用)
-
- [📕2. 枚举](#📕2. 枚举)
-
-
- [2.1 枚举的定义](#2.1 枚举的定义)
- [✏️2.2 枚举的使用](#✏️2.2 枚举的使用)
- [✏️2.3 枚举的构造方法](#✏️2.3 枚举的构造方法)
- [✏️2.4 枚举与反射](#✏️2.4 枚举与反射)
-
- [📕3. Lambda表达式](#📕3. Lambda表达式)
-
-
- [✏️3.1 Lambda表达式语法](#✏️3.1 Lambda表达式语法)
- [✏️3.2 函数式接口](#✏️3.2 函数式接口)
- [✏️3.3 变量捕获](#✏️3.3 变量捕获)
-
📕1. 反射
JAVA反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意一个方法和属性;这种动态获取信息以及动态调用对象方法的功能称为java语言的反射机制。
✏️1.1 反射相关的类
类名 | 用途 |
---|---|
Class类 | 代表类的实体,在运行的Java应用程序中表示类和接口 |
Field类 | 代表类的成员变量(类的属性) |
Method类 | 代表类的方法 |
Constructor | 代表类的构造方法 |
✏️1.2 Class类中的相关方法
方法 | 用途 |
---|---|
getClassLoader() | 获得类的加载器 |
getDeclaredClasses() | 返回一个数组,数组中包含该类中所有的类和接口的对象(包含私有的) |
forName(String className) | 根据类名返回类的对象 |
newInstance() | 创建类的实例 |
getName() | 获得类的完整路径名字 |
✏️1.3 Field类中的相关方法
方法 | 用途 |
---|---|
getField(String name) | 获得某个共有的属性对象 |
getFileds() | 获得所有共有的属性对象 |
getDeclaredField(String name) | 获得某个属性对象 |
getDeclaredFields() | 获得所有属性对象 |
✏️1.4 Method类中的相关方法
方法 | 用途 |
---|---|
getDeclaredMethod((String name, Class<?>... parameterTypes) | 获得该类某个方法 |
getDeclaredMethods() | 获得该类的所有方法 |
getMethod((String name, Class<?>... parameterTypes) | 获得该类某个公有方法 |
getMethods() | 获得该类所有公有方法 |
invoke(对象名,要修改的参数) | 触发方法执行的方法 |
✏️1.5 Constructor类中的相关方法
方法 | 用途 |
---|---|
getConstructor( Class<?>... parameterTypes) | 获得该类中与参类型匹配的某个公有构造方法 |
getConstructors() | 获得该类中所有的公有构造方法 |
geDeclaredtConstructor(Class<?>... parameterTypes) | 获得该类中与参类型匹配的某个构造方法 |
geDeclaredtConstructors() | 获得该类中所有的构造方法 |
✏️1.6 获取Class对象的三种方式
在反射之前,我们需要做的第一步就是先拿到当前需要反射的类的Class对象,然后通过Class对象的核心方法,达到反射的目的
- 我们先构造出一个学生类作为演示示例
java
class Student {
//私有属性name
private String name = "xiaozhuxiaozhu";
//公有属性age
public int age = 18;
//不带参数的构造⽅法
public Student(){
System.out.println("Student()");
}
private Student(String name,int age) {
this.name = name;
this.age = age;
System.out.println("Student(String,name)");
}
private void eat(){
System.out.println("i am eat");
}
public void sleep(){
System.out.println("i am pig");
}
private void function(String str) {
System.out.println(str);
}
@Override
public String toString() {
return "Student{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
}
1.使用 Class.forName("类的全路径名"); 静态方法(前提:已明确类的全路径名。 )。
java
public class test1 {
public static void main(String[] args) throws ClassNotFoundException {
//通过 Class 对象的 forName() 静态⽅法来获取,⽤的最多,但可能抛出 ClassNotFoundException 异常
//注意这⾥是类的全路径,如果有包需要加包的路径
Class c1 = Class.forName("reflection.Student");
}
}
- 使用 .class 方法(仅适合在编译前就已经明确要操作的 Class)。
java
public class test2 {
public static void main(String[] args) throws ClassNotFoundException {
//直接通过 类名.class 的⽅式得到,该⽅法最为安全可靠,程序性能更⾼
Class c2 = Student.class;
}
}
- 使用类对象的 getClass() 方法
java
public class test3 {
public static void main(String[] args) throws ClassNotFoundException {
Student s1 = new Student();
Class c3 = s1.getClass();
}
}
✏️1.7 反射的使用
接下来我们开始使用反射,我们依旧反射上面的Student类
注意:所有和反射相关的包都在 import java.lang.reflect 包下面。
java
package reflection;
import java.lang.reflect.Method;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
public class demo_test {
public static void main(String[] args) throws ClassNotFoundException,
InstantiationException,
IllegalAccessException,
NoSuchMethodException,
SecurityException,
IllegalArgumentException,
InvocationTargetException,
NoSuchFieldException {
// 获取Class对象
Class<?> c1 = Class.forName("reflection.Student");
Object newInstance = c1.newInstance();;
Student student = (Student)newInstance;
System.out.println(student);
// 获取构造方法
Constructor<?> constructors = c1.getDeclaredConstructor(String.class, int.class);
//设置为true后可修改访问权限
constructors.setAccessible(true);
Object newInstance1 = constructors.newInstance("zhangsan", 20);
Student student1 = (Student)newInstance1;
System.out.println(student1);
// 反射私有⽅法
Method method = c1.getDeclaredMethod("function", String.class);
//设置为true后可修改访问权限
method.setAccessible(true);
method.invoke(student1, "hello");
// 反射私有属性
Field field = c1.getDeclaredField("name");
//设置为true后可修改访问权限
field.setAccessible(true);
field.set(student1, "lisi");
System.out.println(student1);
}
}
📕2. 枚举
枚举是在JDK1.5以后引⼊的。本质是一个特殊的类,是 java.lang.Enum 的⼦类,⾃⼰写的枚举类,就算没有显示的继承 Enum ,但是其默认继承了这个类。枚举的关键字为enum,一般表示一组常量,比如一年的 4 个季节,一个年的 12 个月份,一个星期的 7 天,方向有东南西北等。
2.1 枚举的定义
java
限定符 enum 枚举名称{
常量1,常量2,常量3....;
}
✏️2.2 枚举的使用
- switch语句
java
public enum testenum {
RED,BLACK,WHITE;
public static void main(String[] args) {
testenum t1 = testenum.BLACK;
switch (t1) {
case RED:
System.out.println("红色");
break;
case BLACK:
System.out.println("黑色");
break;
case WHITE:
System.out.println("白色");
break;
default:
break;
}
}
}
- 常⽤⽅法
方法名称 | 描述 |
---|---|
values() | 以数组形式返回枚举类型的所有成员 |
ordinal() | 获取枚举成员的索引位置 |
valueOf() | 将普通字符串转换为枚举类型 |
compareTo() | 比较两个枚举成员在定义时的顺序 |
java
//将枚举类型的所有成员以数组形式返回并打印
testenum[] values = testenum.values();
for (int i = 0; i < values.length; i++) {
System.out.println(values[i]);
}
✏️2.3 枚举的构造方法
💡💡💡💡💡注意:当枚举对象有参数后,需要提供相应的构造函数
💡💡💡💡💡注意:枚举的构造函数默认是私有的 这个⼀定要记住
java
public enum testenum {
RED("红色",1),BLACK("黑色",2),WHITE("白色",3);
private String color;
private int key;
private testenum(String color,int key){
this.color=color;
this.key=key;
}
}
✏️2.4 枚举与反射
关于枚举与反射,请记住一个结论:你不能通过反射获取枚举类的实例!
这也是<为什么枚举实现单例模式是安全的?>问题的答案.至于为什么呢,等我学完单例模式之后在来补充...
📕3. Lambda表达式
Lambda 表达式(Lambda expression),基于数学中的λ演算得名,也可称为闭包(Closure) ,是Java SE 8中⼀个重要的新特性. Lambda表达式允许你通过表达式来代替功能接口。 lambda表达式就和方法⼀样,它提供了⼀个正常的参数列表和⼀个使用这些参数的主体(主体可以是⼀个表达式或⼀个代码块)。
✏️3.1 Lambda表达式语法
基本语法: (parameters) -> expression 或(parameters) -> {statement;}
Lambda表达式由三部分组成:
1. paramaters:类似方法中的形参列表,这⾥的参数是函数式接口里的参数。
2. ->:可理解为"被用于"的意思
3. 方法体:可以是表达式也可以代码块,是函数式接口里方法的实现。代码块可返回一个值或者什么
都不反回,这里的代码块块等同于方法的方法体。
java
// 1. 不需要参数,返回值为 2
() -> 2
// 2. 接收⼀个参数(数字类型),返回其2倍的值
x -> 2 * x
// 3. 接受2个参数(数字),并返回他们的和
(x, y) -> x + y
// 4. 接收2个int型整数,返回他们的乘积
(int x, int y) -> x * y
// 5. 接受⼀个 string 对象,并在控制台打印,不返回任何值(看起来像是返回void)
(String s) -> System.out.print(s)
✏️3.2 函数式接口
函数式接口定义:⼀个接口有且只有⼀个抽象方法 。
💡💡注意:
- 如果一个接口只有一个抽象方法,那么该接口就是⼀个函数式接口
- 如果我们在某个接口上声明了 @FunctionalInterface 注解,那么编译器就会按照函数式接口的定义来要求该接口,这样如果有两个抽象方法,程序编译就会报错的。所以,从某种意义上来说,只要你保证你的接口中只有一个抽象方法,你可以不加这个注解。加上就会自动进行检测的。
java
@FunctionalInterface
interface NoParameterNoReturn {
//注意:只能有⼀个⽅法
void test();
}
✏️3.3 变量捕获
java
@FunctionalInterface
interface NoParameterNoReturn {
void test();
}
public static void main(String[] args) {
int a = 10;
NoParameterNoReturn noParameterNoReturn = ()->{
// a = 99; error
System.out.println("捕获变量:"+a);
};
noParameterNoReturn.test();
}