Solana 代币 2022 — Transfer Hook

从零到英雄的 Solana 代币 2022 — Transfer Hook 

 

Token 2022 计划引入了几项令人兴奋的扩展,增强了铸造和代币账户的功能。在这些功能中,我个人最喜欢的是Transfer Hook (转账钩子) 。

想象时间

让我们戴上想象的帽子,想象一下这个美好的场景:你是一个 NFT 项目的所有者。你向持有者发放代币,以奖励他们将 NFT 抵押给你。你将你的项目视为一个“封闭社区”,这意味着只有你的 NFT 持有者才能持有你的代币。在没有转账钩子之前,你必须构建自己的程序来处理转账,以强制执行这种行为。但有了转账钩子,这就非常简单了!你只需要构建一个转账钩子程序,验证转账的目标地址是否确实是白名单地址之一,如果不是,则停止交易。另一个例子?假设你希望用户在每次进行代币转账时支付额外费用……没问题!这也可以通过构建一个处理转账的钩子来实现!

现在,在 NFT 项目的背景下,这些例子可能看起来有些愚蠢,但想象一下更大的图景,这样的钩子可以帮助遵守监管要求,例如强制执行持有期或设置代币的最大持有量。

Transfer Hook — 它到底是什么?

顾名思义,Transfer Hook 扩展与代币转账密切相关。每当一个铸造配置了 Transfer Hook 时,每次在该铸造上执行转账指令时,都会自动触发一个指令。如果这个概念看起来很熟悉,那是因为它确实如此——这个流程与 web2 中的 webhooks 工作方式非常相似。

转账钩子指令可以访问一个变量,即转账金额,但我们可以提供一个额外的账户(extra-account-meta-list),其中包含指令可以使用的其他自定义账户。我们很快会详细讨论这个账户。

虽然转账钩子确实可以访问初始转账账户,但需要注意的是,它们作为只读账户传递,这意味着发送者的签名权限不会扩展到Transfer Hook程序。

最后,当使用 Anchor 编写Transfer Hook程序时,需要一个回退指令来手动匹配原生程序指令鉴别器并调用Transfer Hook指令。这是因为 Token 2022 计划是一个原生程序,因此我们需要“桥接”其原生接口与 Anchor。

是时候动手了

好了,话不多说——让我们构建一些东西!我们将构建一个“鲸鱼警报”转账钩子 🐋!对于每次代币转账,转账钩子指令将比较转账金额与预定义的值(例如,10,000 代币)。如果等于或大于该值,我们将更新一个账户,记录最新的鲸鱼详情,并发出一个事件供客户端处理。

⚒️ 你将需要安装 Solana CLI 工具和 Anchor。如果你还没有安装,请查看 Anchor 文档 以获取安装说明。

第一步:转账钩子程序

让我们设计我们的转账钩子程序。我们的转账钩子程序首先需要一个指令,可以在转账完成后调用。我们将使用 Anchor 构建我们的程序,然而,Token 2022 计划是一个原生 Solana 程序——因此我们需要另一个指令:一个指令来匹配指令鉴别器到转账钩子的 execute 接口,并在匹配时调用 transfer_hook 指令。所以目前有两个指令。

当我们的钩子被调用时,它会将转账金额与一个值进行比较——但这个值来自哪里?当然,我们可以在程序中硬编码这个值——但如果明天我们决定要增加/减少这个值呢?我们需要重新部署程序。更好的处理方式是将比较值保存在一个账户中。要将额外的账户传递给转账钩子,我们使用 extra_account_meta_list 账户。这是一个 PDA 账户,存储转账钩子在调用时可以使用的账户。extra_account_meta_list 账户将始终使用硬编码字符串 extra-account-metas 和代币的铸造地址作为种子。

现在你可能会问自己,我们如何创建和初始化这个 extra_account_meta_list 账户?这就是我们程序的第三个也是最后一个指令——initialize_extra_account_meta_list 指令的作用。

在完成我们程序的高层设计后,让我们开始实际编写转账钩子程序 🎉。

  1. 创建一个新的 Anchor 项目并在你喜欢的 IDE 中打开它:
anchor init transfer-hook-whale
  1. 安装 anchor-spl, spl-transfer-hook-interface 和 spl_tlv_account_resolution crates。这些 crates 包含帮助函数和接口,使我们在处理 SPL 代币和扩展指令时更加轻松。
