话说Java一连设计了两套时间工具,分别是日期类型Date,以及日历类型Calendar,按理说用在编码开发中绰绰有余了.然而随着Java的日益广泛使用,人们还是发现了它们的种种弊端.且不说先天不良的Date类型,单说后起之秀的Calendar类型,这个日历工具在实际开发中仍然存在以下毛病:1.日历工具获取当前月份的时候,与Date一样都是从0开始计数,比如通过get方法获得的一月份数值为0:2.日历工具获取当天是星期几的时候,星期日是排在最前面的,通过get方法获得的星期日数值为1,而星期一数…
前面在<Java开发笔记(九)赋值运算符及其演化>中提到,Java编程中的等号“=”表示赋值操作,并非数学上的等式涵义.Java通过等式符号“==”表示左右两边相等,对应数学的等号“=”:通过不等符号“!=”表示左右两边不等,对应数学的不等号“≠”.可是一个等式真的就一定成立吗?譬如半斤八两这个成语,用Java等式改写的话变为“半斤==八两”.话说当年秦始皇统一中国,不但推行“书同文.车同轨”,而且也制定了重量单位的换算标准,当时规定十六两为一斤,从此沿用了两千多年.直到公元1959年,为了与…
现将本博客的Java学习文章整理成以下笔记目录,方便查阅. 第一章 初识JavaJava开发笔记(一)第一个Java程序Java开发笔记(二)Java工程的帝国区划Java开发笔记(三)Java帝国的特种官吏Java开发笔记(四)Java帝国的度量衡 第二章 数值变量Java开发笔记(五)数值变量的类型Java开发笔记(六)特殊数字的表达Java开发笔记(七)强制类型转换的风险 第三章 算术运算Java开发笔记(八)五种算术运算符Java开发笔记(九)赋值运算符及其演化Java开发笔记(十)一元…
注解属于比较高级的Java开发技术,前面介绍的内置注解专用于编译器检查代码,另外一些注解则由各大框架定义与调用,像Web开发常见的Spring框架.Mybatis框架,Android开发常见的ButterKnife框架等等,都使用了大量的注解.为了更好地弄清注解的应用原理,接下来不妨尝试自定义注解,并在实际开发中对自定义的注解加以运用.之前介绍异常预防的时候,为了避免出现空指针异常,可谓是八仙过海各显神通,一路试验了多项新技术.其中校验某个字段非空尤其是个难点,案例中的苹果类共有四个字段,包括名…
数组作为一种组合形式的数据类型,必然要求提供一些处理数组的简便办法,包括数组比较.数组复制.数组排序等等.为此Java专门设计了Arrays工具,该工具包含了几个常用方法,方便程序员对数组进行加工操作.Arrays工具的方法说明如下: Arrays.equals(a1, a2); // 判断a1和a2两个数组是否相等,也就是每个元素是否都相等 Arrays.fill(a, val); // 往数组a全部填入指定的数值val dest = Arrays.copyOf(src, newLength)…
前面介绍了许多数据类型,除了基本类型如整型int.双精度型double.布尔型boolean之外,还有高级一些的如包装整型Integer.字符串类型String.本地日期类型LocalDate等等,那么这些数据类型为何会分成基本和高级两种呢?这与编程语言的发展历程息息相关,像中文.英文这些是人类社会的自然语言,而计算机能够识别的是机器语言,但是机器语言全为以0和1表达的二进制串,看起来仿佛天书一般,读都读不懂,更别说写出来了.为了方便程序员也能操纵计算机,科学家把机器语言所表达的一些常见操作归纳…
前面介绍了字节缓存的一堆概念,可能有的朋友还来不及消化,虽然文件通道的用法比起传统I/O有所简化,可是平白多了个操控繁琐的字节缓存,分明比较传统I/O更加复杂了.尽管字节缓存享有缓存方面的性能优势,但传统I/O也有缓存输入输出流呀,大家都有缓存机制,凭什么说NIO的文件处理更高效?之所以目前还看不出文件通道的性能优势,是因为前面介绍的仅限于它的基本用法,尚未涉及到高级特性,接下来阐述文件通道的真正杀手锏:使用通道复制文件.复制文件的常规做法很简单,从源文件中读出数据,再将数据写进目标文件.采取文…
不管是基本的char字符型,还是包装字符类型Character,它们的每个变量只能存放一个字符,无法满足对一串字符的加工.为了能够直接操作一连串的字符,Java设计了专门的字符串类型String,该类型允许保存一整串字符,并对字符串进行各种处理.字符串类型不属于基本类型,它的用法与包装类型更为接近.例如给字符串变量赋初始值,就有多达四种的赋值形式(包装类型只有三种赋值),分别介绍如下:1.被双引号包裹着的字符串,可直接用等号赋值给字符串变量,代码示例如下: // 第一种方式:用双引号把字符串括起…
前面介绍了如何通过Date工具获取各个时间数值,但是用户更喜欢形如“2018-11-24 23:04:18”这种结构清晰.简洁明了的字符串,而非啰里八唆依次汇报每个时间单位及其数值的描述.既然日期时间存在约定俗成的习惯表达,那就有劳程序员手工把日期时间转换成字符串呗,于是利用String类型的format方法,可将各个时间单位按照规定格式拼接成符合要求的字符串.下面是通过String.format方法转换日期时间的代码例子: Date date = new Date(); // 手工拼接指定格式…
前面介绍了日历工具Calendar的基本用法,乍看起来Calendar与Date两个半斤八两,似乎没有多大区别,那又何苦庸人自扰鼓捣一个新玩意呢?显然这样小瞧了Calendar,其实它的作用大着呢,接下来不妨深入探讨一下Calendar的几种实际应用,主要包括:Calendar和Date类型互相转换.计算两个日历时间的天数.打印当前月份的月历等,分别说明如下. 1.Calendar和Date类型互相转换虽说Date早就应该被Calendar取代,但毕竟是前辈,而且Java也一直没有抛弃它,特别有…
前面介绍了类的基本用法,主要是如何封装一个类的各项要素,包括成员属性.成员方法.构造方法等,想必大家对类的简单运用早已驾轻就熟.所谓“物以类聚,人以群分”,之所以某些事物会聚在一起,乃是因为它们拥有类似的品性.那么面向对象的目的,就是将一群事物之间共同的行为特征提炼出来,从而归纳为具有普适性的类型.像日常生活中说的昆虫.鱼类.鸟类,便是人们把外表相似.习性相近的一系列动物归类的结果.以鸟类为例,按照科学家的定义,它们是动物界→脊索动物门→鸟纲下面所有动物的总称.倘若按照大众的观点,鸟类为长着一对…
前面介绍了如何自己定义函数式接口,本文接续函数式接口的实现原理,阐述它在数组处理中的实际应用.数组工具Arrays提供了sort方法用于数组元素排序,可是并未提供更丰富的数组加工操作,比如从某个字符串数组中挑选符合条件的字符串并形成新的数组.现在就让我们从零开始,利用函数式接口实现数组元素筛选的功能.首先要定义一个字符串的过滤器接口,该接口内部声明了一个用于字符串匹配的抽象方法,由此构成了如下所示的函数式接口代码: //定义字符串的过滤接口 public interface StringFilt…
一个程序开发出来之后,无论是用户还是程序员,都希望它稳定地运行,然而程序毕竟是人写的,人无完人哪能不犯点错误呢?就算事先考虑得天衣无缝,揣着一笔巨款跑去岛国买了栋抗震性能良好的海边别墅,谁料人算不如天算,碰到猴年马月遇上了一场大海啸,整个别墅被冲到山上去了.计算机程序也是如此,不管是人为的错误,还是意外的风险,都会导致程序在运行时异常退出.引起程序异常的原因多种多样,就已经介绍过的知识点而言,主要有这么几种可能发生异常的情况:数学运算异常.数组越界异常.字符串与日期格式异常.空指针异常.类型转换…
前面介绍的几种异常,其实都存在这样那样的逻辑问题,属于程序员的编码手误.还有一大类系统错误,表面上看不出什么问题,但是程序仍然运行不下去,兹举二例说明.第一个例子且看下列的测试代码: // 测试内存溢出错误:程序需要的内存超过了最大的堆内存配置 private static void testUnlimitedString() { String str = "Hello world"; String result = getUnlimitedString(str); // 获取无限大小…
前面介绍了线程的基本用法,以及多线程并发的问题处理,但实际开发中往往存在许多性质相似的任务,比如批量发送消息.批量下载文件.批量进行交易等等.这些同类任务的处理流程一致,不存在资源共享问题,相互之间也不需要通信交互,总之每个任务都可以看作是单独的事务,仿佛流水线上的原材料经过一系列步骤加工之后变为成品.可要是开启分线程的话,得对每项任务都分别创建新线程并予以启动,且不说如何的费时费力,单说这批量操作有多少任务就要开启多少分线程,系统的有限资源禁不起这么多的线程同时过来折腾.就像工厂里的流水线,每…
前面介绍了HTTP协议的网络通信,包括接口调用.文件下载和文件上传,这些功能固然已经覆盖了常见的联网操作,可是HTTP协议拥有专门的通信规则,这些规则一方面有利于维持正常的数据交互,另一方面不可避免地缺少灵活性,比如下列条条框框就难以逾越:1.HTTP连接属于短连接,每次访问操作结束之后,客户端便会关闭本次连接.下次还想访问接口的话,就得重新建立连接,要是频繁发生数据交互的话,反复的连接和断开将造成大量的资源消耗.2.在HTTP连接中,服务端总是被动接收消息,无法主动向客户端推送消息.倘若客户端…
传统的桌面程序基本是对某种类型的文件进行加工,例如Window自带的记事本用来读写文本文件,自带的画图程序用来查看和修改位图文件.为了方便用户切换各种操作,这些程序在窗口顶端放了一排菜单栏,单击菜单栏上的每个菜单,又会在下方弹出一列菜单项,就像下图所示的记事本菜单那样. 然后单击某个菜单项,比如“新建”.“打开”.“保存”等,记事本程序便会执行相应的处理操作.这组菜单在Swing中被分解为三种控件,首先是顶部的一整条菜单栏,对应的控件叫JMenuBar:其次是菜单栏上的每个菜单,对应的控件叫JM…
桌面程序在运行过程中,时常需要在主界面之上弹出小窗,把某种消息告知用户,以便用户及时知晓并对症处理.这类小窗口通常称作对话框,依据消息交互的过程,可将对话框分为三类:消息对话框.确认对话框.输入对话框,分别介绍如下: 1.消息对话框这类对话框仅仅向用户展示一段文本,告诉用户发生了什么事情.它起到了提示的作用,但不支持用户干预事务.不管用户同意与否,都无法改变事件的进展.在Swing框架中,消息对话框由消息的标题.内容.确定按钮组成.调用JOptionPane工具的静态方法showMessageD…
程序除了处理内存中的数据结构,还要操作磁盘上的各类文件,这里的磁盘是个统称,泛指可以持久保留数据的存储介质,包括但不限于:插在软驱中的软盘.固定在机箱中的硬盘.插在光驱中的光盘.插在USB接口上的U盘.笔记本电脑里的固态盘.手机中的闪存.相机里的SD卡等等.当然,操作系统层面已经统一了这些存储介质,故而编程语言无须理会它们之间的区别,只需专心访问存储介质上保存的文件.为表述方便,接下来将用"磁盘"二字代指以上罗列的各种存储介质.Java使用File工具来操作磁盘文件,只要在构造方法中填…
经过前面的学习,我们发现演示的Java代码越来越复杂,而且每个例子的代码都堆在入口方法main内部,这会导致如下问题:1.一个方法内部堆砌了太多的代码行,看着费神,维护起来也吃力:2.部分代码描述的是通用算法,比如牛顿迭代法.二分查找法等等,这些通用的算法代码结构固定,很多地方会用到,倘若每次都复制粘贴无疑是苦大仇深:基于此,亟需对纷繁复杂的代码段加以梳理,一方面把代码行依据功能进行划分,这样剥离出来的各段代码不会相互影响:另一方面封装通用的算法代码,做到只定义一次,就能被多次调用.这样既提高了…
正如整型int有对应的包装整型Integer那样,字符型char也有对应的包装字符型Character.初始化字符包装变量也有三种方式,分别是:直接用等号赋值.调用包装类型的valueOf方法.使用关键字new创建新变量.倘若要把字符包装变量转换成字符变量,则调用包装变量的charValue方法即可.甚至可以对字符包装变量做加减乘除运算,就像之前对待字符变量一般,字符包装类型的基本使用代码示例如下: // 声明一个包装字符变量 Character character = 'A'; System.…
前面的文章提到,Date是Java最早的日期工具,估计当时的设计师是个技术宅男,未经过充分调研就拍脑袋写下了Date的源码,造成该工具存在先天不足,比如getYear方法返回的不是纯正的公元纪年.getHours方法无法区分12小时制和24小时制等等,这很不利于Java语言的国际化.故而从JDK1.1开始,Java又提供了一个日历工具Calendar,官方建议采用Calendar替代Date,并且Date的相关get方法都被标记为Deprecated(意思是已废弃).接下来就来看看这个全新的Ca…
之前介绍Calendar的时候,提到日历实例无法直接输出格式化后的时间字符串,必须先把Calendar类型转换成Date类型,再通过格式化工具SimpleDateFormat获得字符串.而日期时间的格式化恰恰是最常用的场合,这就很尴尬了,原本设计Calendar是想取代Date,结果大家还在继续使用Date类型,没有达到预期的效果.那么Java8重新设计的本地日期时间家族,为了彻底革了Date的命,同时推出了自己的格式化器具DateTimeFormatter,并定义了几种常见的日期时间格式.例如…
前面介绍了如何定义一个简单的类,以及它的成员属性和成员方法,从示例代码可以看到,不管是OrangeSimple还是OrangeMember,都要先利用关键字new创建一个实例,然后才能通过实例名称访问成员属性和成员方法.不知道大家有没有注意到,new后面的类名跟着一副圆括号,就像下面代码这样: // 创建OrangeMember的一个实例 OrangeMember orange = new OrangeMember(); 可圆括号通常是方法的标配呀,为啥类名后面也能直接跟着圆括号呢?这是因为,类…
前面介绍了类的基本定义,包括成员属性.成员方法.构造方法几个组成要素,可谓是具备了类的完整封装形态.不过在进行下一阶段的学习之前,有必要梳理一下前述的类定义代码,看看是否存在哪些需要优化的地方.首先观察以下的代码片段,主要是重量属性的定义及其设置方法: // 定义了橘子的重量 private double weight; // 设置橘子的重量 public void setWeight(double inputWeight) { weight = inputWeight; } 注意到setWei…
前面介绍了如何从Bird类继承而来Swallow类,按道理子类应当继承父类的所有要素,但是对于构造方法来说,Swallow类仅仅继承了Bird类的默认构造方法,并未自动继承带参数的构造方法.如果子类想继续使用父类的其它构造方法,就得自己重写心仪的构造方法.例如老鹰属于鸟类,那么可以编写继承自Bird类的Eagle类,同时要在Eagle类内部重新定义拥有多个输入参数的构造方法,由此得到如下所示的Eagle类代码: //定义了一个继承自鸟类的老鹰类 public class Eagle extend…
前面介绍了多态的相关用法,可以看到一个子类从父类继承之后,便能假借父类的名义到处晃悠.这种机制在正常情况之下没啥问题,但有时为了预防意外发生,往往只接受当事人来处理,不希望它的儿子乃至孙子来瞎掺和.可是犹记得几种开放性修饰符,只能控制某个实体能否被外部访问,从未听说可决定某个类能否被其它类所继承.毫无疑问,是否开放与能否继承是两种不同的概念,不管是被public修饰的公共类,还是被private修饰的私有类,它们默认都是允许继承的.要想让某个类不能被其它类继承,还得在类名前面额外添加一个关键字f…
通常情况下,一个Java代码文件只定义一个类,即使两个类是父类与子类的关系,也要把它们拆成两个代码文件分别定义.可是有些事物相互之间密切联系,又不同于父子类的继承关系,比如一棵树会开很多花朵,这些花儿作为树木的一份子,它们依附于树木,却不是树木的后代.花朵不但拥有独特的形态,包括花瓣.花蕊.花萼等,而且拥有完整的生命周期,从含苞欲放到盛开绽放再到凋谢枯萎.这样一来,倘若把花朵抽象为花朵类,那么花朵类将囊括花瓣.花蕊.花萼等成员属性,以及含苞.盛开.凋谢等成员方法.既然花朵类如此规整,完全可以定义…
前面介绍了方法引用的概念及其业务场景,虽然在所列举的案例之中方法引用确实好用,但是显而易见这些案例的适用场合非常狭窄,因为被引用的方法必须属于外层匿名方法(即Lambda表达式)的数据类型,像isEmpty.contains.startsWith.endsWith.matches.compareTo.compareToIgnoreCase等等无一例外全部归属String字符串类型,假使Lambda表达式输入参数的数据类型并不拥有式子右边的方法,那么方法引用还能派上用场吗?当然Java8憋出方法引…
前面介绍了如何通过fxml文件编排界面布局,可是光有静态界面根本没法处理业务,必须另外书写业务逻辑的代码,方能响应各按钮的单击事件,并将业务结果即使呈现到界面上.显然,fxml内部写不了Java代码,同时入口程序已经把控件都托管给了fxml文件,也无法在Application代码中干预控件的操作.既然整个界面都托付给了fxml,那么解铃还须系铃人,只能且必须由fxml指定后续的逻辑控制器.具体做法是在fxml的根节点中添加属性“fx:controller”,通过该属性设置当前界面的控制器路径.比…