-
? 表示不确定的 java 类型
-
T (type) 表示具体的一个java类型
-
K V (key value) 分别代表java键值中的Key Value
-
E (element) 代表Element
-
S, U, V 等等 - 第二、第三、第四个类型
💳2. 反射
2.1 定义
Java的反射(reflection)机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意方法和属性,既然能拿到那么,我们就可以修改部分类型信息;这种动态获取信 息以及动态调用对象方法的功能称为java语言的反射(reflection)机制。
2.2 用途
1、在日常的第三方应用开发过程中,经常会遇到某个类的某个成员变量、方法或是属性是私有的或是只对系统应 用开放,这时候就可以利用Java的反射机制通过反射来获取所需的私有成员或是方法 。
2、反射最重要的用途就是开发各种通用框架,比如在spring中,我们将所有的类Bean交给spring容器管理,无论 是XML配置Bean还是注解配置,当我们从容器中获取Bean来依赖注入时,容器会读取配置,而配置中给的就是类 的信息,spring根据这些信息,需要创建那些Bean,spring就动态的创建这些类。
2.3 反射基本信息
Java程序中许多对象在运行时会出现两种类型:运行时类型(RTTI)和编译时类型,例如Person p = new Student();这句代码中p在编译时类型为Person,运行时类型为Student。程序需要在运行时发现对象和类的真实 信心。而通过使用反射程序就能判断出该对象和类属于哪些类。
2.4 反射相关的类
编辑
1. Class类(反射机制的起源 ) 和 Class类中的相关方法
Class帮助文档代表类的实体,在运行的Java应用程序中表示类和接口. Java文件被编译后,生成了.class文件,JVM此时就要去解读.class文件 ,被编译后的Java文件.class也被JVM解析为 一个对象,这个对象就是 java.lang.Class .这样当程序在运行时,每个java文件就最终变成了Class类对象的一个 实例。
我们通过Java的反射机制应用到这个实例,就可以去获得甚至去添加改变这个类的属性和动作,使得这个类成为一个动态的类。
常用获得类相关的方法
编辑
常用获得类中属性相关的方法
编辑获得类中注解相关的方法
编辑获得类中构造器相关的方法
编辑
获得类中方法相关的方法
编辑
2. 反射示例(使用)
a. 获得Class对象的三种方式
在反射之前,我们需要做的第一步就是先拿到当前需要反射的类的Class对象,然后通过Class对象的核心方法,达 到反射的目的,即:在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象, 都能够调用它的任意方法和属性,既然能拿到那么,我们就可以修改部分类型信息。
第一种,使用 Class.forName("类的全路径名"); 静态方法。 前提:已明确类的全路径名。
第二种,使用 .class 方法。 说明:仅适合在编译前就已经明确要操作的 Class。
第三种,使用类对象的 getClass() 方法。
b. 反射的使用
注意:所有和反射相关的包都在 import java.lang.reflect 包下面。
Son 类
public class Son {
private String name;
private int age;
public int aa;
int bb;
Son(){
System.out.println("我是包无参构造");
private Son(String name) {
System.out.println("我是私有有参构造 name = " + name);
public Son(String name, int age){
System.out.println("我是公有有参构造 name = " + name + "age" +age);
void method1(){
System.out.println("我是无参方法");
private void method2(String dd){
System.out.println("我是包访问权限有参方法" + dd);
public void method3(String dd, String cc){
System.out.println("我是公共有参方法" + dd);
}
使用
public class Test {
public static void main(String[] args) throws Exception{
// 得到class
Class<Son> c1 = Son.class;
Class<? extends Son> c2 = new Son().getClass();
Class<?> c3 = Class.forName("Object.reflect.Son");
System.out.println(c1 == c2);
System.out.println(c2 == c3);
// 得到构造方法
Constructor<?>[] constructors = c1.getConstructors();
System.out.println(Arrays.toString(constructors));
Constructor<?>[] declaredConstructors = c1.getDeclaredConstructors();
System.out.println(Arrays.toString(declaredConstructors));
// 得到方法
Method[] methods = c1.getMethods();
System.out.println(Arrays.toString(methods));
Method[] declaredMethods = c1.getDeclaredMethods();
System.out.println(declaredMethods);
// 得到属性
Field[] fields = c1.getFields();
System.out.println(fields);
Field[] declaredFields = c1.getDeclaredFields();
System.out.println(declaredFields);
// 使用反射使用对象私有的构造方法
Class<?> clSon = Class.forName("Object.reflect.Son");
Constructor<?> constructor = clSon.getDeclaredConstructor(String.class);
constructor.setAccessible(true);
Object hh = constructor.newInstance("hh");
Son son = (Son) hh;
System.out.println(son);
// 使用反射设置对象私有的属性
Class<Son> sonClass = Son.class;
Field field = sonClass.getDeclaredField("name");
field.setAccessible(true);
Son son1 = sonClass.newInstance();
field.set(son1, "dd");
System.out.println(field.get(son1));
// 使用反射使用对象私有方法
Class<Son> sonClass1 = Son.class;
Method method2 = sonClass1.getDeclaredMethod("method2", String.class);
method2.setAccessible(true);
Son son2 = sonClass1.newInstance();
method2.invoke(son2, "李四");
}
2.5 反射优点和缺点
优点:
1. 对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意一个方法
2. 增加程序的灵活性和扩展性,降低耦合性,提高自适应能力
3. 反射已经运用在了很多流行框架如:Struts、Hibernate、Spring 等等。
缺点:
1. 使用反射会有效率问题。会导致程序效率降低。
2. 反射技术绕过了源代码的技术,因而会带来维护问题。反射代码比相应的直接代码更复杂 。
💳3. 枚举
枚举的使用
3.1 背景及定义
枚举是在JDK1.5以后引入的。主要用途是:将一组常量组织起来,在这之前表示一组常量通常使用定义常量的方式。
优点:将常量组织起来统一进行管理
场景:错误状态码,消息类型,颜色的划分,状态机等等....
本质:是 java.lang.Enum 的子类,也就是说,自己写的枚举类,就算没有显示的继承 Enum ,但是其默认继承了 这个类。
3.2 使用
1. switch语句
public enum Enum1 {
Red, Blue, Pink;
public static void main(String[] args) {
Enum1 enum1 = Enum1.Red;
switch (enum1){
case Red:
System.out.println("Red"); break;
case Blue:
System.out.println("Blue"); break;
case Pink:
System.out.println("Pink"); break;
}
2. 常用方法
Enum 类的常用方法
编辑
public enum Enum2 {
Red, Blue, Pink;
public static void main(String[] args) {
Enum2[] values = Enum2.values();
// 得到枚举成员及其索引位置
for (Enum2 value : values) {
System.out.println("枚举成员:" + value +" 索引位置:"+value.ordinal());
// 将普通字符串转换为枚举实例
System.out.println(Enum2.valueOf("Red"));
// 得到成员实例
Enum2 red = Enum2.Red;
Enum2 blue = Enum2.Blue;
// compereTo比较两个枚举成员在定义时的顺序
System.out.println(red.compareTo(blue));
System.out.println(Red.compareTo(Blue));
System.out.println(Pink.compareTo(Blue));
}
Java当中枚举实际上就是一个类
public enum Enum3 {
Red("red",1), Blue("blue",2), Pink("pink", 3);
private String name;
private int key;
private Enum3 (String name,int key) {
this.name = name;
this.key = key;
public static Enum3 getEnumKey (int key) {
for (Enum3 t: Enum3.values()) {
if(t.key == key) {
return t;
return null;
public static void main(String[] args) {
System.out.println(Enum3.getEnumKey(1));
}
3.3 枚举优点缺点
优点:
1. 枚举常量更简单安全 。
2. 枚举具有内置方法 ,代码更优雅
缺点:
1. 不可继承,无法扩展
3.4 枚举是否可以通过反射,拿到实例对象呢?
我们刚刚在反射里边看到了,任何一个类,哪怕其构造方法是私有的,我们也可以通过反射拿到他的实例对象,那么枚举的构造方法也是私有的,我们是否可以拿到呢?
不能。
没有对应的构造方法,我们所有的枚举类,都是默认继承与 java.lang.Enum,继承了父类除构造函数外的所有东西,并且子类要帮助父类进行构造! 而我们写的类,并没有帮助父类构造!
枚举被过滤了,所以不能通过反射获取枚举类的实例
!这道题是2017年阿里巴巴曾经问到的一个问题。原版问题是:为什么枚举实现单例模式是安全的?
用枚举实现一个单例模式
public enum TestEnum {
INSTANCE;
public TestEnum getInstance(){
return INSTANCE;
public static void main(String[] args) {
TestEnum singleton1=TestEnum.INSTANCE;
TestEnum singleton2=TestEnum.INSTANCE;
System.out.println("两个实例是否相同:"+(singleton1==singleton2));
}
💳4. Lambda 表达式
4.1 背景
Lambda表达式是Java SE 8中一个重要的新特性。lambda表达式允许你通过表达式来代替功能接口。 lambda表达式就和方法一样,它提供了一个正常的参数列表和一个使用这些参数的主体(body,可以是一个表达式或一个代码 块)。
Lambda 表达式(Lambda expression)可以看作是一个匿名函数,基于数学中的λ演算得名,也可称为闭 包(Closure)。
1. Lambda表达式的语法
基本语法: (parameters) -> expression 或 (parameters) ->{ statements; }
Lambda表达式由三部分组成:
1. paramaters:类似方法中的形参列表,这里的参数是函数式接口里的参数。这里的参数类型可以明确的声明 也可不声明而由JVM隐含的推断。另外当只有一个推断类型时可以省略掉圆括号。
2. ->:可理解为“被用于”的意思
3. 方法体:可以是表达式也可以代码块,是函数式接口里方法的实现。代码块可返回一个值或者什么都不反 回,这里的代码块块等同于方法的方法体。如果是表达式,也可以返回一个值或者什么都不反回。
2. 函数式接口
要了解Lambda表达式,首先需要了解什么是函数式接口,函数式接口定义:一个接口有且只有一个抽象方法 。
注意:
1. 如果一个接口只有一个抽象方法,那么该接口就是一个函数式接口
2. 如果我们在某个接口上声明了
@FunctionalInterface 注解
,那么编译器就会按照函数式接口的定义来要求 该接口,这样如果有两个抽象方法,程序编译就会报错的。所以,从某种意义上来说,只要你保证你的接口 中只有一个抽象方法,你可以不加这个注解。加上就会自动进行检测的。
@FunctionalInterface
interface IMessage{
void printMessage(String msg);
default void printOther(){
System.out.println("接口中的普通方法");
}
4.2 Lambda表达式的基本使用
// 无返回值无参
interface NonReturnNonParameter{
void test();
// 无返回值有参
interface NonReturnHasParameter{
void test(String name, int age);
// 有返回值无参
interface HasReturnNonParameter{
String test();
// 有返回值有参
interface HasReturnHasParameter{
String test(String name, int age);
public class LambdaUsage {
public static void main(String[] args) {
NonReturnNonParameter i1 = () -> System.out.println("Lambda 无返回值无参");
i1.test();
NonReturnHasParameter i2 = (name, age) -> System.out.println("Lambda 无返回值有参");
i2.test("张三", 18);
HasReturnNonParameter i3 = () -> "Lambda 有返回值无参";
System.out.println(i3.test());
HasReturnHasParameter i4 = (name, age) -> "Lambda 有返回值有参";
System.out.println(i4.test("张三", 18));
}
4.3 Lambda在集合当中的使用
为了能够让Lambda和Java的集合类集更好的一起使用,集合当中,也新增了部分接口,以便与Lambda表达式对接。
编辑
4.4 优点和缺点
优点:
1. 代码简洁,开发迅速
2. 方便函数式编程
3. 非常容易进行并行计算
4. Java 引入 Lambda,改善了集合操作
缺点:
1. 代码可读性变差
2. 在非并行计算中,很多计算未必有传统的 for 性能要高
3. 不容易进行调试
分享到此,感谢大家观看!!!
如果你喜欢这篇文章,请
点赞
加
关注
吧,或者如果你对文章有什么困惑,可以私信我。
🏓🏓🏓