cd programs/transfer-hook-whale
cargo add anchor-spl spl-transfer-hook-interface spl_tlv_account_resolution
  1. 从 Anchor 0.30 开始,我们需要告诉 Anchor 为我们使用的 crates 生成类型定义,因此我们需要告诉它为 anchor-spl crate 生成类型定义。打开 Cargo.toml 文件,位于 programs/transfer-hook-whale 文件夹内,并按如下方式更新 idl-build
[features]
...
idl-build = ["anchor-lang/idl-build", "anchor-spl/idl-build"]
  1. 打开 lib.rs 并添加以下 use 语句:
use anchor_lang::system_program::{create_account, CreateAccount};
use anchor_spl::{associated_token::AssociatedToken,token_interface::{Mint, TokenInterface},
};
use spl_transfer_hook_interface::instruction::TransferHookInstruction;use spl_tlv_account_resolution::{account::ExtraAccountMeta, seeds::Seed, state::ExtraAccountMetaList,
};
use spl_transfer_hook_interface::instruction::ExecuteInstruction;

一个转账钩子程序通常由三个指令组成:

  • initialize_extra_account_meta — 一个创建账户(extra_account_meta_list)的指令,该账户保存转账钩子可以使用的额外账户列表。
    在我们的例子中,这个账户将保存最新“鲸鱼”地址和金额的详细信息。
  • transfer_hook — 钩子本身。这是每次发生代币转账时实际调用的指令。
  • fallback — Token 2022 计划是一个原生程序,但我们使用 Anchor 构建我们的程序,因此我们需要添加一个回退指令,该指令将指令鉴别器匹配到转账钩子的 execute 接口,并在匹配时调用我们的 transfer_hook 指令。

实现 initialize_extra_account_meta 指令

  1. 在你的 lib.rs 底部,添加以下账户。此账户将保存最新“鲸鱼”转账的详细信息:
#[account]
pub struct WhaleAccount {pub whale_address: Pubkey,pub transfer_amount: u64
}
  1. 接下来,我们定义 initialize_extra_account_meta 指令执行所需的所有账户。在 LatestWhaleAccount 上方添加以下代码片段:
#[derive(Accounts)]
pub struct InitializeExtraAccountMeta<'info> {#[account(mut)]pub payer: Signer<'info>,/// CHECK: ExtraAccountMetaList Account, must use these exact seeds#[account(mut, seeds=[b"extra-account-metas", mint.key().as_ref()], bump)]pub extra_account_meta_list: AccountInfo<'info>,pub mint: InterfaceAccount<'info, Mint>,#[account(init, seeds=[b"whale_account"], bump, payer=payer, space=8+32+8)]pub latest_whale_account: Account<'info, WhaleAccount>,pub token_program: Interface<'info, TokenInterface>,pub associated_token_program: Program<'info, AssociatedToken>,pub system_program: Program<'info, System>,
}

