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

文章目录

    • 前言
    • 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从入门到精通(持续更新中…)

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

odoo16 安装

1、安装 /bin/zsh -c "$(curl -fsSL https://gitee.com/cunkai/HomebrewCN/raw/master/Homebrew.sh)" 2、安装git brew install git 3、安装python3 brew install python3 brew install python3.10 -- odoo16 如果用python3.12 - 会报错 brew unlink python3.1…

Python数学建模学习-莱斯利(Leslie)种群模型

Leslie模型是一种用于离散时间的生物种群增长模型&#xff0c;经常用于描述年龄结构对种群增长的影响。在1945年&#xff0c;人口生态学家Patrick H. Leslie&#xff08;莱斯利&#xff09;为了研究具有离散年龄结构的种群&#xff0c;特别是对于有不同年龄阶段的生物&#xff…

nginx This request has been blocked; the content must be served over HTTPS问题处理

This request has been blocked; the content must be served over HTTPS问题处理 1.问题现象2.解决问题3.解决后的现象4.proxy_set_header x-forwarded-proto 作用 1.问题现象 Mixed Content: The page at https://www.ssjxx.cn/ssjy/viy-edu/index.html?systemCodeTW0010#/…

电脑与多台罗克韦尔AB PLC无线通讯的搭建方法分为几步?

在实际系统中&#xff0c;同一个车间里分布多台PLC&#xff0c;通过上位机集中控制。通常所有设备距离在几十米到上百米不等。在有通讯需求的时候&#xff0c;如果布线的话&#xff0c;工程量较大耽误工期&#xff0c;这种情况下比较适合采用无线通信方式。本方案以组态王和2台…

OpenCV单通道图像按像素成倍比例放大(无高斯平滑处理)

OpenCV中的resize函数可以对图像做任意比例的放大(/缩小)处理&#xff0c;该处理过程会对图像做高斯模糊化以保证图像在进行放大&#xff08;/缩小&#xff09;后尽可能保留源图像所展现的具体内容&#xff08;消除固定频率插值/采样带来的香农采样信息损失&#xff09;&#x…

QML学习记录:并排页面切换效果的实现

定义一个ApplicationWindow窗口&#xff0c;通过添加SwipeView和PageIndicator来实现页面切换效果和显示当前页面位置的指示器。 ApplicationWindow {id:rootvisible: truewidth: 340height: 480title: qsTr("SwipeView") // 定义一个SwipeView用于页面切换效果 Swip…

支持向量机(SVM)白话之个人理解(学习记录)

本文仅有文字理解部分&#xff0c;没有相应的数学公式推导过程&#xff0c;便于新手理解。 一、什么是支持向量机 首先我们看下面这张图&#xff0c;在图中圆形和三角形分别代表不同的数据类型&#xff0c;如何画出一条直线使两者能够显著地区分开来呢&#xff1f; 答案可以多…

SSL数字证书基本概念

CA机构 CA机构&#xff0c;即证书授权中心&#xff08;Certificate Authority&#xff09;或称证书授权机构。CA认证中心作为电子商务交易中受信任的第三方&#xff0c;承担公钥体系中公钥合法性检验的责任。 SSL证书和SSL协议 安全套接层SSL&#xff08;Secure Sockets Lay…

基于GD32的简易数字示波器(3)- PCB设计

这期记录的是项目实战&#xff0c;做一个简易的数字示波器。 教程来源于嘉立创&#xff0c; 本期介绍PCB设计的大致流程。 下图为示波器的指标 具有选择交流耦合还是直流耦合功能、输入信号不衰减或衰减50倍 输入频率理论最大800KHz输入幅值&#xff08;不衰减&#xff09;…

03-JAVA设计模式-原型模式

原型模式 什么是原型模式 Java原型模式&#xff08;Prototype Pattern&#xff09;是一种创建型设计模式&#xff0c;其核心理念在于通过复制&#xff08;克隆&#xff09;已有的对象来创建新的对象&#xff0c;而不是通过构造函数来创建。 该模式可以显著提高对象创建的效率…

