目录
(一)JAVA环境的搭建
1.下载并安装JDK
Java程序的编译和运行离不开jdk环境,JDK(Java Development kit)是用于开发Java程序的开发包,它提供了运行java的程序所要的各种工具和资源,本次学习jdk8
JRE是指java运行环境。
JDK是java开发工具包。包括了Java运行环境(JRE),一堆Java工具(javac/java/jdb等)和Java基础的类库(即Java API 包括rt.jar)。
JRE:JVM+Java语言的核心类库。
JDK:JRE+Java的开发工具。
JDK 包含JRE,JRE包含JVM。
jdk:常用的版本:本次在windows系统上安装,对应操作系统64位
网址:http://www.oracle.com/technetwork/java/javase/downloads/index.html
jdk的安装目录:
1.bin目录:存放着编译,运行java程序的可执行文件
2.lib目录:存放着java的类库文件
3.jre目录:存放Java运行的环境文件
2.JDK环境变量的设置
1.计算机(此电脑)----属性----高级设置—系统设置
2.新建一个系统变量:变量名:JAVA_HOME,变量值:E:\jdk1.8\jdk
3.添加到Path环境变量中:设置源变量值为:%JAVA_HOME%\bin
%表示连接符,相当于指向的作用。
4.测试jdk是否安装成功:
win键+r键,输入cmd,进入DOS命令窗口:java -version ;然后再输入javac;看指令能否识别
如果不能识别,报错:提示是外部命令
(二)编写一个JAVA程序
1.编写步骤
(1).创建一个Java源程序。Java源程序用以.java作为扩展名,可以使用任意的文本编译器去创建和编写
(2).编译源程序去生成字节码文件。字节码文件的后缀名是.class文件
(3).运行字节码文件。
2.实例
(1).打开记事本
(2).输入关键代码
(3).将文件以后缀名为.java保存
(4).测试运行
1. 进入命令提示行:
先找到Person.java文件所在的上一级的位置:
DOS命令:cd 进入下以及目录(输入第一个字符后,tab可以逐个查找;
cd \返回全部上级目录;dir查看当前目录下的文件
cd…返回上级目录;F:去往F盘;
本机的桌面的路径:C:\Users\86188\Desktop
2.执行输入命令:
javac Person.java (生成了字节码文件)
报错:
提示:少了一个;
报错:表示GBK的不可映射字符,因为我们使用了中文字符
解决方案:
javac -encoding UTF-8 Person.java
java Person(这样就可以输出中文)
3.执行输入命令:java Person
(三)安装IDEA与使用
1.安装IDEA
安装时勾上Java,和安装路径,快捷方式
2.使用
1.新建项目
2.添加JDK
点击 ADD JDK,添加JDK所在路径,之后next,不选择模板
3.设置Project name与存储路径(不要放C盘)
4.右击文件new—package可以创建新的包
5.选中项目,再点击File—new—module,可以创建新的模块(module),模块就是工程里的子项目,工程(preject)是最大的工作单元
6.选中包,new—Java class
7.
File—Settings—Editor—Live Templates这里可以查看快捷的输入方式
比如打main就出public static void main(String[] args) {}
打cout就出System.out.println();
8.src文件夹下写代码(存放的是项目的源文件)
9.IDEA写代码不用保存
在IDEA中,项目>模块>包>类
(四)数据类型与运算
变量
1.变量的命名
Java中的标识符规则有4个:
(1).标识符由字符、数字、下划线(_)、或者$组成
(2).标识符的首字母以字母、下划线、美元符号开头,不能以数字开头
(3).标识符命名不能与关键字、布尔值(false、true)和null相同
(4).标识符区分大小写,没有长度限制、坚持以见名知义的有原则,使用驼峰命名法,如;studentName
2.关键字
- abstract: 用于声明抽象类,以及抽象方法。
- boolean: 用于将变量声明为布尔值类型,只有 true 和 false 两个值。
- break: 用于中断循环或 switch 语句。
- byte: 用于声明一个可以容纳 8 个比特的变量。
- case: 用于在 switch 语句中标记条件的值。
- catch: 用于捕获 try 语句中的异常。
- char: 用于声明一个可以容纳无符号 16 位比特的 Unicode 字符的变量。
- class: 用于声明一个类。
- continue: 用于继续下一个循环,可以在指定条件下跳过其余代码。
- default: 用于指定 switch 语句中除去 case 条件之外的默认代码块。
- do: 通常和 while 关键字配合使用,do 后紧跟循环体。
- double: 用于声明一个可以容纳 64 位浮点数的变量。
- else: 用于指示 if 语句中的备用分支。
- enum: 用于定义一组固定的常量(枚举)。
- extends: 用于指示一个类是从另一个类或接口继承的。
- final: 用于指示该变量是不可更改的。
- finally: 和
try-catch
配合使用,表示无论是否处理异常,总是执行 finally 块中的代码。 - float: 用于声明一个可以容纳 32 位浮点数的变量。
- for: 用于声明一个 for 循环,如果循环次数是固定的,建议使用 for 循环。
- if: 用于指定条件,如果条件为真,则执行对应代码。
- implements: 用于实现接口。
- import: 用于导入对应的类或者接口。
- instanceof: 用于判断对象是否属于某个类型(class)。
- int: 用于声明一个可以容纳 32 位带符号的整数变量。
- interface: 用于声明接口。
- long: 用于声明一个可以容纳 64 位整数的变量。
- native: 用于指定一个方法是通过调用本机接口(非 Java)实现的。
- new: 用于创建一个新的对象。
- null: 如果一个变量是空的(什么引用也没有指向),就可以将它赋值为 null,和空指针异常息息相关。
- package: 用于声明类所在的包。
- private: 一个访问权限修饰符,表示方法或变量只对当前类可见。
- protected: 一个访问权限修饰符,表示方法或变量对同一包内的类和所有子类可见。
- public: 一个访问权限修饰符,除了可以声明方法和变量(所有类可见),还可以声明类。
main()
方法必须声明为 public。 - return: 用于在代码执行完成后返回(一个值)。
- short: 用于声明一个可以容纳 16 位整数的变量。
- static: 表示该变量或方法是静态变量或静态方法。
- strictfp: 并不常见,通常用于修饰一个方法,确保方法体内的浮点数运算在每个平台上执行的结果相同。
- super: 可用于调用父类的方法或者字段。
- switch: 通常用于三个(以上)的条件判断。
- synchronized: 用于指定多线程代码中的同步方法、变量或者代码块。
- this: 可用于在方法或构造函数中引用当前对象。
- throw: 主动抛出异常。
- throws: 用于声明异常。
- transient: 修饰的字段不会被序列化。
- try: 于包裹要捕获异常的代码块。
- void: 用于指定方法没有返回值。
- volatile: 保证不同线程对它修饰的变量进行操作时的可见性,即一个线程修改了某个变量的值,新值对其他线程来说是立即可见的。
- while: 如果循环次数不固定,建议使用 while 循环
注释
java提供了注释有三种:1.单行注释、2.多行注释、文档注释
1.单行注释
最简单类型的注释,只能写在一行的注释,
快捷键:ctrl+/
单行注释语法:
以两个"/"开头
2.多行注释
多行主要用于说明比较复杂的内容,或者说复杂的程序逻辑和算法原理,当一般有多行类容需要被注释的时候,才使用
快捷键方式:ctrl+shift+/(是问好键下的斜杠)
语法:
以“/”开头,以“/”结尾,中间的内容都被注释
3.文档注释:
API文档一样,可以在编写代码时使用文档注释
在idea,输入/**,然后按enter键,iDEA会自动显示文档注释
在Settings----File and Code Templates----Includes中设置
设置后如图
(五)数据类型
Java是强类型的语言,在定义变量时,需要声明数据类型,在Java中主要分为两种数据类型:
基本数据类型、引用数据类型
基本数据类型
整数型:(byte、short、int、long)
浮点型:(float、double)
字符型:char
步尔型:boolean
其中整数型和浮点型又叫数值型,int、double、long 等都是java定义的关键字
基本数据类型 | 大小 | 示例 | 取值范围 |
---|---|---|---|
boolean | 1字节,8位 | true | true、false |
byte | 1字节,8位有符号整数 | -12 | -128~+127 |
short | 2字节,16位有符号整数 | 100 | -32768~+32767 |
int | 4字节,32位有符号整数 | 12 | -2147483648~+2147483647 |
long | 8字节,64位有符号整数 | 1000 | -2147438648~+2147438647 |
char | 2字节,16位Unicode | ‘a’ | 0~65535 |
float | 4字节,32位浮点数(单精度) 有效数字6位 | 3.4f | -3.4E38~3.4E38 |
double | 8字节,64位浮点数(双精度) 有效15位 | -2.1e3D | -1.7E308~1.7E308 |
常量
概念:指Java中在程序运行中,不能改变量,称为常量
变量
概念:与常量相对应,指程序中运行值可以改变的量。它是java程序中存储的一个基本单元
变量的语法格式:
变量类型 变量名 =[初始值]
变量的类型可以在数据类型中选择的
“变量名”是定义变量的名称,要遵循表示符命名的规则
中括号里面的值的内容为初始值,可选项
数据类型转换
概念:
不同的基本数据类型之间进行运算时,需要类型转换,除布尔类型外,所有的基本数据类型进行运算时要考虑类型转换,主要应用在算术运算和赋值运算中
(1)自动类型转换
将低级别的类型赋值给高级别的类型时进行的自动转换
byte<short<int<long<float<double
byte short char在运算时,会直接先提升为int,在进行运算
(2)强制类型转换
将高级别的类型赋值给低级别的类型时,必须要进行的强制转换,在Java中,使用一对小括号进行表示强制类型转换,如:int a=1;byte num=(byte)a;
double a=3.14159;int n=(int)a
运算符
1.赋值运算
赋值运算符号“=”用于给变量指定变量的值,并可以和算术运算符结合起来,组成复合赋值运算符。复合赋值运算符:“+=”、“-=”、“*=”、“/=”、“%=”
2.算术运算
算术运算符包括:“+”,“-”,“*”,“/”,“%”、“++”、“–”
其中:++表示自增运算
--表示自减运算
j=i++是i先赋值给j,再自增
j=++i是i先自增,再赋值给j
对于除法运算,如果两个操作数都是整数,结果也是整数,会舍去小数部分,如果两个数,有一个是浮点数,将会进行自动类型转换,结果也是浮点数,保留小数部分
对于取模运算符,如果两个操作数均是整数,结果也是整数,如果两个操作数有一个浮点数结果也是浮点数,保留小数部分
3.关系运算符
关系运算符有时又叫比较运算符,用于比较两个变量或常量的大小,运行的结果是布尔值:true
或false;
Java中有6个关系运算符:“==”、“!=” “>”,“<”,“>=”;“<=”
注意:
(1)."="表示是赋值运算符;”==“表示等于运算符
(2).”>“;“<”,“>=”;“<=”;只支持数值类型的比较
(3).“==”、“!=”支持所有数据类型的比较,包括数值类型、布尔类型、引用类型
(4).关系运算符,运算后的结果是一个布尔值
(5).“>”,“<”,“>=”;“<=”;运算符的优先级高于”==“、”!=“
4.逻辑运算符
逻辑运算符用于对布尔类型操作数进行运算,其结果还是布尔值,逻辑运算如下
运算符 | 含义 | 运算规则 |
---|---|---|
& | 逻辑与 | 两个操作数都是true,结果才是true;不论左边取值,右边的表达式都会进行运算 |
| | 逻辑或 | 两个操作数一个是true,结果也是true;不论左边取值,右边的表达式都会进行运算 |
^ | 逻辑异或 | 两个操作数相同,结果为false;两个操作数不同,结果为true |
! | 逻辑非 | 操作数为true,结果为false;操作数为false,结果为true |
&& | 短路与 | 运算规则同“&”,不同在于如果左边为fasle,右边表达式不会进行运算 |
|| | 短路或 | 运算规则同“|”,不同在于如果运算符左边的值为true,右边的表达式不会进行运算 |
注意:
(1).操作数类型只能是布尔类型,操作的结果也是布尔类型
(2).优先级别:”!“>“&”>“^”>“|”>“&&”>“||”。
(3).&与&&的区别:当“&&”的左侧为fasle时,将不会计算其右侧的表达式,即左边false则fasle;无论任何情况,“&”两侧的表达式都会参与计算
(4).逻辑或和短路或:的区别和逻辑与与短路与类似
5.条件运算(三目运算符)
是java中唯一需要3个操作数的运算符,又叫三元运算或三目运算
条件运算符的语法格式:
条件? 表达式1:表达式2
运算过程:
(1).先对条件进行判断,结果为true,则返回表示式1的值
(2).如果结果为false,则返回表达式2的值
6.运算符的优先级:
运算符的最低的级别是赋值运算,其次条件运算符
单目运算包括:”!“、”~“、”++“、”–“优先级最高的
可以通过”()“来控制表达式的运算顺序,”()“优先级别最高
总体而言:优先顺序为算术运算符>关系运算符>逻辑运算符
(六)键盘录入
1.导包
import java.util.Scanner;(在idea中自动完成)
2.创建对象
Scanner sc = new Scanner(System.in);
3.接受数据
int i = sc.nextInt();
sc.next(); 字符串(只要字)
sc.nextInt(); 整型
sc.nextDouble(); double类型
sc.nextLine(); 字符(全都要,包括空格)
(七)流程控制
Java中有三种流程控制结构:顺序结构、选择结构、循环结构
顺序结构:顺序结构指的是程序自上而下一次执行的每条语句,中没有任何的判断和跳转,前面所有的结构都是顺序结构
选择结构:
选择结构根据判断条件的结果来执行不同的代码
循环结构:
根据判断条件来重复执行某块代码。Java提供、while语句,do-while语句、for语句来实现循环结构
选择结构
(1)if语句的语法格式如下:
if(表达式){
语句块
}
if是java中的关键字
表达式是布尔类型的表达式,其结果是true或false
(2)if-else语句的语法如下:
if(表达式){
语句块
}else{
语句2
}
当表达式为true时,执行语句块1;
表达式为false时,执行语句块2
(3)多分支if语句的语法格式:
if(表达式1){
语句块1
}else if(表达式2){
语句块2
}else{
语句块3
}
注意:Java中判断两个字符串是否相等,用equals()判断两个字符串的值是否相等,用“==”比较判断内存地址是否相等
(4) switch语句语法的格式:
switch(表达式){
case常量1:
语句
break;
case常量2:
语句
break;
…
default:
语句;
break;
}
switch、case、break、default都是java中的关键字
switch的表达式只能是字符型、枚举型、整数型
case用于表达式匹配
default是选择的,当其他不匹配时,执行default
循环结构
(1)while循环的语法格式:
变量的初始化
while(循环条件){
循环体
}
while语句的执行步骤:
1.首先对循环条件的结果进行判断,如果为真,则执行循环语句
2.执行完毕后,继续对循环条件进行判断,如果为真,继续执行
3.如果结果是假(false),跳出循环语句,去执行后面的语句
(2)do-while循环语句的语法格式如下:
变量初始化
do{
循环体
}while(循环条件)
注意:do-while先执行循环体,再执行循环条件,所以循环体至少执行一次,这点和while循环相反
(3)for循环的语法格式如下:
for(表达式1;表达式2;表达式3){
循环体
}
for语句的执行步骤:
1.首次执行表达式1,一般进行变量初始化的操作
2.然后执行表达式2,即对循环条件进行判断
3.如果结果为真,则执行循环体
4.循环语句执行完毕后执行表达式3,改变循环的变量的值,再次执行表达式2;
如果结果是真,继续循环
5.如果结果是假,终止循环,执行后面的语句
注意:使用fori或变量.fori可以直接出来
跳转语句
Java语言中支持3种类型的跳转语句:continue语句、return语句,break;使用这些语句,可以把控制转移到循环甚至程序的其他地方。
(1).break语句
作用: 在循环种终止当前循环,在switch语句中终止switch语句
(2).continue语句
作用: 强制循环提前返回,也就是让循环跳过本次循环中剩余代码,然后进入下次循环
注意:在while循环和do-while循环中,continue执行完毕后,程序将直接判断循环条件,如果为true,则继续下次循环,否则,终止循环,而在for循环中continue使用程序先跳转到循环变量计算部分,然后再判断循环条件
(八)数组
一维数组
1.定义数组
定义数组时一定要指定数组的名称和数组的类型
必须的抒写方式“[]”,表示的就是定义一个数组,而不是一个普通的变量
"[数组长度]"决定了连续分配的空间长度,通过数组length属性可以获取数组长度
数组的数据类型用于确定分配每个空间的大小
int [] a=new int [5];
int [] b={1,2,3,4}
数组元素分配的初始值
数组元素的类型 | 默认初始值 |
---|---|
byte、short、int、long | 0 |
float、double | 0.0 |
char | ”\u0000“ |
boolean | false |
引用数据类型 | null |
2.获得数组元素的语法格式:
数组名[下标值]
例如
scorce[0] =65 //表示scorce数组的第一个元素赋值给他为65
scorce[1]=87 //表示scorce数组的第二个元素赋值给他为85
3.jdk1.5:之后为我们提供了一个增强for循环,用来实现对数组和集合中的访问,增强for循环的语法格式:
for(元素类型 变量名:要循环的数组或集合){ …}
括号中的第一个元素类型指的时数组或集合中元素类型,变量名在循环时保存每个元素的值,冒号后面是我们要循环的数组或集合的名称
二维数组
int[][] s =new int[3][5];
表面上看是二维数组,但是从内存分配来看,实际上就是一个一维数组,数组名为s,包括了3个元素,分别是s[0]、s[1]、s[2],每个元素是整型数组类型,即一维数组类型。而s[0]又是一个数组的名称,包括了5个元素
分别是s[0][0]、s[0][1]、s[0][2]、s[0][3]、s[0][4]、每个元素都是整数类型。s[1]、s[2]、s[3]情况相同
所以二维数组实际上就是一个一维数组,每个元素又是一个一维数组。
s[1][0]、s[1][1]、s[1][2]、s[1][3]、s[1][4]
Arrays类
JDK中提供了一个专门用于操作数组的攻击类,即Array类,位于java.util包中,该类提供了一系列方法来操作数组,比如排序、复制、比较、填充等、用户直接调用这些方法即可,不需要自己编码去实现,降低开发难度。
方法 | 返回值 | 说明 |
---|---|---|
equals(array1,array2) | boolean | 比较两个数组是否相等 |
sort(array) | void | 对数组arry元素的进行升序的排列 |
toString(arrry) | string | 将一个数组arry转换一个字符串 |
fill(arry,val) | void | 把array数组中所有的元素都赋值为val |
copyOf(arry,length) | 与arry数据类型一致 | 把数组arry复制成一个长度为length的新数组 |
binarySearch(array,val) | int | 查询元素值val在数组arry中的下标 |
Arrays类的equals()方法·用于标胶两个数组是否相等,只有当两个数组长度相等,对应的位置的元素也就一一相等时,该方法就返回true否则返回false
toString()将一个数组转换成一个字符串,它按照顺寻把多个数组元素连接一起,多个元素之间使用英文逗号和空格隔开
Arrays类的copyOf(array,length)方法可以进行数组复制,把原数复制成一个新数组,其中length是新数组的长度。如果length小于原数组的长度,则新数组就是原数组的前面length个元素;如果length大于原来数组的长度,则新数组前面的元素的原数组的所有元素;后面元素是按数组类型补充默认的初始值,如整型补充0,浮点型补充0.0等。
(九)面向对象
对象和类
Java语言就是面向对象的语言。要使用Java进行面向对象编程,首先简历一个面向对象的思想。面向对象是一种直观而且程序结构简单的程序设计方法。它比较符合人类认识现实世界的思维,基本思想:把问题看成若干对象的组成,这些对象之间是独立,但是他们之间又可以相互配合,连接和协调,从而共同完成整个程序实现的任务。
面向对象有三大特征:封装、继承、多态
对象就是用来描述客观事物的一个实体。
类是具有相同的属性和方法的一组对象集合。类定义了对象将会拥有一些特征(属性)和行为(方法)。
类与对象的关系就如同模具和用整个模具制作出的物品之间的关系。一个类给出它的全部对象的一个统一的定义,而它的每个对象则是符合这种定义的一个实体。因此类和对象的关系就是抽象和具体的关系。类是多个对象进行综合的抽象的结果,是实体对象的概念模型,而一个对象是一个类的实例。
(1).定义一个类
定义"人" 类
定义的语法格式:
[访问修饰符] class 类名{
…//省略类的内部代码
}
1.访问符:如public、private、等可选的
2.class表示声明类的关键字
3.按照类名规范,首字母大写
(2).属性
Java中的类的内部主要就包括属性和方法,对象所拥有的特征再类中称为属性
定义属性的语法格式:
[访问修饰符] 数据类型 属性名:
1.访问修饰符可以选的
2.除了访问修饰符之外,其他的语法和声明变量属性
(3).方法:
对象执行操作的行为称为方法,例如:人有工作的行为,称工作这个行为就是人这个类中的一个方法
”人“ 类还有其他的方法,如吃、喝、睡觉等。
定义方法的语法格式:
[访问修饰符] 返回类型 方法名称(参数类型 参数名1,参数类型2 参数名2,。。。。){
方法体代码 }
1.访问修饰符可以选择
2.返回的类型可以是void,返回类型是void时,标明没有返回值,方法体中不必使用”return“关键字来返回具体数据,但是可以使用”return“关键字来退出方法
3.返回类型不是void,那么再方法体中一定要使用”return“关键字,返回对应类型的结果,否则程序会出现编译错误。
4.当需要再方法执行时,为方法传递参数时,蔡需要参数列表,如果不需要参数传递,参数列表可以省略
不过小括号不能省略,传递多个参数使用,分隔。
(4).创建对象
类是一个事物的集合和抽象,代表这类事物共有的属性和方法,以后个对象称为类的实例,是类的一次实例化的结果,例如”张三“ 一个”人“类的具体对象
类的对象可以调用类中的成员,如属性,方法
创建对象的语法格式:
类名 对象名=new 类名()
1.new 是关键字
2.左边的类名为对象的数据类型
3.右边的类名称为类的构造方法(后续会讲)
(5)。使用Java中的对象
在java中,要引用对象的属性和方法,需要”.“
使用java对象的语法格式:
对象名.属性 //引用对象的属性
对象名.方法 //引用对象的方法
(7).面向对象的优点:
1.与人类的思维习惯一致:面向对象的思维方式是从人类考虑问题的角度出发,把人类解决问题的思维过程转变为程序能够理解的过程、面向对象程序设计使用"类"来模拟现实世界中的抽象概念,用"对象"来模拟现实世界的实体从而用计算机解决现实问题
2.信息隐藏,提高了程序的可维护性和安全性:封装实现了模块化和信息隐藏,即将类的属性和行为封装在类中,这保证了对他们的修改不会影响到其他对象,利于维护。同时,封装使的在对象外部不能随意访问对象的属性和方法,避免了外部错误对它影响,提高了安全性
3.提高了程序的可重用性:一个类可以创建多个对象实例,体现了重用性。
(十)成员方法
类中主要包括两部分:成员方法、成员变量
(1).方法重载
方法重载是指一个类中定义多个同名的方法,但要求每个方法具有不同的参数类型或参数个数。
特点:
1.在同一个类中
2.方法名相同
3.参数个数或类型不同
4.方法的返回值不能作为判断方法之间是否构成重载的依据
(2)成员变量:
1.成员变量的作用域:
类中的属性,也就是直接在类中定义的变量称作为成员变量,它定义在方法的外部
注意:
成员变量可以在声明时开始赋值
2.局部变量作用域
局部变量就是定义在我们方法中的变量
注意:
虽然成员变量age和局部变量age名称一样,但是表示的却不是同一个变量,一般情况下,局部变量在使用前需要赋值,否则会出现编译错误
(3)。 成员变量和局部变量的区别
1.作用域不同,局部变量的作用域仅限定义它的方法,在该方法外无法访问它。成员变量的作用域在整个类的内部可见,所有的成员的方法都可以使用它,如果访问权限允许的话,还可以在类的外部使用成员变量
2.初始值不同,对于成员变量,如果类定义没有给它赋予初始值,Java会给它一个默认值,基本数据整数型是0,引用类型是null,但是Java不会给局部变量赋予初始值,因此局部变量必须要定义并复制后使用
3.在同一个方法中,不允许有同名的变量,在不同的方法中,可以用同名的局部变量
4.局部变量可以和成员变量同名,并且一起使用,局部变量更高的优先级别
(4).对比基本数据类型和引用数据类型的区别
分析如下:
int为基本数据类型,当初始化num1并赋值后,将num1赋给num2,然后修改num2的值,运行后发现num1的值没有改变。
class为引用数据类型,当实例化person1对象并对其属性赋值后,将person1对象赋给person2对象,然后修改person2的值,运行后发现person1的属性值发生变化。
几乎同样的操作,为什么会有完全相反的结果?这是因为int和class在内存种的存储方式不同,这也是基本数据类型和引用数据类型的主要区别。
对于基本数据类型,不同的变量会分配不同的存储空间,并且存储空间中存储的是该变量的值,赋值操作传递的是变量的值,改变一个变量的值不会影响另外一个变量的值
对于引用数据类型,赋值是把原对象的引用(可以理解内存地址)传递给另外一个引用,对数组而言,当用一个数组名直接给另一个数组赋值时,相当于传递一个引用,此时,这两个引用指向同一个数组,也就是指向同一内存空间。
(十一)构造方法
java中,当类创建一个对象时会自动调用该类的构造方法,构造方法分为默认构造方法和带参数的构造方法
1.构造方法的主要作用是进行一些数据的初始化
定义构造方法的语法格式:
[访问修饰符] 方法名(参数列表){
方法体代码 }
当开发人员没有编写自定义构造方法时,Java会自动默认添加构造方法,默认构造方法时没有参数,也就是无参的构造方法
注意:
如果自定义一个或者多个构造方法时,则java不会自动添加默认构造方法
2.构造方法重载
构造方法也可以重载,即在同一个类中可以定义多个重载的构造方法,如:
public Person(){};
public Person(String name,int age){
this.name=name;
this.age=age;}
在成员变量的示例中多次用到了this关键字,this的含义是什么呢?
this关键字是对一个对象的默认引用,每个实例方法内部都有一个this引用变量,指向调用这个方法的对象,其实就是指当前对象的引用,通俗点理解本对象自己
(1).this.属性名:
表示本对象自己的属性使用this调用成员变量,解决变量和局部变量的同名冲突
(2)this.方法名:
表示本对象自己的方法
我们给Person类增加了一个”打招呼”的方法叫做greet。在introduce方法当中,就可以通过”this.方法名”的方式来调用这个方法,表示调用的是”本对象自己的greet”方法。这是this关键字的第二种用法。当然,在introduce方法中并没有出现其他对象,所以方法名前面的this关键字也可以省略不写。
public void greet(){
System.out.println(“hello,大家好”);
}
public void introduce(){
this.greet();
System.out.println(“我叫”+name+“,今年”+age+“岁”);
}
(3)this关键字
还有另外一种很重要的用法,那就是在this关键字的后面加上小括号,这样就表示调用了某个类自身的构造方法,为了讲解这种用法我们再来修改一下Person类:
我们给Person类又增加了一个构造方法。这个构造方法只有2个参数,并且只初始化2个属性。为了讲述方便,我们把上面的3个参数的构造方法称之为”构造方法①”,把下面的2个参数的构造方法称之为”构造方法②”。通过观察不难发现,这两个构造方法当中前2行代码是相互重复的,为了避免这种重复性的代码出现,我们可以在”构造方法①”当中调用”构造方法②”。调用的方式如下:
//构造方法1
public Person(String name,int age,double height){
this(name,age); //调用构造方法2
this.height=height;
}
//构造方法2
public Person(String name,int age){
this.name=name;
this.age=age;
}
(4).外部类名.this.属性
this关键字在我们编写内部类代码的时候,还有一种用途,那就是区分属性或方法的具体归属
public class Outter {
public int a=0; //外部类的属性
class Inner{
public int a=10;//内部类的属性
public void printA(){
System.out.println(a);//调用内部类的a属性,输出10
System.out.println(this.a);//调用内部类的a属性,输出10
System.out.println(Outter.this.a);//调用外部类的a属性,输出0
}
}
}
(十二)封装
Java中封装的实质就是将类的状态信息隐藏在类内部,不允许外部程序直接访问,而是通过该类提供的方法开实现对隐藏信息的操作和访问。
封装反映了事物的相对独立性,有效避免了外部错误对此对象的影响,并且能对对象使用者由于大意产生的错误操作起到预防作用。同样面向对象编程提倡对象之间实现松耦合关系。
封装的好处在于隐藏类的实现细节,让使用者只能通过程序员规定的方法来访问数据,可以方便的加入存取控制修饰符,来限制不合理的操作。
将Person类中的属性public修改为private即可
访问时需要通过set个get函数,使用Generate–来快捷定义set,get和构造函数
作用域\修饰符 | 同一类中 | 同一包中 | 子孙类中 | 其他包 |
---|---|---|---|---|
private | 可以使用 | 不可以使用 | 不可以使用 | 不可以使用 |
默认修饰符 | 可以使用 | 可以使用 | 不可以使用 | 不可以使用 |
protected | 可以使用 | 可以使用 | 不可以使用 | 不可以使用 |
public | 可以使用 | 可以使用 | 可以使用 | 可以使用 |
public:公有的
被声明为public的类、方法、构造方法和接口能够被任何其他类访问。
如果几个相互访问的public类分布在不用的包中,则需要导入相应public类所在的包。由于类的继承性,类所有的公有方法和变量都能被其子类继承。Java程序的main() 方法必须设置成公有的,否则,Java解释器将不能运行该类
protected:受保护的
被声明为protected的变量、方法和构造方法能被同一个包中的任何其他类访问,也能够被不同包中的子类访问。
protected访问修饰符不能修饰类和接口,方法和成员变量能够声明为protected,但是接口的成员变量和成员方法不能声明为protected。
子类能访问protected修饰符声明的方法和变量,这样就能保护不相关的类使用这些方法和变量。
private:私有的
私有访问修饰符是最严格的访问级别,所以被声明为private的方法、变量和构造方法只能被所属类访问,并且类和接口不能声明为private。
声明为私有访问类型的变量只能通过类中公共的Getter/Setter方法被外部类访问。
private访问修饰符的使用主要用来隐藏类的实现细节和保护类的数据。
默认的:不使用任何关键字
不使用任何修饰符声明的属性和方法,对同一个包内的类是可见的。接口里的变量都隐式声明为public static final,而接口里的方法默认情况下访问权限为public。
static关键字
一个类可以创建n个对象。如果n个对象中的某些数据需要共用,就需要使用static关键字修饰这些数据。
Java中,一般情况下调用类的成员都需要先创建类的对象,然后同过对象进行调用。使用static关键字可以实现通过类名加".“直接调用类的成员,不需要创建类的对象。使用staic修饰的属性和方法属于类,不属于具体的某个对象。
1.用static关键字修饰属性
将Person类的name、gender和age属性保留,新建一个static修饰的属性,并调用。
分析如下:
使用static修饰的属性不依赖于任何对象,用类名直接加”."调用即可。
使用static修饰的属性不依赖于任何对象,用类名直接加“.”调用即可。
*常量名一般由大写字母组成
*声明常量时一定要赋值初值
2.用static关键字修饰方法
用staic修饰的方法称为静态方法或者类方法,不用static关键字修饰的方法称为实例方法
静态方法只能访问静态成员,实例方法可以访问静态和实例成员。之所以不允许静态方法访问实例成员变量,是因为实例成员变量是属于某个对象的,而静态方法在执行时,并不一定存在对象。同样,因为实例方法可以访问实例成员变量,如果允许静态方法调用实例方法,将间接地允许它使用实例成员变量,所以它也不能调用实例方法。基于同样的道理,静态方法中也不能使用关键字this。
main()方法是一个典型的静态方法,它同样遵循一般静态方法的规则,所以它可以由系统在创建对象之前就调用。
//静态方法只能访问静态
//非静态方法可以访问所有
//静态方法没有this
(十三)包
Java中的包机制也是封装的一种形式。
包的主要有以下方面的作用:
1).包允许将类组合成较小的单元(类似文件夹),易于找到和使用相应的类文件
2).防止命名冲突:Java中只有在不同包中的类才能重名。不同的程序员命名同名的类在所难免,类名就容易管理了,A定义了一个类Sort,封装在包A中,B定义了一个类Sort,封装在包B中,在使用时,为了区别A和B定义的Sort类,可以通过包名区分开,如A.Sort和B.Sort分别对应于A和B定义的Sort类。
定义包的语法格式如下:
package包名:
package是关键字
包的声明必须是Java源文件中的第一条非注释性语句,而且一个源文件只能有一个包声明语句,设计的
包需要与文件系统结构相对应。因此,在命名包时,要遵守以下编码规范。
1).一个唯一的包名前缀通常是全部小写的ASCII字母,并且是一个顶级域名com、edu、gov、net及org,通常使用组织的网络名的逆序。例如,如果域名为javagroup.net,可以声明包为“package net.javagroup.mypackage;”
2) 包名的后续部分依次不同机构各自内部的规范不同而不同。这类名规范可能以特定目录名的组成来区分部门、项目、机器或注册名、如“package net.javagroup.research.powerproject”。research表示项目名,powerproject表示部门名
例如,下面的代码中,为了Person类定义了包cn.shujia.pack1。
package cn.shujia.pack1;
public class Person{
//省略类的内代码}
(十四)继承和多态
继承
继承是面向对象的三大特性之一,继承可以解决编程中代码的冗余问题,是实现代码重用的重要手段。继承是软件可重用性的一种表现,新类可以在不增加自身代码的情况下,通过从现有的类中继承其属性和方法,来充实自身内容,这种现象或行为就称继承。此时新类称为子类,现有的类称为父类,继承最基本的作用就是使得代码可重用,增加软件的可扩充性。
Java中只支持单继承,每一类只能有一个父类。
(1).继承的语法格式:
[访问修饰符] class extends {}
1.在Java中,通过extends关键字来实现,Subclass称为子类,SuperClass称为父类或者基类
2.访问修饰符如果是public ,在整个项目中可用。
3.如果不写访问修饰符,该类只能在当前包下
4.在java中,子类可以在父类继承如下内容:
a.可以继承public 和protected修饰的属性和方法,不论子类和父类是否在同一包中
b.可以继承默认访问修饰符的属性和方法,但是子类和父类必须在一个包中
c.无法继承父类发的构造方法
(2).通过super关键字访问父类的成员的语法格式:
访问父类的构造方法: super(参数)
访问父类的属性和方法:super.<父类属性/方法>
1).super只能出现在子类(子类的方法和构造方法中)而不是在其他位置
2),super只能访问父类的成员:如属性、方法、构造方法
3).具有访问权限的限制,如无法通过super访问父类的private的成员
(3).实例化子类对象
在Java中,一个类的构造方法在如下两种情况下总会被执行
a.创建类的对象(实例化)
b.创建该类的子类的对象(子类的实例对象)
因此,子类在实例化时,会首先执行其父类的构造方法,然后再去执行该子类的构造方法,换言之,当在java语言中创建一个对象时,Java虚拟机会按照父类----子类的顺序一系列的构造方法。子类继承父类时,构造方法的调用规则:
1.如果子类的构造方法中没有通过super显示调用父类的有参构造方法,也没有通过显示this显示调用自身的其他构造方法,则系统会按照默认先调用父类无参的构造方法,在这情况下,我们写不写"super()"语句,效果一样
2.如果子类的构造方法中通过super显示的调用了父类的有参构造,那么将执行父类的相应构造方法,而不是执行无参的构造方法。
3.如果子类的构造方法中通过this显示的调用了自身的其他构造方法,在相应得构造方法中遵循以上两条规则。
(4).多继承
分析:当执行"postGraduate =new PostGraduate()"后,共创建了4个对象。按照创建的先后顺序,依次Object、Person、Student、PostGraduate。在执行Person()时就调用了Object无参构造方法,该方法内容为空
当执行”postGraduate=new PostGraduate(“刘大大”,“北京大学”,“老王老师”);“,也是创建了4个对象,只是此次调用构造方法不同,依次Object(),Person(String name)、Student(String name,String school)、PostGraduate(String name,String school,String guide)
示例:
如果B的父类中A没有自定义的构造方法时,系统会提供一盒无参方法体为空的构造方法,
但是,当B的父类中A定义了构造方法时,系统将不会再提供一个无参的方法体为空的构造方法
程序员必手动去添加一个无参的构造方法
(5).Object类
Object是所有类的父类,通常省略继承Object
方法 | 说明 |
---|---|
toString() | 返回当前对象本身的有关的信息,返回字符串对象 |
equals() | 比较两个对象是否是同一个对象,若是,返回true |
clone() | 生成当前对象的一个副本,并返回 |
hashCode() | 返回该对象的哈希代码值 |
getClass() | 返回当前对象所属的类信息,返回Class对象 |
注意:
equals()比较是否是同一个对象,java.lang.String类重写了Object的equals方法
(6).方法重写
PersonelDept对象personelDept的输出内容是继承来自父类Department的printDetail()方法的内容,所以不能显示PersonelDept的count信息,这显然不符合实际需求
如果父类继承的方法不能满足子类的需求,可以izai子类中对父类的同名方法重写(覆盖),以符合需求。
方法重写必须满足以下要求:
a.重写的方法和被重写的方法必须具有相同的方法名
b.重写方法和被重写方法必须具有相同的参数列表
c.重写方法的返回值必须和被重写方法的返回值类型相同
d.重写的方法不能缩小被重写方法的访问权限。
重写和重载的区别
1.重载涉及同一个类中的同名方法,要求方法名相同,参数列表不同,与返回值类型无关
2.重写涉及的是子类和父类之间的同名方法,要求方法名相同,参数列表相同
多态
多态一词的通常含义是指能够呈现多种不同的形式或形态。而在程序设计的术语中,它意味着一个特定类型的变量可以引用不同类型的对象,并且能自动地调用引用的对象的方法,也就是根据作用到的不同对象类型,响应不同的操作。方法重写是实现多态的基础。
多态意味着在一次方法调用中根据包含的对象的实际类型(即实际的子类对象)来决定应该调用哪个方法,而不是由用来存储对象引用的变量的类型决定的。当调用一个方法时,为了实现多态的操作,这个方法既是在父类中声明过的,也必须是在子类中重写过的方法。
注意:
1.抽象类不能被实例化
2.子类如果不是抽象类,则必须重写抽象类中的全部抽象方法
3.abstract修饰不能和final一起使用
4.abstract修饰的方法没有方法体
5.private不能修饰抽象方法
(1).向上转型
子类向父类的转换向上转型
向上转型的语法:
<父类型> <引用变量名> =new <子类型>()
1.将一个父类的引用指向子类对象称为向转型,系统自动类型转换
2.此时通过父类引用变量调用方法时,子类覆盖或继承了父类的方法,不是父类的方法
3.此时无法通过父类的引用变量调用子类特有的方法
(2).向下转型
当向上转型发生后,将无法调用子类特有的方法,但是弱国需要调用子类特有的方法,可以通过把父类转换为子类的实现
将一个指向子类对象的父类引用给一个子类引用,即父类类型转换为子类类型,称为向下转型,此时必须要强制类型转换
向下类型转换的语法:
<子类型> <引用变量名> =(子类类型)<父类类型的引用变量>
(3).instanceof运算符
在向下转型的过程中,如果不是转换为真实的子类类型,会出现异常
使用instanceof 时,对象类型必须和instanceof后面的参数所指定的类有继承关系,否则会出现编译错误,
例如:代码“pet instanceof String”。=“pet是不是子类”。instanceof通常和强转类型转换结合使用
(4).使用父类作为方法的形参
使用父类作为方法的参数,是java中实现和使用多态的主要方式
(5).使用父类作为方法的返回值
使用父类作为方法的返回,也是java中实现和使用多态的主要方式
(6).调用变量时,编译看左边,运行也看左边。
java编译时看左边有没有这个变量,有的话编译成功,运行时获取的是左边的父类变量。
(7).调用方法时,编译看左边,运行看右边。
java编译时会看左边有没有这个方法,有的话,编译成功,运行时运行的是右边子类的方法。所以不能调用子类特有方法,不过可以再转回子类类型,就可以调用了。
(8).静态方法,左边编译,左边运行
使用父类作为方法的返回,也是java中实现和使用多态的主要方式
(十五)抽象类和接口
抽象方法与抽象类
( 1).区分普通方法和抽象方法
在Java中,当一个类的方法被abstract关键字修饰的时候,被称为抽象方法。抽象方法所在的类必须定义为抽象类。
当一个方法被定义为抽象方法后,意味着该方法不会有具体的实现(没有方法体)。而是在抽象类的子类中通过方法重写进行实现,定义抽象方法的语法格式:
[访问修饰符] abstract<返回类型> <方法名>([参数列表]);
普通方法和抽象方法的相比,主要有两点区别:
a.抽象方法需要用abstract修饰,普通方法不需要
b.普通方法有方法体,抽象方法没有方法体
(2).区分普通类和抽象类
在java中,当一个类被abstract关键字修饰时,该类被称为抽象类.
定义抽象类的语法格式:
abstract class <类名>{
}
普通类和抽象类的区别:
1.抽象类需要abstract 修饰,普通类不需要
2.普通类可以实例化,抽象类不能实例化
(3).定义一个抽象类
当一个类被定义为抽象类,她可以包含各种类型的成员,包括属性、方法,其中方法又分为普通方法和抽象方法。
抽象类的结构:
public abstract class 类名称{
访问修饰符 返回类型 方法名(){ 方法体 } }
注意:抽象方法只能定义在抽象类,但是抽象类中可以包含抽象方法,也可以包含普通方法,还可以包含普通类的一切成员
接口
(4)接口
通俗的来说,接口是一个不能实例化的类型,接口类型的定义的语法格式:
public interface 接口名{
//接口成员 }
和抽象类的不同:定义接口使用的关键是interface修饰,访问修饰符只能是public
接口中的成员可以是全局常量和公共的抽象方法。
实现接口的语法 :
public 类名 implements 接口名{
实现方法
普通方法 }
a.实现接口使用implements关键字
b.实现接口的类必须实现接口中定义的所有的抽象方法。接口的实现类允许包含普通的方法。
类与类:
继承关系,只能单继承,可以多层继承。
类与接口:
实现关系,可以单实现,也可以多实现。
并且还可以在继承一个类的同时实现多个接口。
接口与接口:
继承关系,可以单继承,也可以多继承。
接口成员特点
成员变量;只能是常量,并且是静态的。
默认修饰符:public static final
建议:自己手动给出。
构造方法:接口没有构造方法。
成员方法:只能是抽象方法。
默认修饰符:public abstract
建议:自己手动给出。
所有的类都默认继承自一个类:Object。
类 Object 是类层次结构的父类。每个类都使用 Object 作父超类。
复杂接口
接口本身也可以继承接口
接口继承的语法格式:
【访问修饰符】 interfance 接口名 extends 父类接口1,父接接口2,…{
常量的定义
方法的定义
}
一个普通类只能继承一个父类,但是能同时实现多个接口,也可以同时继承抽象类和实现接口
实现多接口的语法格式:
class 类名 extends 父类名 implements 接口1,接口2,…{
}
注意:
关于定义和实现接口所要注意的地方
1.接口和类、抽象类是一个层次的概念,命名规则相同
2.修饰符如果是public ,则该接口再整个项目中可见,如果省略修饰符,该接口只在当前包中可见
3.接口中可以定义常量,不能定义变量,接口中的属性都默认用"public static final",即接口中的属性都是静态全局常量,接口中的常量必须在定义时给定初始值:
public static final int =3.14
int PI =3.14//在接口中,这两个定义语句效果相同
int PI;// 在接口中定义必须赋值初始化
d.接口中所有的方法都是抽象方法,接口中的方法默认时public
c.和抽象类一样,接口不能实例化,接口中不能有构造方法
e.类中只能继承一个父类,但是可以通过implements实现多个接口,一个类必须实现接口的全部方法,
否则必须定义为抽象类,若一个类在继承父类的同时又实现了多个接口,extends必须位于implements之前
(十六)面向对象设计的原则
在实际开发过程中,遵循以下原则,会让代码更具灵活性,更能适应变化。
1.摘取代码中变化的行为,形成接口
例如,在“愤怒的小鸟”游戏中,鸟叫的行为变化性很大,有的鸟叫,有的鸟不叫。各种鸟的叫声也不一样,这种行为最好定义为接口。
2.多用组合,少用继承
在“愤怒的小鸟”游戏中,通过在抽象类鸟中包含鸟叫的属性来实现组合,有效地减少了代码冗余。
3、针对接口编程,不依赖于具体实现
如果对一个类型有依赖,应该尽量依赖接口,尽量少依赖子类。因为子类一旦变化代码变动的可能性大,而接口要稳定得多。在具体的代码实现中,体现在方法参数尽量使用接口,方法的返回值尽量使用接口,属性类型尽量使用接口等。
4.针对扩展开放,针对改变关闭
如果项目中的需求发生了变化,应该添加一个新的接口或者类,而不要去修改原有的代码。
需要说明的是,这4个面向对象的原则比较抽象,可以先记住它,然后在实际的面向对象开发中尝试应用这些原则,然后加深对这些原则的理解