提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档
姓名:YXT
学号:202302151210
目录
除了查找、转换一类的方法之外,String类还提供了一些其他的方法,比如比较字符串是否相同、判断字符串是否为空等方法,如下表所示。
6.3 StringBuffer类与StringBuilder类
前言
在开启《Java面向对象程序设计》的学习之旅前,我深知自己正站在编程世界的一扇重要门前。此前,我虽对其他计算机语言的基础语法略知一二,能编写些简单程序,但那些代码宛如一盘散沙,缺乏严谨的结构与清晰的逻辑。面向对象编程,恰似一位智慧的建筑师,能将这些散乱的代码片段巧妙组装,构建起功能强大且易于维护的软件大厦。
我怀揣着对知识的渴望与对技术的敬畏,期望通过深入研读该计算机语言,全方位掌握面向对象的核心理念。从理解对象与类的精妙关系开始,学会如何将现实世界的复杂事物抽象为程序中的类,再通过对象的实例化,让这些类在软件中“活”起来,精准执行各自的功能。封装、继承、多态这些面向对象的“三剑客”,更是让我充满好奇与期待。我想要领略封装如何为对象穿上一层神秘外衣,巧妙隐藏内部细节,只将简洁明了的接口展现给外界;继承则如同赋予对象家族血统,让子类能传承并扩展父类的特质,实现代码的高效复用;多态则像是一位魔术师,让同一个方法在不同对象上调用时,呈现出不同的神奇效果,极大提升程序的灵活性与扩展性。
书中关于异常处理的篇章,也让我意识到编程并非总是一帆风顺,错误与异常如影随形。我渴望学会如何优雅地捕获与处理这些异常,让程序在遭遇意外时,能从容不迫地做出应对,而非粗暴崩溃,保障软件的健壮性与用户体验。
对于Java中的常用类,如包装类、大数字运算类、字符串类等,我充满向往。它们宛如编程工具箱里的一件件精巧工具,各自有着独特的功能与用途。掌握这些类的使用方法,无疑将极大提升我的编程效率,让我在处理数据、操作字符串、进行数学计算时,更加得心应手。
学习之路从无坦途,但我已做好准备,以谦逊之心、勤勉之行,逐章逐节深入研读该计算机语言。我深知,只有通过不断的实践与思考,才能将书中的知识内化为自己的技能。未来,我期望能将所学的面向对象知识运用到实际项目中,解决复杂问题,创造出优质软件,为自己的编程生涯开启崭新篇章。
内容
第1章 Java概述
1.1程序设计方法
计算机语言(Computer Language)是人与计算机之间通信的语言,它主要由一些指令组成,这些指令包括数字、符号和语法等内容,程序员可以通过这些指令指挥计算机进行工作。
计算机语言的种类非常多,总的来说可以分成机器语言、汇编语言、高级语言三大类。
机器语言都是由二进制的0和1组成的编码,不便于记忆和识别。
汇编语言采用了英文缩写的标识符,容易识别和记忆;
高级语言采用接近于人类的自然语言进行编程,进一步简化了程序编写的过程。
面向过程
面向过程的程序设计方法又称为结构化方法,采用自顶向下、 逐步求精的方法,把整个程序按功能划分为几个独立的功能模块,通过主过程调用各子过程来解决问题。
面向过程的程序设计中,数据和操作是分离的。
常见的面向过程的程序设计语言:C语言
面向对象
面向对象程序设计是现在主流的程序设计方法。
面向对象程序设计的基本观点:
世界是由实体(对象)所组成的。
在计算机中,使用面向对象的观点来描述、模仿并处理现实问题。
面向对象程序的基本组成单位是类,数据和操作封装在类中。
对象是面向对象程序设计的核心。
常见的面向对象的程序设计语言有Java、C#、python、C++、go 等。
1.2类和对象
对象:万事万物都是对象。 Book computer
类:对相同类型的对象提取出共同特性和行为。
对象是类的实例,类是对象的模板。
1.3 面向对象的三个基本特征
封装:数据及基于其上的操作被封装在对象内部,仅对外公开接口。吗
继承:已有类的基础上扩充或改写其某些属性及方法,生成新的类称为原有类的子类。
多态:同一个接口,使用不同的实例而执行不同操作。
子类对父类方法的覆盖。
利用重载在同一个类中定义多个同名的不同方法。
1.4Java程序设计语言的特点
简单性:Java语言是一种相对简单的编程语言,它通过提供最基本的方法完成指定的任务。
面向对象: Java语言提供了类、接口和继承等原语,只支持类之间的单继承,但支持接口之间的多继承,并支持类与接口之间的实现机制(关键字为implements)。
分布式: Java是分布式语言,既支持各种层次的网络连接,又可以通过Socket类支持可靠的流(stream)网络连接
健壮性:
安全性: Java安全可靠,例如,Java的存储分配模型可以防御恶意代码攻击。
跨平台: Java通过JVM(虚拟机)以及字节码实现跨平台。 Java程序由javac编译器编译成为字节码文件(.class)文件, JVM中的Java解释器会将.class文件翻译成所在平台上的机器码文件,执行对应的机器码文件就可以了。
多线程的: Java语言支持多线程,程序中多个任务可以并发执行
动态性 :
1.5JDK的安装
Java的官方网站下载开发工具的最新版本,下载的网址如下:
1.6系统环境变量配置
安装完毕后,还需对操作系统的环境变量进行配置:
参考资料:课本、链接:https://blog.csdn.net/bigdargon/article/details/124269739
右键“计算机”->属性->高级系统设置->高级->环境变量->系统变量
1.7一个简单的Java程序(HelloWorld案例)
1.8 个人见解
Java是一种成熟且广泛使用的编程语言,以其跨平台性和面向对象的特性而闻名。它的简洁语法和强大的类库使得开发复杂应用变得高效且易于管理。Java的跨平台能力,通过Java虚拟机(JVM)实现,让开发者能够编写一次代码并在多种设备上运行,极大地提高了开发效率和应用的可移植性。此外,Java的安全性和多线程支持使其在企业级应用和网络编程中占据重要地位。随着Java社区的不断发展,它持续为开发者提供丰富的资源和工具,保持了其在编程语言领域的竞争力和影响力.
第2章 Java编程基础
2.1变量与常量
关键字和保留字
标识符与命名规范
标识符只能由字母、数字、下划线、美元符号组成,并且不能以数字开头。
Java标识符大小写敏感,长度无限制
标识符不可以是Java关键字和保留字
数据类型
变量的定义与赋值
变量的本质就是一个“可操作的存储空间”,空间位置是确定的,但是里面放置什么值不确定。变量必须先声明再使用。变量声明的语法如下:
变量赋值语法如下所示:
常量
常量与变量的语法类似,只在变量声明语法前加上final关键字即可。变量是可以改变值的量,而常量一旦被赋值后,就不可以改变了。常量名的命名,一般要求所有字母大写,单词之间使用“_”隔开。常量声明语法如下:
变量的类型转换
Java中的数据类型转换主要分为两种:自动类型转换(隐式转换)和强制类型转换(显式转换)。
首先是自动类型转换,在Java中,占用字节数少的数据类型的值,可以直接赋值给占用字节数多的数据类型的变量,比如short类型的值可以直接赋值给int类型的变量,或者把int类型的值赋值给double类型的变量,如下所示:
其中有个特例:int类型的常量可以直接赋值给char、short、byte,只要不超过它们能够表示的值的范围即可。
强制类型转换则可以强制性地将占用字节数多的数据类型的数据转换成占用字节数少的数据类型的数据,但这个转换过程可能会存在数据精度丢失的问题。强制类型转换的语法如下:
Scanner的使用
Scanner类在java.util包下,使用时需要导包,不过好在所使用的开发工具会自动导包,因此并不需要关心。首先需要使用 new 关键字创建Scanner的对象,再通过Scanner类的next()方法获取用户在控制台输入的字符串,通过nextByte()、nextShort()、nextInt()、nextLong()、nextFloat()、nextDouble()获取用户在控制台输入的基本数据类型。
2.2运算符与表达式
算术运算符
算术运算符是Java中最简单、最常用的运算符,它主要提供了数值的加、减、乘、除以及求余运算的功能。算术运算符分为一元运算符和二元运算符,如下表所示:
赋值运算符
除了赋值运算符之外,Java中还将赋值运算符与算术运算符进行了合并,提供了更简洁的扩展赋值运算符。扩展赋值运算符的作用是简化一部分代码的书写,如下表所示。
关系运算符
逻辑运算符
位运算符
三元运算符
运算符优先级
2.3 选择结构
if语句
程序执行到if语句后会进行判断:当条件表达式1为true时,执行代码块1;否则,当条件表达式2为true时,执行代码块2;否则,当条件表达式3为true时,执行代码块3;否则,执行代码块n。其中,一个if语句之后可以有0至多个else if语句,可以有0或1个else语句。
switch语句
除了if语句外,switch语句也是选择结构。switch语句一般用于做一些精确值的判断,其语法格式如下所示。
switch语句会根据表达式的值从相匹配的case标签处开始执行,一直执行到break语句处或者是switch语句的末尾。如果case全都不匹配,则进入default语句。
选择结构的嵌套
选择结构在使用上可以嵌套,if中的代码块也可以是switch语句,switch语句中的代码块也可以是if语句。通过嵌套,可以去判断更加复杂的逻辑。
两种选择结构对比
if语句和switch语句都可以实现逻辑判断,但它们的使用场景有所不同。if语句一般用于区间值的判断,而switch语句只能用于确定值的判断。凡是switch语句能够实现的,if语句都可以实现,反之则不行。
2.4 循环结构
for语句
for循环的语法格式如下:
while语句
while语句相较于for循环更加简单,它的语法有点类似于if语句,如下所示:
do…while语句
不管是for循环还是while循环,都会在循环之前判断循环条件,如果条件刚开始就为false,那么循环体就不会被执行。实际开发中,可能会存在需要循环体至少执行一次的场景,此时就可以使用do...while循环语句。do...while语句语法格式如下所示:
break和continue语句
在任何循环语句的主体部分,均可用break控制循环的流程。break用于强行退出循环,不执行循环中剩余的语句。而continue则只能终止某次循环,继续下一次循环。
三种循环结构应用场景
三种循环在任何场景下都是可以互相替换的,但实际开发中应当根据合适的需求场景选择不同的循环语句。如果能够确定循环次数,建议使用for循环;如果不能确定循环次数,或者想让循环永远执行,建议使用while循环;如果想让循环体至少执行一次,建议使用do...while循环。当然,这三种循环可以互相通用。
2.5 方法
介绍
方法就是定义在类中的具有特定功能的一段独立小程序,用来完成某个功能操作。在某些语言中方法也称为函数或者过程。
在平时的开发中,不可能把程序的所有功能都写到main()方法中,这样维护起来成本很大,因此需要将功能拆分成一个一个方法,需要完成该功能时只需要调用对应方法即可。
方法声明与调用
当想要使用方法时,必须先声明该方法,才能在其它代码中调用。方法声明语法格式如下所示。
方法的声明包含了很多组成部分,每个组成部分的含义如下:
修饰符:用于控制方法的访问权限,目前学习阶段全部写为public static即可。
返回值类型:方法需要返回给调用者数据的数据类型,如无返回值,必须声明返回值类型为void。
方法名:方法的名字,命名规范在标识符规范的基础之上,采用首字母小写的驼峰命名规则。
形参列表:由参数类型和参数名组成,也称作形式参数(形参),形参可以为任意多个,用于调用者给方法内部传递数据。
方法体:该方法需要实现的具体逻辑。
返回值:方法执行完毕后提供给调用者的数据。如果定义了返回值类型,那么返回值和返回值类型必须保持一致;如果定义的返回值类型为void,那么需要省略返回值,也就是直接用语句“return;”返回或者省略该语句直至该方法执行结束。当方法在执行过程中遇到return语句,就会返回而结束该方法的执行。
当声明了一个方法之后,就可以使用代码在其他方法中调用它了。调用方法的语法格式如下所示:
方法调用时的参数列表称为实际参数(实参)。实参列表的数据类型和参数个数必须与方法声明时完全一致。
方法重载
如果出现了很多功能类似的方法,为了让方法能够做到见名知意,这些方法的命名就需要类似,如果这些方法很多,就会导致方法名非常混乱。为了解决这种问题,就出现了方法的重载。
在同一个类中,允许存在一个以上的同名方法,只要它们的参数个数或者参数类型不同即可,这种现象称作方法重载。需要注意的是,方法重载只与参数和方法名有关,返回值类型不同,不构成方法的重载;形参的名称不同,不构成方法的重载;方法修饰符不同,不构成方法的重载。
从输出结果可以看出,虽然方法名都相同,但是根据传入的参数不同,JVM会自动调用对应的重载方法。System.out.println方法就是个非常典型的重载方法,该方法为了能够打印任何数据类型,就重载了大量的println()方法,为的就是能够支持所有的数据类型,如下图所示。
方法递归
编程语言中,方法直接或间接调用方法本身,则称该方法为递归方法。合理的使用递归,能够解决很多使用循环难以解决的问题。
典型的斐波那契数列问题:指的是这样一个数列:0、1、1、2、3、5、8、13、21、34、……,在数学上,斐波那契数列被以如下递推的方式定义:
F(0)=0,F(1)=1,F(n)=F(n - 1)+F(n - 2) (n ≥ 2,n ∈ N*)
2.6 数组
数组概述
数组的常见操作
1.通过索引操作元素
数组元素的操作都是通过索引(也称作下标)进行的,当创建了一个长度为n的数组后,它的索引范围是[0, n-1]
2.数组的遍历
当数组元素很多时,不可能一个一个使用索引获取元素,而是希望能够通过循环的方式取出数组中每一个元素,这个操作称作遍历。数组的遍历一般使用for循环遍历,从0遍历到数组长度-1即可。
事实上,如果只是想获取数组中的每一个元素,并不需要给数组元素赋值,也不需要操作索引,还有一种更为简便的遍历方式:foreach循环,又称作增强for循环。
foreach循环的语法格式如下所示
3.获取数组的最值
当需要获取到数组的最大值或最小值时,通过常规的思路可能不太好处理,此时可以使用“假设法”。首先假设索引0处的元素是最大值,之后遍历整个数组,每次遍历取出当前元素与所假设的最大值进行比较,如果当前元素比假设的最大值还大,就再假设该元素是最大值,直到数组遍历完毕为止,最后所假设的最大值就是真正的最大值。
4.通过值获取索引
有时可能需要查询数组中某个值所在的索引位置,这个操作也可以通过遍历实现,但需要注意,待查找的值可能在数组中不存在,因此需要先假设待查找值的索引为-1。因为-1这个值不可能是数组的索引,因此当遍历结束后如果索引还是-1,就说明没有找到该值。
5.数组元素的反转
有时候可能需要反转一个数组,将数组元素首尾互换,这可以借助一个新的数组。
数组排序算法
冒泡排序
核心思想:在要排序的序列中,对当前还未排好序的全部元素,自上而下对相邻的两个数依次进行比较和调整,让较大的数往下沉,较小的数往上冒,就好像水泡上浮一样,如果它们的顺序错误,就把它们交换过来,如右图所示。
二分查找法
又称折半查找法,其算法思想是每次查找数组最中间的值,通过比较大小关系,决定再从左边还是右边查询,直到查找到为止。二分查找法的优点是比较次数少,查找速度快,平均性能好;其缺点是要求待查表为有序表,且插入、删除操作困难。因此,折半查找法适用于不经常变动而查找频繁的有序列表,二分查找法依然需要使用到循环,但由于不知道循环次数,所以最好使用while循环实现。
方法中的可变参数
当一个方法中的参数个数不确定,但参数的类型确定时,可以使用可变参数。在实际处理时,可变参数会被当作数组进行处理。可变参数的语法格式如下所示。
二维数组
Arrays工具类
Arrays是Java中提供的操作数组的工具类,通过Arrays类,可以很方便地操作数组。Arrays中提供了大量的方法,其中常见方法如下表所示。
2.7 JVM中的堆内存与栈内存
堆和栈
JVM是基于堆栈的虚拟机,堆栈是一种数据结构,是用来存储数据的。对于一个Java程序来说,它的运行就是通过对堆栈的操作来完成的。
栈内存用于存储局部变量,以及对象的引用,它是一个连续的内存空间,由系统自动分配,性能较高。栈内存具有先进后出、后进先出的特点,虚拟机会为每条线程创建一个虚拟机栈,当执行方法时,虚拟机会创建出该方法的一个栈帧,该方法中所有的局部变量都会存储到这个栈帧中,方法执行完毕后,栈帧弹栈。
堆内存用于存储引用类型的数据,主要是对象和数组。全局只有一个堆内存,所有的线程共用一个堆内存。在堆中产生了一个数组或对象后,还可以在栈中定义一个特殊的变量,让栈中这个变量的取值等于数组或对象在堆内存中的首地址,栈中的这个变量就成了数组或对象的引用变量。引用变量就相当于是为数组或对象起的一个名称,以后就可以在程序中使用栈中的引用变量访问堆中的数组或对象了。
堆内存与栈内存,演示示例的代码在内存中的堆栈结构如下图所示
数据类型传递
编程语言中数据类型传递的方式有值传递和引用传递两种,而Java中只有值传递。尽管Java中存在着引用类型,但实际上在栈内存中引用类型变量记录的是对象在堆内存中的地址值,当引用类型变量互相赋值时,也是赋值的地址值,并没有将引用复制一份出来。比如上面的代码中,method栈帧和main()方法栈帧中的arr变量是完全不同的变量,它们仅仅是值相同。
2.8 个人见解
在此章我学习了数据类型、运算符、控制结构(如if语句和循环语句)、方法、数组等核心概念。这种循序渐进的方式为我提供了扎实的基础,确保我能够逐步建立起对Java编程的整体理解。
每个概念后面都配有具体的示例代码和演示示例,这些实例不仅帮助我理解理论知识,还展示了如何将这些知识应用到实际编程中。例如,通过编写程序判断分数等级和实现简单的计算器,我可以直观地看到if语句和switch语句在实际应用中的效果。这种理论与实践相结合的教学方式,有助于我更好地掌握编程技巧。
在介绍每个主题时,都突出了重点内容和关键点。例如,在变量类型转换部分,详细解释了自动类型转换和强制类型转换的区别及应用场景;在方法部分,强调了方法重载和递归的概念及其重要性。这种突出重点的方式,使得我能够快速抓住每个概念的核心,避免在学习过程中迷失方向。
第3章 面向对象程序设计(基础)
3.1 面向对象的概念
面向对象程序设计的思维方式是一种更符合人们思考习惯的方式。面向对象将构成问题的事物分解成各个对象,这些对象是为了描述某个事物在整个问题解决步骤中的行为。
面向对象以对象为核心,强调事件的角色、主体。在宏观上使用面向对象进行把控,而微观上依然是面向过程。如果说面向过程的思想是执行者,那么面向对象的思想就是指挥者
面向对象具有抽象、封装、继承、多态的特性
3.2 面向对象编程
Java使用class关键字来定义一个类。一个Java文件中可以有多个类,但最多只能有一个public修饰的类,并且这个类的类名必须与文件名完全一致。此外,类名需要符合标识符规则,并且遵循大写字母开头的驼峰规则。
创建一个Student类,拥有name和age变量,以及eat()和study()方法,并且这两个方法也称作成员方法。
要创建一个对象,必须先有一个类,然后通过new关键字来创建一个对象。对象创建语法如下。
为一个类定义成员变量时,可以显式地为其初始化。如果不为成员变量初始化,Java虚拟机也会默认给成员变量进行初始化。
3.3 构造方法
构造方法也称作构造器(constructor),用于给对象进行初始化操作,即为对象成员变量赋初始值。构造方法名称必须与类型相同,并且不能定义返回值,不能出现return关键字。构造方法的调用必须通过new关键字调用,语法格式如下所示。
可以看到,Student类中有一个名为Student的方法,该方法就是编译器默认提供的空参构造方法。而如果手动为其提供了构造方法,那么编译器就不会再为该类提供默认构造方法了。接下来给Student分别提供无参构造方法和有参构造方法,代码如下所示。
默认情况下,当系统没有为类提供任何一个构造方法时,只能使用系统默认的无参构造方法来创建对象;当只为类提供了无参构造方法时,就只能使用无参构造方法来创建对象;当为类同时提供了无参构造方法和有参构造方法时,不但可以使用无参构造方法来创建对象,还可以使用有参构造方法来创建对象。
3.4 this关键字
当创建一个对象成功后,Java虚拟机(JVM)会动态地分配一个引用,该引用指向的就是当前对象,该引用称作this。用更直白地说,this关键字就是在成员方法或者构造方法中使用,用来调用当前对象的成员变量、成员方法或构造方法,它代表当前对象。
this关键字可以调用成员变量、成员方法、构造方法。需要注意的是,成员方法中不能使用this关键字调用构造方法,当使用this关键字调用构造方法时,它必须出现在构造方法的第一行。
3.5 static关键字
在类中,将与成员变量同级的用static修饰的变量称为静态变量或类变量。静态变量优先于对象存在,随着类的加载就已经存在了,该类的所有实例共用这个静态变量,即共用同一份地址空间。当想调用静态变量时,可以使用对象名.变量名进行调用,但不推荐,建议使用类名.变量名进行调用。
static关键字也可以修饰方法,用static修饰的方法称之为静态方法或类方法。静态方法同样是属于类的,优先于对象存在,调用方式与静态变量相同,也是建议使用类名.方法名进行调用。
与静态变量类似,静态方法虽然可以使用对象名调用,但依然不建议。此外,由于静态方法是属于类的,优先于对象存在,也就是说,当调用静态方法时可能程序并没有创建这个类的对象,因此在静态方法中不存在this引用,不能使用this关键字。
在类中,与成员变量和静态变量同级,使用大括号包裹起来的代码块称作构造代码块,当构造代码块使用static关键字修饰时,称作静态代码块。
结论:
同一个类中,成员变量不能赋值给静态变量,静态变量可以赋值给成员变量和静态变量。
同一个类中,静态方法不能调用成员变量和成员方法,成员方法可以调用静态或非静态的方法和变量。
同一个类中,静态代码块不能调用成员变量和成员方法,构造代码块可以调用静态或非静态的方法和变量。
3.6 包
包是Java中重要的类管理方式,开发中会遇到大量同名的类,通过包给类加上一个命名空间,很容易就能解决类重名的问题,也可以实现对类的有效管理。包对于类,相当于,文件夹对于文件的作用。
一般来说,定义的类都需要定义在包下。当要使用一个类时,这个类与当前程序在同一个包中,或者这个类是 java.lang 包中的类时通常可以省略掉包名,直接使用该类。其余情况下使用某一个类,必须导入包。
通过import关键字指定要导入哪个包下的哪个类,比如import java.util.Scanner就导入了java.util包下的Scanner类,而其它包中的Scanner类则不受影响。此外,前面使用到了String类,而该类在java.lang包下,因此可以省略导包。而上面的案例中,Student类与Demo类都是在同一个包下,也可以省略导包。
3.7 个人见解
在此章我学习了面向对象的基本概念,强调了面向对象的思维方式和其特性(抽象、封装、继承、多态)。这种介绍帮助我理解面向对象程序设计的核心思想,即通过对象来模拟现实世界中的事物及其行为,从而提高程序的可维护性和可扩展性。通过对比面向过程和面向对象的思想,使我能够更好地理解面向对象的优势和适用场景。
在类与对象的定义部分,这章详细解释了类和对象的关系,以及如何定义类和创建对象。通过具体的示例代码,展示了类的结构(包括字段和方法),以及如何使用new关键字创建对象。这种详细的讲解使我能够快速掌握类与对象的基本概念和使用方法,为进一步学习面向对象编程打下坚实基础。
此章对构造方法的定义和使用进行了深入讲解,包括默认构造方法、有参构造方法以及构造方法的重载。同时,还介绍了this和static关键字的使用场景和注意事项。这些内容对于理解对象的初始化和类的静态特性非常重要。通过示例代码,我可以清晰地看到如何在实际编程中应用这些概念,增强代码的灵活性和效率.
第4章 面向对象程序设计(进阶)
4.1 内部类
内部类的概念:在一个类的内部再定义一个完整的类。
内部类的特点:
编译之后可以生成独立的字节码文件。
内部类可以直接访问外部类的私有/非私有成员,而外部类不能直接访问内部类。
外部类不能直接访问内部类成员,需要创建内部类对象去访问。
成员内部类
概念:在类的内部定义,与实例变量,实例方法同级别的类。
两个知识点:
创建内部类对象的语法。
当外部类,内部类存在重名属性时,调用的语法。
外部类的一个实例部分,创建内部对象时,必须依赖外部类对象。
Outer outer = new Outer();
In in = outer.new In();
当外部类,内部类存在重名属性时,优先访问内部类属性。当需要访问外部类重名属性时,使用语法:外部类名.this.属性名/方法名;例如:
Outer.this.num
注意:成员内部类不能定义静态成员。
静态内部类
概念:使用static修饰,类似于静态方法,静态内部类不需要外部类对象产生就能使用,静态内部类只能访问外部类的静态部分,不能访问外部类的实例部分。
局部内部类
概念:局部内部类是定义在一个方法或者一个作用域里面的类,它和成员内部类的区别在于局部内部类的访问仅限于方法内或者该作用域内,类似于局部变量。
匿名内部类
没有类名的局部内部类(一切特征都与局部内部类相同)
必须继承一个父类或者实现一个接口
定义类,实现类,创建对象的语法合并,只能创建一个对象
•继承/实现关系
•重写方法
•创建对象
优点:减少代码量
缺点:可读性差
4.2 抽象类与接口
抽象类
概念:在面向对象的概念中,一切皆对象,所有的对象都是通过类来创建的。但并不是所有的类的设计都是为了创建对象。有些类的设计是为了描述一些共性问题,那么满足这些共性问题的具体对象是不存在的,或者说是没有实际意义的。例如:动物类(猫,狗,鱼等),图形类(三角形,梯形等)。
抽象类是用abstract关键字来修饰的。abstract关键字可以修饰类,也可以修饰方法。由abstract修饰的类就是抽象类,由abstract修饰的方法是抽象方法。
抽象类的定义格式:
publice abstract class 抽象类名{
//属性
//方法
}
注意:当一个类被定义成抽象类,这个类将不能再创建对象,即:抽象类不能创建对象(不能被实例化)。
抽象方法
当抽象类中某些方法的实现没有实际意义时,可以将该方法定义为抽象方法。抽象方法只有方法的声明,没有方法体的实现方法。
抽象方法是用abstract关键字来修饰的。并且是只有方法声明,没有方法体的实现。
抽象类和抽象方法的使用
接口
接口的作用主要有两种:
(1)提供一种扩展性的功能,比如实现了Serializable接口的类就拥有了序列化的功能,实现了Clonable接口的类就拥有了克隆的功能。
(2)提供一种功能上的约束,或者说是一种规范。比如在面向接口开发的编程思想中,创建了OrderService接口,规定了接口中拥有订单的增加、删除、修改、查询方法,那么不管是什么订单,只要实现了OrderService接口,就必须拥有这四个方法。
接口的定义
Java中用interface关键字定义接口,接口可以理解为特殊的抽象类。接口中所有的成员方法都是抽象的,所有的属性都是常量。接口是抽象方法和常量值的集合。
接口的定义格式:
访问修饰符 interface 接口名{
//静态常量
//抽象方法
}
接口的使用步骤:
接口不能直接使用,必须有一个实现类来实现该接口;
格式:
public class 实现类名称 implements 接口名称{
//…
}
4.3 封装,继承,多态
封装
概念:尽可能隐藏对象的内部实现细节,控制对象的修改以及访问的权限。
访问修饰符:private(可将属性修饰为私有,仅本类可见)
继承
程序中的继承,是类与类之间特征和行为的一种赠与或获得。
两个类之间的继承关系,必须满足“is a”的关系。
继承
语法:class子类extends父类{} //定义子类时,显式继承父类。
子类继承父类所有成员,但父类中声明为private成员在子类中不能访问。
应用:产生继承关系之后,子类可以使用父类中的属性和方法,也可以定义子类独有的属性和方法。
好处:既可以提高代码的复用性,又提高代码的可扩展性。
特点:
单根性:一个类只能有一个直接父类。
传递性:类之间可以多级继承,属性和方法逐级叠加。
多态
概念:父类引用指向子类对象,从而产生多种形态。
格式:父类名称 对象名 = new 子类名称();
4.4 个人见解
在此章节首先介绍了封装的概念,强调了隐藏对象内部细节的重要性,并通过访问修饰符的使用来实现封装。这种讲解帮助我理解如何通过get()和set()方法来控制对象属性的访问,从而提高代码的安全性和复用性。封装是面向对象设计的核心之一,通过具体的示例代码展示了如何在实践中应用封装原则.
在继承部分,详细解释了Java中的继承机制,包括单继承和多层继承的概念。通过示例代码,展示了如何通过extends关键字实现继承,以及如何在子类中重写父类的方法。这部分内容对于理解Java类之间的关系和如何通过继承实现代码的复用非常有帮助。还强调了方法重写时需要注意的规则,如方法签名的一致性和修饰符的使用,这些细节对于确保程序的正确性和可维护性至关重要.
多态是面向对象的另一大特性,通过生动的示例(如垃圾分类)来说明多态的概念和实现方式。多态使得同一个方法调用在不同对象上表现出不同的行为,这提高了代码的灵活性和扩展性。还介绍了引用类型数据的向上转型和向下转型,以及如何使用instanceof关键字进行类型检查,这些内容对于理解和应用多态非常重要.
在对抽象类和接口进行了详细的讲解,解释了它们的定义、使用以及区别。抽象类用于定义一些无法具体实现的方法,而接口则用于规范实现类必须遵循的方法。通过图形类和USB接口等示例,展示了如何在实际开发中使用抽象类和接口来实现功能的抽象和扩展。JDK 8引入的接口中的default方法和static方法也为接口的使用提供了更多的灵活性.
内部类是Java中一个高级特性,介绍了成员内部类、静态内部类、局部内部类和匿名内部类等类型,并通过示例代码展示了它们的使用场景和特点。内部类使得代码结构更加紧凑,能够更好地组织相关类和方法,同时也提供了访问外部类成员的便利性。对内部类的讲解有助于读者理解Java中类的嵌套关系和作用域的概念.
第5章 异常
5.1 异常概述
Throwable与异常体系
Throwable中定义了所有异常都会用到的3个重要方法:
Exception
Exception是所有异常的父类,其本身是编译时异常,而它的一个子类RuntimeException则是运行时异常。
RuntimeException和它的所有子类都是运行时异常,比如NullPointerException、ArrayIndexOutOfBoundsException等,这些异常在程序编译时不能被检查出,往往是由逻辑错误引起的,因此在编写程序时,应该从逻辑的角度尽可能避免这种异常情况。
Exception和它的子类(不包括RuntimeException及其子类)统称为编译时异常。比如IOException、SQLException。这些异常在编译时会被检查出,程序员必须对其进行处理。
5.2 异常处理
抛出异常
编写程序时,需要考虑程序可能出现的各种问题,比如编写一个方法,对于方法中的参数就需要进行一定程度的校验。如果参数校验不通过,需要告诉调用者问题原因所在,这时候就需要抛出异常。
Java中提供了一个throw关键字,该关键字用于抛出异常。Java中的异常本质上也是类,抛出异常时,实际上是抛出一个异常的对象,并提供异常文本给调用者,最后结束该方法的运行。
抛出异常语法格式如下:
对于数组的操作,可以定义一个方法用来获取数组指定索引的值,当索引不合法时,通过抛出异常的方式来通知调用者。
声明异常
如果方法中抛出的是运行时异常,编译期就不会强制要求开发者将异常声明在方法上,而如果抛出的是编译时异常,则必须将这些异常全部声明在方法上。
捕获异常
一个try必须跟随至少一个catch或者finally关键字。即try...catch结构、try...finally结构和try...catch...finally 结构都是合法的。异常的处理是链式的,如果存在着main->methodA->methodB->methodC的调用链,此时methodC发生了异常,就会抛给methodB去处理。如果methodB处理不了或者没有处理,就会再抛给methodA处理,如果methodA依然没法处理,就会抛给main方法处理,也就是交给虚拟机处理,而虚拟机处理异常的方式简单粗暴:直接打印异常堆栈信息并停止程序的运行。因此,在开发中为了防止死机,程序能进行处理的异常要尽可能交由程序处理。
5.3 异常进阶
自定义异常
自定义异常语法很简单,就是创建一个类并继承Exception或者RuntimeException,提供相应的构造方法。
自定义异常语法格式如下:
编写一个登录案例,用户输入用户名和密码,对于用户名不存在和密码错误两种场景,均提示“用户名或密码错误”,但抛出异常时则抛出不同的异常。
首先定义:UserNotFoundException和PasswordWrongException两个异常类,如下所示:
方法重写中的异常
当一个类的方法声明了一个编译时异常后,它的子类如果重写该方法,重写方法声明的异常不能超过父类的异常,这里只遵循如下两点即可。运行时异常不受这两点约束。
父类方法没有声明异常,子类重写该方法不能声明异常,如下所示。
父类方法声明了异常,子类重写该方法可以不声明异常,或者只声明父类的异常或该异常的子类,如下所示:
5.4 个人见解
在此章节首先明确了异常的定义,将其与日常生活中的不正常现象进行类比,使我能够直观地理解异常的概念。同时还区分了异常和错误,强调了异常是可处理的,而错误通常是不可处理且致命的。这种清晰的定义和区分有助于我在编程过程中正确地识别和处理异常情况.
此章还详细介绍了Java异常体系的结构,包括Throwable类及其子类Exception和Error,以及运行时异常和编译时异常的分类。通过展示异常类的继承关系和分类,我可以更好地理解不同异常类之间的关系以及它们在程序中的作用。还介绍了Throwable类中的重要方法,如getMessage()、getStackTrace()等,这些方法在异常处理中具有重要的应用价值.
此章节全面介绍了Java中异常处理的常用方法,包括抛出异常、声明异常和捕获异常。通过具体的示例代码,展示了如何使用throw关键字抛出异常,如何使用throws关键字声明异常,以及如何使用try...catch...finally结构捕获和处理异常。还强调了异常处理的链式传递机制,说明了在方法调用链中异常的传递和处理过程,这对于编写健壮的程序具有重要的指导意义.
此章节介绍了自定义异常的创建方法,通过继承Exception或RuntimeException类,并提供相应的构造方法,可以创建满足特定需求的自定义异常。自定义异常在实际开发中具有广泛的应用,能够更准确地描述和处理程序中的异常情况。此外,还讨论了方法重写中的异常处理规则,指出子类重写父类方法时,声明的异常不能超过父类方法声明的异常范围。这些内容对于理解Java中的继承和多态特性,以及编写符合规范的代码具有重要的参考价值..
第6章 Java常用类
6.1 包装类
Java是面向对象的语言,但并不是纯面向对象的语言,比如Java中的基本数据类型就不是对象。然而,在实际开发中,要求“一切皆对象”,基本数据类型很多场景下满足不了使用,比如一个APP注册阶段,年龄是非必填项,当用户不填时,在系统中应当如何表示?可能有人会认为,使用0表示未填写,但实际上0岁与未填写是两码事,基本数据类型int就表示不出这种“未填写”的状态。
包装类的主要作用如下:
(1)让基本数据类型可以像对象一样进行操作,提供了更多方便的方法。
(2)提供了null值,让基本数据类型可以表示“未填写”的状态。
基本数据类型与包装类
各种包装类的使用方式基本类似,这里只以Integer为例。Integer中提供了大量让字符串-包装类-基本类型之间进行转换的方法,如下表所示。
大数字运算
BigInteger
BigInteger是Java中表示大整型的类,它可以用来计算远大于long类型的数值。注意,BigInteger参与算术运算时,并不是用传统的加、减、乘、除符号,而是调用它的方法。BigInteger类中的常见方法如下表所示。
BigDecimal
BigDecimal保留小数位使用的是setScale()方法,指定保留小数位个数以及保留方式,保留方式都是以BigDecima中静态常量的方式定义的,如下表所示。
6.2 String类
String 类对象代表不可变的Unicode字符序列,内部使用了一个用final修饰的字符数组存储数据,一旦String的值确定了,就不能再改变了,每次通过截取、拼接等操作字符串时,都产生一个新的字符串。
Java为了方便起见,在使用字符串时也可以像基本数据类型一样直接对其进行赋值,但依然需要了解String的构造方法,如下表所示。
String类查找方法
字符串中提供了大量的查找方法,通过这些方法可以很方便地获取字符串的一些信息。String类中与查找相关的方法如下表所示。
String类转换方法
用户查找字符串的一些信息,为的是根据查询结果对字符串进行一些处理,因此String类中还定义了一些转换字符串的方法,如下表所示。
String类中的其他方法
除了查找、转换一类的方法之外,String类还提供了一些其他的方法,比如比较字符串是否相同、判断字符串是否为空等方法,如下表所示。
6.3 StringBuffer类与StringBuilder类
String代表着不可变的字符序列,每次拼接、截取字符串操作,都是重新创建一个字符串对象,如果这类操作过多,就会在内存中留下大量的无用字符串,比较占用内存。
StringBuffer类是抽象类AbstractStringBuilder的子类,代表可变的Unicode字符序列,即对StringBuffer执行转换操作时,都不会创建新的StringBuffer对象,自始至终操作的都是同一个字符串。StringBuffer并没有像String一样提供了简单的赋值方式,必须创建它的构造方法才可以。StringBuffer类中的构造方法如下表所示。
StringBuffer类常见方法
StringBuffer类和StringBuilder类非常类似,都是继承自抽象类AbstractStringBuilder类,均代表可变的Unicode字符序列。StringBuilder类和StringBuffer类方法一模一样,这里不再演示。不过StringBuilder不是线程安全的,这是与StringBuffer的主要区别:
(1)StringBuffer做线程同步检查,因此线程安全,效率较低。
(2)StringBuilder不做线程同步检查,因此线程不安全,效率较高。
因此在开发中如果不涉及字符串的改变,建议使用String,如果涉及并发问题,建议使用StringBuffer,如果不涉及并发问题,建议使用StringBuilder。
链式编程
6.4 时间和日期相关类
Date类
Date类主要方法如下表所示。
SimpleDateFormat类
Calendar类
Date类一般用于表示时间,如果想计算时间,虽然通过时间戳也可以实现,但比较麻烦。Calendar是Java中的日历类,提供了日期时间的计算方式,通过Calendar类,可以准确地对年、月、日、时、分、秒进行计算。Calendar类中的主要方法如下表所示
6.5 其他常用类
Math类
Math类是Java中与数学相关的类,提供了大量数学计算相关的方法,如开平方、三角函数、随机数等。Math类中的常用方法如下表所示。
Random类
UUID类
UUID是通用唯一识别码(Universally Unique Identifier)的缩写,其目的是让分布式系统中的所有元素都能有唯一的辨识信息,而不需要通过中央控制端做辨识信息的指定。如此一来,每个人都可以创建不与其他人冲突的UUID。
枚举类
枚举是Java 5之后新增的特性,它是一种新的类型,允许用常量表示特定的数据片段,而且全部都以类型安全的形式来表示。枚举使用enum关键字定义,如下所示。
枚举值的命名方式与常量相同,要求以大写字母命名,单词之间使用下划线分隔。如下代码就是定义了一个季节枚举。
枚举的目的是列举出某个字段所有允许的取值,这些取值可能存在中文,因此在不少企业中放开了对中文的限制,允许枚举值使用中文定义。下面的枚举在一些企业里也是符合开发规范的。
6.6 个人见解
在此章节首先介绍了包装类的概念和作用,强调了包装类在将基本数据类型转换为对象时的重要性,尤其是在需要表示“未填写”状态或进行对象操作的场景下。包装类的自动装箱与拆箱机制简化了基本类型与对象之间的转换,提高了编程的便利性。此外,还介绍了BigInteger和BigDecimal类,这两个类在处理大数字运算时非常有用,尤其是当基本数据类型无法满足精度或范围需求时。通过示例代码,展示了如何使用这些类进行大整数和大浮点数的运算,这对于金融、科学计算等领域具有重要意义.
在此章对String类进行了全面介绍,涵盖了字符串的构造方法、查找方法、转换方法以及其他常用方法。String类的不可变性是其核心特性之一,通过示例代码展示了如何使用String类的各种方法进行字符串操作,如查找子串、替换字符、比较字符串等。这些方法在日常开发中应用广泛,是处理文本数据的基础工具。同时,文件还介绍了StringBuffer和StringBuilder类,这两个类提供了可变的字符序列,适用于频繁进行字符串拼接和修改的场景。通过性能比较示例,说明了在不同场景下选择合适字符串类的重要性,强调了StringBuilder在单线程环境下的高效性以及StringBuffer在多线程环境下的安全性.
时间和日期处理是Java开发中的常见需求,此章介绍了时间戳、Date类、SimpleDateFormat类和Calendar类等与时间日期相关的类。时间戳是表示时间的一种方式,通过示例代码展示了如何获取和使用时间戳。Date类提供了基本的时间表示和操作,而SimpleDateFormat类则允许自定义时间格式,方便将时间转换为特定格式的字符串。Calendar类提供了强大的日期时间计算功能,可以对年、月、日等进行精确的计算和调整。这些类的介绍和示例代码使读者能够更好地理解和应用Java中的时间日期处理机制,满足各种时间相关的开发需求.
此章还介绍了一些其他常用的Java类,如Math类、Random类、UUID类和枚举类。Math类提供了丰富的数学计算方法,如三角函数、对数、随机数等,是进行数学运算时的得力助手。Random类提供了多种生成随机数的方法,可以生成指定范围内的随机数,适用于需要随机性功能的场景,如生成验证码等。UUID类用于生成全局唯一的标识符,广泛应用于分布式系统中。枚举类是Java 5引入的新特性,通过枚举可以定义一组常量,提高代码的可读性和类型安全性。这些类的介绍扩展了读者对Java常用类的认识,提供了更多实用的编程工具和解决方案.
总结
通过学习,我明确了对象是现实世界中事物的抽象表示,而类则是对象的模板,定义了对象的属性和行为。这种理解让我能够更好地将现实问题转化为面向对象的程序设计,合理地创建类和对象来解决问题.
掌握了封装的概念和实现方法,让我学会了如何使用访问修饰符来控制类成员的访问权限,以及如何通过get/set方法来安全地访问和修改私有属性。这使我能够有效地隐藏对象的内部实现细节,提高代码的安全性和复用性.
学习了如何使用`extends`关键字实现类的继承,理解了继承的单继承特性和多层继承的概念。通过继承,我能够在一个新的类中复用父类的属性和方法,并根据需要添加或修改功能,提高了代码的复用性和可维护性.
掌握书中丰富的实例,让我深入理解了多态的概念和实现方式。多态使得同一个方法调用在不同对象上表现出不同的行为,这提高了程序的灵活性和扩展性。我还学会了如何使用父类引用指向子类对象,以及如何通过方法重写来实现多态.
系统学习了Java中的异常体系,包括运行时异常和编译时异常的区别,以及如何使用`try-catch-finally`结构来捕获和处理异常。这使我能够更好地应对程序运行过程中可能出现的各种异常情况,避免程序因异常而崩溃,提高程序的健壮性.
通过学习,我掌握了如何创建自定义异常类,以便在程序中更准确地描述和处理特定的异常情况。这让我能够根据实际需求设计更合理的异常处理策略,使程序的异常处理更加清晰和有针对性.
了解了及熟练使用了包装类的作用与基本数据类型之间的关系和用法,掌握了自动装箱与拆箱的机制,以及如何使用包装类提供的方法进行数值转换和操作。这让我在处理涉及基本数据类型和对象的场景时更加得心应手.
-学习了`BigInteger`和`BigDecimal`类的使用方法,能够进行大整数和大浮点数的运算。这对于处理涉及大数字的计算任务,如金融计算等,具有重要意义,能够保证计算的精度和准确性.
深入学习了`String`类及其相关类(如`StringBuffer`和`StringBuilder`)的构造方法、查找方法、转换方法等,掌握了字符串的各种操作技巧。这使我能够高效地处理文本数据,满足各种字符串处理的需求.
学习了时间戳、`Date`类、`SimpleDateFormat`类和`Calendar`类等与时间和日期相关的类的使用方法,能够进行时间的表示、格式化、解析和计算等操作。这让我在处理涉及时间和日期的业务逻辑时更加得心应手.
对`Math`类、`Random`类、`UUID`类和枚举类等其他常用类有了初步的了解,知道它们的基本功能和使用场景。这为我在实际开发中提供了更多的工具和选择,能够根据需求灵活地使用这些类来实现特定的功能.
通过学习面向对象编程,我逐渐培养了面向对象的思维方式,能够从对象的角度来分析和解决问题。这种思维方式有助于我更好地组织和管理代码,提高程序的可读性和可维护性.
对于学习的类的设计原则和编程规范,让我在编写代码时更加注重代码的组织和结构。我学会了如何合理地划分类的职责,如何编写清晰、简洁的代码,以及如何通过注释和文档来提高代码的可读性.
在学习过程中,我遇到了各种各样的问题和挑战,通过不断调试和分析,我提高了解决问题的能力。学会了如何使用调试工具和技巧来定位和修复代码中的错误,以及如何分析异常信息来快速找到问题的原因.