面试总结之Java基础

news2024/12/28 18:44:54

1、反射

1.1、概述

  • 反射:加载类(通过反射将类的字节码文件加载到内存中),并允许以编程的方式解剖类中的各种成分(成员变量、方法、构造器等)
  • 反射需要掌握的内容:
    1)记载类,获取类的字节码:Class对象
    2)获取类的构造器:Constructor对象
    3)获取类的成员变量:Field对象
    4)获取类的成员方法:Method对象

1.2、获取类的字节码

在这里插入图片描述

  • 获取Class对象可以通过如下三种方式:
    1)Class c1 = 类名.class
    2)调用Class类提供的forName方法:public static Class<?> forName(String className)
    3)Object提供的getClass方法: public final native Class<?> getClass();
  • 示例代码:
        Class<Person> p1 = Person.class;
        System.out.println(p1.getName());       // 类的全路径
        System.out.println(p1.getSimpleName()); // 类简称: Person

        Class<?> p2 = Class.forName("com.example.interviewStudy.reflect.Person");  // forName方法中的参数需要是类的全路径
        System.out.println(p1 == p2);   // true, p1和p2指向同一个对象

        Person person = new Person();
        Class p3 = person.getClass();
        System.out.println(p1 == p3);  // true

1.3、获取类的构造器

在这里插入图片描述

  • 获取类构造器的作用:
    在这里插入图片描述
  • 示例代码:
        Class p1 = Person.class;
        Constructor<?>[] con1 = p1.getConstructors();
        for (Constructor<?> c : con1) {
            System.out.println(c.getName() +"<--->获取构造器参数总个数:" +c.getParameterCount());
        }

        System.out.println("获取所有构造器(包括私有的) ==>");
        Constructor<?>[] con2 = p1.getDeclaredConstructors();
        for (Constructor<?> c : con2) {
            System.out.println(c.getName() +"<--->参数总个数:" +c.getParameterCount());
        }

        System.out.println("根据传入参数的类型 调用指定的构造器来创建对象 ==》");
        Constructor  publicPerson = p1.getConstructor(Long.class, String.class);
        Person person1 = (Person) publicPerson.newInstance(10189L, "张三");
        System.out.println(person1);

        System.out.println("根据传入参数的类型 获取指定的 私有构造器 ==》");
        Constructor<Person> privatePerson = p1.getDeclaredConstructor(String.class);
        privatePerson.setAccessible(true);   // 暴力反射,禁止检查访问权限,如果不禁止权限,则会报IllegalAccessException
        
        // 调用无参构造器(将Person类中无参构造改为private修饰)
        Person person2 = privatePerson.newInstance();
        System.out.println(person2);
        // 调用传入pname属性的构造器
        Person person3 = privatePerson.newInstance("张小敬");
        System.out.println(person3);

注意:如果不调用构造器对象的setAccessible,不禁止检查访问权限,就会报如下的
在这里插入图片描述

1.4、获取类的成员变量

在这里插入图片描述
为测试获取Person类的私有属性,需要将Person的pname属性改为private修饰

  • 示例代码:
        Class p1 = Person.class;
        //  p1.getConstructors(): 只能获取public修饰的属性
        //  p1.getDeclaredFields(): 能获取所有的属性
        Field[] fields = p1.getDeclaredFields();
        // 遍历Person类中的成员变量
        for (Field f : fields) {
            System.out.println(f.getName() + "<--->" + f.getType());
        }
        
        // p1.getField(): 只能指定获取public修饰的成员变量
        Field pname = p1.getDeclaredField("pname");
        Person person = new Person();
        // 给private修饰的成员变量赋值,需要禁止检查访问权限
        pname.setAccessible(true);
        pname.set(person,"朱重八");
        System.out.println("person = " + person);

        // 获取成员变量
        // 从person 对象中获取pname
        String name = (String) pname.get(person);
        System.out.println(name);

1.5、获取类的成员方法

在这里插入图片描述

  • 示例代码:
        Class p1 = Person.class;
        Method[] methods = p1.getDeclaredMethods();
        for (Method method : methods) {
            System.out.println(method.getName() + "<-->" + method.getParameterCount() + "<-->访问修饰符:" + method.getModifiers());
        }

        Person person = new Person();
        Method method1 = p1.getDeclaredMethod("printInfo", Long.class, String.class, Integer.class);
        // 暴力反射
        method1.setAccessible(true);

        // 执行包含参数且有返回值的的成员方法,res1就是原本调用方法的返回值
        Object res1 = method1.invoke(person, Long.valueOf(100897), "盛明兰", 26);
        System.out.println(res1);

        // 执行包含无参且没有返回值的成员方法,其原本方法的返回值就是null
        Method method2 = p1.getDeclaredMethod("message");
        method2.setAccessible(true);
        Object res2 = method2.invoke(person);
        System.out.println(res2);

