android 添加一维数组,Android:打造“万能”Adapter与ViewHolder

article/2025/9/28 18:51:11

写在前面

最近一直忙着各种结课大作业,重新看起Android还有种亲切感。前段时间写项目的时候,学习了一个万能Adapter与ViewHolder的写法。说是“万能”其实就是在各种情况下都能通用。

我们知道,在写项目的时候,项目中肯定有很多的ListView或者RecyclerView,这个时候我们就要写大量的Adapter与ViewHolder。尽管重复写的难度并不大,但是这会让项目看起来十分冗余,因为存在大量的重复代码。

所以能不能有一个通用的ViewHolder与Adapter,让项目中只存在一个ViewHolder与Adapter呢?

当然可以,现在就通过一个小Demo将我学习的知识分享给大家。下面是本文的目录:

项目介绍

传统写法分析

简单认识SparseArray

万能ViewHolder

万能Adapter

结语

项目源码

项目介绍

先来看这个Demo,很简单,我就不多说了。

46d7ef09cb88

项目图

这是项目结构,为了方便后期对比,我将三种Adapter分离开了:

46d7ef09cb88

项目结构

MainActivity:模拟新闻页面

NewsBean:封装了新闻的Bean

CommonViewHolder:通用ViewHolder

CommonAdapter:通用Adapter

TraditionAdapterWithTraditionHolder:基于传统Holder的传统Adapter

TraditionAdapterWithCommonHolder:基于通用ViewHolder的传统Adapter

CommonAdapterWithCommoeHolder:基于通用ViewHolder的通用Adapter

传统写法分析

至于页面布局、模拟加载数据在这里我就不提了,十分简单。现在主要看一下传统的Adapter的写法。

/**

* 基于传统Holder的传统Adapter

*/

public class TraditionAdapterWithTraditionHolder extends BaseAdapter {

private Context context;

private List list;

public TraditionAdapterWithTraditionHolder(Context context, List list) {

this.context = context;

this.list = list;

}

@Override

public int getCount() {

return list.size();

}

@Override

public Object getItem(int position) {

return list.get(position);

}

@Override

public long getItemId(int position) {

return position;

}

@Override

public View getView(int position, View convertView, ViewGroup parent) {

ViewHolder viewHolder ;

if (convertView == null) {

convertView = View.inflate(context, R.layout.item_list, null);

viewHolder = new ViewHolder();

viewHolder.titleText = (TextView) convertView.findViewById(R.id.tv_title);

viewHolder.descText = (TextView) convertView.findViewById(R.id.tv_desc);

viewHolder.timeText = (TextView) convertView.findViewById(R.id.tv_time);

viewHolder.phoneText = (TextView) convertView.findViewById(R.id.tv_phone);

convertView.setTag(viewHolder);

}else{

viewHolder = (ViewHolder) convertView.getTag();

}

NewsBean bean = list.get(position);

viewHolder.titleText.setText(bean.getTitle());

viewHolder.descText.setText(bean.getDesc());

viewHolder.timeText.setText(bean.getTime());

viewHolder.phoneText.setText(bean.getPhone());

return convertView;

}

private class ViewHolder {

TextView titleText;

TextView descText;

TextView timeText;

TextView phoneText;

}

}

由于代码也比较简单,基本都是 套路 代码,大家都会写,都能看懂,所以我就不加以详细注释了。

46d7ef09cb88

全都是套路

我们知道,如果需要一个通用的Adapter,肯定要对之前的代码进行封装。所以现在主要来分析一下这个传统写法,看到底哪个地方可以进行封装。

依次来看,首先是构造函数。只要稍微有点经验的开发者都知道,一般来说,这里面传递的参数几乎都是一个 Context 与 List ,而List中通常都装了一个具体内容的 Bean 。

public TraditionAdapterWithTraditionHolder(Context context, List list) {

this.context = context;

this.list = list;

}

所以设想,既然这个Bean每次都需要,那我们是否能否将这个Bean直接给自定义的Adapter呢?比如这样:

public MyAdapter(Context context, List list) {

this.context = context;

this.list = list;

}

先把这个问题抛向天空,来看固定的三个方法,这也没啥好说的,依旧是套路,所以可以封装成固定方法,内部实现它,不需暴露出来再复写:

@Override

public int getCount() {

return list.size();

}

@Override

