再探Java为面试赋能(二)Java基础知识(二)反射机制、Lambda表达式、多态

news2024/11/25 0:59:45

文章目录

    • 前言
    • 1.4 反射机制
      • 1.4.1 Class对象的获取
      • 1.4.2 Class类的方法
      • 1.4.3 通过反射机制修改只读类的属性
    • 1.5 Lambda表达式
      • 1.5.1 函数式接口
      • 1.5.2 Lambda表达式的使用
    • 1.6 多态
      • 1.6.1 多态的概念
      • 1.6.2 多态的实现条件
      • 1.6.3 重载(Overload)和重写(Override)

前言

往期精选:

再探Java为面试赋能(一)Java基础知识(一)变量初始化顺序、构造方法、clone方法

1.4 反射机制

Java语言的反射机制,是指动态获取类或对象的属性以及方法,从而完成调用功能的一种机制。它主要实现了以下功能:

  • 获取类的访问修饰符、属性、方法以及父类信息。
  • 在运行时根据类名创建对象,还可以调用对象的任意方法。
  • 生成动态代理。

1.4.1 Class对象的获取

在反射机制中,Class类是一个非常重要的类,获取Class对象主要有3种方法:

  • 1)通过className.class获取:
public class Food {

    static {
        System.out.println("Food类的静态代码块执行了...");
    }

    {
        System.out.println("Food类的非静态代码块执行了...");
    }

    public static void main(String[] args) {
        Class<Food> aClass = Food.class;
        System.out.println("className = " + aClass.getName());
    }
}

程序运行结果:

Food类的静态代码块执行了...
className = test03.Food
  • 2)通过Class.forName()获取:
public class Food {

    static {
        System.out.println("Food类的静态代码块执行了...");
    }

    {
        System.out.println("Food类的非静态代码块执行了...");
    }

    public static void main(String[] args) throws ClassNotFoundException {
        Class<?> food = Class.forName("test03.Food");
        System.out.println("className = " + food.getName());
    }
}

程序运行结果:

Food类的静态代码块执行了...
className = test03.Food
  • 3)通过Object.getClass()获取:
public class Food {

    static {
        System.out.println("Food类的静态代码块执行了...");
    }

    {
        System.out.println("Food类的非静态代码块执行了...");
    }

    public static void main(String[] args) {
        Class<? extends Food> aClass = new Food().getClass();
        System.out.println("className = " + aClass.getName());
    }
}

程序运行结果:

Food类的静态代码块执行了...
Food类的非静态代码块执行了...
className = test03.Food

如上面的例子所示,三种方式都可以获得类的Class对象,但也有一些区别:

  • 方法 1)2)执行静态代码块,但不执行非静态代码块;
  • 方法 3)由于创建了对象,因此会执行静态代码块和非静态代码块。

1.4.2 Class类的方法

Class类提供了非常多的方法,常用的有三类:

  • 1)获取类的构造方法

构造方法的封装类为Constructor。

源码:java.lang.Class

// 返回类的所有的public构造方法
public Constructor<?>[] getConstructors()
// 返回类的指定参数的public构造方法
public Constructor<T> getConstructor(Class<?>... parameterTypes)
// 返回类的所有构造方法
public Constructor<?>[] getDeclaredConstructors()
// 返回类的指定参数的构造方法
public Constructor<T> getDeclaredConstructor(Class<?>... parameterTypes)
  • 2)获取类的成员变量的方法

成员变量的封装类为Field。

源码:java.lang.Class

// 返回类的所有public成员变量
public Field[] getFields()
// 返回类的指定名称的public成员变量
public Field getField(String name)
// 返回类的所有成员变量
public Field[] getDeclaredFields()
// 返回类的指定名称的成员变量
public Field getDeclaredField(String name)
  • 3)获取类的方法

方法的封装类为Method。

源码:java.lang.Class