1.6、反射的作用和应用场景

1)反射的作用

  • 可以得到类全部的属性、构造器、成员变量、成员方法后进行其他操作
  • 破坏封装性
  • 适合实现Java框架,基本上主流的框架都会基于反射设计出一些通用的功能

2)反射的应用场景

  • 需求:

实现一个简易版的持久化框架,对于任意一个对象,该框架都可以将对象的字段名和对应值,保存到txt格式的文本中

  • 实现步骤:
    1)定义一个方法,可以接收任意对象
    2)每接收到一个对象,都通过反射获取到该对象的Class对象,根据Class对象来获取全部的成员变量
    3)遍历所有的成员变量并获取到该变量在对象中的具体值
    4)将变量和对应的值通过IO流的方式输出到文本中
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.PrintStream;
import java.lang.reflect.Field;

public class ObjectFrame {
    public static void saveEntity(Object entity) throws IllegalAccessException, FileNotFoundException {
        // append追加文本的形式将数据输出data.txt文本中
        PrintStream printStream = new PrintStream(new FileOutputStream("D:\\data1.txt",true));
        Class clazz = entity.getClass();

        String simpleName = clazz.getSimpleName();
        printStream.println("=========" + simpleName + "==========");
        // 获取entity对象所有的成员变量
        Field[] fields = clazz.getDeclaredFields();
        for (Field field : fields) {
            field.setAccessible(true);
            String dataKey = field.getName();
            String dataValue = field.get(entity) + "";
            printStream.println(dataKey + " = " + dataValue);
        }
        printStream.close();
    }
}
  • 测试:
    public static void main(String[] args) throws FileNotFoundException, IllegalAccessException {
        Person p1 = new Person(1009876L,"张小敬",28);
        Person p2 = new Person(2091823L,"雷东宝",32);
        Person p3 = new Person(2091823L,"宋运辉",26);

        ObjectFrame.saveEntity(p1);
        ObjectFrame.saveEntity(p2);
        ObjectFrame.saveEntity(p3);


        Teacher t1 = new Teacher(101L,"李知恩","语文");
        Teacher t2 = new Teacher(104L,"高启强","数学");

        ObjectFrame.saveEntity(t1);
        ObjectFrame.saveEntity(t2);
    }

此外,反射在实际项目中还可以实现日志输出管理、公共字段/属性的自动填充(createUser、createTime、updateUser、updateTime)、事务、权限控制等,这需要结合AOP来实现

1.7、反射的优缺点

  • 反射的优点:
    • 在运行时可以获取任意类的属性、构造方法、成员方法,以及动态调用这些方法和修改属性
    • 提高代码的复用率,如:在动态代理的场景中,使用动态生成的代理类来提升代码的复用性; 在Spring框架中,用反射来实例化Bean对象,用反射实现对象的属性拷贝的BeanUtils.copyProperties()方法;使用反射来自定义注解;
      注意:使用BeanUtils.copyProperties()来完成对象属性的拷贝需要注意泛型擦除的问题
  • 反射的缺点:
    • 反射会涉及动态类型的解析,JVM无法对这些代码进行优化,导致性能比非反射调用低
    • 反射可以绕过一些限制访问的属性和方法(如使用setAccessible方法来禁止检查访问权限),会破坏代码的封装性

2、注解

2.1、概述

在这里插入图片描述

2.2、自定义注解

在这里插入图片描述

2.3、注解的解析

在这里插入图片描述

2.4、应用场景

注解被用错位置在编译期间就会报错

  • 元注解:指修饰注解的注解
    在这里插入图片描述
    在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

3、单例模式

3.1、什么是单例模式

  • 单例模式属于创建型模式,提供了一种创建对象的最佳方式,是指仅在内存中只创建一次对象的设计模式,在程序中多次使用同一个对象且作用相同时,为了防止频繁地创建对象使得内存飙升,单例模式可以让程序仅仅在内存中创建一个对象,让所有需要调用的地方都共享这一单例对象
  • 单例模式的优点:提升使用对象的效率,又可以让类自行把控实例的实现细节,对外部业务代码不产生任何影响
  • 单例模式的应用场景:HttpClient、Spring中的对象、打印日志的logger、数据库连接池对象