public Object getItem(int position) {

return list.get(position);

}

@Override

public long getItemId(int position) {

return position;

}

然后在重头戏 getView 方法中需要一个ViewHolder,来复用已有的View。然后 new 出List中的 Bean ,赋值后显示在View上。这就是基本的套路。

private class ViewHolder {

TextView titleText;

TextView descText;

TextView timeText;

TextView phoneText;

}

Override

public View getView(int position, View convertView, ViewGroup parent) {

ViewHolder viewHolder ;

if (convertView == null) {

convertView = View.inflate(context, R.layout.item_list, null);

viewHolder = new ViewHolder();

viewHolder.titleText = (TextView) convertView.findViewById(R.id.tv_title);

viewHolder.descText = (TextView) convertView.findViewById(R.id.tv_desc);

viewHolder.timeText = (TextView) convertView.findViewById(R.id.tv_time);

viewHolder.phoneText = (TextView) convertView.findViewById(R.id.tv_phone);

convertView.setTag(viewHolder);

}else{

viewHolder = (ViewHolder) convertView.getTag();

}

NewsBean bean = list.get(position);

viewHolder.titleText.setText(bean.getTitle());

viewHolder.descText.setText(bean.getDesc());

viewHolder.timeText.setText(bean.getTime());

viewHolder.phoneText.setText(bean.getPhone());

return convertView;

}

而这个ViewHolder套路就更深了,先定义一个ViewHolder类,类中是布局中所需的控件,然后在getView方法中new一个ViewHolder出来,通过这个ViewHolder找到对应的控件,找到后需要设置个Tag,方便之后复用。最后就是通过ViewHolder设置控件的内容了。

既然熟悉了过程,那封装起来就简单了许多。首先肯定需要封装ViewHolder类,不然怎么算的上通用,但是每一个ListView中item布局可能不一样,肯定不能将控件写死,那么如何定义控件呢?当控件定义好后,又如何找到这些控件呢?控件找到后又如何设置控件内容呢?

仍然将这些问题抛向天空,接下来再考虑convertView的复用问题,固定写法,当然也可以封装。

所以目前来看,如果想要一个Adapter与ViewHolder可以通用,那么 至少 必须做如下工作:

将List的泛型参数转移到Adapter中

封装 getCount、getItem、getItemId方法

封装ViewHolder,并解决不同布局控件不统一问题

通用ViewHolder需要找到相应的控件

通用ViewHolder需要提供方法来设置相应控件的内容

简单认识SparseArray

在写万能ViewHolder之前,先来了解一个新的API。我们知道,在Java中一般会用HashMap以键值对的形式来存储一些数据。但是Android给我们提供了一种工具类 SparseArray ,它是Android框架独有的类,在标准的JDK中不存在这个类。

为什么需要用SparseArray代替HashMap呢?

SparseArray要比 HashMap 节省内存,某些情况下比HashMap性能更好

那为什么SparseArray性能更好呢?按照官方的解释,原因有以下几点:

SparseArray不需要对key和value进行自动装箱

结构比HashMap简单

SparseArray内部主要使用两个一维数组来保存数据,一个用来存key,一个用来存value

不需要额外的数据结构(主要是针对HashMap中的HashMapEntry 而言的)

从源码的构造函数来看,与List一样,可以通过new的形式来创建一个SparseArray,与Map一样,可以通过 put(int key, E value) 的形式来添加键值对。也可以通过 get(int key) 的方式来获取值。

好了,就介绍这么多,关于具体的用法,文末附有参考资料链接,如有需要可以自行查看。

万能ViewHolder

现在就来打造万能ViewHolder,打造之前再次明确我们需要做的事情:

提供方法返回ViewHolder

提供方法获取控件

提供方法对控件进行设置

提供方法返回复用的View,也就是convertView

先来看如何解决不同布局有不同控件的问题。由于每个控件都有自己固定的ID和控件类型,那么我们可以通过键值对的形式来存储这些控件。在之前可以看到SparseArray能够提高性能,所以就用SparseArray来存储控件。

这样可以先写出构造函数,在构造函数中,初始化SparseArray,并设置一些内容。

/**

* 通用ViewHolder

*/