Web3的智能合约:未来合约的新范式

随着区块链技术的不断成熟和发展&#xff0c;智能合约作为其核心应用之一&#xff0c;正逐渐成为数字经济中的重要组成部分&#xff0c;引领着未来合约的新趋势。Web3的智能合约代表了一种全新的合约形式&#xff0c;其特点和应用将在未来产生深远影响。 智能合约的基本原理 智…

React - 你知道props和state之间深层次的区别吗

难度级别:初级及以上 提问概率:60% 如果把React组件看做一个函数的话,props更像是外部传入的参数,而state更像是函数内部定义的变量。那么他们还有哪些更深层次的区别呢,我们来看一下。 首先说props,他是组件外部传入的参数,我们知道…

皮具5G智能制造工厂数字孪生可视化平台,推进企业数字化转型

皮具5G智能制造工厂数字孪生可视化平台&#xff0c;推进企业数字化转型。随着信息技术的快速发展&#xff0c;数字化转型已成为企业提升竞争力、实现可持续发展的关键路径。皮具行业&#xff0c;作为一个传统的手工制造业&#xff0c;正面临着巨大的市场变革和技术挑战。如何在…

07 spring-cloud-gateway 的路由相关

前言 我们这里 大致梳理一下 spring-cloud-gateway 路由的相关处理 spring-cloud 微服务组件中的网关 这里主要分为几个 步骤 路由规则怎么获取如何路由网关过滤器的处理如何转发请求道下游微服务组件 路由规则怎么获取? GatewayAutoConfiguration 中包含了 spring-clou…

华为手机 鸿蒙系统 或者安卓系统的百度网盘下载的文件保存在手机什么位置如何查看

华为手机 鸿蒙系统 或者安卓系统的百度网盘下载的文件保存在手机什么位置如何查看 连接电脑后一般在这里位置 计算机\Mate 20 Pro (UD)\内部存储\Download\BaiduNetdisk 也就是用usb&#xff08;数据线&#xff0c;不是充电线&#xff0c;要四心的 )连接手机后&#xff0c;打…

JVM字节码与类加载——字节码指令集与解析

文章目录 1、概述1.1、字节码与数据类型1.2、指令分类 2、加载与存储指令2.1、局部变量入栈指令2.2、常量入栈指令2.3、出栈装入局部变量表指令 3、算术指令3.1、彻底理解i与i3.2、比较指令 4、类型转换指令4.1、宽化类型转换4.2、窄化类型转换 5、对象、数组的创建与访问指令5…

Leetcode 437. 路径总和 III

心路历程&#xff1a; 这道题递推并不难&#xff0c;但是有细节需要注意&#xff0c;主要就是区间可以不是根节点&#xff0c;以及结束不一定是叶子结点这两个限制。 其余的动态规划即可。 注意的点&#xff1a; 1、由于终点不一定是叶子结点&#xff0c;所以当递归的target…

css字体加粗实例

确定字体粗细的是font-weight属性&#xff1b; 它的number值可取100-900&#xff1b; 如果把属性设为normal&#xff0c;相当于number为400&#xff1b; 设为bold&#xff0c;相当于number为700&#xff1b; html<b>或<strong>跟bold效果一样&#xff1b; <!…

基于velero和minio实现k8s数据的备份

1.30部署minio rootk8s-harbor:/etc/kubeasz/clusters/k8s-cluster1# docker run \ -d --restartalways -p 9000:9000 -p 9090:9090 –name minio -v /data/minio/data:/data -e “MINIO_ROOT_USERadmin” -e “MINIO_ROOT_PASSWORD12345678” quay.io/minio/minio server…

java实现UDP数据交互

1、回显服务器 服务器端 import java.io.IOException; import java.net.DatagramPacket; import java.net.DatagramSocket; import java.net.SocketException;public class UDP_Server {private DatagramSocket socketnull;public UDP_Server(int port) throws SocketExcepti…