面试题总结综合
煞笔!终究转移到这是吗?
简历
1.自我介绍
你好我叫杨凯 23年毕业于河北工业大学211 计算机科学与技术专业 这次应聘的是贵公司测试工程师的(Java后端研发工程师的)岗位
大学期间参加过创新创业大赛 以及acm的培训
(有两年的开发经验,其中一年在实习)
做过的项目有 实习时做的 接口管理工具的项目
在大学期间还做过校内实习项目 垃圾分类知识图谱的构建及可视化 担任小组长,负责实习中小组成员的任务分配 实习文档的编写 负责通过爬虫在网络上爬取垃圾数据,以供后续算法的训练
大学二年级还和同学一起做过一个微信小程序 借阅伴侣的微信小程序
我看了一下岗位对候选人的要求,在业务领域和技术栈这两个板块我认为和本人的匹配度比较高,看了一下工作职责也是个人想长期深耕的领域
2.项目介绍
接口管理工具 可以让团队更好地管理和协作API接口,从而提高软件开发的效率和质量,对于开发人员来说,可以更好地管理和测试API,从而更快地开发出高质量的软件。这个项目包括项目管理模块,有项目的创建修改删除,接口管理模块,有接口的创建,调试,审核,接口文档的生成以及接口审核结果的通知,用户管理模块,有项目成员的邀请,添加用户,确定用户角色
整个项目是前后端分离
前端使用的是angularJS的框架,后端使用springmvc+mybatis+MySQL
(主要实现后端功能)
3.负责内容
-
数据库表设计。根据需求设计合适的数据库表 对一些场景采用软删的方式来存储记录
软删除是指在数据库中不真正删除记录,而是通过标记记录的状态来表示该记录已经被删除。软删除通常是通过在表中增加一个状态字段来实现,当记录被删除时,将状态字段标记为已删除,而不是真正地从数据库中删除记录。这样做的好处是可以方便地恢复被删除的记录,同时也可以保留删除记录的历史信息。在一些场景下,比如用户注销账号、商品下架等情况下,采用软删除的方式可以更好地保留数据完整性和历史记录。 -
负责登录注册功能,使用Redis实现验证码,token的存储,用自定义拦截器完成用户认证、并使用双重拦截器解决token刷新的问题;
(首先,我们可以使用Redis来存储验证码和token,这样可以实现快速的读写操作,并且可以方便地进行过期时间的设置和管理。
然后,我们可以编写自定义拦截器来完成用户认证的逻辑。在用户请求到达后端服务之前,拦截器可以对请求中的token进行验证,并判断用户是否有权限访问相应的资源。
另外,当用户请求需要刷新token时,第一个拦截器可以验证用户的身份并生成新的token,然后将新的token存储到Redis中。接着,第二个拦截器可以再次验证用户的身份,并使用新的token来完成后续的操作。
从而提高系统的安全性和可靠性。) -
其中邮件通知功能使用了spring框架中的javamailsender组件实现,当审核人员审核完接口后就会根据接口状态发送邮件给相关的项目成员,对接口进行操作
-
用户权限的保存:通过Threadlocal配合拦截器来进行token的校验,判断当前用户是否处于登录状态,并使用会话跟踪技术解决了HTTP无状态的问题,达到服务器记住用户信息的效果;
(针对这些缺点,可以采用会话跟踪技术来解决这个问题。 把状态保存在服务器中,只发送回一个标识符,浏览器在下次提交中把这个标识符发送过来;这样,就可以定位存储在服务器上的状态信息了。)
threadlocal的特性:ThreadLocal是Java中一个非常有用的类,它为每个线程提供了一个独立的变量副本,使得每个线程都可以修改自己的变量副本而不会影响其他线程的变量。 ThreadLocal的这种特性使得它非常适合用于实现线程局部的资源,比如线程局部变量、线程局部缓冲区等。
4.实习中的收获:
• 熟悉了在一个项目组中多人协作开发的工作流程,熟练掌握git的日常开发使用
• 熟练基于Java8新特性编写代码,如lambda表达式、方法引用、stream流的熟练使用
• 使用logback输出日志 在linux上用vi或tail命令观察日志文件
1. 刚开始我不熟悉测试和部署等流程,但后来我慢慢熟悉了。
在这个项目里,我们是用Maven管理项目,用jenkins部署项目,用git来管理代码。我在这个项目里,除了写代码外,还参与了单元测试和联调。我们代码发布时,最终会把java代码打成jar包并部署到linux服务器上。
(Jenkins 是一个用 Java 编写的开源自动化工具,带有用于持续集成的插件。Jenkins 用于持续构建和测试软件项目,从而使开发人员更容易将更改集成到项目中,并使用户更容易获得新的构建。它还允许您通过与大量测试和部署技术集成来持续交付软件。借助 Jenkins,组织可以通过自动化来加速软件开发过程。Jenkins 集成了各种开发生命周期过程,包括构建、文档、测试、打包、模拟、部署、静态分析等等。
DevOps是一种IT思维方式,它鼓励软件开发人员和IT操作人员之间的交流、协作、集成和自动化,以提高交付软件的速度和质量。)
2. 刚开始我不熟悉数据库性能调优的问题,但后来熟悉了。
3. 刚开始我只知道在windows里开发,不熟悉linux操作,尤其是在linux里看日志的操作。
1 先说下问题的表现形式。你可以说,在一些下订单的流程中,经常会出现状态码500服务器错误。
2 再说怎么排查。登录到linux服务器上,用vi命令打开日志文件,再用根据错误关键字和时间,搜索找到上下文,再根据该日志的线程ID去查看在该日志文件的其它日志
如果涉及到其它业务模块,可以用traceID去找
3 再说下问题原因和怎么解决。原因你怎么说都行,比如这个点有哪些值钱点呢?大多数初级开发是只会在windows上做业务,不知道项目是部署在linux服务器上,而且缺乏linux的操作经验。这个亮点所涉及的linux技能比较简单,初级开发也能说,但你一旦说出这个亮点,就不仅能进一步证明该项目是商业项目,而且还能说明你有linux开发经验,更不要说你还具有分析和排查问题的能力了。这方面的亮点该怎么说呢?老规矩结合项目说。
价格参数不符规范,或请求类型应该是POST但发GET,往深了说可以说是因高并发导致的问题。怎么解决就一句话的事情,比如发现问题后,我们加了异常处理机制。
4同时再去看下项目里通过logback输出日志的方式,和linux打开文件搜索关键字等命令,以便面试官细问。
4. 我有过通过看底层源码排查问题的能力
这个点很难说成是难点,但可以当成亮点来说。对于初级开发,可以说个简单点的,比如在库存盘点的业务流程里,我们是要通过迭代器遍历ArrayList类型的库存信息。在遍历时,我们同时做了修改,所以就导致了“快速失效”的问题。
快速失效的底层源码不难,网上一搜一大堆,而且解决方法也简单,就别边遍历边修改了。
关于底层源码,哪怕是初级开发也可以准备ConcurrentHashMap的,因为其中不仅包含了红黑树等数据结构,还包含了transient和violate等关键字,还包含了线程同步等细节,而且底层源码不难,网上资料很多。
5.实习中复杂的问题 处理过的技术难点 印象深刻的点
比如独立从0到1搭建微服务架构、第一次参与线上问题的诊断和解决
6.质疑 遇到不会的
你说了通过jenkins部署,说了通过new relic监控,你说下细节。或者问些比较深的问题。这些事情其实是资深开发或架构做的,你一个初级开发能知道就不错了,你可以干脆说,这些是我们架构或项目经理做的,面试官听了也就不会再问了。
7.优缺点 个人评价
本人拥有出色的文档编写能力,能够为团队成员提供易于理解的技术文档,确保信息的有效传递。作为一名持续学习的程序员,我善于吸收新知识,跟上技术发展的步伐。我能够快速掌握新技术,并将其应用到实际项目中。我具有良好的沟通技巧,能够与团队成员高效协作。我可以清晰地表达自己的想法,同时也善于倾听他人的意见和建议。我是一位优秀的团队合作者,擅长与他人共同解决问题。我能够积极参与团队讨论,贡献自己的想法,同时也尊重他人的观点。我对工作充满热情,总是以积极的态度面对各种挑战。我认真负责,对自己的工作成果有高要求,确保交付的每一份工作都符合质量标准。在面对高压环境或复杂问题时,我能够保持冷静,寻找解决方案。我相信困难只是暂时的,通过不懈的努力,总能找到突破点。我热爱技术,始终追求技术创新。我注重代码的质量,坚持写出整洁、可读性强的代码,为项目的长期维护奠定基础。我具备丰富的分布式、高并发系统开发或维护经验,熟悉各种相关技术和工具。我能够设计和实现高效、稳定的系统架构,确保系统的可靠性和可扩展性
8.关于未来从业方向分析
1.对Java技术形成比较体系化的积累,对未来往更高层面发展有很大的帮助,这个是基本盘!!
2.在公司中多参与一些架构设计方案的思考和沉淀,多站在全局的视角去看项目的价值和设计
3.从日常工作复盘整体的项目逻辑,锻炼自己的逻辑能力。同时总结自身技术经验要结合业务需求的角度思考,锻炼自己的业务思维,多思考有没有更优的解决方案
4.管理能力
9.为什么要做这个项目
市面上接口管理工具的确很多,但仍有一些原因促使人们开发新的接口管理工具。
首先,随着Web技术的发展和前后端分离构架的流行,接口管理变得越来越重要。然而,目前许多接口文档不是规范的,可能使用各种形式如Wiki、Word文档甚至即时聊天软件进行沟通。这给前端工程师带来了挑战,他们需要花费大量时间去理解并适应接口的变化。同样,对于后端工程师,维护接口文档也是一个繁琐的任务。
其次,现有的接口管理工具可能无法满足所有团队的需求。每个团队都有自己的工作方式和特定的需求,某些接口管理工具可能无法完全满足这些需求。此外,一些团队可能希望自主开发接口管理工具以更好地整合到自己的工作流程中。
最后,新的接口管理工具可能会引入新的功能或改进现有功能,从而提高开发效率和代码质量。例如,一些新的工具可能集成了自动化测试功能,能够更快速地检测和解决接口数据错误问题。
综上所述,尽管市场上已经有很多接口管理工具,但仍有必要开发新的工具以满足不断变化的技术需求和团队需求。
10.简历中涉及到的技术
协程池
是一种并发处理的技术,它允许多个任务在同一个线程中交替执行,从而提高了程序的并发性能。通过使用协程池,数据分发服务可以同时处理多个推单任务,而不需要为每个任务创建一个新的线程,从而减少了线程的创建和销毁的开销,提高了系统的性能和吞吐量。
异步队列
则是一种消息传递的机制,它允许生产者将消息放入队列中,而消费者则可以异步地从队列中获取消息并处理。通过使用异步队列,数据分发服务可以将批量数据砍单后的单笔推单任务放入队列中,然后由协程池中的协程异步地从队列中获取任务并进行处理,从而实现了任务的异步处理和高效分发。
http为什么无状态
HTTP被认为是无状态的,是因为它不会在多次请求之间保持任何状态信息。每个HTTP请求都是独立的,服务器不会保留关于之前请求的任何信息,也不会知道用户的上下文或状态。这意味着每个请求都需要包含所有必要的信息,例如身份验证凭据或会话标识符。
这种无状态的设计使得HTTP协议更加简单和灵活,并且使得服务器可以更容易地扩展和处理大量的请求。然而,这也意味着开发者需要自行处理状态信息的管理,例如使用会话管理技术来跟踪用户的状态。
排序(五种都要能手写)、快速查找 (二分)、树的深度和广度遍历 这些基本的要能手写
stream
Stream将要处理的元素集合看作一种流,在流的过程中,借助Stream API对流中的元素进行操作。
• stream流的特性
1. stream不存储数据,而是按照特定的规则对数据进行计算,一般会输出结果。
2. stream不会改变数据源,通常情况下会产生一个新的集合或一个值。
3. stream具有延迟执行特性,只有调用终端操作时,中间操作才会执行。
• stream可以由数组和集合创建,对其操作可以分为中间操作和终端操作
中间操作:每次返回一个新的流,可以有多个
终端操作:每个流只能进行一次终端操作,终端操作结束后流无法再次使用。终端操作会产生一个新的集合或值
类加载
类加载是指在程序运行时,将类的字节码文件加载到内存中,并创建对应的Class对象的过程。
Java反射
Java的反射是指在运行时动态地获取类的信息、调用类的方法、访问类的字段等操作
mybatis的动态代理
Java底层数据结构
Java底层数据结构包括数组(Array)和链表(LinkedList)。
数组是一种线性数据结构,它可以存储相同类型的元素,并且可以通过索引快速访问元素。
链表是一种非线性数据结构,它由节点组成,每个节点包含数据和指向下一个节点的指针。除此之外,Java底层还使用了其他数据结构,如哈希表(HashMap)和栈(Stack)等。
这些数据结构在Java中被封装成类,并且提供了丰富的方法和操作来进行数据的存储和处理。
Jvm内存结构
JVM内存结构包括堆(Heap)、方法区(Method Area)、程序计数器(Program Counter Register)、虚拟机栈(VM Stack)和本地方法栈(Native Method Stack)等部分。
堆:用于存储对象实例,是所有线程共享的内存区域,被所有线程共享。堆内存分为新生代、老年代和永久代(在JDK8之前)或元空间(在JDK8之后)。
方法区:用于存储类的结构信息、常量、静态变量等数据。在JDK8之前,方法区是永久代,而在JDK8之后,方法区被替换为元空间。
程序计数器:每个线程都有一个程序计数器,用于记录当前线程执行的字节码指令地址。
虚拟机栈和本地方法栈:用于存储线程的方法调用和局部变量。
JMM(Java内存模型):
JMM定义了Java程序中各种变量的访问规则,它规定了在多线程环境下,如何进行内存的读写操作。JMM通过volatile、synchronized、final、happens-before等关键字和规则来实现多线程内存的可见性、有序性和原子性。
GC算法
GC算法用于回收不再使用的对象,以释放内存空间。常见的GC算法包括标记-清除算法、复制算法、标记-整理算法、分代算法等。
双亲委派机制:
双亲委派机制是指当一个类加载器收到类加载请求时,它首先将请求委派给父类加载器去完成,只有在父类加载器无法找到该类时,才会自己去加载。这种机制可以保证类的唯一性,避免类的重复加载。
G1工作原理:
G1(Garbage First)是JVM中的一种垃圾回收器,它是一种基于分代的垃圾回收器,但与传统的分代垃圾回收器不同,G1并不是严格区分新生代和老年代。G1将整个堆划分为多个大小相等的区域,每个区域可能是新生代也可能是老年代。在进行垃圾回收时,G1会优先选择垃圾最多的区域进行回收,这就是“Garbage First”(垃圾优先)的含义。通过这种方式,G1可以在更短的时间内回收更多的垃圾,从而减少应用程序的停顿时间。 G1还可以自适应地调整堆大小,以满足应用程序的需求。
MQ是消息队列
(Message Queue)的缩写,是一种用于在应用程序之间传递消息的通信模式。消息队列可以实现异步通信,提高系统的可扩展性和可靠性。通过消息队列,不同的应用程序可以在不同的时间和速度处理消息,从而实现解耦、削峰填谷和异步处理等功能。常见的消息队列系统包括RabbitMQ、Kafka、ActiveMQ等。
JMeter
是一个用于性能测试的开源工具,它最初是由Apache软件基金会开发和维护的。JMeter可以用于模拟多种负载类型,包括静态资源的访问、动态资源的访问、数据库访问、FTP访问等,以评估一个系统的性能和承载能力。JMeter可以模拟多种协议的请求,包括HTTP、HTTPS、FTP、JMS、SOAP、REST等。它也可以生成各种图表和报告,用于分析测试结果。JMeter是一个功能强大且广泛使用的性能测试工具,被广泛应用于Web应用程序、数据库服务器、消息队列、API等各种系统的性能测试。
MySQL事务
是数据库管理系统中非常重要的概念,它保证了数据库操作的一致性和可靠性。
原子性(Atomicity):事务的所有操作要么全部成功执行,要么全部回滚到初始状态。
一致性(Consistency):事务执行前后数据库的状态必须保持一致。
隔离性(Isolation):多个事务并发执行时,每个事务的操作都不能被其他事务干扰。
持久性(Durability):事务一旦提交,其对数据库的改变就是永久性的。
实现原理:
日志系统
MySQL的日志系统包括redo log和undo log。redo log记录了事务对数据库的修改操作,用于恢复数据库的一致性。undo log记录了事务对数据库的修改操作的逆操作,用于回滚事务。
在事务执行过程中,数据库会将事务的操作记录到redo log中,然后将操作应用到内存中的数据页。当事务提交时,会将redo log持久化到磁盘,以保证持久性。
锁机制
MySQL使用锁机制来实现事务的隔离性。当一个事务对某个数据进行修改时,会给该数据加上锁,其他事务在进行读取或修改操作时需要等待锁的释放。
锁的粒度可以是行级锁、表级锁或页级锁,不同的锁粒度对并发性和性能有影响。
1.什么是锁?
锁是计算机协调多个进程或线程并发访问某一资源的机制。
锁保证数据并发访问的一致性、有效性;
锁冲突也是影响数据库并发访问性能的一个重要因素。
锁是Mysql在服务器层和存储引擎层的的并发控制
2.为什么要加锁?
数据库是一个多用户使用的共享资源。当多个用户并发地存取数据时,在数据库中就会产生多个事务同时存取同一数据的情况。若对并发操作不加控制就可能会读取和存储不正确的数据,破坏数据库的一致性。
锁是用于管理对公共资源的并发控制。也就是说在并发的情况下,会出现资源竞争,所以需要加锁。
加锁解决了 多用户环境下保证数据库完整性和一致性。
Lock的对象是事务,用来锁定的是数据库中的对象,如表、页、行。并且一般lock的对象仅在事务commit或rollback后进行释放(不同事务隔离级别释放的时间可能不同)。
并发控制
并发控制是为了解决多个事务并发执行时可能出现的问题,如脏读、不可重复读和幻读。
MySQL使用多版本并发控制(MVCC)来解决并发问题。MVCC通过为每个事务创建一个独立的版本来实现隔离性,事务只能看到在事务开始之前已经提交的数据。
存储引擎
MySQL的存储引擎是一组实现了特定数据存储和检索功能的软件组件。MySQL支持多种存储引擎,包括InnoDB、MyISAM、Memory(HEAP)、CSV、Blackhole等。
选择合适的存储引擎需要考虑以下因素:
数据重要性: 如果数据非常重要,需要事务安全和数据恢复功能,应选择InnoDB或其它支持事务的存储引擎。
并发读写需求: 如果应用需要高并发写入,InnoDB是更好的选择,因为它支持行级锁定和事务处理。对于读操作密集型应用,MyISAM可能更适合。
性能要求: 如果对性能要求较高,应考虑使用InnoDB或MyISAM,因为它们经过优化以提高性能。
数据一致性: 如果需要外键约束来维护数据一致性,InnoDB是唯一的选择。
数据大小: 对于非常大的数据集,应考虑使用专门为大数据优化过的存储引擎,如TokuDB或XtraDB。
特殊需求: 如果有特殊的需求,如需要生成审计日志或复制功能,应选择支持这些功能的存储引擎。
索引
以空间换时间
Redis
Redis是一个开源的内存数据库,支持持久化的键值存储系统。它可以用作数据库、缓存和消息中间件。Redis可以部署为单机模式或集群模式。
单机模式下,Redis只运行在一台服务器上,所有的数据都存储在这台服务器的内存中。这种部署方式适用于小型应用或开发环境,它简单、易于部署和管理。
集群模式下,Redis可以运行在多台服务器上,数据分布在各个节点上。这种部署方式适用于大型应用或高可用性要求较高的场景,它可以提供更高的性能和可靠性。
在集群模式下,Redis使用分片来将数据分布到不同的节点上,同时还支持主从复制和故障转移等功能,以确保数据的高可用性和可靠性。同时,Redis集群还提供了自动分片和负载均衡的功能,使得集群的扩展和管理变得更加容易。
CAS
CAS是一种乐观锁,它抱着乐观的态度认为自己一定可以成果。当多个线程同时使用CAS操作一个变量时,只有一个会胜出,并成功更新,其余均会失败。失败的线程不会被挂起,仅是被告知失败,并且允许再次尝试,当然也允许失败的线程放弃操作。基于这样的原理, CAS操作即使没有锁,也可以发现其他线程对当前线程的干扰,并进行恰当的处理。
AQS:即AbstractQueuedSynchronizer, 队列同步器,它是Java并发用来构建锁和其他同步组件的基础框架。
AQS是一个抽象类,主是是以继承的方式使用。AQS本身是没有实现任何同步接口的,它仅仅只是定义了同步状态的获取和释放的方法来供自定义的同步组件的使用。一般是同步组件的静态内部类,即通过组合的方式使用。
抽象的队列式的同步器,AQS定义了一套多线程访问共享资源的同步器框架,许多同步类实现都依赖于它,如常用的ReentrantLock/Semaphore/CountDownLatch
bean生命周期
Spring启动,查找并加载需要被Spring管理的bean,进行Bean的实例化
Bean实例化后 将Bean的引入和值注入到Bean的属性中
如果Bean实现了BeanNameAware接口的话,Spring将Bean的Id传递给setBeanName()方法
如果Bean实现了BeanFactoryAware接口的话,Spring将调用setBeanFactory()方法,将BeanFactory容器实例传入
如果Bean实现了ApplicationContextAware接口的话,Spring将调用Bean的setApplicationContext()方法,将bean所在应用上下文引用传入进来
如果Bean实现了BeanPostProcessor接口,Spring就将调用他们的postProcessBeforeInitialization()方法。
如果Bean 实现了InitializingBean接口,Spring将调用他们的afterPropertiesSet()方法。类似的,如果bean使用init-method声明了初始化方法,该方法也会被调用
如果Bean 实现了BeanPostProcessor接口,Spring就将调用他们的postProcessAfterInitialization()方法。
此时,Bean已经准备就绪,可以被应用程序使用了。他们将一直驻留在应用上下文中,直到应用上下文被销毁。
如果bean实现了DisposableBean接口,Spring将调用它的destory()接口方法,同样,如果bean使用了destory-method 声明销毁方法,该方法也会被调用。
Thread Local
是Java中一个非常有用的类,它为每个线程提供了一个独立的变量副本,使得每个线程都可以修改自己的变量副本而不会影响其他线程的变量。 ThreadLocal的这种特性使得它非常适合用于实现线程局部的资源,比如线程局部变量、线程局部缓冲区等。
Rabbit MQ
最初起源于金融系统,用于在分布式系统中存储转发消息,在易用性、扩展性、高可用性等方面表现非常优异
Lambda的使用场景
其实上面的就知道lambda用在哪的,就是配合函数式接口使用的。lambda表达式必须和函数式接口的抽象函数描述一样的参数类型,它的返回类型也必须和抽象函数的返回类型兼容,并且他能抛出的异常也仅限于在函数的描述范围中。
简化繁杂的代码 简化代码编写
列表迭代
事件监听
Map映射
工厂设计模式的使用场景
- 如果不想让某个子系统与较大的那个对象之间形成强耦合,而是想运行时从许多子系统中进行挑选的话,那么工厂模式是一个理想的选择
- 将new操作简单封装,遇到new的时候就应该考虑是否用工厂模式;
- 需要依赖具体环境创建不同实例,这些实例都有相同的行为,这时候我们可以使用工厂模式,简化实现的过程,同时也可以减少每种对象所需的代码量,有利于消除对象间的耦合,提供更大的灵活性
11.Markdown
12.Git
13.登陆注册中的权限控制
通过拦截器实现权限控制,接着重写logincontroller;
编写拦截器实现类,实现 HandlerInterceptor接口 重写 里面的 preHandle方法 即可 ,true表示放行,false表示拦截;
注册拦截器,包括添加拦截器,添加拦截路径,删除拦截路径;
测试;
拦截器的作用是用于权限验证。
类似于传统的javaweb中的过滤器。
springmvc中的拦截器是AOP的一个体现。
通过拦截器我们可以轻松的实现页面之间的权限的验证,还可以在请求访问前后做一些私人订制。
好处
采用横切的方式进行拦截处理
不会对原本的代码产生丝毫的影响
使用简单,方便、快捷
线程池
线程池是一种利用池化技术思想来实现的线程管理技术,主要是为了复用线程、便利地管理线程和任务、并将线程的创建和任务的执行解耦开来。我们可以创建线程池来复用已经创建的线程来降低频繁创建和销毁线程所带来的资源消耗
线程池的优点
- 降低资源消耗,复用已创建的线程来降低创建和销毁线程的消耗。
- 提高响应速度,任务到达时,可以不需要等待线程的创建立即执行。
- 提高线程的可管理性,使用线程池能够统一的分配、调优和监控。
数据库面试题
C++学习
指针常量和常量指针
指针常量:强调常量,可以修改值,不可以修改指针 int * const p //指针常量
常量指针:强调指针,不可以修改值,可以修改指针指向 const int *p = &a; //常量指针
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 周边上新:园子的第一款马克杯温暖上架
· 分享 3 个 .NET 开源的文件压缩处理库,助力快速实现文件压缩解压功能!
· Ollama——大语言模型本地部署的极速利器
· DeepSeek如何颠覆传统软件测试?测试工程师会被淘汰吗?
· 使用C#创建一个MCP客户端
2023-04-03 2023年4月3日