// 返回类的所有public方法
public Method[] getMethods()
// 返回类的指定名称和参数的public方法
public Method getMethod(String name, Class<?>... parameterTypes)
// 返回类的所有方法
public Method[] getDeclaredMethods()
// 返回类的指定名称和参数的方法
public Method getDeclaredMethod(String name, Class<?>... parameterTypes)

1.4.3 通过反射机制修改只读类的属性

有如下代码:

public class ReadOnlyClass {
    
    private Integer age = 20;

    public Integer getAge() {
        return age;
    }
}

在这个类中,age属性被修饰为private,且只提供了getter方法,而没有提供setter方法,因此这个类型是一个只读的类,无法通过常规方法修改age属性。

但通过Java的反射机制就可以修改age属性。例如:

public static void main(String[] args) throws NoSuchFieldException, IllegalAccessException {
    ReadOnlyClass roc = new ReadOnlyClass();
    System.out.println("修改前age = " + roc.getAge());

    Class<ReadOnlyClass> aClass = ReadOnlyClass.class;
    Field field = aClass.getDeclaredField("age");
    field.setAccessible(true);
    // 修改roc对象的age属性
    field.set(roc, 30);
    System.out.println("修改后age = " + roc.getAge());
}

执行结果:

修改前age = 20
修改后age = 30

1.5 Lambda表达式

简单来说,Lambda表达式就是对匿名内部类的简写。它的基本语法是:

<函数式接口> <变量名> = (参数1, 参数2, ...) -> {
    // 方法体
}

1.5.1 函数式接口

函数式接口就是一个有且仅有一个抽象方法的接口。

例如Runnable接口就是一个函数式接口:

源码:java.lang.Runnable

@FunctionalInterface
public interface Runnable {
    public abstract void run();
}

可见,Runnable接口中只包含一个抽象的run()方法,并且在接口上标注了一个@FuncationInterface注解,此注解就是 Java 8 新增的注解,用来标识一个函数式接口。

想要自定义一个函数式接口也非常简单,只需要在接口中定义一个抽象方法,然后在接口上标记@FunctionalInterface注解。

当然,该注解也可以不标记,只是说标记了该注解,编辑器会自动检测自定义的函数式接口是否有问题。例如:

1.5.2 Lambda表达式的使用

下面是一个自定义的函数式接口,定义了一个有参数有返回值的sum()方法:

@FunctionalInterface
public interface MyInterface {

    public abstract int sum(int a, int b);
}

使用Lambda表达式调用该方法:

public static void main(String[] args) {
    // 使用匿名内部类方式
    MyInterface myInterface = new MyInterface() {
        @Override
        public int sum(int a, int b) {
            return a+b;
        }
    };
    int sum = myInterface.sum(5, 10);
    System.out.println("匿名内部类方式 sum = " + sum);

    // 使用Lambda表达式
    MyInterface myi = (a, b) -> a+b;
    int sum1 = myi.sum(2, 8);
    System.out.println("Lambda表达式方式 sum1 = " + sum1);
}

执行结果:

匿名内部类方式 sum = 15
Lambda表达式方式 sum1 = 15

可见,使用Lambda表达式后,代码变得更加简介。

Lambda表达式还有更多编写规则如下:

  • 1)参数只需要参数名称,不需要参数类型,编译器会自动推断类型。如示例中:(a, b)
  • 2)如果参数只有一个,可以省略小括号(),没有参数或者参数多于一个,不能省略小括号。
  • 3)方法体只有一行代码时,可以省略中括号{}
  • 4)方法体只有一行代码时,且有返回值时,可以省略return关键字。如示例中:-> a+b

1.6 多态

1.6.1 多态的概念

多态是面向对象编程中的一个重要概念,它允许不同类型的对象对同一方法进行不同的实现。

具体来说,多态是指通过父类的引用变量来指向子类的对象,从而实现对不同对象的统一操作。