3.2、单例模式原则

  • 构造器私有(防止类被通过常规方法实例化)
  • 以静态方法或枚举返回实例(保证实例的唯一性)
  • 确保实例只有一个,尤其是在多线程环境下(保证在创建实例时的线程安全)
  • 确保反序列化时不会重新构建对象(在有序列化、反序列化的场景下防止单例被莫名破坏,造成未考虑到的后果)

在这里插入图片描述

3.3、Java实现单例模式有哪些方式

  • 概括起来,实现单例需要关注如下几点:
    • 构造函数需要是private访问权限,以此避免外部通过new创建实例
    • 考虑是否支持延迟加载
    • 考虑对象创建时的线程安全问题
    • 考虑获取实例的getInstance()方法性能是否够高(是否加锁)
1)懒汉式单例
  • 懒汉式单例:需要实例对象时,调用getInstance方法才去创建对象(适用于对象比较大的情况,不希望类被加载时就实例化从而拖慢程序的启动时长)
/***
 * 懒汉模式
 */
public class LazySingleton {

    private static LazySingleton instance;

    private LazySingleton(){ }

    // 如果不加锁,则不能保证线程安全
    // 锁的粒度较粗,同JDK1.0中的HashTable的设计,故HashTable不建议使用
    public static synchronized LazySingleton getInstance(){
        if (instance == null){
            instance = new LazySingleton();
        }
        return instance;
    }
}
2)饿汉式单例
  • 饿汉式单例:可保证线程安全,不管需不需要单例对象instance ,都在类加载时进行初始化,会浪费内存资源,基于ClassLoader机制避免了多线程的同步问题
public class HungrySingleton {
    
    private static HungrySingleton instance = new HungrySingleton();
    
    private HungrySingleton(){ }
    
    public static HungrySingleton getInstance(){
        return instance;
    }
}
3)双重锁式单例
// DCL: Double Check Lock,双重锁校验
public class DCLSingleton {

     // 基于volatile来保证可见性、有序性,禁止指令重排
    private static volatile DCLSingleton instance;

    private DCLSingleton() {
    }

    public static DCLSingleton getInstance() {
        if (instance == null) {  // 第一次检查
            // 加锁保证线程安全
            synchronized (DCLSingleton.class) {
                if (instance == null) {  // 再次检查防止同时进入synchronized 
                    instance = new DCLSingleton();
                }
            }
        }
        return instance;
    }
}
  • 为什么双重锁式单例中instance要有volatile修饰?
    在JVM执行过程中,instance实例的创建主要分为三步:
    1)在堆中为对象分配内存空间
    2)初始化对象(为属性赋值)
    3)将实例对象指向堆内存中的内存空间
    但由于JVM指令重排的优化,可能会出现
    同时,volatile是轻量级的同步机制,可及时刷新内存,但volatile不能保证原子性,故需要配合synchronized来保证其可靠性
4)静态内部类式单例
  • 基于延迟加载的方式,静态内部类实现单例模式:
/**
 *  静态内部类实现单例,线程安全
 * StaticInnerSingleton类被装载了,instance不一定被实例化,因为SingletonHolder类没有被主动使用
 * 当执行getInstance时,才会显示地装载SingletonHolder类,实例化instance
 */
public class StaticInnerSingleton {

    private StaticInnerSingleton() {
    }

    private static class SingletonHolder {
        private static final StaticInnerSingleton instance = new StaticInnerSingleton();
    }

    public static final StaticInnerSingleton getInstance() {
        return SingletonHolder.instance;
    }
}
5)枚举式单例
public enum EnumSingleton {

    INSTANCE;

    // 执行业务代码
    public void doSomeThing(){
        System.out.println("执行业务逻辑....");
    }
}
6)CAS式单例
import java.util.concurrent.atomic.AtomicReference;

public class Singleton {

    priavte static final AtomicReference<Singleton> casInstance = new AtomicReference<>();

    public static final Singleton getInstance() {
        for (; ; ) {
            Singleton singleton = casInstance.get();
            if (singleton != null) return singleton;
            // 如果casInstance为null,则创建单例对象并返回
            casInstance.compareAndSet(null,new Singleton());
            return casInstance.get();
        }
    }
}

