【JDBC】Java连接数据库

目录

  • JDBC的工作原理
  • JDBC API:
  • JDBC开发步骤
    • 加载并注册JDBC驱动:
    • 建立数据库连接:
    • 创建Statement对象:
    • 执行SQL语句:
    • 处理结果:
    • Connection接口的常用方法
    • Statement接口的常用方法
    • ResultSet接口的常用方法
  • SQL注入
    • 注入原理
    • 防止SQL注入的方法
    • PreparedStatement接口
      • 使用
      • 代码示例(部分)
  • 代码封装+DAO模式
    • DAO起着转换器的作用
    • Properties类来读取配置文件
      • 代码示例
    • JDBC封装步骤
    • 数据库连接池
      • 程序中的连接池技术
      • 连接池的工作原理
      • 数据源
      • 三层架构
        • 分层的特点
        • 分层原则
        • 案例:使用分层开发实现登录的思路
      • BaseDao
      • DataSourceConfig
      • 数据库连接池:DruidDataSourceConfig
      • 统一响应模板
      • 实体类
      • 数据访问层——Dao层
      • 业务逻辑层——service层

JDBC (Java DataBase Connectivity)是Java数据库连接技术的简称,提供连接各种常用数据库的能力

JDBC的工作原理

  • SUN提供一套访问数据库的规范(就是一组接口),并提供连接数据库的协议标准
  • 各个数据库厂商会提供一套API用来访问自己公司的数据库服务器,且API遵循SUN的规范
  • JDBC是里面封装着操作各数据库的接口,而JDBC驱动才是接口的实现,没有驱动无法完成数据库连接!每个数据库厂商都有自己的驱动,用来连接自己公司的数据库。
    在这里插入图片描述

JDBC API:

  1. DriverManager类 作用:管理各种不同的JDBC驱动
  2. Connection接口:负责连接数据库并担任传送数据的任务
  3. Statement接口:由 Connection 产生、负责发送执行SQL语句
  4. ResultSet接口:负责保存Statement执行后所产生的查询结果
    在这里插入图片描述

JDBC开发步骤

加载并注册JDBC驱动:

  • 这是建立数据库连接的第一步,我们需要先加载JDBC驱动,然后通过DriverManager的registerDriver方法进行注册。
    先导入依赖:mysql-connector-java-5.1.46.jar
    Class.forName("com.mysql.jdbc.Driver");
    

建立数据库连接:

  • 通过DriverManager的getConnection方法,我们可以建立与数据库的连接。

    String url = "jdbc:mysql://127.0.0.1:3306/myschool?useSSL=false";
    String userName = "root";
    String password = "123456";
    Connection conn = DriverManager.getConnection(url,userName,password);
    

创建Statement对象:

  • 通过Connection对象的createStatement方法,我们可以创建一个Statement对象,用于执行SQL语句。

    Statement stmt = conn.createStatement();
    

执行SQL语句:

  • 通过Statement对象的executeQuery或executeUpdate方法,我们可以执行SQL语句,获取结果或者更新数据库。

           String sql = "SELECT COUNT(1) FROM USER";ResultSet rs = stmt.executeQuery(sql);
    