例如,猫和狗都是动物,都有“吃”这个共同行为,具体表现在狗身上可能是啃骨头,表现在猫身上可能是吃猫粮。这就是多态的表现,即同一件事情,发生在不同的对象身上,就会产生不同的结果。

1.6.2 多态的实现条件

在Java中,要实现多态性,就必须满足以下条件:

  • 1)继承关系
  • 2)方法重写
  • 3)父类引用指向子类对象

例如,首先定义一个父类Animal,该类有一个eat()方法:

public class Animal {

    public void eat() {
        System.out.println("动物吃东西...");
    }
}

再定义两个子类Dog和Cat,均继承父类Animal,并重写其eat()方法:

public class Dog extends Animal {

    // 1.继承关系
    // 2.方法重写
    @Override
    public void eat() {
        System.out.println("狗啃骨头...");
    }
}
public class Cat extends Animal {

    // 1.继承关系
    // 2.方法重写
    @Override
    public void eat() {
        System.out.println("猫吃猫粮...");
    }
}

最后编写测试方法:

public class Main {

    public static void main(String[] args) {
        // 3.父类引用指向子类对象
        Animal dog = new Dog();
        Animal cat = new Cat();

        dog.eat();
        cat.eat();
    }
}

执行结果:

狗啃骨头...
猫吃猫粮...

1.6.3 重载(Overload)和重写(Override)

Java中多态的实现条件之一是方法重写,是指子类重新定义和实现从父类继承而来的方法,以改变方法的行为,提供自己特定的实现。

方法重写必须遵循一些规则:

  • 1)子类重写方法的名称、参数列表(包括数量、类型、顺序)和返回值类型都必须与父类中被重写的方法相同。
  • 2)重写方法的访问修饰符的权限不能低于父类方法的权限。例如,父类方法被public修饰,则子类中重写方法就不能声明为protected
  • 3)重写方法不能抛出比父类方法更多或更宽泛的异常,重写方法可以抛出相同的异常或更具体的异常,或者不抛出异常。
  • 4)重写方法可以通过super()函数调用父类方法的逻辑。

重载是指在一个类中定义了多个同名的方法。 它也必须遵循一些规则:

  • 1)重载的方法必须定义在一个类中,它们的名称必须相同。
  • 2)重载的方法的参数列表必须不同,可以通过参数的个数、类型、顺序的不同来进行区分。
  • 3)重载的方法的返回值类型可以相同也可以不同。

总结一下,重载和重写的区别:

  • 1)定义位置。重载方法定义在同一个类中,而重写方法定义在父类和子类之间。
  • 2)方法签名。重载方法具有相同的名称,但方法签名(参数类型、个数或顺序)不同,而重写方法具有相同的名称和方法签名。
  • 3)调用时机。重载方法是根据方法签名的不同进行静态绑定,在编译时就确定,而重写方法是根据对象的实际类型进行动态绑定,要在运行时确定。

本节完,更多内容请查阅分类专栏:再探Java为面试赋能

感兴趣的读者还可以查阅我的另外几个专栏:

  • SpringBoot源码解读与原理分析(已完结)
  • MyBatis3源码深度解析(已完结)
  • Redis从入门到精通(持续更新中…)

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1579093.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Java入门-数组

数组 什么是数组 数组( array )是一种最简单的复合数据类型&#xff0c;它是有序数据的集合&#xff0c;数组中的每个元素具有相同的数据类型&#xff0c;可以用一个统一的数组名和不同的下标来确定数组中唯一的元素。 数组的内存结构是分配一系列内存大小相等的连续空间。 …

ESP32cam 摄像头 AIcam 全球远程视频监控的实现方法

AIcam远程视频监控 ​ 在学习应用各种物联网创客场景时我们时常会用到远程视频监控&#xff0c;当然我们可以通过发送图片的方式的来远程查看&#xff0c;但如果能视频查看将会更加的生动&#xff0c;比如在公司查看家里宠物的动态&#xff0c;鱼儿的活动情况。。。。。。 这个…