public class CommonViewHolder {

//所有控件的集合

private SparseArray mViews;

//记录位置 可能会用到

private int mPosition;

//复用的View

private View mConvertView;

/**

* 构造函数

*

* @param context 上下文对象

* @param parent 父类容器

* @param layoutId 布局的ID

* @param position item的位置

*/

public CommonViewHolder(Context context, ViewGroup parent, int layoutId, int position) {

this.mPosition = position;

this.mViews = new SparseArray<>();

//构造方法中就指定布局

mConvertView = LayoutInflater.from(context).inflate(layoutId, parent, false);

//设置Tag

mConvertView.setTag(this);

}

}

接下来我们就需要得到一个ViewHolder,这个比较简单,大家都能看懂,就是对Adapter中的getView方法进行一定的封装:

/**

* 得到一个ViewHolder

*

* @param context 上下文对象

* @param convertView 复用的View

* @param parent 父类容器

* @param layoutId 布局的ID

* @param position item的位置

* @return

*/

public static CommonViewHolder get(Context context, View convertView, ViewGroup parent, int layoutId, int position) {

//如果为空 直接新建一个ViewHolder

if (convertView == null) {

return new CommonViewHolder(context, parent, layoutId, position);

} else {

//否则返回一个已经存在的ViewHolder

CommonViewHolder viewHolder = (CommonViewHolder) convertView.getTag();

//记得更新条目位置

viewHolder.mPosition = position;

return viewHolder;

}

}

再接下来就是一个重难点,如何得到布局中的控件?因为我们肯定知道控件的ID,那么可以通过控件的ID来从SparseArray得到具体的控件类型。而Android中所有的控件都是继承自 View ,所以可以如下这样写:

/**

* 通过ViewId获取控件

*

* @param viewId View的Id

* @param View的子类

* @return 返回View

*/

public T getView(int viewId) {

View view = mViews.get(viewId);

if (view == null) {

view = mConvertView.findViewById(viewId);

mViews.put(viewId, view);

}

return (T) view;

}

通过上述方法,就能得到对应的控件类型。既然得到了,那么设置控件内容就比较简单了,在本例中都是TextView,所以我封装了下面的方法:

/**

* 为文本设置text

*

* @param viewId view的Id

* @param text 文本

* @return 返回ViewHolder

*/

public CommonViewHolder setText(int viewId, String text) {

TextView tv = getView(viewId);

tv.setText(text);

return this;

}

最后提供一个方法返回复用的convertView,这也比较简单。

/**

* @return 返回复用的View

*/

public View getConvertView() {

return mConvertView;

}

好了,再来看全部的代码,是不是清晰了很多:

/**

* 通用ViewHolder

*/

public class CommonViewHolder {

//所有控件的集合

private SparseArray mViews;

//记录位置 可能会用到

private int mPosition;

//复用的View

private View mConvertView;

/**

* 构造函数

*

* @param context 上下文对象

* @param parent 父类容器

* @param layoutId 布局的ID

* @param position item的位置

*/

public CommonViewHolder(Context context, ViewGroup parent, int layoutId, int position) {

this.mPosition = position;

this.mViews = new SparseArray<>();

mConvertView = LayoutInflater.from(context).inflate(layoutId, parent, false);

mConvertView.setTag(this);

}

/**

* 得到一个ViewHolder

*

* @param context 上下文对象

* @param convertView 复用的View

* @param parent 父类容器

* @param layoutId 布局的ID

* @param position item的位置

* @return

*/

public static CommonViewHolder get(Context context, View convertView, ViewGroup parent, int layoutId, int position) {

//如果为空 直接新建一个ViewHolder

if (convertView == null) {

return new CommonViewHolder(context, parent, layoutId, position);

} else {

//否则返回一个已经存在的ViewHolder

CommonViewHolder viewHolder = (CommonViewHolder) convertView.getTag();

//记得更新条目位置

viewHolder.mPosition = position;

return viewHolder;

}

}

/**

* @return 返回复用的View

*/

public View getConvertView() {

return mConvertView;

}

/**

* 通过ViewId获取控件

*

* @param viewId View的Id

* @param View的子类

* @return 返回View

*/

public T getView(int viewId) {

View view = mViews.get(viewId);

if (view == null) {

view = mConvertView.findViewById(viewId);

mViews.put(viewId, view);

}

return (T) view;

}

/**

* 为文本设置text

*

* @param viewId view的Id

* @param text 文本

* @return 返回ViewHolder

*/

public CommonViewHolder setText(int viewId, String text) {

TextView tv = getView(viewId);

tv.setText(text);

return this;

}

}