3.4、关于设计模式

  • 按照设计模式的应用目的进行分类,设计模式可以分为创建型模式、结构型模式、行为型模式
  • 创建型模式:是对象在创建过程中各种问题和解决方案的总结,包括工厂模式、单例模式、原型模式、构建者模式
  • 结构型模式:是针对软件设计结构的总结,关注于类、对象、组合方式的实践经验,常见的结构型模式有桥接模式、适配器模式、门面模式、装饰者模式、代理模式、享元模式等
  • 行为型模式:是类或对象之间交互、职责划分等角度总结的设计模式,常见的行为型模式有策略模式、观察者模式、迭代器模式、适配器模式、模板方法模式、访问者模式等

在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

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

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

相关文章

实习项目遇到的bug

问题1&#xff1a; 大概是因为没设置ts类型&#xff0c;它查不到的问题&#xff0c;不定义的话加上问号&#xff0c;加上可选链就不会报错了 {{bizEquipmentInfo.lastUnlockingVO?.lastUnlockingTime.replace(T, )? bizEquipmentInfo.lastUnlockingVO?.lastUnlockingTime.r…

通讯网关软件024——利用CommGate X2Access实现Modbus TCP数据转储Access

本文介绍利用CommGate X2ACCESS实现从Modbus TCP设备读取数据并转储至ACCESS数据库。CommGate X2ACCESS是宁波科安网信开发的网关软件&#xff0c;软件可以登录到网信智汇(http://wangxinzhihui.com)下载。 【案例】如下图所示&#xff0c;实现从Modbus TCP设备读取数据并转储…

【EventLoop】问题一次搞定

&#x1f4cd; JS的事件循环机制恐怕是大多数前端开发者头顶上的一座大山之一&#xff0c;最近通过拜读两篇文档&#xff0c;对eventloop进行了深刻的理解&#xff1b;通过这篇文档对要点进行总结&#xff1b; article1&#xff1a; 波神的这篇eventLoop文章适合反复重温&…

Ubuntu22安装Docker engine(apt安装方式)

一、准备工作 新创建一个虚拟机。 进入虚拟机&#xff1a; 二、安装docker docker现在对用不同主机提供了不同安装包&#xff1a;docker engine 和 docker desktop。 docker desktop适用于图形化的桌面电脑&#xff0c;docker engine适用于服务器。我们这里当然是安装docker…

Mac 远程 Ubuntu

1. Iterm2 添加ssh 参考&#xff1a;https://www.javatang.com/archives/2021/11/29/13063392.html 2. Finder 添加远程文件管理 2.1 ubuntu 配置 安装samba sudo apt-get install samba配置 [share]path /home/USER_NAME/shared_directoryavailable yesbrowseable ye…

快速计算发票金额

快速计算发票总额 背景 在日常的工作中&#xff0c;我们不免需要面临费用报销问题&#xff0c;在进行费用报销时&#xff0c;我们需要提供费用相关的发票&#xff0c;并需要在报销单上填写相关的金额数据。这时我们将面临核对和计算发票金额的需求。 核对发票 如今&#xf…

基于和声优化的BP神经网络(分类应用) - 附代码

基于和声优化的BP神经网络&#xff08;分类应用&#xff09; - 附代码 文章目录 基于和声优化的BP神经网络&#xff08;分类应用&#xff09; - 附代码1.鸢尾花iris数据介绍2.数据集整理3.和声优化BP神经网络3.1 BP神经网络参数设置3.2 和声算法应用 4.测试结果&#xff1a;5.M…

STM32成熟变频逆变器方案

该方案是一款成熟的变频逆变器的方案&#xff0c;主要是把电源从直流到3相交流的转换&#xff0c;包含变频控制板&#xff0c;逆变主板&#xff0c;IO板&#xff0c;变频控制板主控是STM32F103VET6&#xff0c;配套软件。每一块板子都是原理图和PCB一一对应&#xff0c;并且配套…

函数调用:为什么会发生stack overflow?

在开发软件的过程中我们经常会遇到错误&#xff0c;如果你用 Google 搜过出错信息&#xff0c;那你多少应该都访问过Stack Overflow这个网站。作为全球最大的程序员问答网站&#xff0c;Stack Overflow 的名字来自于一个常见的报错&#xff0c;就是栈溢出&#xff08;stack ove…

Python中图像相似性度量方法汇总

