精华内容
下载资源
问答
  • 前言 MyBatis,曾经给我的感觉是一个很神奇的东西,我们只...有人会说是动态代理,现在我就来通过手写一个迷你版的MyBatis来彻底理解它的设计思想! 如果你不了解JDK动态代理,请参考:《纯手写实现JDK动态代理》 ...

    前言


    MyBatis,曾经给我的感觉是一个很神奇的东西,我们只需要按照规范写好XXXMapper.xml以及XXXMapper.java接口。要知道我们并没有提供XXXMapper.java的实现类,MyBatis到底是怎么做到这一点的呢?有人会说是动态代理,现在我就来通过手写一个迷你版的MyBatis来彻底理解它的设计思想!

    如果你不了解JDK动态代理,请参考:《纯手写实现JDK动态代理》

    如果你不了解MyBatis的使用,请参考:《MyBatis+Spring MVC开发指南(一)》

    如果你对Spring MVC感兴趣,请参考:《写出我的第一个框架:迷你版Spring MVC》

     

    动手写一个迷你版的MyBatis


    MyBatis原理架构图

     

    其实对于MyBatis最为关键的就在于:

    XXXMapper mapper = sqlSession.getMapper(XXXMapper.class);

    大家可以以这个为切入口,进行源码跟踪,容易得到上面的调用链。

    我们先来看一下迷你版MyBatis的整体框架思路:

    迷你版MyBatis

     

    执行器MyExecutor:

    MyExecutor提供query方法

     

    在MyBatis中,比如说select有多种形式,比如selectOne,selectList,那么其实到最后,还是向JDBC发出一个SQL而已。对于执行器而言,其实对于查询,提供一个query接口就可以了。

    这里,为了简便,直接执行已经处理好的SQL语句(动态SQL以及输入类型,这不是迷你版MyBatis关心的)。另外执行器的实现类MyBaseExecutor其实就是一段JDBC的操作代码。

    query的JDBC实现

     

    这里为了简化处理,在RequestMapping这块硬编码了。

    StudentMapper.java/StudentMapper.xml:

    Mapper接口

     

    Mapper.xml

     

    这里,为了不牵涉到XML的解析过程,直接提供已经处理完毕的结果。其实就是namespace/statementID/SQL的存储、映射。

    对外暴露的API接口(MySqlSession):

    MySqlSession

     

    MySqlSession实现

     

    从这里,你能够看到一些端倪:

    第一,MyDefaultSqlSession持有执行器的引用,调用selectOne等方法,就是在调用执行器的query方法。

    第二,在getMapper的获取过程中,我们看到了具体业务处理Handler的身影:MyMapperProxy,根据JDK动态代理的知识,我们知道,最终都是要回调Handler的invoke方法完成的。

    MyMapperProxy:

    MyMapperProxy

     

    当invoke方法被调用时,我们根据调用的方法,进行反射,得到namespace以及对应的SQL,然后,我们把SQL交给sqlSession进行执行即可。

    启动测试类Bootstrap:

    Bootstrap

     

    看到没有,我们完全通过自己的类,自己的理解,去实现了和MyBatis一样的功能!

     

    OK,一个迷你版的MyBatis就竣工了,有一种油然而生的成就感,哈哈~

     

     

    手写系列相关爆文


    【手写系列】写出我的第一个框架:迷你版Spring MVC

    【手写系列】透彻理解Spring事务设计思想之手写实现

    【手写系列】纯手写实现一个高可用的RPC

    【手写系列】理解数据库连接池底层原理之手写实现

    【手写系列】对HashMap的思考及手写实现

    【手写系列】纯手写实现JDK动态代理

    【手写系列】写一个迷你版的Tomcat



    作者:张丰哲
    链接:https://www.jianshu.com/p/73ee8caddc68
    來源:简书
    简书著作权归作者所有,任何形式的转载都请联系作者获得授权并注明出处。

    展开全文
  • MyBatis,曾经给我的感觉是一个很神奇的东西,我们只需要按照规范好...有人会说是动态代理,现在我就来通过手写一个迷你版的MyBatis来彻底理解它的设计思想!        动手一个迷你版的MyBatis   ...

    MyBatis,曾经给我的感觉是一个很神奇的东西,我们只需要按照规范写好XXXMapper.xml以及XXXMapper.java接口。要知道我们并没有提供XXXMapper.java的实现类,MyBatis到底是怎么做到这一点的呢?有人会说是动态代理,现在我就来通过手写一个迷你版的MyBatis来彻底理解它的设计思想!

      

     

      

      动手写一个迷你版的MyBatis

      

      MyBatis原理架构图

      其实对于MyBatis最为关键的就在于:

      XXXMapper mapper = sqlSession.getMapper(XXXMapper.class);

      大家可以以这个为切入口,进行源码跟踪,容易得到上面的调用链。

      我们先来看一下迷你版MyBatis的整体框架思路:

      迷你版MyBatis

      执行器MyExecutor:

      

      MyExecutor提供query方法

      在MyBatis中,比如说select有多种形式,比如selectOne,selectList,那么其实到最后,还是向JDBC发出一个SQL而已。对于执行器而言,其实对于查询,提供一个query接口就可以了。

      这里,为了简便,直接执行已经处理好的SQL语句(动态SQL以及输入类型,这不是迷你版MyBatis关心的)。另外执行器的实现类MyBaseExecutor其实就是一段JDBC的操作代码。

      

      query的JDBC实现

      这里为了简化处理,在RequestMapping这块硬编码了。

      StudentMapper.java/StudentMapper.xml:

      Mapper接口

      Mapper.xml

      这里,为了不牵涉到XML的解析过程,直接提供已经处理完毕的结果。其实就是namespace/statementID/SQL的存储、映射。

      对外暴露的API接口(MySqlSession):

      

      MySqlSession

      

      MySqlSession实现

      从这里,你能够看到一些端倪:

      第一,MyDefaultSqlSession持有执行器的引用,调用selectOne等方法,就是在调用执行器的query方法。

      第二,在getMapper的获取过程中,我们看到了具体业务处理Handler的身影:MyMapperProxy,根据JDK动态代理的知识,我们知道,最终都是要回调Handler的invoke方法完成的。

      MyMapperProxy:

      

      MyMapperProxy

      当invoke方法被调用时,我们根据调用的方法,进行反射,得到namespace以及对应的SQL,然后,我们把SQL交给sqlSession进行执行即可。

      启动测试类Bootstrap:

      

      Bootstrap

      看到没有,我们完全通过自己的类,自己的理解,去实现了和MyBatis一样的功能!

      OK,一个迷你版的MyBatis就竣工了,有一种油然而生的成就感,哈哈~

      链接:https://www.jianshu.com/p/73ee8caddc68

    展开全文
  • 来源:labuladong 作者:labuladong很多读者反应,就算看了前文 动态规划详解,了解了动态规划的套路,也不会状态转移方程,没有思路,怎么办?本文就借助「最长递增子序列」来讲一种设计动态规划的通用技巧:数学...

    05db809c8957d42aa15fc0bea320af18.png

    来源:labuladong    作者:labuladong

    很多读者反应,就算看了前文 动态规划详解,了解了动态规划的套路,也不会写状态转移方程,没有思路,怎么办?本文就借助「最长递增子序列」来讲一种设计动态规划的通用技巧:数学归纳思想。

    最长递增子序列(Longest Increasing Subsequence,简写 LIS)是比较经典的一个问题,比较容易想到的是动态规划解法,时间复杂度 O(N^2),我们借这个问题来由浅入深讲解如何写动态规划。

    比较难想到的是利用二分查找,时间复杂度是 O(NlogN),我们通过一种简单的纸牌游戏来辅助理解这种巧妙的解法。

    先看一下题目,很容易理解:

    d8973e4f799001d7a5953900f493c905.png

    注意「子序列」和「子串」这两个名词的区别,子串一定是连续的,而子序列不一定是连续的。下面先来一步一步设计动态规划算法解决这个问题。

    一、动态规划解法

    动态规划的核心设计思想是数学归纳法。

    相信大家对数学归纳法都不陌生,高中就学过,而且思路很简单。比如我们想证明一个数学结论,那么我们先假设这个结论在 k 时成立,然后想办法证明 k=n 的时候此结论也成立。如果能够证明出来,那么就说明这个结论对于 k 等于任何数都成立。

    类似的,我们设计动态规划算法,不是需要一个 dp 数组吗?我们可以假设 dp[0...i1] 都已经被算出来了,然后问自己:怎么通过这些结果算出dp[i] ?

    直接拿最长递增子序列这个问题举例你就明白了。不过,首先要定义清楚 dp 数组的含义,即 dp[i] 的值到底代表着什么?

    我们的定义是这样的:dp[i] 表示以 nums[i] 这个数结尾的最长递增子序列的长度。

    举个例子:

    5fa352d4e407e17dcb364b028dfd0e61.png

    c4cbef435e98904176a55889bfc68b0d.png

    算法演进的过程是这样的:1a5170dabc1e43b3300cc0a99bb95b47.gif

    根据这个定义,我们的最终结果(子序列的最大长度)应该是 dp 数组中的最大值。

    int res = 0;
    for (int i = 0; i     res = Math.max(res, dp[i]);
    }
    return res;

    读者也许会问,刚才这个过程中每个 dp[i] 的结果是我们肉眼看出来的,我们应该怎么设计算法逻辑来正确计算每个 dp[i] 呢?

    这就是动态规划的重头戏了,要思考如何进行状态转移,这里就可以使用数学归纳的思想:

    我们已经知道了 dp[0...4] 的所有结果,我们如何通过这些已知结果推出 dp[5] 呢?

    53591934c068e0be83e0e20f382a5412.png

    根据刚才我们对 dp 数组的定义,现在想求 dp[5] 的值,也就是想求以 nums[5] 为结尾的最长递增子序列。

    nums[5] = 3,既然是递增子序列,我们只要找到前面那些结尾比 3 小的子序列,然后把 3 接到最后,就可以形成一个新的递增子序列,而且这个新的子序列长度加一。

    当然,可能形成很多种新的子序列,但是我们只要最长的,把最长子序列的长度作为 dp[5] 的值即可。

    f7ded34573d5b498f222d78a801f79ea.gif

    06bcfae10680935b25640f51e6a46a50.png

    这段代码的逻辑就可以算出 dp[5]。到这里,这道算法题我们就基本做完了。读者也许会问,我们刚才只是算了 dp[5] 呀,dp[4], dp[3] 这些怎么算呢?

    类似数学归纳法,你已经可以通过 dp[0...4] 算出 dp[5] 了,那么任意 dp[i] 你肯定都可以算出来:

    b642b3213b74063d4dd2cb6bb16c3ef9.png

    还有一个细节问题,就是 base case。dp 数组应该全部初始化为 1,因为子序列最少也要包含自己,所以长度最小为 1。下面我们看一下完整代码:

    0e63236b02e937f397bcaf14238d2e02.png

    至此,这道题就解决了,时间复杂度 O(N^2)。总结一下动态规划的设计流程:

    首先明确 dp 数组所存数据的含义。这步很重要,如果不得当或者不够清晰,会阻碍之后的步骤。

    然后根据 dp 数组的定义,运用数学归纳法的思想,假设 dp[0...i1] 都已知,想办法求出 dp[i],一旦这一步完成,整个题目基本就解决了。

    但如果无法完成这一步,很可能就是 dp 数组的定义不够恰当,需要重新定义 dp 数组的含义;或者可能是 dp 数组存储的信息还不够,不足以推出下一步的答案,需要把 dp 数组扩大成二维数组甚至三维数组。

    二、二分查找解法

    这个解法的时间复杂度会将为 O(NlogN),但是说实话,正常人基本想不到这种解法(也许玩过某些纸牌游戏的人可以想出来)。所以如果大家了解一下就好,正常情况下能够给出动态规划解法就已经很不错了。

    根据题目的意思,我都很难想象这个问题竟然能和二分查找扯上关系。其实最长递增子序列和一种叫做 patience game 的纸牌游戏有关,甚至有一种排序方法就叫做 patience sorting(耐心排序)。

    为了简单起见,后文跳过所有数学证明,通过一个简化的例子来理解一下思路。

    首先,给你一排扑克牌,我们像遍历数组那样从左到右一张一张处理这些扑克牌,最终要把这些牌分成若干堆。

    967b71c4e8848449941e4a7fe84f062d.png

    处理这些扑克牌要遵循以下规则:

    只能把点数小的牌压到点数比它大的牌上。如果当前牌点数较大没有可以放置的堆,则新建一个堆,把这张牌放进去。如果当前牌有多个堆可供选择,则选择最左边的堆放置。

    比如说上述的扑克牌最终会被分成这样 5 堆(我们认为 A 的值是最大的,而不是 1)。

    e0ded7585f8dd81a8314f77d07adb363.png

    为什么遇到多个可选择堆的时候要放到最左边的堆上呢?因为这样可以保证牌堆顶的牌有序(2, 4, 7, 8, Q),证明略。

    51043f7d9ce44ec66e03dd9cdc7b1ac8.png

    按照上述规则执行,可以算出最长递增子序列,牌的堆数就是我们想求的最长递增子序列的长度,证明略。

    c0c0aa41e5cda8f16a39bacfffef2f33.png

    我们只要把处理扑克牌的过程编程写出来即可。每次处理一张扑克牌不是要找一个合适的牌堆顶来放吗,牌堆顶的牌不是有序吗,这就能用到二分查找了:用二分查找来搜索当前牌应放置的位置。

    PS:旧文 二分查找算法详解 详细介绍了二分查找的细节及变体,这里就完美应用上了。如果没读过强烈建议阅读。

    f4900016b42fe425955bee615ecc8187.png

    至此,二分查找的解法也讲解完毕。

    这个解法确实很难想到。首先涉及数学证明,谁能想到按照这些规则执行,就能得到最长递增子序列呢?其次还有二分查找的运用,要是对二分查找的细节不清楚,给了思路也很难写对。

    所以,这个方法作为思维拓展好了。但动态规划的设计方法应该完全理解:假设之前的答案已知,利用数学归纳的思想正确进行状态的推演转移,最终得到答案。

    你可能会喜欢

    1、腾讯面试:一条SQL语句执行得很慢的原因有哪些?---不看后悔系列

    2、为什么你学不会递归?告别递归,谈谈我的一些经验

    3、一文读懂一台计算机是如何把数据发送给另一台计算机的

    4、如何只用2GB内存从20/40/80亿个整数中找到出现次数最多的数

    5、字符串匹配Boyer-Moore算法:文本编辑器中的查找功能是如何实现的?

    e91c29fd74683b06e9a81ea397b4226d.png

    展开全文
  • 软件测试工作日志 软件测试工作日志 通过对软件的实际测试 _从思想上改变了自己对数据备份保护的概念XX的硬盘动态备份技术能够在不占用固定硬盘空间非用户使用空间实现数据的快速备份与恢复堪称典范不愧是行业的创新...
  • 前言MyBatis,曾经给我的感觉是一个很神奇的东西,...有人会说是动态代理,现在我就来通过手写一个迷你版的MyBatis来彻底理解它的设计思想!同时还配套了手写MyBatis框架视频教学,有需要的朋友可以私信回复我【视...

    前言

    MyBatis,曾经给我的感觉是一个很神奇的东西,我们只需要按照规范写号XXXMapper.xml以及XXXMapper.java接口。要知道我们并没有提供XXXMapper.java的实现类,MyBatis到底是怎么做到这一点的呢?有人会说是动态代理,现在我就来通过手写一个迷你版的MyBatis来彻底理解它的设计思想!同时还配套了手写MyBatis框架视频教学,有需要的朋友可以私信回复我【视频】即可免费获取,诚意满满,无套路!!!

    如果你对手写RPC感兴趣,请参考:

    《纯手写实现高可用的RPC框架,Java架构师必备技能》

    如果你对Spring MVC感兴趣,请参考:

    《携程Java架构师手把手教你手写SpringMVC,剑指优秀开源框架灵魂》

    如果你对Tomcat感兴趣,请参考:

    《还不清楚原理就晚了,Java技术大咖带你手写Tomcat》

    动手写一个迷你版的MyBatis

    50ea2d38424a2fbd69e189fbb64b4c70.png

    MyBatis原理架构图

    其实对于MyBatis最为关键的就在于:

    XXXMapper mapper = sqlSession.getMapper(XXXMapper.class);

    大家可以以这个为切入口,进行源码跟踪,容易得到上面的调用链。

    我们先来看一下迷你版MyBatis的整体框架思路:

    d21725d0caa4b7f7da0666cafce0d7a9.png

    迷你版MyBatis

    执行器MyExecutor:

    6c79342a9f86d0a7ba0ce2ad6e4a7d95.png

    MyExecutor提供query方法

    在MyBatis中,比如说select有多种形式,比如selectOne,selectList,那么其实到最后,还是向JDBC发出一个SQL而已。对于执行器而言,其实对于查询,提供一个query接口就可以了。

    这里,为了简便,直接执行已经处理好的SQL语句(动态SQL以及输入类型,这不是迷你版MyBatis关心的)。另外执行器的实现类MyBaseExecutor其实就是一段JDBC的操作代码。

    994552575b9a899aea532edfbf5f908c.png

    query的JDBC实现

    这里为了简化处理,在RequestMapping这块硬编码了。

    StudentMapper.java/StudentMapper.xml:

    52300c90cea7af555626a4dc44e432e7.png

    Mapper接口

    31666b8de2bb21e76e6cbf0bd0834fb5.png

    Mapper.xml

    这里,为了不牵涉到XML的解析过程,直接提供已经处理完毕的结果。其实就是namespace/statementID/SQL的存储、映射。

    对外暴露的API接口(MySqlSession):

    23b291907d175fb1679d41b937296669.png

    MySqlSession

    eb7790597d76ee15cdae5a478a24b0ce.png

    MySqlSession实现

    从这里,你能够看到一些端倪:

    第一,MyDefaultSqlSession持有执行器的引用,调用selectOne等方法,就是在调用执行器的query方法。

    第二,在getMapper的获取过程中,我们看到了具体业务处理Handler的身影:MyMapperProxy,根据JDK动态代理的知识,我们知道,最终都是要回调Handler的invoke方法完成的。

    MyMapperProxy:

    269c0591df6af30f4359aa14ffc1662f.png

    MyMapperProxy

    当invoke方法被调用时,我们根据调用的方法,进行反射,得到namespace以及对应的SQL,然后,我们把SQL交给sqlSession进行执行即可。

    启动测试类Bootstrap:

    0ee6a0be5caf2b53247a524b953976a3.png

    Bootstrap

    看到没有,我们完全通过自己的类,自己的理解,去实现了和MyBatis一样的功能!

    OK,一个迷你版的MyBatis就竣工了,哈哈~

    手写的MyBatis框架视频教学分享

    为了方便大家学习,在这里还是免费分享一下这位大咖的手写MyBatis框架视频给大家,提供大家学习观看,有需要的朋友希望能得到你们的转发关注支持一下,后续还会更新更多手写系列文章及视频免费分享给大家!

    视频免费获取方式:转发+关注后,私信回复我【视频】即可免费领取这份视频资料及上面提到的手写系列视频资料,我会一一回复下载链接给私信的朋友!

    deff6219108e507efa4d821dd540278e.png

    视频教学截图

    更多学习资料分享

    814f32c5b1af4f994aa3e62202ab21a2.png

    更多视频笔记分享

    5e16dc2f156b8f197f0fa9daed2a143f.png
    d31ee2a634ad5195233feaa859cb7b0c.png
    展开全文
  • 获取用户动态在一些论坛等社交网络中很常见,甚至可以说,就是一个微博嘛。其实这个系统很简单的,很容易就能出来。 当然,你平时要做好准备,在你...现在举一个例子来说明,怎么编写一个获取动态系统,也就是微博。
  • 动态规划与其他的算法不一样,动态规划是...或者说,做出来了怎么写题解呢?这里给大家介绍一种分析动态规划的方法: 1:写出DP状态的表达。也就是f[XX]等于XX。 2:写出DP的转移方程。也就是f[XX] = min(f[X...
  • 权限管理的一点思路但是最近有小伙伴在学习微人事项目时,对动态菜单这一块还是有疑问(即不同用户登录成功后会看到不同的菜单项),因此松哥打算再来一篇文章和大家聊一聊前后端分离开发中的动态菜单问题。...
  • jdk动态代理

    2021-04-07 17:37:55
    jdk动态代理,也是代理模式的体现,同时就是java面向切面思想的一种实现。打个比方,玩王者荣耀,突然有事挂机,系统在默默的代替我在玩,这就是代理的思想。 这里看一下SystemPlayerImpl是怎么实现的. 个...
  • java 动态代理

    2019-09-16 17:26:05
    最近工作中也是因为用到动态代理,网上找了一篇是和入门,的不错! 在学习Spring的时候,我们知道Spring主要有两大思想,一个是IoC,另一个就是AOP,对于IoC,依赖注入就不用多说了,而对于Spring的核心AOP来说,...
  • java动态代理原理详解

    2020-07-29 17:27:54
    我们知道Spring主要有两大思想,一个是IoC,另一个就是AOP,对于IoC,依赖注入就不用多说了,而对于Spring的核心AOP来说,我们不但要知道怎么通过AOP来满足我们的功能,我们更需要学习的是其底层是怎么样的一个原理...
  • 动态规划算法总结

    2021-03-30 11:20:31
    思想 名词解释:通过一个例子来解释 A : "1+1+1+1+1+1+1+1 =?" A : "上面等式的值是多少" B : 计算 "8!" A : 在上面等式的左边上 "1+" A : "此时等式的值为多少" B : "9!" (quickly) A : "你怎么这么快就知道...
  • JDK动态代理说明

    2011-06-23 21:22:00
    如果我们想实现类似AOP的思想,自己代码用代理或叫装饰模式也是可以实现的,但这样我们就面临必须给每个需要被装饰(我们暂时就叫它装饰吧)的接口装饰子类,通过添加自己需要的特定功能并委托实体接口子类完成...
  • 代理模式-动态代理

    2017-11-12 00:15:24
    大半夜的博客,点击保存莫名其妙的消失了,csdn也是醉了,没办法,重写吧。 前面讲了代理模式的思想和静态代理的实现,静态代理有问题,实际项目中...先看一下用这两个类怎么实现动态代理。 同样提供一个接口: publi
  • 前置知识:静态点分治(主要是容斥思想,一般看出来是点分治的话,想到怎么容斥剩下的操作就很机械了,还有一种LCT,目前是我的盲区),线段树(树状数组)。可以通过线段树和树状数组的题来理解这两个维护的...
  • 如果不了解什么是状态转移方程可以去搜索一下,这里就不详细描述了,有点抽象,我刚开始学算法的时候,也不了解,感觉十分抽象,但是写了几道题目就发现,其实还是蛮好理解的,就是很多时候想不到方程应该怎么写。...
  • 在学习Spring的时候,我们知道Spring主要有两大思想,一个是IoC,另一个就是AOP,对于IoC,依赖注入就不用多说了,而对于Spring的核心AOP来说,我们不但要知道怎么通过AOP来满足的我们的功能,我们更需要学习的是其...
  • 没有别的捷径,理解其算法思想后,就是多练,写的多了,就知道怎么写了。 这是leetCode的一道题,来看来动态规划的运用。原题目链接 给定一个整数数组 nums ,找到一个具有最大和的连续子数组(子数组最少包含一个...
  • 转载自:https://blog.csdn.net/mu399/article/details/7722810之前学习的时候一直在找动态规划怎么解01背包的问题,这是我找得到的最容易理解的文章,也帮助我基本了解动态规划的思想01背包问题,是用来介绍动态...
  • Spring之AOP思想分析

    2020-11-27 17:57:46
    AOP:面向切面编程,通过预编译方式和运行期动态代理实现程序功能的统一维护的一种技术。 其实我最讨厌这种官方的话语,什么叫AOP?什么是面向切面编程? 举个常见的例子来说,比如,我们一般的开发项目,主要就是前...
  • 我们先说怎么实现JDK为我们提供的动态代理。(这篇文章目的是为Spring框架中的AOP思想提供技术支持) 0.用到反射包下的类,以及InvocationHandler接口。      Object invoke(Object proxy, Method ...
  • 题目分析:问到了方案数肯定是动态规划,我们就要设计一下动态规划该怎么写,因为拓扑排序用到的是bfs,每次完整的排序都能得到一条单链,所以我们可以用树形dp的思想来设计,我们令dp[i]代表终点为i时的方案数,...
  • 解析xml文件动态拼接sql语句

    千次阅读 2018-10-27 16:26:37
    现在有很多开源的持久层框架,比如Mybatis、BeetlSQL、Hibernate、DbUtils。当我们需要自己手写sql的时候。...使用了这么多框架,如果想编程思想更上一层,不仅要怎么使用,还要学习其实现原理。接下...
  • 微信动态页面的图片下拉变大效果

    千次阅读 2016-09-22 13:04:56
    我在网上看了其他一些实现效果,不怎么完美,所以自己了一个,第一次,不清楚的话多包涵 先说说思想:self.imageView就是效果图中的图片,self.headerView是tableView中的头视图( _tableView.tableHeaderView...

空空如也

空空如也

1 2 3 4 5 ... 7
收藏数 126
精华内容 50
关键字:

思想动态怎么写