接下来我们就重写一个基于万能ViewHolder的Adapter,其他方法都不变,主要是getView方法。

@Override

public View getView(int position, View convertView, ViewGroup parent) {

//得到一个ViewHolder

CommonViewHolder viewHolder = CommonViewHolder.get(context, convertView, parent, R.layout.item_list, position);

NewsBean bean = list.get(position);

//直接设置控件内容,链式调用

viewHolder.setText(R.id.tv_title, bean.getTitle())

.setText(R.id.tv_desc, bean.getDesc())

.setText(R.id.tv_time, bean.getTime())

.setText(R.id.tv_phone, bean.getPhone());

//返回复用的View

return viewHolder.getConvertView();

}

现在来与之前的方法对比,是不是简单了很多,只需三步:

得到一个ViewHolder

通过这个ViewHolder直接设置控件内容

返回复用的View

看到这里大家肯定有个疑问,在上面ViewHolder中只提供了TextView设置文本的方法,那如果控件不是TextView呢?没关系,继续在万能ViewHolder中封装就好了:

/**

* 设置ImageView

*

* @param viewId view的Id

* @param resId 资源Id

* @return

*/

public CommonViewHolder setImageResource(int viewId, int resId) {

ImageView iv = getView(viewId);

iv.setImageResource(resId);

return this;

}

/**

* 还可以添加更多的方法

*/

至此,我们就搞定了一个通用的“万能”ViewHolder。

万能Adapter

有了万能ViewHolder,我们就可以来打造万能Adapter了,在文章开头已经分析过,需要做的事情有一下几点:

将Bean对象直接设置成Adapter的泛型

封装三个固定方法

封装getView方法

提供方法设置控件内容

先直接上代码,其实比较简单,大家应该能看懂:

/**

* 通用Adapter抽象类

*/

public abstract class CommonAdapter extends BaseAdapter {

protected Context context;

protected List list;

private int layoutId;

public CommonAdapter(Context context, List list, int layoutId) {

this.context = context;

this.list = list;

this.layoutId = layoutId;

}

@Override

public int getCount() {

return list.size();

}

@Override

public T getItem(int position) {

return list.get(position);

}

@Override

public long getItemId(int position) {

return position;

}

/**

* 封装getView方法

*/

@Override

public View getView(int position, View convertView, ViewGroup parent) {

//得到一个ViewHolder

CommonViewHolder viewHolder = CommonViewHolder.get(context, convertView, parent, layoutId, position);

//设置控件内容

setViewContent(viewHolder, (T) getItem(position));

//返回复用的View

return viewHolder.getConvertView();

}

/**

* 提供抽象方法,来设置控件内容

*

* @param viewHolder 一个ViewHolder

* @param t 一个数据集

*/

public abstract void setViewContent(CommonViewHolder viewHolder, T t);

}

这里可以看到我们先自定义一个Adapter继承BaseAdapter,并将Bean换成Adapter的泛型T了,然后封装了四个方法。又由于各个控件不一样,所以提供抽象方法来设置控件内容,我们只要复写就行了。

此时我们再来看基于万能ViewHolder的万能Adapter应该怎样写:

/**

* 继承通用Adapter且使用通用Holder的适配器

*/

public class CommonAdapterWithCommonHolder extends CommonAdapter {

public CommonAdapterWithCommonHolder(Context context, List list) {

super(context, list,R.layout.item_list);

}

/**

* 复写抽象方法

* @param viewHolder 一个ViewHolder

* @param bean Bean对象

*/

@Override

public void setViewContent(CommonViewHolder viewHolder, NewsBean bean) {

//直接设置内容 链式调用

viewHolder.setText(R.id.tv_title, bean.getTitle())

.setText(R.id.tv_desc, bean.getDesc())

.setText(R.id.tv_time, bean.getTime())

.setText(R.id.tv_phone, bean.getPhone());

}

}

看到这里,是不是有点神奇,对比之前的Adapter,这里只要几行代码就OK了。

结语

由于本文说明的不是一种固定的知识,而是一种设计的思想,所以理解起来比较晦涩难懂。我自己在学这个的时候,也是消化了很久,现在回头看看真的是很巧妙。