illustrator编组后透明图形也能挡住后面的不透明图形的问题

今日学习使用illustrator&#xff0c;使用3D中的突出和斜角生成了一个圆柱体之后&#xff0c;扩展图形&#xff0c;修改之后发现一个奇怪的问题&#xff0c;编组中的透明物体挡住了后面的图形&#xff08;后面的图形是有颜色的&#xff09; 后面发现&#xff0c;原来是扩展生成…

在 Amazon Bedrock 上使用 Mistral Large 处理复杂的推理任务

上个月&#xff0c;我们宣布两款高性能的 Mistral AI 模型&#xff08;即 Mistral 7B 和 Mixtral 8x7B&#xff09;已在 Amazon Bedrock 上线。作为 Mistral 的首个基础模型&#xff0c;Mistral 7B 支持英语文本生成任务&#xff0c;并具备自然编码能力&#xff1b;Mixtral 8x7…

oj赛(双周赛第二十四次)

目录 1. 八大藤校2025fall标化要求已全部出炉 2. 上海“2024人才储备”计划启动&#xff01; 伐木工小码哥 杰瑞吃奶酪 小码哥处理订单 黑手党 第k小的距离 养竹鼠 甜品配置 礼物 合数分解 均分糖果 持盾 咖啡品鉴师小码哥 1. 八大藤校2025fall标化要求已全部…

安全威胁情报的漏洞挖掘

前段时间edu上出现了两个网安总队收取安全情报&#xff0c;不收漏洞&#xff0c;下面简单分析一下如何挖掘安全情报。 在发现在edu中新增了两个网安总队收安全情报等漏洞&#xff0c;那威胁情报又会包含哪些内容呢&#xff1f;以前或许会看到各种ss网站、bc网站、yx网站满天飞&…

小程序开发SSL证书下载和安装

在开发小程序时&#xff0c;确保数据的安全传输至关重要&#xff0c;而实现这一目标的关键在于正确获取与安装SSL证书。以下详细介绍了从获取到安装SSL证书的完整流程&#xff0c;以助您为小程序构建可靠的加密通信环境。 一、小程序SSL证书类型选择&#xff1a; 域名验证型D…

简单的跳马问题,遍历dp[j][i]到某个值那个数据不对了,如何解决??

&#x1f3c6;本文收录于「Bug调优」专栏&#xff0c;主要记录项目实战过程中的Bug之前因后果及提供真实有效的解决方案&#xff0c;希望能够助你一臂之力&#xff0c;帮你早日登顶实现财富自由&#x1f680;&#xff1b;同时&#xff0c;欢迎大家关注&&收藏&&…

K8s技术全景:架构、应用与优化

一、介绍 Kubernetes的历史和演进 Kubernetes&#xff08;简称K8s&#xff09;是一个开源的容器编排系统&#xff0c;用于自动化应用程序的部署、扩展和管理。它最初是由Google内部的Borg系统启发并设计的&#xff0c;于2014年作为开源项目首次亮相。 初始阶段 Kubernetes的诞生…

测开面经分享:计算机网络part2

什么是 HTTP 和 HTTPS&#xff1f;它们之间有什么区别&#xff1f; a. HTTP&#xff08;超文本传输协议&#xff09;和HTTPS&#xff08;安全超文本传输协议&#xff09;是用于在Web上传输数据的协议。它们之间的区别在于安全性和数据传输方式。 b. HTTP是一种不安全的协议&…

聚道云连接器打通红圈CRM和金蝶云星辰,赋能环境科技公司数字化转型

一、客户介绍 某环境科技有限公司是一家专注于环保科技领域的领先企业&#xff0c;致力于为客户提供全方位的环境解决方案。公司拥有一支经验丰富、技术精湛的团队&#xff0c;不断推动环保技术的创新与应用。作为业内的佼佼者&#xff0c;该公司在环境治理、资源回收和节能减…

利用Java代码调用Lua脚本改造分布式锁

