由于butterfly这个主题并没有明确的说明,但作为一个博主应该要知道如何去设置rss订阅,这里就简单的说明一下
在butterfly的插件推荐中就说明了有hexo的rss插件,叫hexo-generator-feed
首先先添加插件,这里使用的是npm添加
1 | npm install hexo-generator-feed --save |
然后在_config.yml中添加如下配置
1 | feed: |
实际上官网还说明了一些其他东西,如
1 | hub: |
enable
: 默认开启可以省略type
: RSS的类型(atom/rss2)path
: 文件路径,默认是 atom.xml/rss2.xmllimit
: 展示文章的数量,使用 0 或则 false 代表展示全部hub
: 如果使用不到可以为空content
: (可选)设置 true
可以在 RSS 文件中包含文章全部内容,默认:falsecontent_limit
: (可选)摘要中使用的帖子内容的默认长度。 仅在内容设置为false且未显示自定义帖子描述时才使用。content_limit_delim
:(可选)如果content_limit用于缩短帖子内容,则仅在达到字符限制之前在此分隔符的最后一次出现处剪切。默认不使用。icon
: (可选)自定义图标。默认为主配置中指定的电子邮件头像。autodiscovery
: 添加提要自动发现,默认开启template
: 自定义模板路径。该文件用于生成 xml 文件在主题的_config.yml中添加配置
1 | rss: /atom.xml |
这样你后面在用hexo clean && g生成的时候会在public中生成一个atom.xml文件
然后在主题中的social settings中添加如下配置
1 | fas fa-rss: https://dclef.icu/atom.xml |
因为butterfly主题中带有fas图标,所以直接可以使用
然后进行部署
1 | hexo g -d |
设置完成以后如下图
]]>首先本人重新开坑 ,
go总体来讲就是将c和java的特性给结合和优化所诞生出来的,由Rob Pike(罗伯.派克),Ken Thompson(肯.汤普森)和Robert Griesemer(罗伯特.格利茨默)三位大佬所创造出来的,拥有比较简洁的语法和很好的性能,同时也是编译性语言,而go主要用于web或者游戏服务器,简单来说就是后台,也就是为什么越来越多的公司选择后端都会使用go,而不是繁琐的java。
安装的sdk实际上直接看官网即可,这里就将安装在windows上。
Windows 下载的是 .msi 后缀,默认情况下 .msi 文件会安装在 c:\Go 目录下。你可以去自定义,但是要将go目录添加倒环境变量中,也就是系统变量中的Path路径。安装完成以后,在cmd中输入go version,如果有显示版本证明安装成功。
如果你没有梯子的话安装go的扩展是会非常慢的,这点请注意。
安装完以后看默认文档中的bin是否有这些文件,有就没问题,然后在vscode中的工作文件夹中创建一个名为main.go的文件,写下hello world
1 | package main |
然后在vscode的终端中输入go run ./main.go
即可编译成功,如图
跟很多语言的数据类型一样,都会int float string 等众多数据类型,如
int unint byte float32 float64 等等,其中int有负数,unint无负数
浮点数代码项目中的小数,零值是一个变量的默认值
接下来,将用代码来解释数字类型
1 | //整数i int类型 |
类型实际上是有默认值,如
1 | var i int //i的值为0 |
而如果我们要声明一个变量,实际上还可以进行简化
1 | e := 10 //int |
定义一个常量很简单,只需要关键词const即可,但常量一旦定义则不可修改
1 | //常量 |
类型转换实际上是用的strconv这个包,关于里面的api这里就不必多少了这里就简单的说明一些,代码所示
1 | //Itoa int类型转为string类型 |
strings包也是go官方的api库,跟java中的string包也是类似,这里就写几个api,如下代码所示
1 | s1 := "abcdefgh" |
首先要说明的是if后面的表达式不需要(),这跟很多语言不同,比如说java,每个条件分支大括号是必须的,if紧跟大括号,{不能占一行,else同理,在if…else条件语句中可以增加多个else if…else
1 | //if语句 |
if语句也可以进行简化,将定义变量合并起来
1 | if i := 6; i > 10 { |
当if条件过多时,就可以用switch语句来替代。switch的case从上到下逐一进行判断。
一旦满足条件,立即执行对应的分支并返回,其余分支不再做判断
1 | switch i := 6; { |
简单语句,一般用于for循环的初始化。for循环的条件,表示for循环什么时候结束。
更新语句,一般用于更新循环的变量
1 | sum := 0 |
由于go没有while语句,所以只能用for来模仿一个
1 | sum1 := 0 |
也跟其他语言一样,有着break和continue。continue可以跳出本次循环,继续执行下一个循环
break可以跳出整个for循环,哪怕for循环没有执行完,也会强制终止。
1 | //break |
数组是具有相同唯一类型的一组已编号且长度固定的数据项序列,这种类型可以是任意的原始类型例如整型、字符串或者自定义类型。
1 | array := [5]string{"a", "b", "c", "d", "e"} |
也可以用…来省略
1 | array1 := [...]string{"a", "b", "c", "d", "e"} |
如果要初始化索引则不可用…来进行省略
1 | array2 := [5]string{1: "b", 3: "d"} |
数组也可以用for循环来进行表示
1 | for i := 0; i < 5; i++ { |
但大部分情况下使用的是for range这种Go语言的新型循环
1 | for i, v := range array { |
如果不需要索引值,可以使用_将索引丢弃
1 | for _, v := range array { |
1 | func main() { |
UTF8编码下,一个汉字对应三个字节,所以字符串s的长度其实是12
1 | s1 := "hello 世界" |
切片和数组类似,可以把它理解为动态数组,对数组任意分隔,就可以得到一个切片。基于数组生成切片,包含索引start,但是不包含索引end,切片和数组一样,也可以通过索引定位元素
1 | array3 := [5]string{"a", "b", "c", "d", "e"} |
1 | //修改切片 |
这里的len函数是指slice的长度,而cap函数指的是整个数组的长度
1 | slice1 := []string{"a", "b", "c", "d", "e"} |
append的简单使用
1 | //追加一个元素 |
map是一一个无序的K-V键值对集合,结构为map[K]V,其中K对应Key,V对应Value
map的门操作符可以返回两个值
1.第一个值是对应的Value
2.第二个值标记该Key是否存在,如果存在,它的值为true
添加键值对或者更新对应Key的Value
nameAgeMap[“世界”] = 20
获取指定Key对应的Value
age := nameAgeMapr[“世界”]
1 | //声明 |
对于map,for range返回两个值
1.第一个是map的Key
2.第二个是map的Value
1 | nameAgeMap["世界"] = 20 |
通过函数,可以把开发任务分解成一个个小的单元,这些小单元可以被其他单元复用,进而提高开发效率、降低代码重合度任何一个函数的定义,都有一个func关键字main是函数的名字main函数名字后面的一对括号0是不能省略的括号里可以定义函数使用的参数
函数的声明格式
1 | func funcName(params) result { |
关键字func
函数名字funcName
函数的参数params,用来定义形参的变量名和类型
result是返回的函数值,用于定义返回值的类型
1 | func sum(a, b int) int { |
Go语言的函数可以返回多个值,也就是多值返回
第一个值返回函数的结果,第二个值返回函数出错的信息
不管是自定义的函数sum、sum1,还是我们使用到的函数Printin,都会从属于一个包也就是package,不同包的函数要被调用,那么函数的作用域必须是公有的,也就是函数名称的首字母要大写
函数名称首字母小写代表私有函数,只有在同一个包中才可以被调用
函数名称首字母大写代表公有函数,不同的包也可以调用
任何一个函数都会从属于一个包
1 | func sum1(a, b int) (int, error) { |
方法必须要有一个接收者,这个接收者是一个类型,这样方法就和这个类型绑定在一起,称为这个类型的方法,接收者的定义和普通变量、函数参数等一样
前面是变量名,后面是接收者类型
在函数中再定义函数(函数嵌套),定义的这个匿名函数,也可以称为内部函数更重要的是,在函数内定义的内部函数,可以使用外部函数的变量等,这种方式也称为闭包
1 | type Age uint |
本期我们讲了安装使用、数据类型、条件语句、数组、切片、Map和函数。如果有代码基础,实际上这些只需要一个小时即可掌握。
如果硬要难的话可能是函数中的闭包没有见过,这里需要着重看一下。
]]>1、声明Bean的注解
注解 | 作用 |
---|---|
@Component | 组件,没有明确的角色 |
@Service | 在业务逻辑层使用(service层) |
@Repository | 在数据访问层使用(dao层) |
@Controller | 在展现层使用,控制器的声明 (Controller层) |
2、注入bean的注解
注解 | 作用 |
---|---|
@Autowired | 减少或者消除属性或构造器参数的设置 |
@Inject | 与@Autowired相同,但无request属性 |
@Resource | 在根据名称进行自动装配的,会指定一个name属性 |
3、java配置类相关注解
注解 | 作用 |
---|---|
@Configuration | 声明当前类为配置类,相当于xml形式的Spring配置 |
@Bean | 注解在方法上,声明当前方法的返回值为一个bean,替代xml中的方式 |
@Configuration | 声明当前类为配置类,内部组合了@Component注解,表明这个类是一个bean |
@ComponentScan | 用于对Component进行扫描 |
@WishlyConfiguration | @Configuration与@ComponentScan的复合注解 |
4、切面(AOP)相关注解
注解 | 作用 |
---|---|
@Aspect | 声明一个切面 |
@After | 在方法执行之后执行 |
@Before | 在方法执行之前执行 |
@Around | 在方法执行之前与之后执行 |
@PointCut | 在声明切点 |
5、异步相关注解
注解 | 作用 |
---|---|
@EnableAsync | 配置类中,通过此注解开启对异步任务的支持 |
@Async | 放到方法上,调用该方法的线程与此方法异步执行,需要配合@EnableAsync注解使用 |
6、定时任务相关注解
注解 | 作用 |
---|---|
@EnableScheduling | 在配置类上使用,开启计划任务的支持 |
@Scheduled | 申明这是一个任务,有cron,zone,fixedDelay等8个参数 |
8、Enable相关注解
注解 | 作用 |
---|---|
@EnableAspectJAutoProxy | 开启对AspectJ自动代理的支持 |
@EnableAsync | 开启异步方法的支持 |
@EnableScheduling | 开启计划任务的支持 |
@EnableWebMvc | 开启Web MVC的配置支持 |
@EnableConfigurationProperties | 开启对@ConfigurationProperties注解配置Bean的支持 |
@EnableJpaRepositories | 启对SpringData JPA Repository的支持 |
@EnableTransactionManagement | 开启注解式事务的支持 |
@EnableTransactionManagement | 开启注解式事务的支持 |
@EnableCaching | 开启注解式的缓存支持 |
8、测试相关注解
注解 | 作用 |
---|---|
@RunWith | 运行器,Spring中通常用于对JUnit的支持 |
@ContextConfiguration | 用来加载配置ApplicationContext,其中classes属性用来加载配置类 |
注解 | 作用 |
---|---|
@EnableWebMvc | 在配置类中开启Web MVC的配置支持 |
@Controller | 声明该类为SpringMVC中的Controller 作用修饰class,用来创建处理http请求的对象 |
@RequestMapping | 配置url映射 |
@ResponseBody | 支持将返回值放在response内,而不是一个页面,默认返回json数据 |
@RequestBody | 允许request的参数在request体中,而不是在直接连接在地址后面 |
@PathVariable | 用于接收路径参数 |
@RestController | 复合注解,相当于@Controller和@ResponseBody的组合,默认返回json数据 |
@ControllerAdvice | 通过该注解,我们可以将对于控制器的全局配置放置在同一个位置 |
@ExceptionHandler | 用于全局处理控制器里的异常 |
@InitBinder | 用来设置WebDataBinder,WebDataBinder用来自动绑定前台请求参数到Model中 |
@ModelAttribute | 绑定键值对到Model里 |
PS:markdown的表格有点反人类,差点就给我整不会了。
]]>第7层 应用层
主条目:应用层
应用层(Application Layer)提供为应用软件而设计的接口,以设置与另一应用软件之间的通信。例如:HTTP、HTTPS、FTP、Telnet、SSH、SMTP、POP3等。
第6层 表示层
主条目:表示层
表示层(Presentation Layer)把数据转换为能与接收者的系统格式兼容并适合传输的格式。
第5层 会话层
主条目:会话层
会话层(Session Layer)负责在数据传输中设置和维护计算机网络中两台计算机之间的通信连接。
第4层 传输层
主条目:传输层
传输层(Transport Layer)把传输表头(TH)加至数据以形成数据包。传输表头包含了所使用的协议等发送信息。例如:传输控制协议(TCP)等。
第3层 网络层
主条目:网络层
网络层(Network Layer)决定数据的路径选择和转寄,将网络表头(NH)加至数据包,以形成分组。网络表头包含了网络资料。例如:互联网协议(IP)等。
第2层 数据链路层
主条目:数据链路层
数据链路层(Data Link Layer)负责网络寻址、错误侦测和改错。当表头和表尾被加至数据包时,会形成信息框(Data Frame)。数据链表头(DLH)是包含了物理地址和错误侦测及改错的方法。数据链表尾(DLT)是一串指示数据包末端的字符串。例如以太网、无线局域网(Wi-Fi)和通用分组无线服务(GPRS)等。
分为两个子层:逻辑链路控制(logical link control,LLC)子层和介质访问控制(Media access control,MAC)子层。
第1层 物理层
主条目:物理层
物理层(Physical Layer)在局部局域网上发送数据帧(Data Frame),它负责管理电脑通信设备和网络媒体之间的互通。包括了针脚、电压、线缆规范、集线器、中继器、网卡、主机接口卡等。
下列以一张图来解释
这样便可以解释游戏加速器为什么能加速客户端游戏,至于会有延迟是因为你的客户端需要先传输到它的服务器通过它的服务器来返回传输的内容,这好比一个中转站承载着流量运输。
1 | public interface water { |
现在实现两种水的类,方便展示,把它们先写在一起
1 | // Hotwater.java |
实现一个业务层,也就是从两种水中获取到热水
1 | // UserService.java |
实现一个用户类
1 | // User.java |
以上是调用业务层UserService获取到热水,试想一下,如果现在我想喝冷水怎么办?这样便要修改业务层代码
1 | // UserService.java |
从上述不难发现每当用户需求发生改变时,我们的代码都要做出相应的修改,那么如果我们工程量大,修改的内容很多怎么办?或者说如果修改会对其他业务逻辑产生BUG怎么办?解决的思路应该是在不修改源代码的前提上,我们要考虑的是控制权应该在用户上和不是饮水机(业务层)。
所以需要修改业务层的代码实现控制权的转换
1 | public class UserService { |
加入set方法,使用户层可以注入不同的对象,这样我们就可以在用户层传入哪个对象,就会获得哪个结果
1 | // Hotwater |
以前主动权在业务层,每次用户提出需求业务层就需要跟着做出改变,现在我们把主动权交给了用户,它传进什么值,就得到什么样的结果,这样业务代码就不用跟着改变了。试想一下,以前我们是要求饮水机给我们水,我们还要自己动。现在是拿着一个杯子,大喊一声:水来!饮水机便自动给你水杯中到热水或者冷水。
这便是IOC(控制反转)的核心思想。
1.3、AOP(面向切面)
1.3.1、什么是AOP?
要想了解AOP首先就要了解OOP(面向对象编程)比如照软件重构的思想,如果多个类中出现重复的代码,就应该考虑定义一个共同的抽象类,将这些共同的代码提取到抽象类中,比如Teacher,Student都有username,那么就可以把username及相关的get、set方法抽取到User中,这种情况,我们称为纵向抽取。
但有些功能并不适合定义横向的关系,如认证、日志、事物等,例如日志代码往往横向地散布在所有对象层次中,而与它对应的对象的核心功能毫无关系对于其他类型的代码,这种散布在各处的无关的代码被称为横切,在OOP设计中,它导致了大量代码的重复,而不利于各个模块的重用。
而AOP它利用一种称为”横切”的技术,剖解开封装的对象内部,并将那些影响了多个类的公共行为封装到一个可重用模块,并将其命名为”Aspect”,即切面。所谓”切面”,简单说就是那些与业务无关,却为业务模块所共同调用的逻辑或责任封装起来,便于减少系统的重复代码,降低模块之间的耦合度,并有利于未来的可操作性和可维护性。
举一个例子,双十一它有验证有效期,验证是否登录,如果要写业务逻辑验证有效期和验证登录要写两遍,有多少接口,就要多少次代码,所以提出一个公共方法,每个接口都来调用这个接口,同样有个问题,我虽然不用每次都写一遍代码了,但每个接口都要调用这个方法。于是将方法注入到接口调用的某个地方。这样接口只需要关心具体的业务,而不需要关注其他非该接口关注的逻辑。
1.3.2、AOP概述
连接点(Joinpoint) 程序执行的某个特定位置,如某个方法调用前,调用后,方法抛出异常后,这些代码中的特定点称为连接点。简单来说,就是在哪加入你的逻辑增强 连接点表示具体要拦截的方法,上面切点是定义一个范围,而连接点是具体到某个方法
切点(PointCut) 每个程序的连接点有多个,如何定位到某个感兴趣的连接点,就需要通过切点来定位。比如,连接点–数据库的记录,切点–查询条件 切点用于来限定Spring-AOP启动的范围,通常我们采用表达式的方式来设置,所以关键词是范围
增强(Advice) 增强是织入到目标类连接点上的一段程序代码。在Spring中,像BeforeAdvice等还带有方位信息 通知是直译过来的结果,我个人感觉叫做“业务增强”更合适 对照代码就是拦截器定义的相关方法,通知分为如下几种:
前置通知(before):在执行业务代码前做些操作,比如获取连接对象
后置通知(after):在执行业务代码后做些操作,无论是否发生异常,它都会执行,比如关闭连接对象
异常通知(afterThrowing): 在执行业务代码后出现异常,需要做的操作,比如回滚事务
返回通知(afterReturning):在执行业务代码后无异常,会执行的操作
环绕通知(around): 这个目前跟我们谈论的事务没有对应的操作,所以暂时不谈
目标对象(Target):需要被加强的业务对象
织入(Weaving):织入就是将增强添加到对目标类具体连接点上的过程。 织入是一个形象的说法,具体来说,就是生成代理对象并将切面内容融入到业务流程的过程。
代理类(Proxy): 一个类被AOP织入增强后,就产生了一个代理类。
切面(Aspect) 切面由切点和增强组成,它既包括了横切逻辑的定义,也包括了连接点的定义,SpringAOP就是将切面所定义的横切逻辑织入到切面所制定的连接点中。 比如上文讨论的数据库事务,这个数据库事务代码贯穿了我们的整个代码,我们就可以这个叫做切面。 SpringAOP将切面定义的内容织入到我们的代码中,从而实现前后的控制逻辑。 比如我们常写的拦截器Interceptor,这就是一个切面类。
举一个例子 ,以数据库的操作为例来说明:
获取连接对象对应前置通知
执行SQL(核心业务代码)对应连接点
如果有异常
回滚事务对应返回通知
无异常则提交事务对应异常通知
关闭连接对应后置通知
整个的执行过程便是切面
1.3.3、AOP代码实例
动态代理
动态代理指的是动态创建一组指定的接口的实现对象
先写个接口
1 | public interface Begin { |
给出该接口的实现类
1 | public class ServerBegin implements Begin { |
添加一个前置增强接口
1 | /** |
把产生代理对象的代码封装为一个类
1 | import com.sun.org.apache.regexp.internal.RE; |
变可得到以下结果
运行中
你好
再见
2、Spring-boot的核心功能
独立运行的 Spring 项目
Spring Boot 可以以 jar 包的形式独立运行,运行一个 Spring Boot 项目只需通过 java–jar xx.jar 来运行。
内嵌 Servlet容器
Spring Boot 可选择内嵌 Tomcat、Jetty 或者 Undertow,这样我们无须以 war 包形式部署项目。
简化Maven配置
Spring 提供了一系列的 starter pom 来简化 Maven 的依赖加载,例如,当你使用了spring-boot-starter-web 时,会自动加入如图 1 所示的依赖包。
自动配置 Spring
Spring Boot 会根据在类路径中的 jar 包、类,为 jar 包里的类自动配置 Bean,这样会极大地减少我们要使用的配置。当然,Spring Boot 只是考虑了大多数的开发场景,并不是所有的场景,若在实际开发中我们需要自动配置 Bean,而 Spring Boot 没有提供支持,则可以自定义自动配置。
准生产的应用监控
Spring Boot 提供基于 http、ssh、telnet 对运行时的项目进行监控。
无代码生成和 xml 配置
Spring Boot 的神奇的不是借助于代码生成来实现的,而是通过条件注解来实现的,这是 Spring 4.x 提供的新特性。Spring 4.x 提倡使用 Java 配置和注解配置组合,而 Spring Boot 不需要任何 xml 配置即可实现 Spring 的所有配置。
3、Spring Boot的优缺点
3.1、优点
快速构建项目。
对主流开发框架的无配置集成。
项目可独立运行,无须外部依赖Servlet容器。
提供运行时的应用监控。
极大地提高了开发、部署效率。
与的天然集成。
3.2、缺点
版本更新速度很快,一些模块改动很大。
由于不用自己做配置,报错时很难定位。
网上现成的解决方案比较少。
1 | 查看当前所有的数据库: |
另外MySQL有三大类数据类型
分别为数字、时间、字符串
整数: tinyint、smallint、mediumint、int、bigint
浮点数: float、double、real、decimal
时间: date、time、datetime、timestamp、year
字符串: char、varchar
单行注释 // 快捷键 ctrl+/
多行注释 多行注释不能嵌套
文档注释 JavaDoc
大驼峰命名 (类名) 例如SelectById
小驼峰 (方法名 变量) 例如 selectById
一般全小写的命名是数据库的命名
对所有的数据进行分类(都有默认值)
byte[-128,127] short int long —–0
float[单精度浮点数] double[双精度浮点数] —-0.0
char 单子字符或汉字 —空
‘A’ ‘a’ ‘好’ ‘牛牛’ ‘鸀’
boolean 只有两个取值 —–false
true false
“sadasdasd撒大苏打飒飒大”
默认值都是 null
常量: 一个固定不变的值
语法一: 先定义 后赋值
语法二: 定义同时赋值
语法三: 同时定义多个变量
1.定义的位置类里面,方法的外面
2.全局都可以使用
3.不赋值也是可以使用的 有默认值
1.定义在方法内部或者代码块里面
2.只能在当前的方法 或者代码块的内部使用
3.必须先赋值后使用
局部变量可以和成员重名,一般不推荐这么写。
在使用的时候 优先使用局部变量,其次才使用成员变量
数据类型直接的相互转换
多个不同类型的数据 进行数学运算的时候 进行自动提升
把大的数据类型 使用一个小的类型来接收
语法:小数据类型 变量名 = (小数据类型)大类型值/大类型变量名;
注意:使用float或者Double精度会缺失需要用到BigDecimal方法
+的功能 除了数学运算,可以拼接字符串
自增 自减 对于一个变量的操作
++ 在前 :先自增 再使用值(使用的是自增以后的值)
++ 在后:先使用值 再自增(使用的是自增之前的值)
+= -= *= /= %=
使用的场景,把运算完成以后的结果赋值给本身
< >= <= == != instanceof
instanceof:判断一个对象,或者实例 常量是否属于一个类型
语法: x ? y : z;// 表示如果x为true,执行y,x为false则执行z。
x:比较运算的结果 boolean类型的变量
开发很少用,效率高,可读性差
概念,综合多个比较的结果得出一个统一的概念
&——并且
|——或者
!——取反
具有短路效果,可能效率要高一些
&& 和 &最终的结果是一致
|| 和 |最终的结果是一致
改变代码的执行流程
1 | if(①判断结构){ |
如果 ①最终结果为true 就去执行 ②的功能语句
如果 ①最终结果为false 就不执行 ②的功能语句
1 | if(①判断结构){ |
如果 ①最终结果为true 就去执行 ②的功能语句,否则就去执行③功能语句
1 | if(①判断结构){ |
使用场景:一般用于有几种固定的取值情况
1 | switch(变量){ |
相当于条件语句中else,所有的case匹配不上执行
特点结束当前的匹配功能语句。
特点结束当前的匹配功能语句。
循环结构:重复的去执行一段代码
床–食堂–游戏
家–旅游–洗脚–公司
1 | while(①判断语句){ |
基本语法
1 | do { |
第1次:1. 初始化条件语句 => 3. 循环体 => 4. 循环控制语句
第2次:2.条件判断语句 => 3. 循环体 => 4. 循环控制语句
第3次:2.条件判断语句 => 3. 循环体 => 4. 循环控制语句
1 | for(①初始化条件语句; ②条件判断语句; ③循环后语句) { |
第一次循环: ①—②–true–④—③
第二次循环: ②–true–④—③
第三次循环: ②–true–④—③
第四次循环: ②–true–④—③
…
第n次循环: ②–false —终止循环
break: 表示结束当前层循环
continue:跳过本次循环
return:结束当前方法
定义一个空数组(动态创建)
数据类型[] 名字=new 数据类型[长度];
定义一个指定长度的空数组
定义一个数组并赋值(静态)
数据类型[] 名字={值1,值2,值3,值4….}
数组名[索引位置]=值;
数组名[索引位置]
1.取值与赋值不能超出索引范围
2.数组一旦定义长度不能更改
3.数组的遍历(把数组里面的每一个数据读取出来)
和主方法差不多 ,主方法main,有特殊性程序运行的唯一入口
其他的方法,普通方法
方法:就是功能的封装
语法:
[修饰符] 返回值类型 方法名([形参1,形参2,..]){
//方法体,这个方法的功能逻辑代码
}
void:返回值类型之一,没有返回值[占位符,为了满足语法需要]
程序只会执行main方法里面的内容
只能在main里面去调用普通方法
调用者和被调用者,必须在同一个类里面,两者要么都有static修饰,要么都没有static修饰
被调用的方法有static修饰 类名:被调用方法所在类的类名【必须掌握,用的非常多】
被调用的方法没有static修饰【暂时不管】【必须掌握,用的非常多】
1.main 执行的顺序 还是从上到下依次执行,遇到调用方法的时 候,把方法内部的逻辑全部执行完成以后,再继续往下执行
2.方法的每一次调用都是完全独立的
形式参数,注重只是传出的参数类型,方法在设计的时候不确定的值 (由用户在调用的时候才传入的值)
方法名(数据类型 变量名,数据类型 变量名,….)
*
没有返回值,void只是占位满足语法需求
方法执行结束以后 返回一个指定类型的 数据
return 返回值; 返回数据的语法
把方法内部的执行结果返回给方法的调用者
把同一类的方法,一般名字都保持一直。
Overload[重载] – Override[覆写]
方法名一致,形参列表不同【个数,类型,类型顺序】
存储的变量名 基本数据类型的值
引用数据类型的值
基本数据类型传递的值得本身,引用数据类型传递的是地址的引用
语法在定义方法的时候 可以使用数据类型
可变参数的本质还是数组
注意:在定义方法的时候 只能有一个可变参数,并且放在方法形参的末尾
本质还是for
1 | for(数据类型 变量名 :数据源){ |
变量名:就是循环以后数组里面的每一个值
数据类型:数组里面装的是什么类型
特点:foreach 没有下标
以后在使用的过程中,什么时候使用for循环 什么时候使用for–each
如果要用到索引,必须要使用普通for循环
System
static void arraycopy(Object src, int srcPos, Object dest, int destPos, int length)
将指定源数组中的数据从指定位置复制到目标数组的指定位置。
src - 源数组。
srcPos - 源数组中的起始位置。
dest - 目标数组。
destPos - 目的地数据中的起始位置。
length - 要复制的数组元素的数量。
构造方法主要是用来创建对象
构造方法的语法
要求:没有返回值类型,方法名和类名保持一致(包括大小写)
[修饰符] 类名([形参]){
*
}
1.主要使用来创建对象的,没有可用的构造方法 就不能创建对象
2.创建对象的时候赋值
1.每一个类都有一个隐式公共无参数的构造方法–学习了反射就能够证明
2.如果类里面显示的写了构造方法,隐式的无参数的构造方法就不存在了—–如果要显示的添加构造方法,一般建议把无参数的构造方法也加上
构造方法 方法
1.返回值类型 无 有
2.方法的名字 必须和类名一致 无特殊要求
3.static 不能修饰 可以修饰
4.调用方式 new 类名./对象名.
5.功能 创建对象 普通工具
public Account(){} 是
public void Account(){} 不是【不建议这么去定义普通方法】
对象的生命周期:
开始—被创建的时候(new)
结束—被垃圾回收器回收的时候,失去引用的时候
对象的生命周期:
人的生命周期:
开始—出生
结束—死亡(心脏,脑死亡,失踪,被所有人遗忘的时候)
public class 类名 extends 父类的类名{}
属性
方法
非私有化的成员变量和方法
构造方法不能被继承
1.java里面3类只能单继承,一个类只能一个直接父类
2.java支持多层级继承
3.如果一类没有显示的去继承任何一个类,这个类继承于Object
Object:超类,所有类的直接或间接父类
当父类方法的功能无法满足子类的需要,需要方法覆写
1.子类方法的权限修饰符,大于等于父类权限修饰符
2.子类方法的返回值类型必须要小于等于父类方法的返回值类型
3.方法.名一致
4.形参类型一致
方法名+形参列表=方法签名
方法的覆写都是把父类的方法直接copy过来,更改里面的方法体就ok
一般来讲,在调用方法的时候有限找子类方法,如果子类没有,就去找父类的方法
1.可以在子类构造方法里面调用父类的构造方法,必须写在第一行
2.当子类里面的方法或者属性和父类的方法或者属性重名的时候,区分二义性
子类的构造方法里面,默认都是在调用父类的无参数构造方法
this:就是指当期对象—-this就是对象
super:指的是父类的成员(属性,方法),但是不是父类对象,不持有父类对象的地址引用
抽象类定义的语法
把由abstract 修饰类 叫做抽象类
普通方法
抽象方法
构造方法:有构造方法,但是不能创建对象,由protected修饰的,主要是用于继承的时候子类调用;
成员变量
[父类定义了一些规范]
由abstract 修饰的方法叫做抽象方法,方法的没有方法体
子类继承父类以后,必须要去覆写父类的所有抽象方法
只能出现在抽象类中
abstact 抽象的 出现在修饰符与 返回值之间
抽象类中可以有变量 方法 抽象方法(可有可无)
1.必须知道抽象类的定义语法
2.抽象里面可以定义那些成员
3.抽象方法不能创建对象
4.子类必须要去覆写父类的所有抽象方法
1.用来定义规范
2.解耦
1.jdbc 定义的规范
2.servlet 也是一套接口 定义了规范
接口和类 是同一个级别,但是完全不同的两种类型
interface 接口名字{
}
接口的里面可以有哪些成员:
成员变量
抽象方法【百分之90接口只是提供抽象方法】
1.可以有静态方法 -由static修饰的
2.可以有默认方法 -由default修饰的
实现的语法:
class 类名 implements 接口名{
//必须要去覆写所有接口的抽象方法
}
父类方法功能无法满足子类需求的时候 ,去覆写父类方法
优先找子类的方法,如果子类没有,再找父类的方法
当继承的父类的某个方法,不满足现有的需求,那么可以在子类中进行重写
方法的重写:将父类的方法直接继承到子类中,主要改写,该方法体的内容
方法重写的条件:必须在继承关系中去实现
方法重写:修饰符(子类中修饰符权限更大) 返回值为void是,父类和子类中的返回值类型一致 如果父类中的返回值不为void类型
那么子类中的返回值应该小于等于父类中的返回值为八大类型,那么子类的返回值应该与父类的返回值一致
自定义类型比较:进行排序使用
自定义类型比较的实施:在自定义类中重写equals方法
boolean equals(Object obj) 指示一些其他对象是否等于此。[非常重要]
protected void finalize() 当垃圾收集确定不再有对该对象的引用时,垃圾收集器在对象上调用该对象。 –回收垃圾
Class<?> getClass() 返回此 Object的运行时类。
int hashCode() 返回对象的哈希码值。 –对象存储的在内存里面的位置值
== 是用来比较基本数据类型的值是否相等
如果用于引用数据类型的比较,比较的是两个对象的地址值
注意:特殊情况除外,例如String 以及八大基本数据类型对应的包装类除外
比较两个对象,到底是应该比较两个对象的地址,还是比较两个对象的里面存储的数据?
例如 两张身份证长得一模一样 姓名 性别 出生年月 身份证号码 图片
在java领域里面 引用数据类型比较应该使用equals方法—Object[能够比较里面存储的数据]
注意:默认 equals方法底层还是 == 在比较两个对象地址值是否相等,
覆写equals方法比较两个对象里面的值是否相等。
说一说 == 和 equals 的区别?
自己先尝试整理一个稍微专业一点的回答话术。
== 用于比较基本数据类型的两个值是否相等,如果用于比较引用数据类型,比较的是两个对象地址值
equals:用于比较两个对象里面存储的数据是否相等,但是equals底层还是==,所以我们在使用的时候要腹泻equals方法
一个人 是 人 Person p = new Person()
一头猪 是 猪 Pig pig = new Pig()
一个人 是 动物 Animal a = new Pserson()
一头猪 是 动物 Animal a2 = new Pig()
一个人 是 猪(错误) Pig p = new Person()
一头猪 是 人 (错误) Person p = new Pig()
编译时类型和运行时类型不一致的情况叫做多态
使用父类类型接收子类对象,或者使用接口 接收接口的实现类对象–多态
使用多态的时候,方法的调用的问题:
方法覆写以后,方法的调用顺序是不变的
super用在子类中的–只有在子类中才会区别,到底是使用的父类的属性/方法还是使用子类中的属性/方法
super可以直接打印吗?
super代指的父类(没有持有父类的对象(没有创建))this可以直接打印,持有当前对象
Super():只能放在子类中的构造方法的第一行,子类创建对象的时候,先要调用父类的构造方法,是为了可以继承的相关属性和方法
也是一个修饰符,翻译过来是最终的
成员变量 局部变量 构造方法 普通方法 内部类, 类
类,成员变量 局部变量 普通方法 内部类
类:final修饰的类不能被其他类继承 开发中有没有类不允许继承? String-八大基本数据类型对应的包装类
成员变量:final修饰的成员变量不允许更改值
局部变量:一旦赋值就不能个更改
普通方法:final修饰的方法不能够被覆写
成员变量:被所有对象所共享 应用场景:火车站卖票,对象之间应该共享的属性
方法:修饰方法的时候仅仅只是为了方便调用,使用类名就可以直接调用,一般工具类的方法适合定义为static修饰的方法 例如 Arrays
面向对象阶段:如果要操作非static的成员变量的时候,不考虑static
静态方法不能操作非静态的成员变量
类名.属性名
修饰的方法:
类名.方法名();
1.方法名(); 在同一个类里面,要么都被static修饰,要么都没有被static修饰
2.类名.方法名(); 被修饰的方法被static修饰
3.对象.方法名(); 被调用的方法没有被static修饰
类名 | 位置 | 是否有static | 生命周期开始 | 生命周期结束 |
---|---|---|---|---|
类变量 | 类中 | 有 | 类被加载的时候 | 类被卸载的时候 |
实例变量 | 类中 | 无 | 创建对象的时候 | 对象失去引用 |
局部变量 | 方法代码块中 | 无 |
Usb这个接口不能new 创建对象
1.新建一个类 实现Usb这个接口
2.创建实现类对象,并调用接口方法
1.接口的里面的抽象方法并不多(1-3个)
2.对于接口的实现类对象不会重复使用(只是需要一个对象用一次)
3.不想再去多创建一个实现类文件
由 { 代码 } 包裹起来的代码 叫做代码块
从代码块存放的位置来讲把代码块分为3类:
写在类里面的代码块,叫做构造代码块,创建对象的时候执行【没啥用】
因为构造代码块编译以后里面的内容就会放到构造方法中,所以构造代码块随着对象的创建而去执行
放在类里面由static修饰的代码块【以后会使用】
随着类的加载而执行一次 应用场景
【加载配置文件,应为配置文件只是加载一次】
放在方法的内部,主要作用用于区分方法功能性【没啥用】
随着方法的执行而执行
面向过程关注过程每一个实现的步骤
面向对象关注的结果把没有给步骤交给其他类和方法处理
面向对象编程:万物皆可对象将世间万物看不见的抽象成对象
对象:数据的集合,包含了属性和方法
为了使成员变量更加安全和私密,给成员变量加上private进行私有化。
–先加上SetName GetName –pubilc
减少代码量/减少重复的代码
子类可以直接使用父类的属性/方法 无需再定义
如果父类中的属性/方法,如果使用了private修饰,那么子类是无法继承的
子类无法同时继承多个类 但是继承支持多层继承
创建了子类对象 使用父类来 接收 -这种场景称为多态
官方说法:编译时类型与运行时类型不一致的情况叫做多态
编译时类型:等号的左边,编译阶段编译器看成的类型
运行时类型: 等号右边,运行阶段,对象真实的类型
答:就是针对8大基本数据类型,提供的类的表示形式
byteByte
shortShort
intInteger
longLong
floatFloat
doubleDouble
charCharacter
booleanBoolean
例如 上面的就是基本数据类型对应的包装类,Byte 描述的就是 [-128,127] 这一类事物
答:基本数据类型 只能单纯的表示一个数字或者值,类除了可以表示一个值 还可以提供方法
例如 byte 只能表示 [-128,127]的数字,但是包装类除了可以表示 [-128,127]的数字 提供的有对应一些方法
基本数据类型 有各自默认值
包装类 默认值是 null
基本数据类型 不能够去调用方法
引用数据类型可以调用方法
装箱:把基本数据类型赋值给一个对应的包装类的过程
自动装箱拆箱只支持 基本数据类型和其对应的包装类
拆箱:把一个包装类的类型 赋值给一个对应的基本数据类型的过程
享元模式:设计思想和常量池有点类似 轻量级框架设计
享元模式:把[-128,127]之间所有的数组都缓存起来,方便节约内存重复使用
包装类:享元模式 提前缓存好
String:常量池 用的时候先去找,没找到再缓存
结论:比较两个包装类型的数字是否想的还是应该使用equals
表示字符串的
“abc” 和 new String(“abc”)都是String的对象
构造方法:
String() 初始化新创建的 String对象,
使其表示空字符序列。 相当于 “”
char charAt(int index) 返回 char指定索引处的值。
String concat(String str) 将指定的字符串连接到该字符串的末尾。
boolean endsWith(String suffix) 测试此字符串是否以指定的后缀结尾。
int indexOf(int ch) 返回指定字符第一次出现的字符串内的索引。
boolean isEmpty() 返回 true如果,且仅当 length()为 0 。
int length() 返回此字符串的长度。
String replace(CharSequence target, CharSequence replacement)
将与字面目标序列匹配的字符串的每个子字符串替换为指定的字面替换序列。
String[] split(String regex) 将此字符串分割为给定的 regular expression的匹配。
String substring(int beginIndex) 返回一个字符串,该字符串是此字符串的子字符串。
String substring(int beginIndex, int endIndex) 返回一个字符串,该字符串是此字符串的子字符串。
char[] toCharArray() 将此字符串转换为新的字符数组。
String toLowerCase() 将所有在此字符 String使用默认语言环境的规则,以小写。
String toUpperCase() 将所有在此字符 String使用默认语言环境的规则大写。
String trim() 返回一个字符串,其值为此字符串,并删除任何前导和尾随空格。
对于引用数据类型:
== 比较的两个对象的地址值
equals 比较的是两个对象里面存储的数据
按照对象的存储特点,每一个对象在堆里面的引用地址都不一致,如果使用== 比较都应该是false
(1)当第一次使用String str = “A”; 的方式赋值,会将该字符串值【对象】放入到常量池
(2)当再次使用String str = “A”; 的方式会先检查常量池是否有”A”值,
①如果存在直接引用
②如果不存在,会创建”A”放入常量池
(3)字符串拼接
①常量方式拼接,并直接使用赋值符号赋值,会检查常量池
②变量方式拼接,不会检查常量池【注意】
结论:String的比较还是应该使用equals不能使用==
StringBuffer(String str) 构造一个初始化为指定字符串内容的字符串缓冲区。
StringBuilder,StringBuffer
StringBuffer append(Object obj) 追加 Object参数的字符串表示。
【可以动态的拼接字符串】
使用场景:一般用于有大量的字符拼接的情况,例如生成 csv格式对账单{80-150w}
String 的拼接效率太低了
等到线程那一天学习:
StringBuffer:是线程安全的 效率稍低 使用单线程
StringBuilder:线程不安全的 效率最高 使用多线程
static double random() 返回带正号的 double 值,该值大于等于 0.0 且小于 1.0。
方法都不怎么常用,在某些特定领域用的就非常多(小猿搜题)
BigInteger(基本不用-了解)
可以用来去表示比Long更大的数字
|-可以用来去表示精确浮点数
(double和float都不能精确的表示一个小数)
BigDecimal(String val) 将 BigDecimal 的字符串表示形式转换为 BigDecimal。
形参为什么不给一个double去表示一个精确的小数
数字常用的操作 + - * / 都是通过方法来完成
1 | public BigDecimal add(BigDecimal augend) // 求和 |
返回一个 BigDecimal,其值为 (this + augend),
1 | BigDecimal divide(BigDecimal divisor) //除法 |
返回一个 BigDecimal,其值为 (this / divisor),
1 | BigDecimal multiply(BigDecimal multiplicand) //乘法 |
返回一个 BigDecimal,其值为 (this × multiplicand),
1 | BigDecimal subtract(BigDecimal subtrahend) //减法 |
返回一个 BigDecimal,其值为 (this - subtrahend)
BigDecimal一般需要表示一些精确的小数的时候都需要使用它,涉及到钱相关的,建筑行业
关于数学数字处理 不是一味地四舍五入
数字的舍入方式: 银行卡的余额 一般是小数点后面 2位
金融领域里面:利息和手续费
利息 –例如312.359—312.35
手续费–例如0.231—-0.24
static double random() 返回带正号的 double 值,该值大于等于 0.0 且小于 1.0。
int nextInt() 返回下一个伪随机数,它是此随机数生成器的序列中均匀分布的 int 值。
生成一个 int 范围内的随机数
int nextInt(int n) 返回一个伪随机数,它是取自此随机数生成器序列的、在 0(包括)和指定值(不包括)之间均匀分布的 int 值。
ThreadLocalRandom:—1.7版本
int nextInt(int origin, int bound) 返回指定原点(含)和指定边界(排除)之间的伪随机 int值。
生成 [origin,bound)
UUID:生成的是一个唯一不重复的随机数
static UUID randomUUID() 静态工厂检索一个类型4(伪随机生成)的UUID。
static long currentTimeMillis() 返回以毫秒为单位的当前时间。
static void gc() 运行垃圾回收器。 java里面的垃圾回收器是自动回收
这个方法只能主动的催促运行垃圾回收器,但是不是立即运行
static void arraycopy(Object src, int srcPos, Object dest, int destPos, int length)
从指定源数组中复制一个数组,复制从指定的位置开始,到目标数组的指定位置结束。
获取Runtime的对象
static Runtime getRuntime() 返回与当前 Java 应用程序相关的运行时对象。
方法
Process exec(String command) 在单独的进程中执行指定的字符串命令。 可以调用windows程序
void gc() 运行垃圾回收器。
Date() 分配一个 Date对象,并初始化它,以便它代表它被分配的时间,测量到最近的毫秒。
Date(long date) 分配一个 Date对象,并将其初始化为表示自称为“时代”的标准基准时间以后的指定毫秒数,即1970年1月1日00:00:00 GMT。
方法或者类已弃用【已过时】
这一类的方法或者类都是不建议再使用了,但是不是不能用。
win10 — win xp
默认打印时间的格式为:Sat Nov 13 14:19:49 CST 2021 不符合国内的习惯
SimpleDateFormat:时间格式化的类
SimpleDateFormat(String pattern) 使用给定模式 SimpleDateFormat并使用默认的 FORMAT语言环境的默认日期格式符号。
pattern:用户指定的格式 例如国内习惯时间 2021-11-13 14:23:56
yyyy-MM-dd HH:mm:ss
String format(Date date) 将日期格式化成日期/时间字符串。
Date parse(String source) 从给定字符串的开始解析文本以生成日期。
代码出现不正常的情况
Object
|–Throwable
|–Error –体系下面的问题,可能都是一些硬件等问题,可能不是通过代码能解决的
例如一段程序需要联网传输数据
|–Exception–体系下面的问题,都是一些参数,调用方式等问题造成
1.捕获异常
2.抛异常
在我看来不管是哪一种解决方案,都没真正的去处理异常本身的问题
语法:
1 | try{ |
执行流程:
如果try 里面的代码 出现了错误,就立即执行catch里面代码
如果try 里面的代码没有错误,就不执行catch里面的代码
finally里面的代码 无论try里面代码有没有发生异常都要去执行 finally里面的代码
1.记录日志——方便后期排错–log4j
2.打印异常信息(前期多是这种方案)e.printStackTrace();
3.获取错误信息–可以做额外处理
捕获异常有什么效果:对于可能发生异常代码做捕获的处理,在后期运行的如果发生异常不会因为异常而导致整个程序停止运行
抛异常:不处理异常
语法:
在方法的后面加关键字throws 抛出的异常类型
1 | public void 方法名字() throws 异常类型1,异常类型2{ |
一旦发生异常后面的代码就停止执行
java里面的异常类是非常多的,其实大多数的异常类里面的都没有额外逻辑
java里面之所以定义很多异常类主要的目的就是为了进行错误的分类
例如:ArithmeticException:算术异常–一般是因为不符合数学规范造成错误
NullPointerException:空指针异常–一般是因为使用一个空对象去调用方法出现的错误
ArrayIndexOutOfBoundsException:索引越界–一般是因为数组的角标超出索引范围
ClassCastException:类型转换异常–一般是因为类型不一致之间的转换造成
我们可以自己去扩展,异常的类型来符合功能业务的需要
创建并启动线程的方式一
继承Thread类
public class Thread extends Object implements Runnable
1.写一个类继承Thread
2.覆写run方法
3.创建类的实例【对象】,并且调用start()方法
常用方法:
void start() 导致此线程开始执行;
Java虚拟机调用此线程的run方法。
【这个方法会开启一个新的线程并且调用run()方法】
注意点:
启动线程是调用的start()方法
答:3个线程
main–主线程–开启两个新的线程
musicThread.start();
gameThread.start();
答:调用run方法 仅仅只是在主线程,对象调用方法,不会开启新的线程
start(),开启一个新的线程,准备就绪去尝试分配CPU资源,由JVM去调用里面的run方法执行逻辑
1.每一个线程都应该做不同的事情
2.官方在定义这个run方法时候能不能去决定用户的业务逻辑–不能
3.覆写这个run方法主要的目的就是让用户自己去定义自己的逻辑
1 | static Thread currentThread() //返回对当前正在执行的线程对象的引用。 |
1 | String getName() //返回此线程的名称 |
1 | void setName(String name) //将此线程的名称更改为等于参数 name 。 |
1 | static void sleep(long millis) //线程休眠 |
实现Runnable接口【掌握】
1.自己去新建一个类,实现Runnable接口
2.实现接口里面的run 方法 自己去定义线程的业务逻辑
3.创建一个Runnable实现类的对象,作为一个Thread对象的参数
4.调用start方法启动线程
1.把可能发生线程安全问题的代码抽取成一个方法
2.在方法上面添加一个synchronized
1 | synchronized (控制同步资源) { |
控制同步资源—–>WindowThread.class —>Class实例(唯一性) 在Jvm里面只有一份
同步锁-Lock –接口
1.有一把锁
2.上锁
4.释放锁
Lock –接口—创建对象
–实现类ReentrantLock
常用方法:
void lock() 获得锁。 【上锁】
void unlock() 释放锁。
锁为共享锁,必须要加static
在使用阻塞等待获取锁的方式中,必须在try代码块之外,并且在加锁方法与try代码块之间没有任何可能抛出异常的方法调用,,避免加锁成功后,在finally中无法解锁。
1.时间
2.任务
Timer【java.util】
线程调度任务以供将来在后台线程中执行的功能。 任务可以安排一次执行,或定期重复执行。
Timer() 创建一个新的计时器。
1 | void cancel() //终止此计时器,丢弃任何当前计划的任务。 |
1 | void schedule(TimerTask task, Date time) //在指定的时间安排指定的任务执行。 |
1 | void schedule(TimerTask task, Date firstTime, long period) //从指定 的时间开始 ,对指定的任务执行重复的 固定延迟执行 。 |
1 | void schedule(TimerTask task, long delay) //在指定的延迟之后安排指定的任务执行。 |
1 | void schedule(TimerTask task, long delay, long period) //在指定 的延迟之后开始 ,重新执行 固定延迟执行的指定任务。 |
time:未来执行的时间点
System.currentTimeMillis() 当前的时间
System.currentTimeMillis()+1000*10 在当前时间上面+10秒钟
new Date(System.currentTimeMillis()+1000*10) 创建一个延后10秒钟的时间Date对象
这任务具体的逻辑需要用户自己去写,官方来讲 顶多只能定义好标准【接口,抽象类】
断定TimerTask 不是接口 就是抽象类
task:任务
1.变量—只能放指定类型的一个数据 booolean b= true;
2.数组—能够放指定类型 多个数据
2.1 数组也有类型的约束 int[] String[]
2.2 数组的长度一旦申明以后 长度就不能够改变了 new int[10];
能够存储任意类型,任意长度的容器
1.底层可以定义一个数组来存储数据 Object[]
2.添加数据方法【如果发现容量不够的时候,可以自动扩容】
3.提供一个获取数据方法【根据索引去获取】
4.返回存储了多少个数据的方法
5.删除数据的方法
1 | boolean add(E e) //将指定的元素添加到此列表的尾部。 |
1 | E get(int index) // 返回此列表中指定位置上的元素。 |
1 | E remove(int index) // 移除此列表中指定位置上的元素。 |
1 | int size() //返回此列表中的元素数。 |
1 | void add(int index, E element) //将指定的元素插入此列表中的指定位置。 |
1 | void clear() //移除此列表中的所有元素。 |
1 | Object[] toArray() //按适当顺序(从第一个到最后一个元素)返回包含此列表中所有元素的数组。 |
把集合里面的所有的数据取出来
Object get(int index); 获取指定索引位置的值
int size(); 返回集合的长度
1 | Iterator iterator() //返回一个在一组 T 类型的元素上进行迭代的迭代器 |
Iterator
1 | boolean hasNext() //如果仍有元素可以迭代,则返回 true。 |
1 | E next() //返回迭代的下一个元素。 |
1 | void remove() //移除一个元素 |
一个list里面 现有数据[“AA”,”BB”,”CC”,”DD”,”EE”,”FF”,”GG”]
for(int i=0;i<list.size();i++){
list.remove(i)
}
答:还剩BB DD FF
原理为动态变化,当第一次删除时删除AA,还剩BB CC DD EE FF GG
当第二次删除时删下标为1的值也就是CC,还剩BB DD EE FF GG
当第三次删除下标为2的值也就是EE,还剩BB DD FF GG
当第四次删除下标为3的值也就是GG,还剩BB DD FF
i=3时结束循环
第一次环:i =0 [“BB”,”CC”,”DD”,”EE”,”FF”,”GG”] i=1 size=6
第二次循环:i =1 [“BB”,”DD”,”EE”,”FF”,”GG”] i=2 size=5
第三次循环:i =2 [“BB”,”DD”,”FF”,”GG”] i=3 size=4
第四次循环:i =3 [“BB”,”DD”,”FF”] i=4 size=3 判断为false 结束循环
请问以上代码 for循环几次 ,删除哪些数据,剩余哪些数据?
for(int i=0;i<list.size();i++){
list.remove(i)
}
ArrayList LinkedList
都是集合容器
1.如何创建一个容器
2.如何添加数据
3.如何获取数据
4.遍历数据
5.移除数据
LinkedList() 构造一个空列表。
1 | boolean add(E e) //将指定元素添加到此列表的结尾。 |
1 | E get(int index) //返回此列表中指定位置处的元素。 |
1 | E remove(int index) //移除此列表中指定位置处的元素。 |
1 | int size() //返回此列表中的元素数。 |
针对链表的结构 提供了很多操作头和尾的方法
1 | void addFirst(E e) // 将指定元素插入此列表的开头。 |
1 | E getFirst() //返回此列表的第一个元素。 |
1 | E getLast() // 返回此列表的最后一个元素。 |
LinkedList:删除数据,添加数据速度较快
ArrayList:查询速度较快。
(无序【添加顺序】不可重复的容器)
|–HashSet
|–TreeSet
构造方法
HashSet() 构造一个新的空 set
1 | boolean add(E e) //如果 set 中尚未存在指定的元素,则添加此元素(可选操作)。 |
1 | void clear() //移除此 set 中的所有元素(可选操作)。 |
1 | boolean remove(Object o) // 如果 set 中存在指定的元素,则将其移除(可选操作)。 |
1 | Iterator<E> iterator() // 返回在此 set 中的元素上进行迭代的迭代器。 |
1 | int size() //返回 set 中的元素数(其容量)。 |
|–HashSet –不允许放入重复的数据,
1.先判断元素的hashCode 是否一致
2.在hashCode相等情况下。继续通过equals方法来判断两个数据是否相等
如果hashCode相等和equals的结果为true 就认为是同一个值
Hash–本身也是一套算法,如果说存储的数据特别多,有可能值不同,hashcode值是一致
HashSet 基于HashMap实现,底层也是键值对,hash值一致 数组+链表+红黑树去实现的(1.8)
如果一个类的对象要放到HashSet里面,覆写hashCode 和equals 方法
里面放的数据类型要一直,内部需要排序
TreeSet() 构造一个新的空 set
1 | boolean add(E e) //如果 set 中尚未存在指定的元素,则添加此元素(可选操作)。 |
1 | void clear() // 移除此 set 中的所有元素(可选操作)。 |
1 | boolean remove(Object o) // 如果 set 中存在指定的元素,则将其移除(可选操作)。 |
1 | Iterator<E> iterator() // 返回在此 set 中的元素上进行迭代的迭代器。 |
1 | int size() //返回 set 中的元素数(其容量)。 |
放到TreeSet里面的数据类型必须实现Comparable接口,并覆写里面的方法 public int compareTo(T o);
Comparable
|–int compareTo(T o)
0: 代表是重复的元素
正整数: 升序
负整数:降序
定制排序:
一个人 : 名字 年龄 手机号 地区
不同的人 有不同的理解
1.根据年龄排序 年龄小的排前面 年龄大 后面
2.名字,姓氏的首字符排序
3.地区,地区的首字符
Map是一个全新的结构,和Collection没有半毛钱关系
将键映射到值的对象。一个映射不能包含重复的键;每个键最多只能映射到一个值。
map存储数据的时候 键值对的形式
key不允许重复
一个key只能定义一个值
|–HashMap
HashMap() 构造一个具有默认初始容量 (16)
1 | Object put(Object key, Object value) //将指定的值与此映射中的指定键关联(可选操作)。 将添加和修改合为一体 |
1 | int size() //返回此映射中的键-值映射关系数。 |
1 | void clear() //从此映射中移除所有映射关系 |
1 | Object get(Object key) //根据key 获取值 |
1 | V remove(Object key) //如果存在一个键的映射关系,则将其从此映射中移除(可选操作)。 |
把map里面所有的key取出来 返回一个Set集合
1 | Set<K> keySet() //返回此映射中包含的键的 Set 视图。 |
把map里面所有的Value取出来
1 | Collection<V> values() //返回此映射中包含的值Collection 视图 |
1 | Set<Map.Entry<K,V>> entrySet() //返回此映射中包含的映射关系的 Set 视图。 |
构造一个新的空 set,该 set 根据其元素的自然顺序进行排序。
TreeSet(Comparator comparator) 构造一个新的空 TreeSet,它根据指定比较器进行排序。
TreeSet:存储数据
类必须实现Comparable接口
1.针对要存储的数据单独写一个比较类【排序的规则】,实现接口Comparator
2.覆写方法compare,编写比较的逻辑
3.在创建容器对象的时候传入比较类的对象
作用:泛型就是一种约束,例如集合里面的数据,只能放指定类型
在定义的时候不去指定具体的类型,在使用的时候由使用者自己去指定类型
1.泛型如果不加,类型就是Object
2.泛型不支持基本数据类型
Point
T由用户在使用的时候去指定T的类型
T(Type):类型
E(Element):元素
K(Key):键
V(Value):值
如果用double:领导找到你 说 double不精确
–把类型改String
String:操作起来可能有些不方便 要转换
–要不还是用double
A团队:String要好用一点,准确
B团队:double要好用一些,操作起来方便 不用转换
1 | public class Properties extends Hashtable |
1 | void load(InputStream inStream) //从输入流中读取属性列表(键和元素对)。 |
1 | void list(PrintStream out) //将属性列表输出到指定的输出流。 |
1 | String getProperty(String key) //用指定的键在此属性列表中搜索属性。 |
1 | Object setProperty(String key, String value) //调用 Hashtable 的方法 put。 |
Collection
–List:以特定顺序存储
–ArrayList、LinkList、Vector
–Set:不能包含重复的元素
–HashSet、TreeSet
Map
–HashMap、HashTable、TreeMap
添加的方法 | 获取值方法 | 移除的方法 | 遍历的方式 | |
---|---|---|---|---|
ArrayList | add() | get() | remove() | for、foreach、 Iterator |
LinkedList | add() | get() | remove() | for、foreach、 Iterator |
HashSet | add() | contains() | remove() | foreach、 Iterator |
TreeSet | add() | 无 | 无 | foreach、 Iterator |
HashMap | put() | get() | remove() | foreach、 Iterator |
1.文件
2.文件夹
在Java里面一个File对象就是表示一个文件夹 或者 文件
File(String pathname) 通过将给定路径名字符串转换为抽象路径名来创建一个新 File 实例。
File(String parent, String child) 根据 parent 路径名字符串和 child 路径名字符串创建一个新 File 实例。
File(File parent, String child) 根据 parent 抽象路径名和 child 路径名字符串创建一个新 File 实例。
File这个类,既可以表示文件,又可以表示文件夹
1 | boolean createNewFile() //创建文件 注意:不能创建文件夹 |
1 | boolean delete() //删除此抽象路径名表示的文件或目录。 |
1 | boolean exists() //测试此抽象路径名表示的文件或目录是否存在。 |
1 | String getName() //返回由此抽象路径名表示的文件或目录的名称。 |
1 | String getParent() //返回此抽象路径名父目录的路径名字符串;如果此路径名没有指定父目录,则返回 null。 |
1 | File getParentFile() //返回此抽象路径名父目录的抽象路径名;如果此路径名没有指定父目录,则返回 null。 |
1 | boolean isDirectory() //测试此抽象路径名表示的文件是否是一个目录。 |
1 | boolean isFile() //测试此抽象路径名表示的文件是否是一个标准文件。 |
1 | boolean mkdir() // 创建此抽象路径名指定的目录。 |
1 | boolean mkdirs() //创建此抽象路径名指定的目录,包括所有必需但不存在的父目录。 |
注意:没有权限是不能操作的
1 | static File[] listRoots() //列出可用的文件系统根。 |
1 | String[] list() //返回一个字符串数组,这些字符串指定此抽象路径名表示的目录中的文件和目录。 |
1 | File[] listFiles() //返回一个抽象路径名数组,这些路径名表示此抽象路径名表示的目录中的文件。 |
简单的理解在一个方法的内部自己调用自己
方法的递归调用的注意事项:
递归必须要有出口,如果没有出口最终只有一个结果 栈内存溢出 StackOverflowError
f(0)=0 f(1)=1
已知有个公式 f(n)=f(n-1)+f(n-2) 前提条件 n>=2
f(2)=f(1)+f(0) =1
f(3)=f(2)+f(1) =2
f(4)=f(3)+f(2) =3
f(5)=f(4)+f(3) =5
f(6)=f(5)+f(4) =8
使用程序算 f(5) 等于多少?
1.知道是怎么一回事就可以了
2.递归的次数越多,效率越低
3.理解这种思想就够了,后面其实很少用到
4.哪些地方要使用递归,有层级关系,菜单栏
1.每次读取的单位是一个字节
2.写程序去文件里面读取数据【把文件里面的数据取出来】
InputStream:字节输入流的所有类的父类
抽象类:不能直接创建对象【不能new】,如果要创建对象,找InputStream的子类
FileInputStream:用于读取诸如图像数据之类的原始字节流
FileInputStream(File file) 就是去读取一个指定的文件
FileInputStream(String name) 读取一个指定文件【传入文件的路径】
1.一个字母占一个字节
2.一个中文占两个字节【GBK】
大多数读取的数据方法都叫-read
int read() 从此输入流中读取一个数据字节。 返回字母的ASCII ,如果已到达文件末尾,则返回 -1。
1.输出的单位 字节
2.输出流,把数据写到文件里面去
OutputStream:抽象类
1 | FileOutputStream(File file) //创建一个向指定 File 对象表示的文件中写入数据的文件输出流。 |
1 | FileOutputStream(File file, boolean append) //创建一个向指定 File 对象表示的文件中写入数据的文件输出流。 |
1 | FileOutputStream(String name) //创建一个向具有指定名称的文件中写入数据的输出文件流。 |
1 | FileOutputStream(String name, boolean append) //创建一个向具有指定 name 的文件中写入数据的输出文件流。 |
append:如果为true 就是追加内容
append:如果是false 或者不写 就是覆盖内容
1 | void write(int b) //将指定字节写入此文件输出流。 |
1 | void write(byte[] b) //将 b.length 个字节从指定 byte 数组写入此文件输出流中。 |
1 | void write(byte[] b, int off, int len) //将指定 byte 数组中从偏移量 off 开始的 len 个字节写入此文件输出流。 |
off:从b这个数组里面第几个位置开始写出数据
len:写几个数据出去
1 | void write(byte[] b) //将 b.length 个字节从指定 byte 数组写入此文件输出流中。 |
1 | void write(byte[] b, int off, int len) //将指定 byte 数组中从偏移量 off 开始的 len 个字节写入此文件输出流。 |
off:从b这个数组里面第几个位置开始写出数据
len:写几个数据出去
中文
gbk:占2个字节
UTF-8:占3个字节
1.不适合读取中文,如果说一段数据 边读取边查看
2.多用于去读取视频,音频,图片等二进制文件【不适合去读取一些文字类的文件 txt doc】
Reader:用于读取字符流的抽象类
FileReader:
1 | FileReader(String fileName) //在给定从中读取数据的文件名的情况下创建一个新 FileReader。 |
1 | FileReader(File file) //在给定从中读取数据的 File 的情况下创建一个新 FileReader。 |
1 | int read() //读取单个字符。 如果达到文件末尾 返回-1 |
1 | int read(char[] cbuf) //将字符读入数组。 |
BufferReader 这个类里面有一个方法叫做readLine() 可以一次性读取一行数据
要求:大家立即查看api文档,学习这个类 读取一个java文件在控制台打印内容。
Writer:-抽象类
1 | FileWriter(File file) //根据给定的 File 对象构造一个 FileWriter 对象。 |
1 | FileWriter(File file, boolean append) //根据给定的 File 对象构造一个 FileWriter 对象。 |
1 | FileWriter(String fileName) //根据给定的文件名构造一个 FileWriter 对象。 |
1 | FileWriter(String fileName, boolean append) //根据给定的文件名以及指示是否附加写入数据的 boolean 值来构造 FileWriter 对象。 |
一般适合去操作文本文件
InputStreamReader
InputStreamReader(InputStream in) 创建一个使用默认字符集的 InputStreamReader。
OutputStreamWriter
OutputStreamWriter(OutputStream out) 创建使用默认字符编码的 OutputStreamWriter。
java 1.7以后针对这种关闭流资源比较臃肿的情况提供了一种新的结构
需要自动关闭的流资源-必须实现AutoCloseable接口
1 | try(需要自动关闭的流资源){ |
在Java8之前Java中接口里面的方法默认都是public abstract 修饰的抽象方法并且没有方法体;
1、使用static修饰接口中的方法并且必须有主体;
2、接口的static方法只能够被接口本身调用;接口名.方法名(…);
3、接口的static方法不能够被子接口继承;
4、接口的static方法不能够被实现类覆写及直接调用;
在接口中可定义一个使用default修饰有方法体的方法,接口中可以对这个方法提供默认的一种实现。
1、使用default修饰接口中的方法并且必须有主体;
2、接口的default方法不能够被接口本身调用,需要接口的实例(实现类对象)来调用;
3、接口的default方法可以被子接口继承、覆写或者直接调用;
4、接口的default方法可以被实现类覆写及直接调用;
在接口中,经过static和default修饰的方法必须有方法体;
static修饰的方法调用方式为类.方法名
default修饰的方法必须是实现类的对象调用
static修饰的方法不能被子接口继承,default修饰的方法可以被子接口继承
并复写方法,就可以创建子接口实现类对象进行调用
抽象方法
成员变量
静态方法 — 静态方法如何去调用 类名.方法名()
默认方法 — 默认方法如何使用 实现类对象.方法名()
在Java8以后新增了一个注解
就是一种要求,把只有一个抽象方法的接口叫做函数式接口【静态方法和默认方法个数无关】
回顾一下:我们以前学过的接口里面 哪些有以上特征【函数式接口】
Runnable
Comparator:定制排序
@FunctionalInterface:可以去验证一接口是否是函数式接口
1 | 基本语法: |
(参数1,参数2…)表示参数列表;->表示连接符;{}内部是方法体
1、=右边的类型会根据左边的函数式接口类型自动推断;
2、如果形参列表为空,只需保留();
3、如果形参只有1个,()可以省略,只需要参数的名称即可;
4、如果执行语句只有1句,且无返回值,{}可以省略,若有返回值,则若想省去{},则必须同时省略return,且执行语句也保证只有1句;
5、形参列表的数据类型会自动推断;
6、lambda不会生成一个单独的内部类文件;
7、lambda表达式若访问了局部变量,则局部变量必须是final的,若是局部变量没有加final关键字,系统会自动添加,此后在修改该局部变量,会报错
Lambda:主要是针对匿名内部类简写优化【借鉴了前端的语法】
Lambda表达式只能对函数式接口进行书写
lambda表达式不会产生字节码文件
java8以后,更推荐链式编程
Stream:就是针对数据进行一些连续的操作
1.筛选
2.排序
3.分组
4.分页
Stream(流)是一个来自数据源的元素队列并支持聚合操作
<strong元素队列< strong=””>元素是特定类型的对象,形成一个队列。 Java中的Stream并不会存储元素,而是按需计算。</strong元素队列<>
数据源 流的来源。 可以是集合,数组,I/O channel(nio new IO非阻塞式IO), 产生器generator 等。
聚合操作 类似SQL语句一样的操作, 比如filter, map, reduce, find, match, sorted等。
和以前的Collection操作不同, Stream操作还有两个基础的特征:
在 Java 8 中, 集合接口有两个方法来生成流:
stream() − 为集合创建串行流。
parallelStream() − 为集合创建并行流。
]]>先进入BLOG在themes文件夹里右键gitbash进入并输入
1 | > git clone https://github.com/iissnan/hexo-theme-next themes/next |
修改主题
在config.yml找到themes,这里可直接使用ctrl+shift+f快速查找
找到themses时,lanspeas修改为next
然后在blog文件夹右键gitbash输入
1 | > hexo clean |
然后你就可以在你的入http://yourname.github.io看到你的新主题了
注意事项
主题里也有个config.yml你需要修改
站点config.yml
1 | > title: 老猫的博客 #网站标题 |
创建分类标签归档关于
1 | > hexo new page categories |
分别在分类标签归档关于里的index文件中添加
1 | > type: "categories" |
1 | > # 中文主题配置详解 |
链接:https://pan.baidu.com/s/1tKn9P0r0vw4dU0GkRIIafA
提取码:mwfw
复制这段内容后打开百度网盘手机App,操作更方便哦
第二步:安装node.js
安装时一直点下一步就行了(安装位置自己想放哪就放哪)
第三步:安装cmder
https://cmder.net/
安装迷你版即可
安装完以后在cmder查看是否有npm和node版本出现如果有说明你安装成功并进入下一步
PS:最好讲cmder和JAV文件夹放在一起方便一些
第四步:进入JAV文件夹,在JAV文件夹安装npm依赖
这一步可能不起作用因为我给的是压缩包0.0里面自带
第四步:运用该脚本
输入node jav -h 你可以看到一下内容
接下来你就可以为所欲为了
设置我就不用说了就说一点如果要让你磁力链成功播放那就输入
node jav -a
搜索番号用
node jav -a -s XXXX-XXXX(输入你想要的番号)
如果只要一个链接就不需要-a
]]>首先需要明白什么是指令和头文件?
1 |
#include是一条C预处理器指令,C编译器在编译前做的准备工作,而stdio.h是头文件,此文件包含共编译器使用的输入和输出函数,如scanf(),printf()等等。
没有此头文件,你前期的代码根本完成不了,那么问题来了
为什么不内置一个输入和输出,这样做不是更简单吗?
原因很简单,有些程序根本用不到输入和输出,那么不就多此一举了吗。
main()函数
1 | int main() |
此为入口文件,C程序通常情况下按main()开始执行。
int是返回值,但也是默认值。表明main()函数返回值是整数。
在现有学生阶段我们还可以用这样写
1 | viod mian() |
但是这种写法并不认可,如果你用多个编辑器写的程序用此可能会报错。
注释过于简单不讲只讲风格
/* 这也是一条注释
, 被分成两行。*/
//这种注释只能写一行
花括号
花括号把main()函数括起来。一般而言,所有的C函数都使用花括号标记函数体的开始和结束。这是死规定,不能省略。
声明
1 | int i,j,k; |
此代码声明有i,j,k三个标识符,也就一个变量、函数或其他实体的名称。int 表明i,j,k三个标识符是一个整数。
return语句
1 | return 0; |
有返回值的C函数要有return语句。该语句以return关键字开始,后面是待返回的值,并以分号结尾。
getchar();
这行代码会让程序等待击键,窗口会在用户按下一个键后才关闭。
关于浮点数
1是整数,1.00是浮点数
C语言提供3个附属关键字修饰基本整数类型:short、long和unsigned。
应记住以下几点。
short 类型占用的存储空间可能比int少,short是有符号类型。
long占用的存储空间可能比int多,适用于较大数值,long是有符号类型。
unsigned int或unsigned只用于非负值。这种类型与有符号类型表示的范围不同。例如,16位unsigned int允许的取值范围是0~65535,而不
是-32768~32767。用于表示正负号的位现在用于表示另一个二进制位,所以无符号整型可以表示更大的数。
char类型用于储存字符,它与int 声明都是一样的,这里只讲数组。
float 单精度浮点数,至少精确到小数点6位。
double 双精度浮点数,至少能表示小数点10位。
long double,更高精度,这里不讲。
字符串
C语言没有专门用于储存字符串的变量类型,字符串都被储存在char类型的数组中。数组由连续的存储单元组成,字符串中的字符被储存在相邻的存储单元中,每个单元储存一个字符。
注意每一个数组末尾都有字符\0,这为控字符,它表示字符串的结束,这意味着你定义储存40个字符实际上只能储存39个字符,剩下一个给空字符\0用的。
明示常量
1 |
printf函数(针对常用的)
1 | %c //单个字符 |
用法
1 | printf("%8d %8d %8d\n", a, b c);//这样会间隔一样比较美观 |
scanf函数
printf()函数使用变量、常量和表达式,而scanf()函数使用指向变量的指针。
如果用scanf()读取基本变量类型的值,在变量名前加上一个&。
但如果scanf()把字符串读入字符数组中,就不用&。
如以下代码
1 |
|
常用运算符
赋值运算符:=
等号左侧是一个变量名,右侧是赋给该变量的值。符号=被称为赋值运算符。赋值行为从右往左进行。
如i=i+1;
该语句的意思是:找出变量 i 的值,把该值加 1,然后把新值赋值变量i
加法运算符:+(不讲)
**减法运算符:-*(不讲)
乘法运算符:(不讲)
**除法运算符:/**(不讲)
运算符的优先级
对于C语言,运算符的优先级是从乘除到加减,优先级相同从左到右的顺序,当然=除外。(=是从右往左)
递增运算符:++
前缀递增符:++a
后缀递增符:a++
不同:优先级不同,前缀递增符先递增后运算。
后缀递增符先运算后递增。
举个例子:i=233*++a
a递增1,然后233乘以a,并赋值给i
i=233*a++
2乘以a,并将结果给i,然后a递增1
**递减运算符:–**(与递增相同)
循环
C语言有3种循环:for、while、do while
whlie循环
1 |
|
以上的代码打印2个的烫
如何强制退出循环?
break;
goto;等语句这里不必多讲
for循环
主要形式
for(初始值;初始值对比;初始值增加)
举个例子:
1 |
|
以上代码会输出两个烫
do while
至少执行循环体中内容一次
do
{
}while();
举个例子
1 |
|
以上代码会出现三个烫
switch和break语句
1 | switch ( 整型表达式) |
数组
数组类型
int ID[20];//储存20个int类型整数的数组
char Name[20];//储存20个字符的数组
float mark[20];//储存20个float类型的数组
二维数组
float a[5][12];//内含5个数组元素的数组,每个数组元素内含12个float类型的元素
float a[5][12]; // rain是一个内含5个元素的数组
float a[5][12] ; // 一个内含12个float类型元素的数组
if语句常见错误
1 | if (a < x < z) // 错误,没有使用逻辑运算符 |
正确的方式是用逻辑运算符连接两个关系表达式:
1 | if (a < x && x < z) // 使用&&组合 |
1 |
|
1 | $ hexo new "My New Post" |
More info: Writing
1 | $ hexo server |
More info: Server
1 | $ hexo generate |
More info: Generating
1 | $ hexo deploy |
More info: Deployment
]]>