不过值得注意的是,这里说的“万能”其实就是一个俗称,代表一种通用的Adapter,能避免项目中的大量的重复代码,提高代码质量。而这种通用,不一定就是文中的这样的格式,这里只是提供一个设计思想与大致流程,大家可以自己写一个通用的、更加强大的Adapter。

最后由于我水平有限与篇幅限制等原因,在写文章的过程中,有很多地方写的不够详细或者有明显的疏漏与错误,欢迎大家交流与指正。

参考资料

项目源码


http://chatgpt.dhexx.cn/article/D5IPB8sp.shtml

相关文章

RecyclerView中ViewHolder重用机制理解,解决网络图片错乱和闪烁问题

&#x1f5a5; 原文转载自&#xff1a; https://blog.csdn.net/xyq046463/article/details/51800095作者&#xff1a;lanceJin. https://www.jianshu.com/p/ef7d0e16d999部分来自作者内容补充 文章目录 1. 概述2. 验证item的变化过程3. 异步网络导致ViewHolder出现图片错乱的原…

CCF CSP认证成绩代替考研复试机试!

最近整理考研资料&#xff0c;慢慢了解到CSP在考研方面还是挺有用的&#xff0c;算是给自己多了些机会。 已参加认证的高校对CSP认证成绩给予高度认可&#xff0c;部分知名院校通过不同方式对CSP认证成绩给予认可&#xff0c;其中包括&#xff1a; &#xff08;1&#xff09;…

CCF-CSP认证 202303 500分题解

202303-1 田地丈量&#xff08;矩形面积交&#xff09; 矩形面积交x轴线段交长度*y轴线段交长度 线段交长度&#xff0c;相交的时候是min右端点-max左端点&#xff0c;不相交的时候是0 #include<bits/stdc.h> using namespace std; int n,a,b,ans,x,y,x2,y2; int f(in…

谈一下两次CSP认证从180分到380分的感想

最近联系我的小可爱们比较多&#xff0c;我用qq建了一个ccf csp考试交流群&#xff0c;群号673612216&#xff0c;如果感觉有用可以加一下哦~~ 欢迎访问我的CCF认证考试题解目录哦 https://blog.csdn.net/richenyunqi/article/details/83385502&#xff0c;目前正在准备考研&am…

第22次 CCF CSP认证一二题题解及感悟

第22次 CCF CSP认证一二题题解及感悟 第一题灰度直方图题目重述题目分析代码及注释&#xff08;C&#xff09; 第二题邻域均值题目重述题目分析代码及注释&#xff08;C&#xff09;感悟 第一题灰度直方图 题目重述 一幅长宽分别为 n 个像素和 m 个像素的灰度图像可以表示为一…

CCF CSP认证2022年12月题解 现值计算、训练计划、JPEG 解码

题目 http://118.190.20.162/home.page T1 现值计算 思路 根据题意第 k k k年的 x x x元的当前价值为 x ( 1 i ) − k x\times (1i)^{-k} x(1i)−k计算各个价值&#xff0c;最后求和。 代码 int main() {int n; double i;scanf("%d %lf", &n, &i);i…

第29次CCFCSP认证经验总结

鄙人有幸参加了由中国计算机学会举办的第29次计算机软件能力认证考试&#xff0c;在此进行一些考试细节和经验的总结。 如果没有仔细了解过的小白去网上搜索CCFCSP&#xff0c;可能出现的是CSP-J/S&#xff0c;但是详细了解会发现&#xff0c;首先CSP-J/S分初试和复试&#xff…

第28次csp认证T3 JPEG 解码解析

第28次csp认证T3 JPEG 解码解析 题目说明 问题比较长&#xff0c;就只放个链接吧&#xff1a;http://118.190.20.162/view.page?gpidT158 经验分享 做这种大模拟的题目&#xff0c;对于经验不是很丰富的新手来说&#xff0c;更应该着眼于得分点&#xff0c;先做那些问题简单、…

csp认证考试准备Day-3

昨天复习了一点点&#xff0c;今天浅浅做几个第一道的真题吧 &#xff08;1&#xff09;202212-1 #include<bits/stdc.h> using namespace std; int main() {double n,i,b;scanf("%lf", &n);scanf("%lf", &i);double a[60];for(int j0;j<…

csp认证考试准备Day-1