4.8 利用Java代码调用Lua脚本改造分布式锁 lua脚本本身并不需要大家花费太多时间去研究&#xff0c;只需要知道如何调用&#xff0c;大致是什么意思即可&#xff0c;所以在笔记中并不会详细的去解释这些lua表达式的含义。 我们的RedisTemplate中&#xff0c;可以利用execute方…

【D3.js Tidy tree绘制树形图,单棵树,左右树,平移,拖拽,树形中的天花板实现,源码实现】

这里写自定义目录标题 D3.js Tidy tree绘制树形图,单棵树,左右树,平移,拖拽,树形中的天花板实现,源码实现D3 简介D3 官网有很多例子,这里说的是Tidy tree[树形图表svg][左侧关系->中间对象<-右侧关系 ] 树形实现 D3.js Tidy tree绘制树形图,单棵树,左右树,平移,拖拽,树形…

C语言易错知识点(3):字符数组的修改、sscanf、sprintf

字符数组是一个很细节的语法&#xff0c;涉及很多知识点&#xff0c;这篇文章我主要分享一下如何理解字符数组&#xff0c;以及对应的sscanf、sprintf有什么用 1.字符数组的初始化以及内容修改易错点 字符数组的初始化方式有两种&#xff0c;一种是直接用字符串进行初始化&am…

【SCI绘图】【热力图系列1 R】多特征相关性分析热力图R语言实现

SCI&#xff0c;CCF&#xff0c;EI及核心期刊绘图宝典&#xff0c;爆款持续更新&#xff0c;助力科研&#xff01; 本期分享&#xff1a; 【SCI绘图】【热力图系列1 R】多特征相关性分析热力图R语言实现 1.环境准备 library(gplots) library(RColorBrewer) 2.数据示例 ###…

Qt快速入门到熟练(3.程序运行发布与设置图标)

程序运行发布 当我们执行过qt过后&#xff0c;将会在项目目录里面生成出一个debug构建目录&#xff0c;点击进去选择debug文件夹&#xff0c;就可以看到我们生成出来的可执行文件。 很显然我们的项目就叫做MyFirstWidget&#xff0c;所以生成的可执行文件在没有人为设置的情…

深入理解JVM垃圾收集器

相关系列 深入理解JVM垃圾收集算法-CSDN博客 目前市面常见的垃圾收集器有Serial、ParNew、Parallel、CMS、Serial Old、Parallel Old、G1、ZGC以及有二种不常见的Epsilon、Shenandoah的&#xff0c;从上图可以看到有连线的的垃圾收集器是可以组合使用&#xff0c;是年轻代老年代…

LeetCode初级算法书Java题解日常更新

LeetCode初级算法高效题解&#xff08;含思路注释&#xff09; 文章目录 LeetCode初级算法高效题解&#xff08;含思路注释&#xff09;前言一、数组1.删除排序数组中的重复项2.买卖股票的最佳时机 II3.旋转数组4.存在重复元素 总结 前言 决定用四个月过一下算法 一、数组 1.…

全国月均太阳辐射空间分布数据/月度降雨量分布/月均气温分布

引言 我国幅员辽阔&#xff0c;地形复杂&#xff0c;位于亚欧大陆东部&#xff0c;太平洋西岸。气候特征为&#xff1a;季风气候明显&#xff0c;大陆性气候强&#xff0c;气候类型复杂多样&#xff0c;水热同期。我国太阳辐射西部多于东部&#xff0c;北部多于南部&#xff0c…

【算法基础】插入排序与二分查找、升级二分查找

文章目录 1. 插入排序1.1 插入排序的思想1.2 插入排序的实现 2. 普通二分查找2.1 普通二分查找的思想2.2 普通二分查找的实现 3. 升级二分查找3.1 升级二分查找思想3.2 升级二分查找实现 1. 插入排序 1.1 插入排序的思想 插入排序很类似于已有一副有序的扑克牌&#xff0c;不断…