🧑‍🏫 提示

  • 将保存额外账户的账户 (extra_account_meta_list必须有一个非常特定的种子用于其 PDA:字节串 extra-account-metas 和代币的 mint 账户的公钥。
  • 将保存鲸鱼详细信息的账户 (latest_whale_account) 将有一个简单的种子用于其 PDA:字符串 whale_account 的字节。这意味着我们铸造的所有代币将共享同一个账户。
  • 我们必须为指令提供代币程序、关联代币程序和系统程序,因为它在运行时需要使用它们。
  1. 接下来,让我们添加 initialize_extra_account_meta 指令。用以下内容替换默认的 initialize 指令:
pub fn initialize_extra_account(ctx: Context<InitializeExtraAccountMeta>) -> Result<()> {// 这是我们需要的额外账户的向量。在我们的例子中// 只有一个账户 - 鲸鱼详细信息账户。let account_metas = vec![ExtraAccountMeta::new_with_seeds(&[Seed::Literal {bytes: "whale_account".as_bytes().to_vec(),}],false,true,)?];// 计算账户大小和租金let account_size = ExtraAccountMetaList::size_of(account_metas.len())? as u64;let lamports = Rent::get()?.minimum_balance(account_size as usize);// 从上下文中获取铸造账户公钥。let mint = ctx.accounts.mint.key();// ExtraAccountMetaList PDA 的种子。let signer_seeds: &[&[&[u8]]] = &[&[b"extra-account-metas",&mint.as_ref(),&[ctx.bumps.extra_account_meta_list],]];// 创建 ExtraAccountMetaList 账户create_account(CpiContext::new(ctx.accounts.system_program.to_account_info(),CreateAccount {from: ctx.accounts.payer.to_account_info(),to: ctx.accounts.extra_account_meta_list.to_account_info(),},).with_signer(signer_seeds),lamports,account_size,ctx.program_id,)?;// 使用额外账户初始化 ExtraAccountMetaList 账户ExtraAccountMetaList::init::<ExecuteInstruction>(&mut ctx.accounts.extra_account_meta_list.try_borrow_mut_data()?,&account_metas,)?;Ok(())
}

这里有很多内容,让我们逐步理解:

  1. 首先我们声明一个 ExtraAccountMeta 账户的向量 (account_metas),指定我们将使用的不同额外账户。这些可以从种子、公钥等指定。在我们的例子中,我们只需要一个额外账户——鲸鱼详细信息账户。
  2. 我们计算账户大小,并基于此计算租金所需的 lamports 数量。
  3. 我们指定需要签名的种子为 extra_account_meta_list PDA。
  4. 我们调用 create_account CPI 实际创建 extra_account_meta_list 账户,提供所有需要的数据(付款人、签名者种子、账户大小等)。
  5. 最后,我们用在步骤 1 中声明的额外账户向量初始化新创建的账户。

实现 transfer_hook 指令

我们达到了程序的核心——transfer_hook 指令!这是实际操作发生的地方,因为每当进行交易时都会调用此指令。

  1. 我们首先为指令添加传入账户。在 lib.rs 中 InitializeExtraAccountMeta 下方添加以下内容:
#[derive(Accounts)]
pub struct TransferHook<'info> {#[account(token::mint = mint, token::authority = owner)]pub source_token: InterfaceAccount<'info, TokenAccount>,pub mint: InterfaceAccount<'info, Mint>,#[account(token::mint = mint)]pub destination_token: InterfaceAccount<'info, TokenAccount>,/// CHECK: source token account owner,   /// can be SystemAccount or PDA owned by another program  pub owner: UncheckedAccount<'info>,/// CHECK: ExtraAccountMetaList Account,#[account(seeds = [b"extra-account-metas", mint.key().as_ref()],bump)]pub extra_account_meta_list: UncheckedAccount<'info>,#[account(mut, seeds=[b"whale_account"], bump)]pub latest_whale_account: Account<'info, WhaleAccount>,
}

🧑‍🏫 提示

  • 这里指定的账户顺序很重要:
    • 前四个账户是代币转账所需的账户(源、铸造、目标和所有者——按此顺序),
    • 第五个账户是 ExtraAccountMetaList 账户的地址。
    • 剩余的账户是 ExtraAccountMetaList 账户所需的额外账户。
  • 注意我们在这里传递的约束——它们是为了帮助我们确保传递的账户确实是我们期望的账户(即正确的铸造账户,正确的所有者等)。
  1. 现在我们可以继续进行实际指令。在 initialize_extra_account 指令下方添加以下代码片段:
pub fn transfer_hook(ctx: Context<TransferHook>, amount: u64) -> Result<()> {msg!(&format!("Transfer hook fired for an amount of {}", amount));if amount >= 1000 * (u64::pow(10, ctx.accounts.mint.decimals as u32)) {// 我们有一个鲸鱼!ctx.accounts.latest_whale_account.whale_address = ctx.accounts.owner.key();ctx.accounts.latest_whale_account.transfer_amount = amount;emit!(WhaleTransferEvent {whale_address: ctx.accounts.owner.key(),transfer_amount: amount});}Ok(())
}

🦁 这里没有太多疯狂的事情:

  • 我们检查转账金额是否大于或等于 1000 代币(这是我选择的任意金额,你可以选择其他金额)。
  • 如果金额确实是 1000 或更多,我们更新鲸鱼详细信息账户的新地址和金额。
  • 最后,我们发出一个名为 WhaleTransferEvent 的事件,供客户端(例如 Discord 机器人、Web 应用程序等)监听。
  1. 在 lib.rs 底部添加实际的事件声明:
#[event]
pub struct WhaleTransferEvent {pub whale_address: Pubkey,pub transfer_amount: u64,
}

实现 fallback 指令

最后但同样重要的是,fallback 指令。在 transfer_hook 指令之后添加以下代码片段:

pub fn fallback<'info>(program_id: &Pubkey,accounts: &'info [AccountInfo<'info>],data: &[u8],
) -> Result<()> {let instruction = TransferHookInstruction::unpack(data)?;// 匹配指令识别符以执行 transfer hook 接口指令// token2022 程序在代币转移时调用此指令match instruction {TransferHookInstruction::Execute { amount } => {let amount_bytes = amount.to_le_bytes();// 在我们的程序中调用自定义 transfer hook 指令__private::__global::transfer_hook(program_id, accounts, &amount_bytes)}_ => return Err(ProgramError::InvalidInstructionData.into()),}
}

fallback 指令取自 Solana 的hello-world transfer hook 示例 。

虽然看起来很复杂,但这个指令其实相当简单:

  1. 解包指令数据并将其转换为 TransferHookInstruction
  2. 匹配 TransferHookInstruction 枚举。
  3. 如果是 Execute 指令,获取转移的金额并调用 transfer_hook 指令。
  4. 如果不是 Execute 指令,则返回无效指令数据的错误。

继续将程序部署到 Devnet 🎉

第 2 步:铸造

好的,我们的程序已经部署,现在我们可以将注意力转向创建一个实际使用它的代币铸造。

  1. 使用以下命令创建一个铸造:
spl-token --program-id TokenzQdBNbLqP5VEhdkAS6EPFLC1PHnBqCXEpPxuEb create-token --transfer-hook <your transfer hook program id>

🧑‍🏫 提示

  • 注意命令中的程序 id?那是 Token 2022 程序的地址。我们必须指定它以便铸造实际使用新标准。
  • 为铸造注册 transfer hook 就像在 spl-token 命令中添加 --transfer-hook <address> 子命令一样简单。
  1. 为你配置的钱包创建代币账户:
spl-token create-account <the token address from previous step>
  1. 向你的钱包铸造一些代币:
spl-token mint <the token address from previous step> 3000

第 3 步:初始化 ExtraAccountMeta 账户

如果你尝试转移代币(例如使用 spl-token transfer 命令),你将遇到 AccountNotFound 错误。这是因为我们从未初始化我们的老朋友 ExtraAccountMetaList

我们在程序中创建了一个指令来初始化账户,initialize_extra_account,所以现在是调用它的最佳时机。

我创建了这个小的 TypeScript 代码来调用它,但你可以随意使用任何你喜欢的方法:

import { readFile } from "fs/promises";
import * as anchor from "@coral-xyz/anchor";
// 这两个文件是从构建的 Anchor 程序 Target/idl 和 Target/types 文件夹中复制的。
import { TransferHookWhale } from "./program/transfer_hook_whale";
import idl from './program/transfer_hook_whale.json';import { TOKEN_2022_PROGRAM_ID, ASSOCIATED_TOKEN_PROGRAM_ID } from "@solana/spl-token";
import "dotenv/config";const kpFile = ".<your keypair file>";
const mint = new anchor.web3.PublicKey("<your mint public address>")const main = async () => {if (!process.env.SOLANA_RPC) {console.log("Missing required env variables");return;}console.log("💰 Reading wallet...");const keyFile = await readFile(kpFile);const keypair: anchor.web3.Keypair = anchor.web3.Keypair.fromSecretKey(new Uint8Array(JSON.parse(keyFile.toString())));const wallet = new anchor.Wallet(keypair);console.log("☕️ Setting provider and program...");const connection = new anchor.web3.Connection(process.env.SOLANA_RPC);const provider = new anchor.AnchorProvider(connection, wallet, {});anchor.setProvider(provider);const program = new anchor.Program<TransferHookWhale>(idl as TransferHookWhale, provider);console.log("🪝 Initializing transfer hook accounts");const [extraAccountMetaListPDA] = anchor.web3.PublicKey.findProgramAddressSync([Buffer.from("extra-account-metas"), mint.toBuffer()],program.programId);const [whalePDA] = anchor.web3.PublicKey.findProgramAddressSync([Buffer.from("whale_account")], program.programId);const initializeExtraAccountMetaListInstruction = await program.methods.initializeExtraAccount().accounts({mint,extraAccountMetaList: extraAccountMetaListPDA,latestWhaleAccount: whalePDA,systemProgram: anchor.web3.SystemProgram.programId,tokenProgram: TOKEN_2022_PROGRAM_ID,associatedTokenProgram: ASSOCIATED_TOKEN_PROGRAM_ID,}).instruction();const transaction = new anchor.web3.Transaction().add(initializeExtraAccountMetaListInstruction);const tx = await anchor.web3.sendAndConfirmTransaction(connection, transaction, [wallet.payer], {commitment: "confirmed",});console.log("Transaction Signature:", tx);
}main().then(() => {console.log("done!");process.exit(0);
}).catch((e) => {console.log("Error: ", e);process.exit(1);
});

💈 完整项目在GitHub

第 4 步:让转移开始!

就是这样,朋友们!随着 transfer hook 程序的部署,配置使用它的铸造,以及 ExtraAccountMetaList 账户的初始化,我们终于可以开始使用我们的 hook 了:

transfer hook 正在运行,更多相关信息,,https://t.me/gtokentool 

 

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

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

相关文章

自定义类型:结构体(一)

一 . 结构体的相关概念 结构体&#xff0c;无需多言&#xff0c;是我们的老朋友了&#xff0c;我们之前就学习过一些有关结构体的知识&#xff0c;今天我们就来正式认识一下这个朋友 结构体属于一种自定义类型&#xff0c;在我们C语言中&#xff1a;自定义类型并非只有结构体…

使用匿名管道时出现程序一直运行问题

父进程创建两个子进程&#xff0c;父子进程之间利用管道进行通信。要求能显示父进程、子进程各自的信息&#xff0c;体现通信效果。(源程序pipe_1.c) 一开始&#xff0c;我忘了初始化pipe,很傻*的直接把fd当管道使&#xff0c;出现了儿子喊爸爸"i am your father."的…

协程4 --- 一个特殊的栈溢出例子

文章目录 代码运行结果分析 代码 先看下面这个程序流程&#xff1a; 有个长度位24的字符数组buffer&#xff0c;前面16个字符初始化。 把attack函数的地址复制到后面8个字符&#xff08;编译成64位程序&#xff0c;指针大小为8Byte&#xff09;。 打印信息&#xff1a;do Some…

C++用string实现字符串相加

. - 力扣&#xff08;LeetCode&#xff09; -》》》》》题目链接 实现思路&#xff1a;计算数字符串长度并用数组的方式计算出字符位置&#xff0c;用字符的ask码‘0’计算出字符本身。 class Solution { public:string addStrings(string num1, string num2) {string str;int…

03 Oracle进程秘籍:深度解析Oracle后台进程体系

文章目录 Oracle进程秘籍&#xff1a;深度解析Oracle后台进程体系一、Oracle后台进程概览1.1 DBWn&#xff08;Database Writer Process&#xff09;1.2 LGWR&#xff08;Log Writer Process&#xff09;1.3 SMON&#xff08;System Monitor Process&#xff09;1.4 PMON&#…

【大数据学习 | kafka高级部分】文件清除原理

2. 两种文件清除策略 kafka数据并不是为了做大量存储使用的&#xff0c;主要的功能是在流式计算中进行数据的流转&#xff0c;所以kafka中的数据并不做长期存储&#xff0c;默认存储时间为7天 那么问题来了&#xff0c;kafka中的数据是如何进行删除的呢&#xff1f; 在Kafka…

浏览器存储策略解析(三)Local/sessionStorage实战:如何查看本地浏览器上数据

物理意义上的localStorage/sessionStorage在哪里 我们都知道&#xff0c;localStorage存于本地&#xff0c;sessionStorage存于会话&#xff0c;这是见名知意可以得到的。但是在物理层面他们究竟存储在哪里呢&#xff1f; localStorage和sessionStorage一样&#xff0c;是存储…

设计模式讲解02—责任链模式(Chain)

1. 概述 定义&#xff1a;责任链模式是一种行为型模式&#xff0c;在这个模式中&#xff0c;通常创建了一个接收者对象的链来处理请求&#xff0c;该请求沿着链的顺序传递。直到有对象处理该请求为止&#xff0c;从而达到解耦请求发送者和请求处理者的目的。 解释&#xff1a;责…

判断二叉搜索树(递归)

给你一个二叉树的根节点 root &#xff0c;判断其是否是一个有效的二叉搜索树。binary search tree (BST) 有效 二叉搜索树定义如下&#xff1a; 节点的左子树只包含 小于 当前节点的数。节点的右子树只包含 大于 当前节点的数。所有左子树和右子树自身必须也是二叉搜索树。 …

私有化视频平台EasyCVR海康大华宇视视频平台视频诊断技术是如何实时监测视频质量的?

在现代视频监控系统中&#xff0c;确保视频流的质量和稳定性至关重要。随着技术的进步&#xff0c;视频诊断技术已经成为实时监测视频质量的关键工具。这种技术通过智能分析算法对视频流进行实时评估和处理&#xff0c;能够自动识别视频中的各种质量问题&#xff0c;并给出相应…

大语言模型(LLM)量化基础知识(一)

请大家关注我的知乎博客&#xff1a;- 派神 - - 知乎 随着大型语言模型 (LLM) 的参数数量的增长,与其支持硬件&#xff08;加速器内存&#xff09;增长速度之间的差距越来越大&#xff0c;如下图所示&#xff1a; 上图显示&#xff0c;从 2017 年到 2022 年&#xff0c;语言模…

【comfyui教程】ComfyUI 现已支持 Stable Diffusion 3.5 Medium!人人都能轻松上手的图像生成利器

前言 ComfyUI 现已支持 Stable Diffusion 3.5 Medium&#xff01;人人都能轻松上手的图像生成利器 大家翘首以盼的Stable Diffusion 3.5 Medium模型终于来了&#xff01;就在今天&#xff0c;Stability AI 正式推出了这款“亲民版”平衡模型&#xff0c;让创作者们得以在消费…

大模型微调技术 --> LoRA 系列之 AdaLoRA

AdaLoRA 1.摘要 之前的微调方法(如低秩更新)通常将增量更新的预算均匀地分布在所有预训练的权重矩阵上&#xff0c;并且忽略了不同权重参数的不同重要性。结果&#xff0c;微调结果不是最优的。 为了弥补这一差距&#xff0c;我们提出了AdaLoRA&#xff0c;它根据权重矩阵的…

带你搞懂红黑树的插入和删除

文章目录 1. 红黑树1.1 红黑树的概念1.2 红黑树的性质1.3 红黑树节点的定义1.4 红黑树的插入找到插入的位置调节平衡 1.5 红黑树的删除删除节点平衡调整 1.6 红黑树和AVL树的比较 1. 红黑树 1.1 红黑树的概念 红黑树也是一种二叉搜索树,但是在每一个节点上增加了一个存储位表…

揭秘全向轮运动学:机动艺术与上下位机通信的智慧桥梁

✨✨ Rqtz 个人主页 : 点击✨✨ &#x1f308;Qt系列专栏:点击 &#x1f388;Qt智能车上位机专栏: 点击&#x1f388; 本篇文章介绍的是有关于全向轮运动学分析&#xff0c;单片机与上位机通信C代码以及ROS里程计解算的内容。 目录 大纲 ROS&#xff08;机器人操作系统&…

移远通信推出八款天线新品,覆盖5G、4G、Wi-Fi和LoRa领域

近日&#xff0c;全球领先的物联网整体解决方案供应商移远通信宣布&#xff0c;再次推出八款高性能天线新品&#xff0c;进一步丰富其天线产品阵容&#xff0c;更好地满足全球客户对高品质天线的更多需求。具体包括5G超宽带天线YECT005W1A和YECT004W1A、5G天线YECT028W1A、4G天…

【设计模式系列】桥接模式(十三)

一、什么是桥接模式 桥接模式&#xff08;Bridge Pattern&#xff09;是一种结构型设计模式&#xff0c;其核心目的是将抽象部分与实现部分分离&#xff0c;使它们可以独立地变化。这种模式主要用于处理那些在设计时无法确定实现细节的场合&#xff0c;或者需要在多个实现之间…

Java多态和继承(下篇)

今天接着学习多态和继承 目录 1 继承1.1 再谈初始化1.2 protect关键字1.3 继承方式1.4 final 关键字1.5 组合 2 多态2.1 多态的概念2.2 多态实现条件2.3 重写2.4 向上转型和向下转型2.4.1 向上转型2.4.2 向下转型 2.5 多态的优缺点2.6 避免在构造方法中使用重写的方法 总结 1 继…

动态规划理论基础和习题【力扣】【算法学习day.25】

前言 ###我做这类文档一个重要的目的还是给正在学习的大家提供方向&#xff08;例如想要掌握基础用法&#xff0c;该刷哪些题&#xff1f;&#xff09;我的解析也不会做的非常详细&#xff0c;只会提供思路和一些关键点&#xff0c;力扣上的大佬们的题解质量是非常非常高滴&am…

数据结构之顺序表(C语言)

1 线性表 线性表是n个具有相同特性的数据元素的有限序列&#xff0c;是一种在实际中广泛应用的数据结构&#xff0c;常见的线性表有&#xff1a;顺序表、链表、栈、队列、字符串等。 线性表在逻辑上是线性结构&#xff0c;也就说是连续的一条直线。但是在物理结构上并不一定是…