今天&#xff0c;开启了我的第一个专栏&#xff0c;用来记录我的2023年3月的csp认证考试。 语言&#xff1a;c 本人状况&#xff1a;半学期几乎没敲过代码&#xff0c;学过c和数据结构&#xff0c;csp第一题应该能做出来。 目标&#xff1a;保证在csp考试时做出一二题&#…

第23次CSP认证题解

这是我第一次参加CSP&#xff0c;一共得了260分&#xff0c;100,70,70,20,0。这两天试着写一下题解&#xff0c;大家哪里看不懂直接留言问我就好。 目录 第一题&#xff1a;数组推导&#xff08;100分&#xff09;第二题&#xff1a;非零段划分&#xff08;100分&#xff09;第…

csp认证真题

出行计划 要在t时刻进入场所&#xff0c;获得核酸检测结果的时间点&#xff08;tk应该在[t-c1,t]内&#xff08;上段文字中c值为24&#xff09;&#xff0c;核酸检测结果才能生效。由于获得核酸检测结果的时刻>1&#xff08;因为等待核酸检测结果的时间k>0&#xff0c;所…

【经验】CCF CSP认证问题

202109-4收集卡牌 状压dp&#xff0c;注意保留10位小数&#xff0c;是样例里给出的最长的&#xff0c;五位也不行&#xff0c;double保留到小数点后15位以后就不准了 202104-2 邻域均值 要利用前缀和&#xff0c;不然会超时 202012-2 期末预测之最佳阈值 也是要利用前缀和&…

有关CCF的CSP认证

有关CCF的CSP认证 一、CSP认证考点的知识要求 在数据结构中&#xff0c;线性表是基础&#xff0c;树是常考点&#xff0c;集合和映射要夕纪学。 背包问题&#xff08;动态规划&#xff09; 考试要求 二、考试题型 第一题&#xff1a;一般为水题&#xff0c;把C学扎实便可…

记 CSP 认证

欢迎访问我的CCF认证解题目录 现在越来越忙了&#xff0c;估计后面也不参加了&#xff0c;纯粹是记录贴。 先晒一下成绩吧&#xff0c;至于为什么参加这么多次&#xff0c;主要是学校可以报销&#xff0c;干就完了&#xff0c;哈哈。 分别是 17、18、20、21 第一次参加 c…

CSP认证

【CSP】试题编号 202212-2-训练计划 题目&#xff1a;训练计划计算最早/最晚开始时间最早开始时间发散最晚开始时间 代码与上机代码上机结果 题目&#xff1a;训练计划 此题目样例有坑&#xff1a;样例中没有正确输出过一个最晚开始时间 所以在最开始处理问题的时候&#xff0…

CCF CSP认证

文章目录 :heart:[CCF CSP认证 (cspro.org)](https://www.cspro.org/):heart:1.主办单位2.认证目的3.认证内容4.认证方式5.准备认证上机环境6. 选择考试语言7. 选择编译环境8. 选择IDE9.认证前模拟练习10.成绩效力&#xff1a; ❤️CCF CSP认证 (cspro.org)❤️ 1.主办单位 中…

四大含金量高的算法证书考试

证书考试推荐 一、PAT 计算机程序设计能力测试二、CCF CSP认证三、团体程序设计天梯赛四、蓝桥杯大赛 一、PAT 计算机程序设计能力测试 官网&#xff1a;PAT 计算机程序设计能力测试 PAT为浙江大学出的一款程序设计的测试网站&#xff0c;分为乙级、甲级、顶级三种&#xff0…

2阶实对称矩阵特征值和特征向量的简单求解方法

2阶实对称矩阵特性 定理&#xff1a;2阶实对称矩阵H的特征值是实数 H[a,b;b,c] a,b,c是实数&#xff0c;λ 是特征值 A[a-λ,b;b,c-λ] 特征值求解方法为&#xff1a;(a- λ )(c- λ) - b2 0 求解方程得到两个根为&#xff1a;λ&#xff08;ac&#xff09;&…

求解矩阵特征值的QR算法

1. 算法原理介绍&#xff1a; 1. Householder变换&#xff1a; 2. Givens变换&#xff1a; 3. 矩阵的QR分解 4. 计算特征值的QR方法 5. 上Hessenberg矩阵方法&#xff1a; 2. 实施过程&#xff1a; 1. 约化过程&#xff1a; 1. Householder变换&#xff1a; 2. Givens变换&a…