1. 引言 在当前到处充满着图像的世界里&#xff0c;测量和量化图像之间的相似性已经成为一项关键的任务。无论是图像检索、内容推荐还是视觉搜索&#xff0c;图像相似性方法在现代计算机视觉的应用中都发挥着关键的作用。 幸运的是&#xff0c;Python提供了大量的工具和库&am…

Zabbix监控系统系列之二十二:ESXi虚拟化监控

背景概述 此前写了一篇VMware虚拟化监控的文章&#xff0c;但它主要是针对vCenter Server而不是ESXi。 Zabbix监控系统系列之七&#xff1a;VMware虚拟化监控 本次自己家中组建HomeLab实验环境&#xff0c;因此我将对于ESXi单机环境的监控方式进行记录。 操作步骤 创建ESXi普…

独立式三相无源逆变电源设计

摘要 面对全球日趋严重的能源危机问题&#xff0c;可再生能源的开发和利用得到了人们的高度重视。其中辐射到地球太阳能资源是十分富饶的&#xff0c;绿色清洁的太阳能不会危害我们的生存环境&#xff0c;因而受到了人们的广泛利用。光伏发电作为可再生能源被广泛的应用&#x…

阿里云在云原生领域喜获多项 OSCAR 开源尖峰案例奖

当前&#xff0c;国内开源技术正逐渐在各领域落地&#xff0c;越来越多的企业已经或准备使用开源&#xff0c;优秀的开源案例可以起到领航和参考作用。为了更好地推动开源技术在中国市场的落地&#xff0c;鼓励企业和厂商使用开源&#xff0c;鼓励企业或个人进一步探索我国开源…

Leetcode 23.旋转排序数组

整数数组 nums 按升序排列&#xff0c;数组中的值 互不相同 。 在传递给函数之前&#xff0c;nums 在预先未知的某个下标 k&#xff08;0 < k < nums.length&#xff09;上进行了 旋转&#xff0c;使数组变为 [nums[k], nums[k1], ..., nums[n-1], nums[0], nums[1], ..…

crypto:rsarsa

题目 下载压缩包后得到提示文本 根据提示文本信息&#xff0c;我们知道p q e c&#xff0c;可以求出n、φ(n)、d&#xff0c;进而求出m import gmpy2p 964842302901051567659055174001042653494573763923573980064398935203985250729849139956103500916342705037010757073363…

数据结构之堆排序和前,中,后,层序遍历,链式二叉树

首先我们要知道升序我们要建小堆&#xff0c;降序建大堆&#xff0c;这与我们的大多人直觉相违背。 因为我们大多数人认为应该将堆顶的数据输出&#xff0c;但如果这样就会导致堆顶出堆以后&#xff0c;堆结构会被破坏&#xff0c;显然我们不能这样。 所有我们反其道而行&…

anzo capital昂首资本:MT4和MT5 EA测试的主要区别

MT4和MT5EA测试仪的主要区别&#xff0c;anzo capital昂首资本认为体现在以下方面&#xff1a; 首先&#xff0c;对于专业模式的测试&#xff0c;MT4所需的时间大约为30分钟&#xff0c;MT5最多需要10分钟&#xff0c;显然MT5效率更高。 在优化方面&#xff0c;MT4对优化建议…

嵌入式养成计划-41----C++ auto--lambda表达式--C++中的数据类型转换--C++标准模板库(STL)--list--C++文件操作

九十九、auto 99.1 概念 C11引入了自动类型推导&#xff0c;和Python不一样&#xff0c;C中的自动类型推导&#xff0c;需要auto关键字来引导比如 &#xff1a;auto a 1.2; 会被编译器自动识别为 a 为 double 类型 99.2 作用 auto修饰变量&#xff0c;可以自动推导变量的数…

PyQt5开发相关

代码来源&#xff1a;cxinping/PyQt5: 《PyQt5快速开发与实战》配套代码 (github.com) 《PyQt5快速开发与实战》 (1)使用气泡提示 import sys from PyQt5.QtWidgets import QWidget, QToolTip, QApplication from PyQt5.QtGui import QFontclass Winform(QWidget):def __ini…

缺少 Google API 密钥,因此 Chromium 的部分功能将无法使用

当前版本&#xff1a;Chromium 114.0.5724.0 (开发者内部版本) &#xff08;32 位&#xff09; 1 使用 chromedriver.exe 驱动打开&#xff0c;则没有&#xff0c;于是查看参数&#xff0c;发现 --test-typewebdriver。 2 将 chrome.exe 发送到桌面&#xff0c;右键--属性--目…