处理结果:

  • 对于查询操作,我们需要处理ResultSet结果集;对于更新操作,我们不需要处理结果。

    			int userCount = 0;while (rs.next()){//userCount = rs.getInt(1);userCount = rs.getInt("count(1)");}System.out.println("该表中一共有" + userCount + "条记录!");
    
  1. 关闭资源:
  • 最后,我们需要关闭打开的资源,包括ResultSet、Statement和Connection。

    		    if(rs!=null){rs.close();}if(stmt!=null){stmt.close();}if(conn!=null){conn.close();}
    

Connection接口的常用方法

在这里插入图片描述

Statement接口的常用方法

在这里插入图片描述

ResultSet接口的常用方法

在这里插入图片描述

SQL注入

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

注入原理

注入原理:利用现有应用程序,将(恶意的)SQL命令注入到后台数据库引擎执行的能力,它可以通过在Web表单中输入(恶意)SQL语句得到一个存在安全漏洞的网站上的数据库,而不是按照设计者意图去执行SQL语句

防止SQL注入的方法

  1. 过滤用户输入的数据中是否包含非法字符;
  2. 分步校验!先使用用户名来查询用户,如果查找到了,再比较密码;
  3. 使用 PreparedStatement 接口。

PreparedStatement接口

PreparedStatement接口是Statement的子接口,你可以使用该接口来替换Statement接口。

  • 提高了代码的可读性和可维护性
  • 提高了SQL语句执行的性能
  • 提高了安全性

使用

  • 使用Connection对象的prepareStatement(String sql):即创建它时就让它与一条SQL语句绑定;
  • 编写SQL语句时,如果存在参数,使用“?”作为数据占位符;
  • 调用PreparedStatement的setXXX()系列方法为占位符设置值,索引从1开始;
  • 调用executeUpdate()或executeQuery()方法,但要注意,调用没有参数的方法;

代码示例(部分)

    /*** 用户登录* @param userName 用户名* @param userPass 用户密码* @return*/public User toLogin(String userName,String userPass){//1.获取连接对象getConnection();//2.编写SQL语句String sql = "select ID,USERNAME,ROLE from user where userName = ? and userPass = ?";System.out.println("要执行的SQL语句是:" + sql);//3.创建statement对象User user = null;try {ps = connection.prepareStatement(sql);//3.1处理参数ps.setString(1,userName);ps.setString(2,userPass);//4.执行并解析结果resultSet = ps.executeQuery();while (resultSet.next()){user = new User();user.setId(resultSet.getInt(1));user.setUserName(resultSet.getString(2));user.setRole(resultSet.getInt(3));}} catch (SQLException e) {e.printStackTrace();}finally {closeResource();}return user;}

代码封装+DAO模式

加载驱动、建立连接、关闭资源与业务无关。而业务中又要根据多个SQL的执行结果来进行业务处理,若代码全都放在一起,则:

  1. 可读性差
  2. 不利于后期修改和维护
  3. 不利于代码复用

采用面向接口编程,可以降低代码间的耦合性

  • 隔离业务逻辑代码和数据访问代码
  • 隔离不同数据库的实现
    在这里插入图片描述

DAO起着转换器的作用

把实体类转换为数据库中的记录,dao层也被成为数据访问层
在这里插入图片描述

Properties类来读取配置文件

信息存储在MySQL数据库中,但在开发和部署时有可能使用不同的数据库,也可能因为客户的需求而更换数据库产品。数据库连接信息直接写死在java代码中会导致切换麻烦,因此可以将这类信息写在外部的配置文件中,这样切换配置/环境时,不需要重新编译程序。
让用户脱离程序本身修改相关的变量设置——使用配置文件

在这里插入图片描述

代码示例

private static String driverClassName;private static String url;private static String username;private static String password;static{Properties properties = new Properties();String path = "database.properties";InputStream is = BaseDao.class.getClassLoader().getResourceAsStream(path);try {properties.load(is);} catch (IOException e) {e.printStackTrace();}driverClassName = properties.getProperty("driverClassName");url = properties.getProperty("url");username = properties.getProperty("username");password = properties.getProperty("password");}

JDBC封装步骤

  1. 定义实体类传输数据;
  2. 将所有增删改查操作抽取成接口;
  3. 由不同数据库的实现类分别实现接口;
  4. 将通用的操作(打开、关闭连接、增、删、改、查等)封装到数据库工具类BaseDao的通用方法中。
    在这里插入图片描述

数据库连接池

  • 当一个用户要使用软件时,就需要频繁的使用数据库进行增删改查,每次增删改查操作都需要获取连接,频繁的连接导致系统的安全性和稳定性差。
  • 如果说一个用户的频繁获取连接尚能接受,那么成千上万的用户进行增删改查来获取连接,对系统来说将是一个巨大的负荷!
  • 我们可以设计一个用来存放连接的池子,这个池子起名为连接池。
  • 连接池中存放一定数量的连接,当用户需要获取连接时,就从这个池子中获取,用完后关闭资源,再将连接放回连接池。
  • 如此,一个连接就可以被反复使用,大大降低系统的压力解决了建立数据库连接耗费资源和时间很多的问题,提高了性能。

程序中的连接池技术

  • 连接池技术的核心思想是:连接复用,通过建立一个数据库连接池以及一套连接使用、分配、管理策略,使得该连接池中的连接可以得到高效、安全的复用,避免了数据库连接频繁建立、关闭的开销。
  • 由于对JDBC中的原始连接进行了封装,从而方便了数据库应用对于连接的使用(特别是对于事务处理),提高了获取数据库连接效率,也正是因为这个封装层的存在,隔离了应用的本身的处理逻辑和具体数据库访问逻辑,使应用本身的复用成为可能。
  • 连接池主要由三部分组成:连接池的建立、连接池中连接的使用管理、连接池的关闭。

连接池的工作原理

在这里插入图片描述连接池自动分配连接对象并对闲置的连接进行回收

数据源

  • 连接池中的连接对象是由谁创建的呢——数据源
  • javax.sql.DataSource接口负责建立与数据库的连接;
  • 各个厂商需要让自己的连接池实现这个接口,缩减开发成本。
  • 知名的连接池厂商:DBCP 、C3P0、Druid(阿里巴巴)

三层架构

表示层、业务逻辑层、数据访问层

分层的特点
  • 分层将解决方案的组件分隔到不同的层中
  • 在同一个层中组件之间保持内聚性
  • 层与层之间保持松耦合
  • 每一层都有自己的职责
  • 上一层不用关心下一层的实现细节,上一层通过下一层提供的对外接口来使用其功能
  • 上一层调用下一层的功能,下一层不能调用上一层功能
    在这里插入图片描述
分层原则
  1. 封装性原则:每个层次向外公开接口,但是隐藏内部细节
    比如:钥匙开锁,只知道锁提供的接口,但不知道锁的内部细节

  2. 顺序访问原则:下一层为上一层服务,但不使用上层的服务
    比如:盖楼时需要先打地基,地基为上层建筑服务,但不使用上层的服务

分层结构中,不同层之间通过实体类传输数据
在这里插入图片描述

案例:使用分层开发实现登录的思路
  1. 表示层:设计用户登录界面,提醒用户输入用户名和密码,发送登录请求,调用业务逻辑层相关的接口,处理登录请求。
  2. 业务逻辑层:设计业务逻辑层的业务接口,设计业务接口的实现类,在相应的方法中调用数据访问层的接口,处理数据访问层返回的数据,将处理的结果返回给表示层。
  3. 数据访问层:设计数据访问层的接口,设计接口的实现类,执行查询操作,返回数据给业务层。

BaseDao

package com.myschool.day05.base;import com.myschool.day05.config.DataSourceConfig;import java.io.IOException;
import java.io.InputStream;
import java.sql.*;
import java.util.List;
import java.util.Properties;/*** @author: zjl* @datetime: 2024/1/13* @desc:*/
public abstract class BaseDao {private static DataSourceConfig dataSourceConfig = DataSourceConfig.getInstance();private static String driverClassName = dataSourceConfig.getValue("driverClassName");private static String url = dataSourceConfig.getValue("url");private static String username = dataSourceConfig.getValue("username");private static String password = dataSourceConfig.getValue("password");private PreparedStatement ps;public ResultSet rs;//1.加载驱动、创建数据库连接对象public static Connection getConn(){Connection conn = null;try {Class.forName(driverClassName);conn = DriverManager.getConnection(url,username,password);conn.setAutoCommit(false);} catch (ClassNotFoundException e) {e.printStackTrace();} catch (SQLException e) {e.printStackTrace();}return conn;}//2.封装增删改的通用方法public int executeUpdate(Connection conn, String sql, List<Object> params) throws SQLException {int line = 0;try {ps = conn.prepareStatement(sql);if(params!=null && !params.isEmpty()){for (int i = 0; i < params.size(); i++) {ps.setObject((i + 1),params.get(i));}}line = ps.executeUpdate();} catch (SQLException e) {e.printStackTrace();}finally {close();}return line;}//3.封装查询的通用方法public ResultSet executeQuery(Connection conn, String sql, List<Object> params) throws SQLException {ps = conn.prepareStatement(sql);if(params!=null && !params.isEmpty()){for (int i = 0; i < params.size(); i++) {ps.setObject((i + 1),params.get(i));}}rs = ps.executeQuery();return rs;}//4.关闭链接public void close() throws SQLException {if(rs!=null){rs.close();}if(ps!=null){ps.close();}}
}

DataSourceConfig

package com.myschool.day05.config;import java.io.IOException;
import java.io.InputStream;
import java.util.Properties;/*** @author: zjl* @datetime: 2024/1/13* @desc:*/
public class DataSourceConfig {private static DataSourceConfig dataSourceConfig;private Properties properties;private DataSourceConfig(){properties = new Properties();String path = "database.properties";InputStream is = DataSourceConfig.class.getClassLoader().getResourceAsStream(path);try {properties.load(is);} catch (IOException e) {e.printStackTrace();}}public static DataSourceConfig getInstance(){if(dataSourceConfig == null){ synchronized (DataSourceConfig.class){if(dataSourceConfig == null){dataSourceConfig = new DataSourceConfig();}}}return dataSourceConfig;}public String getValue(String key){return properties.getProperty(key);}
}

数据库连接池:DruidDataSourceConfig

package com.myschool.day05.config;import com.alibaba.druid.pool.DruidDataSourceFactory;import javax.sql.DataSource;
import java.io.IOException;
import java.sql.Connection;
import java.util.Properties;/*** @author: zjl* @datetime: 2024/1/16* @desc:*/
public class DruidDataSourceConfig {private static DruidDataSourceConfig dataSourceConfig;private Properties properties;private static DataSource dataSource;public DruidDataSourceConfig(){properties = new Properties();try {properties.load(DruidDataSourceConfig.class.getClassLoader().getResourceAsStream("database.properties"));dataSource = DruidDataSourceFactory.createDataSource(properties);} catch (IOException e) {e.printStackTrace();} catch (Exception e) {e.printStackTrace();}}public static DruidDataSourceConfig getInstance(){if(dataSourceConfig == null){synchronized (DruidDataSourceConfig.class){if (dataSourceConfig == null) {dataSourceConfig = new DruidDataSourceConfig();}}}return dataSourceConfig;}public Connection getConnection() {try {Connection connection = dataSource.getConnection();connection.setAutoCommit(false);return connection;} catch (Exception e) {e.printStackTrace();}return null;}
}

统一响应模板

package com.myschool.day05.vo;/*** @author: zjl* @datetime: 2024/1/13* @desc:*/
public class ResponseResult<T> {//private boolean success;//响应状态private int code;//响应码private String msg;//响应信息private T data;//响应数据//有响应数据的模板方法public ResponseResult(int code, String msg, T data) {this.code = code;this.msg = msg;this.data = data;}//无响应数据的模板方法public ResponseResult(int code, String msg) {this.code = code;this.msg = msg;}public int getCode() {return code;}public void setCode(int code) {this.code = code;}public String getMsg() {return msg;}public void setMsg(String msg) {this.msg = msg;}public T getData() {return data;}public void setData(T data) {this.data = data;}
}

实体类

package com.myschool.day05.pojo;/*** @author: zjl* @datetime: 2024/1/10* @desc:*/
public class User {private int id;private String userName;private String userPass;private int role;public User(int id, String userName, String userPass, int role) {this.id = id;this.userName = userName;this.userPass = userPass;this.role = role;}public User() {}public int getId() {return id;}public void setId(int id) {this.id = id;}public String getUserName() {return userName;}public void setUserName(String userName) {this.userName = userName;}public String getUserPass() {return userPass;}public void setUserPass(String userPass) {this.userPass = userPass;}public int getRole() {return role;}public void setRole(int role) {this.role = role;}@Overridepublic String toString() {return "User{" +"id=" + id +", userName='" + userName + '\'' +", userPass='" + userPass + '\'' +", role=" + role +'}';}
}

数据访问层——Dao层

package com.myschool.day05.dao;import com.myschool.day05.pojo.User;import java.sql.Connection;
import java.sql.SQLException;
import java.util.List;public interface UserDao {User selectUserByUserNameAndUserPass(Connection conn,String userName, String userPass) throws SQLException;List<User> selectUserByUserNameAndRole(Connection conn,String keyWords,int role) throws SQLException;int updateUserPassById(Connection conn,User user) throws SQLException;
}package com.myschool.day05.dao.impl;import com.myschool.day05.base.BaseDao;
import com.myschool.day05.dao.UserDao;
import com.myschool.day05.pojo.User;
import com.mysql.jdbc.StringUtils;import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;/*** @author: zjl* @datetime: 2024/1/13* @desc:*/
public class UserDaoImpl extends BaseDao implements UserDao {@Overridepublic User selectUserByUserNameAndUserPass(Connection conn, String userName, String userPass) throws SQLException {String sql = "SELECT ID,USERNAME,ROLE FROM USER WHERE USERNAME = ? AND USERPASS=?";List<Object> params = new ArrayList<>();Collections.addAll(params,userName,userPass);User user = null;try {rs = executeQuery(conn,sql,params);while (rs.next()){user = new User();user.setId(rs.getInt(1));user.setUserName(rs.getString(2));user.setRole(rs.getInt(3));}}finally {this.close();}return user;}/*** 如果 keyWords为null,role==0  表示查询全部* 如果 keyWords为null,role!=0  表示按照role查询* 如果 keyWords不为null,role==0  表示按照userName模糊查询* 如果 keyWords不为null,role!=0  表示按照userName模糊查询并且按照role查询* @param conn* @param keyWords* @param role* @return* @throws SQLException*/@Overridepublic List<User> selectUserByUserNameAndRole(Connection conn,String keyWords,int role) throws SQLException {//String sql = "SELECT * FROM USER WHERE 1=1";StringBuffer sbf = new StringBuffer("SELECT * FROM USER WHERE 1=1");List<User> userList = new ArrayList<>();try {List<Object> params = new ArrayList<>();//if(keyWords!=null && keyWords.trim().length()>0){if(!StringUtils.isNullOrEmpty(keyWords)){sbf.append(" AND USERNAME LIKE CONCAT('%',?,'%') ");params.add(keyWords);}if(role != 0){sbf.append(" AND ROLE = ?");params.add(role);}System.out.println("动态的SQL语句是:" + sbf.toString());rs = executeQuery(conn,sbf.toString(),params);User user = null;while (rs.next()){user = new User();user.setId(rs.getInt(1));user.setUserName(rs.getString(2));user.setUserPass(rs.getString(3));user.setRole(rs.getInt(4));userList.add(user);}}finally {close();}return userList;}@Overridepublic int updateUserPassById(Connection conn,User user) throws SQLException {String sql = "UPDATE USER SET USERPASS=? WHERE ID=?";List<Object> params = new ArrayList<>();Collections.addAll(params,user.getUserPass(),user.getId());int line = executeUpdate(conn,sql,params);return line;}
}

业务逻辑层——service层

package com.myschool.day05.service;import com.myschool.day05.pojo.User;
import com.myschool.day05.vo.ResponseResult;import java.util.List;public interface UserService {/*** 用户登录的业务* @param userName* @param userPass* @return*/ResponseResult<User> login(String userName,String userPass);ResponseResult<List<User>> getUserList(String keyWords,int role);ResponseResult modifyPassword(User user);
}package com.myschool.day05.service.impl;import com.myschool.day05.base.BaseDao;
import com.myschool.day05.config.DruidDataSourceConfig;
import com.myschool.day05.dao.UserDao;
import com.myschool.day05.dao.impl.UserDaoImpl;
import com.myschool.day05.pojo.User;
import com.myschool.day05.service.UserService;
import com.myschool.day05.vo.ResponseResult;
import org.apache.log4j.Logger;import java.sql.Connection;
import java.sql.SQLException;
import java.util.List;/*** @author: zjl* @datetime: 2024/1/13* @desc:*/
public class UserServiceImpl implements UserService {Logger log = Logger.getLogger(UserServiceImpl.class);UserDao userDao = new UserDaoImpl();@Overridepublic ResponseResult<User> login(String userName, String userPass) {log.info("登录请求:"+userName+" "+userPass);//Connection conn = BaseDao.getConn();Connection conn = DruidDataSourceConfig.getInstance().getConnection();try {User user = userDao.selectUserByUserNameAndUserPass(conn,userName,userPass);//System.out.println(5/0);log.info("登录信息是:" + user);if(user!=null){return new ResponseResult<>(200,"登录成功!",user);}return new ResponseResult<>(0,"登录失败!");}catch (Exception e){log.error("程序异常,异常信息为:" + e);e.printStackTrace();return new ResponseResult<>(500,"程序错误!");}finally {try {if (conn!=null) {conn.close();}} catch (SQLException e) {e.printStackTrace();}}}@Overridepublic ResponseResult<List<User>> getUserList(String keyWords,int role) {Connection conn = BaseDao.getConn();try {List<User> userList = userDao.selectUserByUserNameAndRole(conn,keyWords,role);if(userList!=null && !userList.isEmpty()){return new ResponseResult<>(200,"查询用户列表成功!",userList);}return new ResponseResult<>(0,"查询用户列表失败!");}catch (Exception e){e.printStackTrace();}finally {try {if (conn!=null) {conn.close();}} catch (SQLException e) {e.printStackTrace();}}return new ResponseResult<>(500,"程序异常!");}@Overridepublic ResponseResult modifyPassword(User user) {Connection conn = BaseDao.getConn();try {int line = userDao.updateUserPassById(conn,user);if (line > 0){conn.commit();return new ResponseResult(200,"密码修改成功!请重新登陆!");}return new ResponseResult(0,"密码修改失败!请检查数据!");}catch (Exception e){e.printStackTrace();}finally {try {if (conn!=null) {conn.close();}} catch (SQLException e) {e.printStackTrace();}}try {conn.rollback();} catch (SQLException e) {e.printStackTrace();}return new ResponseResult(500,"程序错误!");}
}

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

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

相关文章

LeetCode.2917. 找出数组中的 K-or 值

题目 2917. 找出数组中的 K-or 值 分析 这道题其实是要我们求第i位二进制为1的元素个数至少为k&#xff0c;把符合条件的2^i全部加到一起。 因此&#xff0c;我们的思路就是枚举数组的每一位&#xff0c;并且进行以下两个步骤&#xff1a; 统计所有元素第i位1的个数cnt。…

20240306-1-大数据的几个面试题目

面试题目 1. 相同URL 题目: 给定a、b两个文件&#xff0c;各存放50亿个url&#xff0c;每个url各占64字节&#xff0c;内存限制是4G&#xff0c;让你找出a、b文件共同的url&#xff1f; 方案1&#xff1a;估计每个文件的大小为50G64320G&#xff0c;远远大于内存限制的4G。所以…

【系统学习】2-Java进阶知识总结-3-集合-1-补充【泛型、树、数据结构】

文章目录 泛型什么是泛型&#xff1f;常见的泛型标识符泛型类泛型方法泛型接口通配符 树树的基本概念什么是二叉树&#xff1f;二叉树--普通二叉树二叉树--二叉查找树定义规则优缺点 二叉树--平衡二叉树定义规则旋转机制 二叉树--红黑树定义规则红黑规则 常见数据结构总体特点结…

实时渲染技术流化方案在ilab评审中有哪些作用?

先说两个在日常沟通中一线用户反馈的&#xff0c;高校虚拟仿真课程在使用中遇到的场景。 场景1&#xff1a;虚拟仿真课程开发比较早&#xff0c;当时使用的引擎是 web player&#xff0c;学生使用的机器也好几年了&#xff0c;原来的课程在使用的过程中加载很慢&#xff0c;无…

数据结构—KMP 算法:

算法思想&#xff1a; KMP算法实现寻找主串中子串的位置时&#xff0c;主串指针地址不回退&#xff0c;在比对过程中串仅仅遍历一次&#xff0c;子串的回退可以是与当前主串可重新最多匹配的地址位置。 BF与KMP算法比对&#xff1a; KMP BF 主串不用回退 主串回退&#xf…

OracleXE112、plsqldev1207的安装和基本配置

OracleXE112、plsqldev1207的安装和基本配置 OracleXE112、plsqldev1207的安装和基本配置Oracle安装oracle是什么Oracle两个版本下载安装包 安装OracleXE112_Win64注意&#xff1a;安装到空目录下&#xff1b;输入口令&#xff08;记住啊&#xff01;&#xff09;安装成功&…

线性表试题(二)——顺序表应用

二、综合应用题 01&#xff0e;从顺序表中删除具有最小值的元素&#xff08;假设唯一&#xff09;并由函数返回被删元素的值。空出的位置由最后一个元素填补&#xff0c;若顺序表为空&#xff0c;则显示出错信息并退出运行。 02&#xff0e;设计一个高效算法&#xff0c;将顺序…

Leetcoder Day39| 动态规划part06 完全背包问题

完全背包理论 有N件物品和一个最多能背重量为W的背包。第i件物品的重量是weight[i]&#xff0c;得到的价值是value[i] 。每件物品都有无限个&#xff08;也就是可以放入背包多次&#xff09;&#xff0c;求解将哪些物品装入背包里物品价值总和最大。 示例&#xff1a; 背包最大…

第 5 章 ROS常用组件动态坐标变换(自学二刷笔记)

5.1.3 动态坐标变换 所谓动态坐标变换&#xff0c;是指两个坐标系之间的相对位置是变化的。 需求描述: 启动 turtlesim_node&#xff0c;该节点中窗体有一个世界坐标系(左下角为坐标系原点)&#xff0c;乌龟是另一个坐标系&#xff0c;键盘控制乌龟运动&#xff0c;将两个坐…

书籍强烈推荐:“计算机界三大神书”之一 ——SICP

文章目录 1. 书籍推荐2. 粉丝福利3. 自主购买 1. 书籍推荐 《计算机程序的构造和解释》&#xff08;Structure and Interpretation of Computer Programs&#xff0c;简记为 SICP&#xff09;是MIT的基础课教材&#xff0c;出版后引起计算机教育界的广泛关注&#xff0c;对推动…

鸿蒙Harmony应用开发—ArkTS声明式开发(基础手势:Checkbox)

提供多选框组件&#xff0c;通常用于某选项的打开或关闭。 说明&#xff1a; API version 11开始&#xff0c;Checkbox默认样式由圆角方形变为圆形。 该组件从API Version 8开始支持。后续版本如有新增内容&#xff0c;则采用上角标单独标记该内容的起始版本。 子组件 无 接口…

Android视角看鸿蒙第一课(工程目录)

Android视角看鸿蒙第一课&#xff08;工程目录&#xff09; 导读 鸿蒙马上就来了&#xff0c;这个工作很有可能落到Android开发的头上&#xff0c;既是机遇也是挑战&#xff0c;希望能跟上时代的浪潮&#xff0c;迫不得已开始学习鸿蒙开发&#xff0c;顺带分享记录下 我的学…