Java必学的基础部分为1-10章,其中每个部分包含少量的扩展内容,而扩展内容会随着时间增加,对于初学者不必太纠结扩展内容,当基础内容学完,扩展内容便可达到一种豁然开朗的程度。
建议初学自学者根据视频结合自己的理解参考本笔记,右侧有大纲,点击直达相关位置,对于未来的复习也很有帮助。
对于自学,视频建议观看狂神,和尚硅谷。在这里也要感谢他们提供了免费的学习路线和全套的教学视频。本笔记参考了许多教程视频,整合而来。
希望初学者,对Java感兴趣,对做网站感兴趣,对编程感兴趣,对底层充满好奇,对计算机充满好奇,对这个世界充满好奇。
什么东西都不是凭空产生的,多了解底层,了解实现这些功能背后的原理。
如果你想做一个自己的动态网站,相信你自己,通过传统路线很快就能达到。
[info:]
本文使用MarkDown语法编写
0、初见:
第一代:机器语言。二进制,直接输入给计算机使用,不经过任何的转换。
第二代:汇编。相对机器语言人性化了不少。
第三代:高级语言。面向过程(如:C语言)和面向对象(如:C++语言、JAVA语言、C#语言、Python、PHP、JavaScript)
Java是在1991年由SUN公司的James Gosling(Java之父)及其团队所研发的一种编程语言。
在1995年更名为Java(印度尼西亚爪哇岛的英文名称,因盛产咖啡而闻名)。
JAVA语言特性:
-
JAVA是一种面向对象的编程语言
-
简单易学:相对于其他编程语言来说,JAVA语言的语法相对简单,易于学习和理解。
-
平台无关性:JAVA程序可以在不同的操作系统上运行,只要安装了JAVA虚拟机(JVM)即可。
-
面向对象:JAVA是一种纯粹的面向对象的编程语言,通过封装、继承和多态等特性,可以更好地组织和管理代码。
-
安全性:JAVA提供了一些安全性机制,如类加载机制、异常处理机制以及访问控制等,可以保证程序的安全性。
-
高性能:虽然JAVA是解释型语言,但通过JIT编译器的优化,可以提高代码的执行效率。
-
线程支持:JAVA内置了对线程的支持,方便开发多线程程序,实现并发操作。
-
开放性:JAVA提供了大量的开源库和框架,方便开发人员快速构建复杂的应用程序。
-
可移植性:由于JAVA的平台无关性,JAVA程序可以在不同的硬件平台上运行,保证了程序的可移植性。
-
自动内存管理:JAVA通过垃圾回收器(Garbage Collector)来管理内存,开发人员无需手动进行内存管理。
- JavaSE:Java平台的标准版,它提供了Java语言的核心API和基本功能,适用于开发普通的桌面应用程序、命令行工具和服务器端应用程序等。
- JavaME(Java Micro Edition):是Java平台的微型版,专门设计用于嵌入式设备和移动设备的应用程序开发。我们熟知的Android它所运行的app也是由Java编写的(更多可了解kotlin)
- JavaEE(JavaEnterpriseEdition):是Java平台的企业版,用于开发大型、复杂的企业级应用程序。JavaEE提供了一套丰富的API和服务,用于构建分布式、可扩展和安全的企业应用。
JDK\JVM\JRE的区别:
- JDK(Java Development Kit)Java开发工具包,包含Java语言、Java虚拟机、Java类库,是支持Java程序开发的最小环境。
- JVM(Java Virtual Machine)Java虚拟机,运行于各种操作系统Linux,Windows,Solaris等之上,执行编译好的Java字节码class文件。
- JRE(Java Runtime Environment)Java运行时环境,包含JavaSE中核心类库API和Java虚拟机,简单理解为JVM+核心类库API。
-
右键 This PC(此电脑) -> Properties(属性) -> Advanced system settings(高级系统设置) -> Environment Variables(环境变量)
-
新建JAVA_HOME 变量
-
变量名:JAVA_HOME 变量值:电脑上JDK安装的绝对路径
-
-
新建/修改 CLASSPATH 变量
-
变量名:CLASSPATH 变量值:.;%JAVA_HOME%\lib\dt.jar;%JAVA_HOME%\lib\tools.jar;
-
-
新建两条Path路径
-
%JAVA_HOME%\bin %JAVA_HOME%\jre\bin
-
-
打开cmd输入 java 出现一连串的指令说明配置成功了。
O.o 常见的Dos命令:
Win键+R 输入"cmd"打开
切换盘符:
格式:盘符 + :
C:\User\Administrator>d:
D:\>
查看当前目录下所有的文件夹和文件
格式:dir+Enter回车(dir是英文directory的缩写,意为“目录)
切换目录
格式:cd+空格+要切换的目录(cd是英文change directory的缩写)
D:\> cd softwareDevelopment
D:\softwareDevelopment>
输入cd…返回上一层目录
D:\softwareDevelopment>cd..
D:\>
回到此盘根目录
D:\softwareDevelopment\doc\ajax>cd\
D:\>
创建文件夹
格式:md+空格+文件夹名称(md是英文make directory的缩写)
删除文件夹
格式:rd+空格+文件夹名称(rd是英文remove directory的缩写)
创建文件
格式:copy con+空格+文件名
删除文件
格式:del+空格+文件名(del是单词delete的简写)
清屏
格式:cls(cls是英文clear screen的缩写)
退出命令行界面
格式:exit
o.O hello word
新建一个文件夹,创建一个名为Hello后缀为.java的文件
编辑内容:(可以使用notepad++编辑)
public class Hello{
public static void main(String args){
System.out.println("Hello,World!");
}
}
开始编译:
在这个Java文件的地址栏输入cmd回车
输入 javac Hello.java
会在目录里生成class文件
输入 Hello
运行成功后会输入一句Hello,World!
可能遇到的情况:
- Java大小写时非常敏感的,主要大小写
- 尽量使用英文
- 文件名和类名必须保持一致,并且首字母大写
- 结尾分号,使用英文分号
- 以上情况都没遇到则可能是之前Java环境配置出现了问题
如何学习Java
Java是一个面向对象编程的编程语言,重在培养面向对象的编程思想,这是根据自己的理解一步步形成的思想。
遇到困难或者不能理解的部分,要多思考,当然可能依然是似懂非懂的感觉,但是学习到了后面就会逐渐理解。
要学会自己做笔记,最好是自己发表博客,像我一样,每天都要写,每天都要发布。如果你也发表了博客请记得艾特我,我也好奇你写的啥。
必学MarkDown语法
无论是做笔记还是编写博客,或者以后写项目的说明档.md文件都需要学习MarkDown语法,这个很简单也很好学习,教程很多,例如你编辑一篇新的CSDN文档的时候,默认显示的就是语法教程(在编辑界面右上角也有语法说明)。
个人记笔记建议使用Typora,是一款很方便的markdown语法编辑器,这里附上教程:
1、注释Comments
package com.bsy;
/**
* @author bsy
* 文档注释
*/
public class Comments {
public static void main(String[] args) {
//编辑注释
//TODO 标签主要标记遇到的问题
//在工具类最下方点击TODO窗口,可以查看当前所有的项目代码中标识的TODO标签
System.out.println("hello worold!!!");
/*
* 长注释
*
*
* 注释在setting → editor → Java 中的 comments中进行设置样式
*
* comments表示注释的意思,翻译可以为“评论”的意思
*
*/
}
}
1.1、标识符Identifier
//TODO 标识符的命名规则
//1,英文字母
String name = "xiaoming";
String xingming = "xiaohong";
//2,可使用的符号
//标识符只能采用下划线和美元$符号,其余不可用,包括空格、@、#、%等
String _name = "";
String $name = "";
//3,数字
//0-9阿拉伯数字只能放在标识符的除开头以外的位置,放在开头会被识别为数字而非标识符
//4,一个作用域内不允许出现同名(标识符不允许重复)。
//5,标识符区分大小写
//6,标识符不能为Java关键字(例如static、public、final等
//7,使用驼峰命名,先小后大;尽量见名知意(看见其名字就知道其含义)。
String userNameFist = "";
//8,标识符长度没有限制
2、基本数据类型Primitive Tpye
package com.bsy;
public class PrimitiveType {
//整数类型Datatype:
//bit位:比特,数据运算的最小单位,采用二进制存储,见下方。
byte numByte = -128;//字节。1byte=8bit位
byte numByte1 = 127;//字节:计算机存储数据的最小单位
short numShort = -32768;//16位
short numShort1 = -32767;
int numInt = -2147483648;//32位
int numInt1 = 2147483647;
long numLong = 30L;//64位,Long类型后面加上L进行标记(范围-9223372036854775808L~9223372036854775807L)
//浮点数
float numFloat = 50.1F;//单精度浮点类型
//Float类型在后面加上F进行表示,部分大小写,不写f会被识别为双精度。范围+/-3.4E+38F(6~7 个有效位)
double numDouble = 3.1415926;//双精度浮点类型
//+/-1.8E+308 (15 个有效位)
//布尔
boolean aBoolean = true;// ture or false
//字符
char aChar = '字';//单一字符(ISO 单一字符集)
//字符串(不是关键字,不属于八大类型,是类)
String name1 = "字符串";
/*
* bit 位 最小存储单位,例如 11001100是一个 八位 二进制 数。
* 1Byte = 8bit(1B = 8b)
* 1KB = 1024B
* 1M 1024KB
* 1G = 1024M
*/
}
2.1、扩展
2.1.1 Float、Double
float 是有限 离散 舍入误差 大约 接近但不等于的。不要用浮点型进行作比较。因为↓
float d1 = 123123123F;
float d2 = d1 +1;
System.out.println(d1 == d2);//ture
如果要使用很大的数值作比较可以使用一个现有的类
BigDecimal 数学工具类
2.1.2 强制转换
所有的字符本质是数字
char a1 = 'a';
char a2 = "中";
System.out.println(a1);//a
System.out.println((int)a1);//97
System.out.println(a2);//中
System.out.println((int)a1);//20013
Unicode编码表对应的编号数字(范围:U0000 - UFFFF)
char a3 = '\u0061';
System.out.println(a3);//a
2.1.3 转义字符
\r 表示回车符,将光标定位到当前行的开头,不会跳到下一行。
\n 表示换行符,换到下一行的开头。
\t 表示制表符,将光标移到下一个制表符的位置,就像在文档中用Tab键一样。
\b 表示退格符号,就像键盘上的Backspace键。
Java以下的字符都有特殊意义,无法直接表示,所以用反斜杠加上另外一个字符来表示。
\’ 表示单引号字符,Java代码中单引号表示字符的开始和结来,如果直接写单引字符('),程序会认为前两个是一对,会报错,因此需要使用转义符“\’”。
\" 表示双引号字符,Java代码中双引号表示字符串的开始和结来,包含在字符串中的双引号需要转义,比如(hesays,\”thankyou\”.)。
\ 标识反斜杠字符,由于在Java代码中的反斜杠(\)是转义字符,因此需要表示字面意义上的\,就需要使用双反斜杠(\)。
2.1.4 布尔值扩展
boolean flag = ture;
if (flag==ture){}
if (flag){}//默认等于ture,可以不写=ture
//Less is More! 代码要精简易读,更少就是更多。
2.2、引用数据类型
类、字符串、接口、数组、枚举等可以引用的数据类型都是引用数据类型
String name = "xiaoming";//这就是一个引用数据类型
3、类型转换
Java是强类型语言,运算时要进行类型转换
从上方得知,每种数据类型所能包含数的大小是不同的,例如你用一个32位的int大盒子装小的16位short盒子肯定可以直接装下。但是用小盒子装大盒子不是说不能装,而是会丢失一部分大盒子里的数据(精度丢失见下方)。
低 -------------------------------------------------→高
byte -> short -> char -> int -> long -> float -> double
3.1、强制类型转换
上面说到盒子的例子,在Java里低转高需要进行强制转换。
//高到低
int i = 128;
byte b = (byte)i;//byte最大127此时会发生内存溢出
//强制转换格式: (类型)变量名
3.2、自动类型转换
//低到高
int i = 128;
double b = i;//128.0
demo:
//根据上方的从低到高的顺序举例
byte b = 10;
short s = b;
int i = s;
long lon = i;
float f = lon;
double d = f;
注意:
1,不能对布尔值进行转换。
2,不能吧对象类型转换为不相干类型。
3,在把高容量转换到低容量的时候,要使用强制转换。
3,转换的时候可能存在内存溢出,或者精度问题。
//精度问题
System.out.println((int)23.7);//23
System.out.println((int)-45.89f);//-45
//char
char c = 'a';
int d = c + 1;
System.out.println(d);//98
System.out.println((char)d);//b
//可以将Unicode表打印出来
for(i=0;i<26;i++){
char c = 'a';
int d = c+i;
System.out.println((char)d);
}
扩展:
int money = 100_000_000;//数字之间可以使用下划线分割
int years = 20;
int total = money*years;//内存溢出
long total2 = money*years;//依然内存溢出,因为先计算int类型之后才进行转换
long total3 = money*((long)years);//先把一个数转换为long就可以
System.out.println(total3);
4、变量&常量
变量,可以改变的向量存储
变量:
package com.bsy;
public class Demo1 {
//类变量
static double salary = 2500;
//实例变量
//布尔值:默认false
String name;//默认值 null
int age;//默认值0
//main方法
public static void main(String[] args) {
//局部变量
int i = 10;
System.out.println(i);
Demo1 demo1 = new Demo1();
System.out.println(demo1.age);
System.out.println(demo1.name);
//类变量 static
System.out.println(salary);
}
}
常量:
package com.bsy;
public class Demo2 {
//修饰符不分先后顺序,写成final statci对结果没有影响
static final double PI = 3.14;//常量名使用大写
/*
常量定义格式:
final 常量名 = 值;
*/
public static void main(String[] args) {
System.out.println(PI);
}
}
(命名要见名知意,遵循驼峰命名法。常量使用大写字母加下划线MAX_VALUE。方法名首字母小写)
5、运算符
5.1、算术运算符:
+(加),-(减),*(乘),/(除),%(求余),++(自增),–(自减)
System.out.println(1+2);
System.out.println(2-2);
System.out.println(3*2);
System.out.println(4/2);
System.out.println(1/2);//0(int,int)=>int
System.out.println(1.0/2);//0.5(double,int)=>double
System.out.println(5%2);//1(取余,模运算)
//TODO 最小使用类型位int
byte b1 = 10;
byte b2 = 20;
int b3 = b1 + b2;//如果写按照上面的(byte,byte)=>byte就不行了
byte b4 = (byte)(b1 + b2);//强转可使其为byte类型
//Java计算也是由优先级的
System.out.println(1 + 2 * 3);//7
System.out.println((1 + 2) * 3);//9
5.1.1、自增自减:
// ++ --
//a = a + 1;
int b = a++;//先赋值,再自增。相当于b=a,然后再进行下一步自增,也就是隐藏了一步代码
int c = ++a;//先自增,再赋值。上面自增之后a=4,这里a先自增a=5,再赋值给c。
int i = 0;
int j = i++;//先赋值给j,赋值时i还没有自增。
System.out.println(i +"\n"+ j);//i = 1,j = 0
int i = 0;
int j = ++i;//i先自增为1再赋值给j,此时j为1
System.out.println(i +"\n"+ j);//i = 1,j = 1
5.2、赋值运算符:
=(等于),+=(自加一次等于),-=(自减一次等于),*=(自乘一次等于),/=(自除一次等于),+(字符串连接符)
//等号就是赋值运算符:将等号右边的表达式结果赋值给等候左边的变量
//赋值运算符需要考虑类型的关系
String name = "zhangsan";
byte b = 10;
char c = '字';
//复合赋值运算符
//如果元素进行运算后重新赋值给自己,那么可以将运算和赋值的符合进行简化
int i = 1;
i = i + 1;
i += 1;//其他的 -=、*=、/=同理
//如果使用复合赋值运算,那么数据的类型不会发生变化
byte b = 10;
b = b + 20;//20默认为int类型,而int不能直接转换为byte,所以报错。
b += 20;//但是使用复合赋值运算则不会。
5.3、比较(关系)运算符:
用于比较两个数据之间关系的运算符,返回结果只有:true或者false
(大于),<(小于),>=(大于等于),<=(小于等于),==(比较等于),!= instanceof(不等于)
int i = 10;
int j = 20;
System.out.println(i > j);//false
System.out.println(i < j);//ture
5.4、逻辑运算符:
&(按位与),&&(短路与),|(按位或),||(短路或),!(非,即取反)
5.4.1、与&&或||非!
boolean a = ture;
boolean b = false;
System.out.pintln("a && b:"+(b&&a));//逻辑与运算:两个变量都为真,结果才为真ture
System.out.pintln("a || b:"+(a||b));//逻辑或运算:两个变量只要有一个为真,则结果就为真ture
System.out.pintln("!(a && b):"+!(a&&b));//如果是真,则变为假,如果是假,则变为真。
//逻辑与运算:如果第一个变量都为假,则第二个就不会运算直接输出结果为假:
//短路运算:
int c = 5;
boolean d = (c<4)&&(c++ <4);
System.out.pintln(d);
System.out.pintln(c);//5 因为与运算要求两个都为真结果才为真,但是第一个都为假,所以直接输出结果false,根本不需要第二个运算。如果做了第二个运算说明输出结果为6,本程序说明了&&运算的逻辑。
5.4.2、位运算(都是基于二进制来计算):
位运算符:& | ^ ~ >> << >>>
&(按位与),|(按位或),^(异或运算),<<(左移运算符),>>(右移运算符),>>>(无符号运算符),~(非、取反运算符)
**效率极高!!!**因为是底层,可以做一些很巧妙的计算。
/*
A = 0011 1100
B = 0000 1101
A&B = 0000 1100 (进行每一位的比较,上下都是1才为1,不是则为0)
A|B = 0011 1101 (如果每个位都为0结果才为0,否则为1)
A^B = 0011 0001 (异或运算,两个位相同则为0,否则为1)
~B = 1111 0010 (取反)
<< (左移:相当于 *2)
>> (右移:相当于 /2) 举例:
将2*8 更快的计算出来:(计算机理解为2*2*2*2)
System.out.pintln(2<<3);//16
二进制里面表示的数为:
0000 0000 0
0000 0001 1
0000 0010 2
0000 0011 3
0000 0100 4
0000 1000 8
0001 0000 16
把1数字向左移动一位,数字就变大,2移动一位就变成4了。移动3位就变成16,所以2*2*2*2看乘几个2就移几位。而移动3位就是16。
*/
5.5、条件(三元)运算符?:
三个元素参与运算的运算符
// x ? y : z
//如果x==ture,则结果为y,否则结果为z
int score = 80;
//如果成绩大于 60 则为及格,给一个String类型的变量type赋值为“及格”
String type = score < 60 ? "不及格" : "及格";
5.6、扩展赋值运算符:
+= -= *= /=
int a = 10;
int b = 20;
a += b;//a = a+b
a -= b;//a = a-b
……
5.6.1、字符串连接符 +
int a = 10;
int b = 20;
//字符串连接 + 两侧只要一方出现String类型,就变成字符串拼接
System.out.pintln(""+a+b);//1020
System.out.pintln(a+b+"");//30
//程序是自上而下自左而右运算的,当字符串在前面则识别为字符串拼接,当运算在前面则先进行运算。
5.6.2、优先级()
跟数学算数一样,优先算一部分。
System.out.println(1 + 2 * 3);//7
System.out.println((1 + 2) * 3);//9
5.7、Math 数学工具类:
很多特殊的运算都需要到它,例如幂运算。
6、包机制
包的本质就是文件夹
**包名:**域名倒置。例如com.baidu
**导包:**import
**导入包下所有类:*通配符
import com.clover.base.*;
7、JavaDoc
@author 作者名
@version 版本号
@since 指明需要最早使用的jdk版本
@param 参数名
@return 返回参数情况
@throws 异常抛出情况
可使用CMD命令生成说明文档:
javadoc -encoding UTF-8 -charset UTF-8 Doc.java
(encoding编码格式,charset字符集编码)
Tools > Generate JavaDoc
参数举例:-encoding UTF-8 -charset UTF-8 -windowtitle “文档HTML页面标签的标题” -link http://docs.Oracle.com/javase/7/docs/api
8、Java流程控制
Java基础的第二部分,前面就像是游戏的新手教程,现在可以开始玩了。
8.1、Scanner对象
获取用户的输入
8.1.1、next()
package com.bsy;
import java.util.Scanner;
public class scannerDemo1 {
public static void main(String[] args) {
//创建一个扫描器对象,用于接收键盘数据
Scanner scanner = new Scanner(System.in);//System.in输入,System.out输出
System.out.println("使用next方式接收:");
//判断用户有没有输入
if (scanner.hasNext() == true){//默认为ture可以省略不写
String str = scanner.next();
System.out.println("输出的内容为" +str);
}
scanner.close();//IO流类的用完关掉,节省资源。好比水龙头用完要关掉。
/**
* 1、一定要读取到有效字符后才可以结束输入。
* 2、对输入有效字符之前遇到的空白,next()方法会自动将其去掉。
* 3、只有输入有效字符后才将其后面输入的空白作为分隔符或者结束符。
* 4、next()不能得到带有空格的字符。
*/
}
}
8.1.2、nextLine()
package com.bsy;
import java.util.Scanner;
public class scannerDemo2 {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
System.out.println("使用nextLine方式接收:");
if (scanner.hasNext()){
String str = scanner.nextLine();
System.out.println("输出内容为:"+str);
}
scanner.close();
/**
* 1、以Enter为结束符,也就是说nextLine()方法返回的输入回车之前的所有字符。
* 2、可以获得空白。
*/
}
}
不使用if语句:
package com.bsy;
import java.util.Scanner;
public class scannerDemo3 {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
System.out.println("请输出数据:");
String str = scanner.nextLine();
System.out.println("输出的内容为:"+str);
scanner.close();
}
}
8.1.3、next()的多种用法
package com.bsy;
import java.util.Scanner;
public class scannerDemo4 {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
//从键盘接收数据
int i = 0;
float f = 0.0f;
System.out.println("请输入整数:");
if (scanner.hasNextInt()){
i = scanner.nextInt();
System.out.println("整数数据:"+i);
} else {
System.out.println("输入的不是整数数据!");
}
System.out.println("请输入小数:");
if (scanner.hasNextFloat()){
f = scanner.nextFloat();
System.out.println("小数数据:"+f);
} else {
System.out.println("输入的不是小数数据!");
}
scanner.close();
}
}
8.1.4、举例
package com.bsy;
import java.util.Scanner;
public class scannerDemo5 {
public static void main(String[] args) {
//我们可以输入多个数字,并求其总和与平均数,每输入一个数字用回车确认,通过输入非数字来结束输入执行结果。
Scanner scanner = new Scanner(System.in);
//和
double sum = 0;
//计算输输入了多少个数字
int m = 0;
//通过循环判断是否还有输入,并在里面对每一次进行统计求和统计。
while ((scanner.hasNextDouble())){
double x = scanner.nextDouble();
m++;//m = m + 1;
sum+=x;//sum = sum + x;
System.out.println("你输入了"+m+"个数据,当前总和为:"+m+"当前平均值为:"+(sum / m));
}
System.out.println(m+"个数的和为"+ sum);
System.out.println(m+"个数的平均值是"+(sum / m));
scanner.close();
}
}
8.2、顺序结构
Java的基本结构就是顺序结构,除非特别指明,否则就按照顺序一句一句执行。它是任何一个算法都离不开的一种基本算法结构。
8.3、选择结构
8.3.1、if
8.3.1.1、if单选择结构
很多时候需要判断一个东西是否可行,然后我们才会去执行,这样一个过程在程序中使用if语句来表示。
package com.bsy;
import java.util.Scanner;
public class IfDemo1 {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
System.out.println("请输入Tencent的中文名");
String str = scanner.nextLine();
if (str.equals("腾讯")){
System.out.println("回答正确");
}else {
System.out.println("回答错误");
}
System.out.println("END");
scanner.close();
}
}
8.3.1.2、if多选择结构
if语句至多且必须有一个else语句,并且是在所有else if语句之后。
一旦其中一个else if语句检测为ture,其他else if以及else语句都将跳过执行。
package com.bsy;
import java.util.Scanner;
public class IfDemo3 {
public static void main(String[] args) {
//根据输入的分数划分等级
Scanner scanner = new Scanner(System.in);
System.out.println("请输入成绩:");
int score = scanner.nextInt();
if (score == 100){
System.out.println("恭喜满分");
} else if (score<100 && score>=90) {
System.out.println("A");
} else if (score<90 && score>=80) {
System.out.println("B");
} else if (score<80 && score>=70) {
System.out.println("C");
} else if (score<70 && score>=60) {
System.out.println("D");
} else if (score<60 && score>=0) {
System.out.println("不及格");
} else {
System.out.println("成绩不合法");
}
scanner.close();
}
}
8.3.1.3、if嵌套结构
8.3.2、switch多选择结构
switch case语句判断一个变量与一系列值中某一个值是否相等,每个值成为一个分支。
- switch语句中的变量类型可以是:
- byte
- short
- int
- char
- String
- 同时case标签必须字符串或字面量
package com.bsy;
public class SwitchDemo1 {
public static void main(String[] args) {
//不写break会发生case穿透
//switch匹配一个具体的值
char grade = 'C';
switch (grade){
case 'A':
System.out.println("优秀");
break;
case 'B':
System.out.println("良好");
break;
case 'C':
System.out.println("及格");
break;
case 'D':
System.out.println("优秀再接再厉");
break;
case 'E':
System.out.println("挂科");
break;
default:
System.out.println("未知等级");
}
}
}
8.4、循环结构
8.4.1、while循环
- while是最基本的循环
- 只要Boolean表达式为ture,循环就会一直执行下去
- 我们大多数情况是会让循环停止下来,需要一个让表达式时效的方式来结束循环。
- 少部分情况需要一直执行,比如服务器的请求响应监听等。
- 循环条件一直为ture就会造成死循环,我们正常的业务编程中应尽量避免死循环。回应性程序性能或者程序崩溃。
Demo1:
package com.bsy;
public class WhileDemo1 {
public static void main(String[] args) {
//输出1~100
int i = 0;
while (i<100){
i++;
System.out.println(i);
}
}
}
Demo2:
package com.bsy;
public class WhileDemo2 {
public static void main(String[] args) {
//计算1+2+3+...+100=?
int i = 0;
int sum = 0;
while (i<=100){
sum+=i;
i++;
}
System.out.println(sum);
}
}
8.4.2、do…while循环
- 对于while语句,即使不满足条件也至少循环一次。
- while和do…while的区别:
- while先判断后执行,不满足条件一次都不会执行。
- do…while先执行一次再进行判断,即使不满足循环条件也会至少循环一次。
package com.bsy;
public class DoWhileDemo1 {
public static void main(String[] args) {
int i = 0;
while (i<0){
System.out.println(i);
i++;
}
System.out.println("----------------");
do {
System.out.println(i);
i++;
}while (i<0);
}
}
8.5、for循环
- 虽然所有循环结构都可以使用while或者do…while表示,但Java提供了另一种语句——for循环,使一些循环结构变得更加简单。
- for循环语句是支持迭代的一种通用结构,是最有效、最灵活的循环结构。
- for循环执行的次数是在执行之前就确定的。
while和for的对比:
package com.bsy;
public class ForDemo1 {
public static void main(String[] args) {
int a = 1;//初始化条件
while (a<=100){//条件判断
System.out.println(a);//循环体
a+=2;//迭代
}
System.out.println("while循环结束!");
//初始化 //条件判断//迭代
for (int i=1;i<=100;i++){
System.out.println(i);
}
System.out.println("for循环结束!");
}
}
关于for循环:
- 先执行初始化步骤,可以声明一种类型,但可初始化一个或多个循环控制变量,也可以是空语句。
- 随后检测Boolean表达式,为ture循环体被执行。
- 执行一次循环后,更新循环控制变量(迭代因子控制循环变量的增减)。
- 再次检测Boolean表达式,循环上面的过程,如果为false则循环终止。
//死循环
for(;;){}
Demo1:
package com.bsy;
public class ForDemo2 {
public static void main(String[] args) {
//计算0到100之间奇数和偶数的和
int oddSum = 0;
int evenSum = 0;
for (int i = 0; i <= 100; i++) {//快捷键100.for
if (i%2 != 0){//奇数
oddSum+=i;
}else {
evenSum+=i;//偶数
}
}
System.out.println("奇数的和为:"+oddSum);
System.out.println("偶数的和为:"+evenSum);
}
}
Demo2:
package com.bsy;
public class ForDemo3 {
public static void main(String[] args) {
//用while或者for循环输出1-1000之间能被5整除的数,并且每行输出三个
for (int i = 1; i <= 1000; i++) {
if (i%5==0){//5的倍数
System.out.print(i+"\t");//输出5的倍数,添加制表符使其易读。
}
if (i%(5*3)==0){//每行
System.out.println();//换行
//System.out.print("\n");
}
}
//注意print和println的使用
}
}
Demo3:九九乘法表
package com.bsy;
public class ForDemo4 {
public static void main(String[] args) {
//打印乘法表
//1、先打印第一列
//2、把固定的1再用一个循环包起来
//3、去掉重复项 i <= j
//4、调整样式
for (int j = 1; j <= 9; j++) {
for (int i = 1; i <= j; i++) {
System.out.print(j+"*"+i+"="+(j*i)+"\t");
}
System.out.println();
}
}
}
8.5.1、增强for循环
- Java5引入了一种主要用于数组或者集合的增强型for循环
package com.bsy;
public class ForDemo5 {
public static void main(String[] args) {
int[] numbers = {10,20,30,40,50};
//遍历数组的元素
for (int x:numbers){
System.out.println(x);
}
//等同于:
for (int i = 0; i < 5; i++) {
System.out.println(numbers[i]);
}
}
}
8.6、Break & Continue
- break在任何循环语句的主体部分,均可以用break控制循环的流程。break用于强行退出循环,不执行循环中剩余的语句。(break语句也在switch语句中使用)
package com.bsy;
public class BreakDemo {
public static void main(String[] args) {
int i = 0;
while(i<100){
i++;
System.out.println(i);
if (i==30){
break;
}
}
System.out.println("123");
}
}
- continue语句用在循环体语句体中,用于终止某次循环过程,即跳过循环体中尚未执行的语句,接着进行下一次是否执行循环的判定。
package com.bsy;
public class ContinueDemo {
public static void main(String[] args) {
int i = 0;
while (i<100){
i++;
if ((i%10==0)){
System.out.println();
continue;
}
System.out.print(i);
}
}
}
8.6.1、Label标签
- 关于goto关键字
- goto关键字很早就在程序设计语言上出现。尽管goto仍是Java的一个保留字,但是并未在语言中得到正式使用;Java没有goto。然而在break和continue这两个关键字上,仍然能够看到一些goto的影子,那就是带标签的break和continue、
- “标签”是指后面跟一个冒号的标识符,例如:label:
- 对于Java来说唯一用到标签的地方就是在循环语句之前。而在循环之前设置标签的唯一理由:我们希望在其中嵌套另一个循环,由于break和continue关键字通常只中断当前循环,但若随同标签使用,他们就会终端到存在标签的地方。
package com.bsy;
public class LabelDemo {
public static void main(String[] args) {
//打印101-150之间所有的质数
//指数:大于1的自然数中,除了1和它本身意外不再有其他因数的自然数。
int count = 0;
outer:for (int i=101;i<150l;i++){//设置一个标签outer
for (int j = 2;j<i/2;j++){
if (i % j == 0){
continue outer;//当满足这一个条件之后,从小的循环直接跳到外面的大循环。
}//所以outer标签就是一个定位的作用。
}
System.out.print(i+" ");
}
}
}
9、Java方法
前面我们使用的那些点出来的都是方法,例如System.out.print();就是系统类里面的标准输出对象out的print方法。
- 方法是语句的集合,他们呢在一起执行一个功能。
- 方法是解决一类问题的步骤的有序组合。
- 方法包含于类或者对象中。
- 方法在程序中被创建,在其他地方被调用。
package com.bsy.method;
public class Demo {
public static void main(String[] args) {
int sum = add(1,2);
System.out.println(sum);
}
//加法
public static int add(int a,int b){
return a+b;
}
}
-
设计方法的原则:一个方法就完成一个功能,有利于后期的扩展。
-
Java的方法类似于其他语言的函数,是一段用来完成特定功能的代码片段。
-
方法包含的部分:
- 修饰符:可选,告诉编译器如何调用方法。
- 返回值类型:方法可能会返回值,returnValueType是返回值的数据类型,没有返回值的关键字void。
- 方法名:方法的实际名称。遵循驼峰命名法,先小后大。
- 参数类型:传递值给参数,可选。
- 形式参数:方法被调用时用于接收外界的输入数据。
- 实参:调用方法时实际传给方法的数据。
- 方法体:方法具体的语句,功能等。
修饰符 返回值类型 方法名(参数类型 参数名){
……
方法体
……
return 返回值;
}
9.1、return 0;
在执行到return时则终止方法。意思就是在有返回值的方法中,已经获得返回值了,下面的任何东西已经没有意义了,所以在return下面的代码则不会被执行。
//比大小
public static int max(int num1,int num2){
int result = 0;
if (num1==num2){
System.out.println("num1==num2)");
return 0;
}
if (num1>num2){
result = num1;
}else {
result = num2;
}
return result;
}
9.2、方法调用
对象名.方法名(实参列表);
public static void main(String[] args) {
int max = max(10,20);
System.out.println(max);
}
9.3、方法的重载
在一个类中,可以有多个同名的方法,但形参不同。
-
方法的重载的规则:
- 方法名称必须相同。
- 参数列表必须不同(个数不同、或类型不同、参数排列顺序不同等)。
- 方法的返回值类型可以相同也可以不同。
- 仅仅返回类型不同不足以成为方法的重载。
-
实现理论:
- 方法名称相同时,编译器会根据调用方法大参数个数、参数类型等去逐个匹配,以选择对应的方法发,如果匹配失败,则编译器报错。
package com.bsy.method;
public class Demo3 {
public static void main(String[] args) {
double max = max(10.4,20.5);
System.out.println(max);
}
//比大小
public static double max(double num1,double num2){
int result = 0;
if (num1==num2){
System.out.println("num1==num2)");
return 0;
}
if (num1>num2){
result = (int)num1;
}else {
result = (int) num2;
}
return result;
}
//比大小
public static int max(int num1,int num2){
int result = 0;
if (num1==num2){
System.out.println("num1==num2)");
return 0;
}
if (num1>num2){
result = num1;
}else {
result = num2;
}
return result;
}
}
9.4、命令行传参
有时候你希望运行一个程序时再传递给它消息。这要靠传递命令参数给main()函数实现。
注意:javac后运行class文件目录在src开始,不然提示找不到。
例如:java com.bsy.method.Demo4 This is bsy
9.5、可变参数
不确定给你多少个参数,有事我们也不确定传进来多少个参数,如果为每一种可能都写一个方法进行重载,那么会相当浪费时间。可变参数就是可以接收不确定数量的参数然后进行运算。这里使用数组举例。
- JDK1.5开始,Java支持传递同类型的可变参数给一个方法。
- 在方法声明中,在指定参数类型后加一个省略号(…)
- 一个方法中只能指定一个可变参数,它必须是方法的最后一个参数。任何普通的参数必须在它之前声明。
package com.bsy.method;
public class Demo5 {
public static void main(String[] args) {
//调用可变参数的方法
printMax(34,5,22,3,5,8.7);//传递参数
printMax(new double[]{1,2,3});//传递数组也可以
}
public static void printMax(double... numbers){
if (numbers.length == 0){
System.out.println("No argument passed");
return;
}
double result = numbers[0];
//排序
for (int i = 0; i < numbers.length; i++) {
if (numbers[i] > result){
result = numbers[i];
}
}
System.out.println("The max value is "+result);
}
}
9.6、递归
A方法可以调用B方法,而递归则是可以自己调用自己。
利用递归可以用简单的程序解决一些复杂的问题,大大地减少了程序的代码量。
- 递归结构包含两个部分:
- 递归头:什么时候不调用自身方法。如果没有结束自我调用的判定条件,也就是没有这个头,那么将陷入死循环。
- 递归体:什么时候需要调用自身方法。
package com.bsy.method;
public class Demo6 {
/**
* 阶乘概念:
* 1! 1*1
* 2! 2*1
* 3! 3*2*1
* 5! 5*4*3*2*1
*/
public static void main(String[] args) {
System.out.println(f(5));
}
public static int f(int n){
if (n==1){
return 1;
}else {
return n*f(n-1);
}
}
}
在数值比较小的时候可以使用。Java是栈机制,如果数值过大会占用很多内存。
9.7、数组
- 相同类型数据的有序集合
- 通过下标访问。从0开始。
package com.bsy.array;
public class Demo1 {
public static void main(String[] args) {
//变量类型 变量的名字 = 变量的值;
//数据类型
int[] nums;//1,声明了一个数组,但是没有分配空间
int nunms2[];//跟上面的类型一样,这种是为了让C跟C++程序员更快适应Java
nums = new int[10];//2,创建。定义了数组的长度
int[] nums3 = new int[10];//声明和创建写一块也可以。
//3,给数组中的元素赋值
nums[0] = 1;
nums[1] = 2;
nums[2] = 3;
nums[3] = 4;
nums[4] = 5;
nums[5] = 6;
nums[7] = 8;
nums[8] = 9;
nums[9] = 10;
System.out.println(nums[6]);//如果不赋值则默认值为0
//计算所有元素的和
int sum = 0;
//获取数组的长度:arrays.length
for (int i = 0; i < nums.length; i++) {
sum = sum + nums[i];
}
System.out.println("总和为:"+sum);
}
}
- 数组的4个基本特点:
- 长度是确定的。数组一旦被创建,他的大小是不可以改变的。
- 其元素是相同类型,不允许出现混合类型。
- 数组中的元素是可以是任何数据类型,包括基本类型和引用类型。
- 数组变量是引用类型,数组本身就是对象,,Java中的对象是在堆中,数组对象本身是在堆中的。
9.7.1、内存分析 & 三种初始化
-
Java内存
- 堆:
- 存放new的对象和数组
- 可以被所有线程共享,不会存放别的对象引用
- 栈:
- 存放基本变量类型(会包含这个基本类型的具体数值)
- 引用对象的变量(会存放这个引用在堆里面的具体地址)
- 方法区:
- 可以被所有线程共享
- 包含了所有的class和static变量
三种初始化:
-
静态初始化
-
//创建 + 赋值 int[] a = {1,2,3}//花括号都是代表数组,一旦写好长度是固定的。 Man[] mans = {new Man(1,1),new Man(2,2)};//引用类型,引用了Man类
-
-
动态初始化
-
int[] a = new int[2]//声明数组类型,创建空间。包含默认初始化。 a[0] = 1; a[1] = 2;
-
-
数组的默认初始化
- 数组是引用类型,它的元素相当于类的实例变量,因此数组一经分配空间,其中的每个元素也被按照实例变量同样的方式被隐藏式初始化。
- 堆:
9.7.2、数组边界
下标合法区间:[0,length-1],如果越界就会报错
public static void main(String[] args){
int[] a = new int[2];
System.out.print(a[2]);
}
public static void main(String[] args){
int[] a = {1,2,3,4,5}
for (int i = 0;i <= a.length;i++){//这里注意不能用<=数组的长度是5但是下标最高为length-1也就是4
System.out.print(a[i]);
}
}
便会报错:ArraylndexOutOfBoundsException:数组下标越界异常
- 数组是相同数据类型(数组类型可以为任意类型)的有序集合。
- 数组也是对象。数组的元素相当于对象的成员变量。
- 数组长度的确定的,是不可变的。
9.7.3、数组使用
- 普通的for循环:
package com.bsy.array;
public class ArrayDemo01 {
public static void main(String[] args) {
int[] arrays = {1,2,3,4,5};
//打印全部数组元素
for (int i = 0; i < arrays.length; i++) {
System.out.println(arrays[i]);
}
//计算所有元素的和
int sum = 0;
for (int i = 0; i < arrays.length; i++) {
sum+=arrays[i];
}
System.out.println("sum="+sum);
//查找最大元素
int max = arrays[0];
for (int i = 0; i < arrays.length; i++) {
if (arrays[i] > max){
max = arrays[i];
}
}
System.out.println("max="+max);
}
}
增强for循环(For-Each循环)、数组作为方法参数、数组作返回值:
package com.bsy.array;
public class ArrayDemo02 {
public static void main(String[] args) {
int[] arrays = {1,2,3,4,5};
//快捷键 array.for
for (int array : arrays) {//方便遍历,没有下标
System.out.println(array);
}
int[] reverse = reverse(arrays);
pringArray(reverse);
}
//打印数组元素
public static void pringArray(int[] arrays){
for (int i = 0; i < arrays.length; i++) {
System.out.print(arrays[i]+" ");
}
}
//反转数组
public static int[] reverse(int[] arrays){
int[] result = new int[arrays.length];
//反转的操作
for (int i = 0, j=result.length-1; i< arrays.length; i++,j--) {
result[j] = arrays[i];
}
return result;
}
}
9.7.4、多维数组
数组的数组。
package com.bsy.array;
public class Demo05 {
public static void main(String[] args) {
int[][] array = {{1,2},{2,3},{3,4},{4,5}};
/**
* int[长][宽]
* 拆开就是:
* 1,2 array[0]表示下标为0的数组
* 2,3 array[1]表示下标为1的数组
* 3,4 array[2]
* 4,5 array[3]
*/
System.out.println(array[0]);//直接打印不出来的
ArrayDemo02.pringArray(array[0]);//使用前面写的打印数组元素方法
System.out.println(array[0][0]);//打印第0个数组的第0个元素
System.out.println(array[0][1]);//打印第0个数组的第2个元素
//三维数组即array[][][]三个点来确定一个数
//更多维度跟现实生活不一样,而Java只是一种量化
//遍历出二维数组的全部元素
for (int i = 0; i < array.length; i++) {//array里面有4个数组,长度为4
for (int j = 0; j < array[i].length; j++){//array里面每一个数组的元素
System.out.println(array[i][j]);
}
}
}
}
9.7.5、Arrays类
- 数组工具类java.util.Arrays
- 里面很多方法可以快速使用按Alt+鼠标左键点进去,在IDEA界面左侧下方Structure查看所有方法。
自己多试试,或者看帮助文档。
9.7.6、冒泡排序
package com.bsy.array;
import java.util.Arrays;
public class Demo6 {
public static void main(String[] args) {
/**
* 冒泡排序
* 1、比较数组中,两个相邻的元素,如果第一个数比第二个大,我们就交换他们的位置。
* 2、每一次比较,都会产生一个最大、最小数。
* 3、下一轮就可以少一次排序。
* 4、依次循环,直到结束.
*/
int[] a = {2,6,22,92,76,9,36,12,75,30,68,19,25};
System.out.println(Arrays.toString(sort(a)));
}
public static int[] sort(int[] array){
//临时变量(第三个空杯子)
int temp = 0;
//外层循环,判断要走多少次。
for (int i = 0; i < array.length-1; i++) {
//内层循环,比较两个数,如果第一个数比第二个数大,则交换位置。
for (int j = 0; j < array.length-1-i; j++) {
if (array[j+1] > array[j]){
temp = array[j];
array[j] = array[j+1];
array[j+1] = temp;
}
}
}
return array;
}
}
9.7.7、稀疏数组
原始数组:
0 | 0 | 0 | 22 | 0 | 0 |
---|---|---|---|---|---|
0 | 11 | 0 | 0 | 0 | 0 |
0 | 0 | 0 | -6 | 0 | 0 |
0 | 0 | 0 | 0 | 9 | 0 |
0 | 0 | 0 | 0 | 0 | 0 |
91 | 0 | 0 | 0 | 0 | 0 |
0 | 0 | 28 | 0 | 0 | 0 |
转化为稀疏数组:
行(row) | 列(col) | 值(value) | |
---|---|---|---|
0 | 7 | 6 | 6 |
1 | 0 | 3 | 22 |
2 | 1 | 1 | 11 |
3 | 2 | 3 | -6 |
4 | 3 | 4 | 9 |
5 | 5 | 0 | 91 |
6 | 6 | 2 | 28 |
表中0行 表示这组数据为 7行6列共有6个有效数据。
第1个数据在 第0行的 第3列 值为22。
package com.bsy.array;
public class ArrayDemo08 {
public static void main(String[] args) {
//1、创建一个二维数组 11*11 0:没有棋子,1:黑棋,2:白棋
int[][] array1 = new int[11][11];
array1[1][2] = 1;
array1[2][3] = 2;
//输出原始数组
System.out.println("输出原始数组");
for (int[] ints : array1) {//遍历array1二维数组
for (int anInt : ints) {//遍历数组中每个数组的元素
System.out.print(anInt+"\t");
}
System.out.println();
}
//获取有效值的个数
//转换为稀疏数组保存
int sum = 0;
for (int i = 0; i < array1.length; i++) {
for (int j = 0;j < array1.length;j++){
if (array1[i][j] != 0){
sum++;
}
}
}
System.out.println("有效值个数为:"+sum);
//2、创建一个稀疏数组的数组
int[][] array2 = new int[sum+1][3];//行、列、值。有效个数+1是稀疏数组的表头。所以这里是三行三列。
//这张稀疏数组的表头,也就是声明了这张稀疏数组的表是11行,11列,一共有sum有效数据。
array2[0][0] = 11;//行
array2[0][1] = 11;//列
array2[0][2] = sum;//值
//遍历二维数组,将非零的值,存放稀疏数组中
int count = 0;
for (int i = 0; i < array1.length; i++) {//遍历原始二维数组表
for (int j = 0;j < array1[i].length;j++){//遍历二维数组中每一个元素
if (array1[i][j] != 0){//如果里面的元素不为零
count++;//那么计数+1,第一个数也就出来了
array2[count][0] = i;//存放横坐标
array2[count][1] = j;//存放纵坐标
array2[count][2] = array1[i][j];//存放这个坐标的数值
}
}
}
//输出稀疏数组
System.out.println("稀疏数组");
for (int i = 0; i < array2.length; i++) {
System.out.println(array2[i][0]+"\t"
+array2[i][1]+"\t"
+array2[i][2]+"\t");
}
//还原稀疏数组
//1、读取稀疏数组
int[][] array3 = new int[array2[0][0]][array2[0][1]];
//2、给其中的元素还原它的值
for (int i = 1; i < array2.length; i++) {
array3[array2[i][0]][array2[i][1]] = array2[i][2];
}
//3、打印还原
System.out.println("输出还原的数组");
for (int[] ints : array3) {
for (int anInt : ints) {
System.out.print(anInt+"\t");
}
System.out.println();
}
}
}
10、面向对象编程
-
面向过程思想:
- 步骤清晰简单,第一步做什么,第二部做什么……
- 适合较为简单的问题
-
面向对象思想
- 分类思想模式,解决问题需要哪些分类,对分类进行单独思考。
- 适合复杂的问题,多人协作。
-
对于描述复杂的事物,为了从宏观上把握、从整体上合理分析,我们需要使用面向对象的思路来分析整个系统。从具体到微观操作,仍然需要面面向过程的思路去处理。
-
什么是面向对象
- 面向对象编程OOP(Object-Oriented Programming)
- 面向对象的本质就是:以类的方式组织代码,以对象的组织(封装)数据。
- 抽象
- 三大特性:
- 封装
- 继承
- 多态
- 从知识论的角度考虑是先有对象,后有类。对象:具体的事物。类:抽象概念。
- 从代码运行的角度考虑是先有类,后有对象。类就是对象的模板。
10.1、方法的定义
package com.bsy.oop;
//Demo01类
public class Demo01 {
//main方法
public static void main(String[] args) {
}
/*
修饰符 返回值类型 方法名(……){
//方法体
return 返回值;
}
*/
public String sayHello(){//方法名要见名知意,驼峰命名,先小后大
return "Hello,world";//return 结束方法,返回一个结果,返回可以为空。
}
public int max(int a,int b){
return a>b ? a : b;//【三元运算符】如果a大于b,那么就返回a,否则就返回b
}
}
10.2、方法的调用
10.2.1、静态方法 & 非静态方法
我们先创建一个学生类,里面有静态方法和非静态方法
package com.bsy.oop;
//学生类
public class Student {
//静态方法
public static void say(){
System.out.println("学生说话了");
}
//非静态方法
public void eat(){
System.out.println("学生吃东西了");
}
//static表示跟类一起加载的,类存在了他就跟着存在
public static void aVoid(){
//在这里不能直接调用bVoid,因为它现在还不存在。
//如果aVoid和bVoid都为非静态类 或者都为静态类,那么是可以互相调用的。
}
//非静态类,一开始不存在的,待类被实例化之后才存在
public void bVoid(){
}
}
然后我们要分别去调用两种方法
package com.bsy.oop;
public class Demo02 {
public static void main(String[] args) {
//静态方法 static 的调用
Student.say();
//非静态方法的调用(将对象实例化出来)
Student student = new Student();
//对象类型 对象名 = 对象值;
student.eat();//直接使用对象名调用即可。
}
}
10.2.2、形参和实参
就是形式参数和实际参数
package com.bsy.oop;
public class Demo03 {
public static void main(String[] args) {
Demo03 demo03 = new Demo03();
//实参和形参的类型要一一对应
System.out.println(demo03.add(1,2));//提供的实际参数的类型要符合形参对类型的定义。我们这里是int,所以就不能能写个sort、char之类的。
}
public int add(int a,int b){//形式参数a和b,名字无所谓,只是表示这个参数
return a+b;
}
}
10.2.3、值传递
package com.bsy.oop;
//值传递
public class Demo04 {
public static void main(String[] args) {
int a = 1;
System.out.println(a);
Demo04.change(a);//1 因为a传递进change方法后并没有返回值,又返回主程序了
}
//返回值为空
public static void change(int a){
a = 10;//值传递到这里为10,但没有返回值,相当于经过这个方法但是不产生变化。
}
}
10.2.4、引用传递
package com.bsy.oop;
//引用传递:对象,本质还是值传递
public class Demo05 {
public static void main(String[] args) {
Person person = new Person();
System.out.println(person.name);//null
Demo05.change(person);
System.out.println(person.name);//白三叶
}
public static void change(Person person){
person.name = "白三叶";
}
}
//定义了一个Person类,有一个属性name;
class Person{
String name;
}
10.3、类与对象的关系
- 类是一种抽象的数据类型,是对某一类事物整体的描述、定义,只能代表整体,并不能代表某一个具体的事物,对象才是代表一个具体的事物。
- 例如Person类、Pet类、Car类等。
- 对象是抽象概念的举例实例
- 例如,张三,是人类里面一个具体的实例。张三家里的狗是狗类里的一个具体的实例。
- 能够展现出特点,展现出功能的是具体的实例,而不是一个抽象的概念。
10.3.1、创建与初始化对象
- 使用new关键字创建对象
- 使用new关键字创建对象的时候,除了分配内存空间之外,还会给创建好的对象进行默认初始化,以及对类中构造器的调用。
package com.bsy.oop.Demo01;
//学生类
public class Student {
//属性:字段
String name;//默认初始化:null
int age;//0
//方法
public void study(){
System.out.println(this.name+"在学习");//this代表当前对象,用的是当前对象的东西(下面有总结)
}
}
package com.bsy.oop.Demo01;
import com.bsy.oop.Demo01.Student;
//一个项目应该只存在一个main方法
public class Application {
public static void main(String[] args) {
//使用new关键字创建对象
//类:抽象的,需要实例化。
//类实例化后会返回一个自己的对象
//student对象就是一个Student类具体的实例!
Student xiaoming = new Student();//同一个类可以产生不同的对象
Student xh = new Student();
/*
使用new关键字创建的时候,除了分配内存空间之外,还会给创建好的对象 进行默认的初始化
以及对类中构造器的调用。
*/
xiaoming.name = "小明";
xiaoming.age = 3;
System.out.println(xiaoming.name);
System.out.println(xiaoming.age);
xh.name = "小红";
xh.age = 12;
System.out.println(xh.name);
System.out.println(xh.age);
}
}
面向对象编程的本质就是:以类的方式组织代码,以对象的组织(封装)数据。
10.4、构造器
-
构造器
- 和类名相同
- 没有返回值
-
作用
- new本质就是在调用构造方法
- 初始化对象的值
-
注意点
- 定义了有参构造之后,如果想使用无参构造,就必须显示定义一个无参构造器
-
生成构造器快捷键
- Alt + Insert
- 选择你需要添加的构造器之后,点击“ok”生成有参构造器,点击“Select None”生成无参构造器。
-
this.
-
根据”同名情况下,局部变量的优先级更高”原则,在构造方法执行的过程中,虚拟机会把参数值赋给”参数本身”,而不是赋值给对象的属性。
-
把一个值赋值给对象的一个属性,而不是”再一次”把它赋值给构造方法的参数,就需this.
-
本对象自己的属性
-
String name; public Person(String name){ this.name = name; } //如果不写this.那么赋值的时候就会name属性重新赋值给name本身
-
Demo:
package com.bsy.oop.Demo01;
public class Person {
//一个类即使什么都不写,他会存在一个方法(默认生成的,在java文件中不显示,但是在编译后的class文件中显示)
//显示的定义构造器
String name;
//实例化初始值
public Person(){//无参构造器
}
/*
1、使用new关键字,本质是在调用构造器
2、用来初始化值
*/
//有参构造:一旦定义了有参构造,再调用无参构造,无参构造器就必须显示(代码必须打出来)
public Person(String name){
this.name = name;//this.本对象自己的属性,而不是上面的。
}
//快捷键:alt + insert,选择constructor生成构造器;点击ok生成有参构造器,点击“select none”生成无参构造器
}
package com.bsy.oop.Demo01;
//一个项目应该只存在一个main方法
public class Application {
public static void main(String[] args) {
Person person = new Person("bsy");//如果有值,那么会调用有参构造器(方法的重载)
System.out.println(person.name);
}
}
10.5、创建对象内存分析
栈:存放方法、变量的引用
堆:存放具体的对象。堆里面有一个特殊的区域:方法区,方法区里面有一个静态方法区。
10.6、封装
程序设计追求“高内聚,低耦合”。
-
高内聚:类的内部数据操作细节自己完成,不允许外部干涉。
-
低耦合:仅暴露少量的方法给外部使用。
封装(数据的隐藏):
- 通常应该禁止直接访问一个对象中数据的实际表示,而应通过操作接口来访问。
属性私有,get/set
封装的作用:
1,提高程序的安全性,保护数据
2,隐藏代码实现细节
3,统一接口
4,增加系统可维护性
package com.bsy.demo04;
public class Student {
//private:属性私有
private String name;
private int id;
private char sex;
private int age;
//提供一些可以操作这些属性的方法
//提供一些public的get、set方法。(快捷键Alt + Insert)
//get 获取这个数据
public String getName() {
return name;
}
//set 给这个数据设置值
public void setName(String name) {
this.name = name;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public char getSex() {
return sex;
}
public void setSex(char sex) {
this.sex = sex;
}
public int getAge() {
return age;
}
//对数据的合法性与安全性可以在set中作出限制,例如年龄的限制。
public void setAge(int age) {
if (age>120 || age<0){
this.age = 0;
} else {
this.age = age;
}
}
}
package com.bsy.demo04;
public class Application {
public static void main(String[] args) {
Student student = new Student();//new出对象
student.setName("白三叶");//set放入数据
System.out.println(student.getName());//获取数据
student.setAge(-1);//不合法的年龄,我们设置为0
System.out.println(student.getAge());
}
}
10.7、继承
extends的意思是“扩展”。子类继承父类使用关键字extends来表示。
继承是类跟类之间的关系,除此之外还有依赖,组合,聚合。
//Person 人(作为父类,也叫基类)
public class Person{}
//Student 学生类(作为子类,继承父类,也叫做派生类)
public class Student extends Person{}
//除了继承可以使用父类的方法之外,还可以使用聚合
public class Teacher{
Person person();
}
快捷键:ctrl + H查看继承关系(继承树状图)Java中所有的类,都默认直接或者间接继承object类。
Java中类只有单继承,没有多继承,但是可以间接继承别的类。(接口可以多继承)
私有的private无法被继承。
package com.bsy.oop.demo05;
//在Java中所有的类,都默认直接或者间接继承object类。相当于extends Object,只是不显示。
public class Person {
public void say(){
System.out.println("说了一句话");
}
private int money = 10_0000_0000;//私有的是无法继承的。
//public 公共的,优先级排序
//protected 受保护的
//default 默认,不写修饰符则为默认
//private 私有的,一般属性才是私有的
//私有的属性(钱)不让你直接使用,但是给了你方法可以使用。那就是get、set
public int getMoney() {
return money;
}
public void setMoney(int money) {
this.money = money;
}
}
package com.bsy.oop.demo05;
//子类继承了父类,就会拥有父类的全部方法。
public class Student extends Person{}
package com.bsy.oop.demo05;
public class Ace extends Student{}
package com.bsy.oop.demo05;
public class Application {
public static void main(String[] args) {
Student student = new Student();
student.say();//调用student继承父类Person的方法。
Ace ace = new Ace();
ace.say();//间接继承了Person类。
}
}
10.7.1、super
super注意点:
- super调用父类的构造方法,必须在构造方法的第一个。
- super必须只能出现在子类的方法或者构造方法中!
- super和this不能同时调用构造方法!
super和this:
- this调用本类的对象
- super代表父类对象
- this没有继承也可以使用
- super只能在继承条件下才可以使用
构造方法:
- this();本类的构造
- super();父类的构造
package com.bsy.oop.demo05;
//在Java中所有的类,都默认直接或者间接继承object类。相当于extends Object,只是不显示。
public class Person {
protected String name = "whitClover";
public void print(){
System.out.println("Person");
}
public Person() {
System.out.println("Person无参构造器执行了");
}
//如果父类使用了有参构造器,没有写出无参构造器,那么子类在调用的无参构造器的时候会出错。
//一般父类写出有参构造器,同时还要写出无参构造器,为了避免出现这个问题。
}
package com.bsy.oop.demo05;
//子类继承了父类,就会拥有父类的全部方法。
public class Student extends Person{
private String name = "bsy";
public void print(){
System.out.println("Student");
}
public void test1(String name){
System.out.println(name);//本方法传进来的name 白三叶
System.out.println(this.name);//本类的name bsy
System.out.println(super.name);//父类的name whiteClover
}
public void test(){
print();//Student
this.print();//Student
super.print();//Person
}
public Student() {
//无参构造器这里有一行隐藏代码 super();调用了父类的无参构造器。默认调用无参。
super();//调用父类的构造器,必须在子类构造器的第一行。
System.out.println("Student无参构造器执行了");
}
}
package com.bsy.oop.demo05;
public class Application {
public static void main(String[] args) {
Student student = new Student();
student.test1("白三叶");
student.test();
}
}
10.8、方法重写
前提:需要有继承关系,子类重写父类方法
- 方法名必须相同
- 参数列表必须相同
- 修饰符:范围可以扩大,但不能缩小(public > protected > default > private)
- 抛出的异常:范围,可以被缩小,但不能扩大(ClassNotFoundException --> Exception(大))
子类的方法名和父类必须要一直,方法体不同。
作用:
- 父类的功能子类不一定需要,或者不一定满足。
- 快捷键:Alt + Insert 选择override
package com.bsy.oop.demo05;
//重写都是方法的重写,和属性无关
public class B {
public void test(){
System.out.println("B=>test()");
}
}
package com.bsy.oop.demo05;
public class A extends B{
//Override 重写
@Override//注解:有功能的注释
public void test() {
System.out.println("A=>test()");
}
}
package com.bsy.oop.demo05;
public class Application {
public static void main(String[] args) {
//方法的调用只和左边的类型有关,定义的数据类型有关
A a = new A();
a.test();//A
//父类的引用指向了子类
B b = new A();
b.test();//A
}
}
10.9、多态
即同一方法可以根据发送对象的不同,而采用多种不同的行为方式。
一个对象的实际类型是确定的,但可以指向对象的引用类型有很多。
注意事项:
- 多态是方法的多态,属性没有多态
- 要有继承关系才能转换,不然会出现类型转换异常 ClassCastExecption
存在条件:
- 要有继承关系
- 子类重写父类方法
- 父类引用子类对象 Fater f1 = new Son();
不能实现重写的方法关键字:
- static 属于类,不属于实例
- final 常量
- private 方法
在下方的例子中,运行的run()方法可能是父类的,也可能是子类重写父类的,让程序更加灵活:
package com.bsy.oop.demo06;
public class Person {
public void run(){
System.out.println("person");
}
}
package com.bsy.oop.demo06;
public class Student extends Person{
@Override
public void run() {
System.out.println("student");
}
public void eat(){
System.out.println("eat");
}
}
package com.bsy.oop.demo06;
public class Application {
public static void main(String[] args) {
Student student = new Student();//student能调用自己和父类的方法
Person person = new Student();//person父类,可以指向子类,但是不能调用子类独有的方法
Object obj = new Student();
//对象能执行哪些方法,主要看对象左边的类型,和右边关系不大
((Student) person).eat();//类似于之前数据类型的强制转换,高转低。
student.eat();
}
}
10.9.1、instanceof & 类型转换
instanceof:判断一个对象时什么类型,判断两个类之间是否存在父子关系。
举例:(其中Student跟Teacher都继承Person类)
package com.bsy.oop.demo07;
public class Application {
public static void main(String[] args) {
//Object > String
//Object > Person > Teacher
//Object > Person > Student
Object obj = new Student();
System.out.println(obj instanceof Student);//true//Object是基类不要忘了
System.out.println(obj instanceof Person);//true
System.out.println(obj instanceof Object);//true
System.out.println(obj instanceof Teacher);//false//中间隔了一层,不再有关系
System.out.println(obj instanceof String);//false
System.out.println("=====================");
Person person = new Student();
System.out.println(person instanceof Student);//true
System.out.println(person instanceof Person);//true
System.out.println(person instanceof Object);//true
System.out.println(person instanceof Teacher);//false
//System.out.println(person instanceof String);编译报错
System.out.println("=====================");
Student student = new Student();
System.out.println(student instanceof Student);//true
System.out.println(student instanceof Person);//true
System.out.println(student instanceof Object);//true
//System.out.println(student instanceof Teacher);//跟teacher同级了
//System.out.println(person instanceof String);//八竿子打不着
}
}
类型转换:
package com.bsy.oop.demo07;
public class Application {
public static void main(String[] args) {
/*
类型之间的转换:
类型之间的转换,高转低需要强转,低转高则不需要。
而类的转换可以理解为强转
*/
//高 低
Person person = new Student();
//person.go();person里面没有go方法,是student里面才有
//将person转换为student类型,我们就可以使用student类型的方法了
//Student student = (Student)person;
//student.go();//这样就可以了
//可以将上面两句话写成一句话,类似于强转(光标在person后方按alt+enter)
((Student) person).go();
//子类转换为父类,可能会丢失一些自己的方法
Student student = new Student();
Person person1 = student;
person1.run();//此时的person已经走不了go方法了。
((Student) person1).go();
}
}
总结:
- 父类引用指向子类对象
- 把子类转换为父类,向上转型;
- 把父类转换为子类,向下转型;(强制转换。数据类型强转会丢失精度,类强转会丢失方法)
- 方便方法的调用,减少重复代码,提高代码复用率,更加简洁。
10.10、static
static静态的,可以不通过对象来访问,而是通过类直接访问。就像其他非静态常量变量方法等需要通过new一个对象来访问,而通过static修饰的则不需要。
注意:
-
static关键词修饰的成员变量和方法都属于类,不属于某个对象;
-
普通变量和方法属于某个对象,每个对象都有自己的变量和方法,彼此之间是隔离的;
-
静态方法不能调用非静态的变量和非静态的方法,否则编译时就会报错。
静态变量与实例变量的区别:
- JVM虚拟机只会为静态变量分配一次内存,在加载类的过程中完成对静态变量的内存分配;
- 而实例变量,每创建一个Java实例对象,JVM虚拟机就会为该实例变量分配一次内存;
(售票demo:票数是一定数量的,如果使用非静态,每个对象(售票员)被new出来的时候在内存里也生成了一份,这时候每个售票员都可以卖出票,但不符合现实中票数是一定数量的条件,要解决这个问题,就是将总票数的量设置为静态,因为静态的变量常量等跟类一起加载而且只加载一次,就不会出现每new一个对象JVM就分配新的内存,产生不符合现实的票。)
静态属性:
package com.bsy.oop.demo07;
public class Demo09 {
private static int age;//静态的变量
private double score;//非静态的变量
public static void main(String[] args) {
Demo09 demo09 = new Demo09();
System.out.println(Demo09.age);//对于静态的推荐通过类名去访问
System.out.println(demo09.score);//对于非静态的只能使用对象去访问
System.out.println(demo09.age);//静态变量也可以使用对象去访问,但是不推荐
}
}
静态方法:
package com.bsy.oop.demo07;
public class Demo09 {
private static int age;//静态的变量
private double score;//非静态的变量
public void run(){
go();//非静态方法可以调用静态方法
}
public static void go(){
//静态方法可以调用静态方法(为什么?结合类加载顺序理解)
}
public static void main(String[] args) {
new Demo09().run();//非静态方法只能通过new对象来调用
Demo09.go();//静态方法可以直接用类名调用
go();//在本类中甚至可以不用类名直接调用
}
}
/*
static方法跟类一起加载,所以当调用非静态方法的时候这个方法才被加载,
但这个非静态方法所要调用的静态方法早就跟类一起生成了,所以可以调用。
如果静态方法调用非静态方法,静态方法跟类一起加载的时候,非静态方法还没有生成,
那就会调用一个不存在的方法,就会报错。
*/
代码块:(类加载顺序)
package com.bsy.oop;
import com.bsy.oop.demo07.Person;
public class demo08 {
{//2,其次执行,赋初始值
System.out.println("代码块(匿名代码块,在构造器之前)");
}
static {//1,首先执行,只执行一次
System.out.println("静态代码块(可以用于加载初始的数据,跟类一起加载,只加载一次)");
}
public demo08(){//3,最后执行
System.out.println("构造方法");
}
public static void main(String[] args) {
demo08 demo08 = new demo08();
}
}
静态导入包:
final:
package com.bsy.oop.demo07;
//静态导入包
import static java.lang.Math.random;
import static java.lang.Math.PI;
public final class Test {//使用了final关键字修饰,就不能有子类继承了,相当于断子绝孙了
public static void main(String[] args) {
System.out.println(random());
System.out.println(PI);
}
}
10.11、抽象类
abstract修饰符所修饰的类和方法被称为 抽象类 和 抽象方法。
为了在复杂庞大的项目中更好的细分,做一些特殊功能等。
demo:
package com.bsy.oop.Demo08;
//abstract 抽象类
public abstract class Action {
//约束,有人帮我们实现
//abstract抽象方法,只有方法名字,没有具体的实现
public abstract void doSomething();
}
package com.bsy.oop.Demo08;
//抽象类的所有方法需要继承了他的子类去实现。
//也就是说继承了抽象类的子类,必须实现父类这个抽象类的方法。除非:
//除非这个子类也是抽象类,那就可以让这个子类的子类去实现。(无限套娃)
public class A extends Action{
@Override
public void doSomething() {
}
}
注意点:
- 不能new抽象类,只能靠子类去实现它
- 抽象类中可以写普通方法
- 抽象方法必须在抽象类中
(抽象类也是有构造器的)
10.12、接口 interface
- 普通类:只有具体实现
- 抽象类:具体实现和规范(抽象方法)都有
- 接口:只有规范。(只能干约束,约束和实现分类。面向接口编程)
在大型系统开发中,一般先设计好接口、开发规范,然后找码农去填补。
- 接口是规范,定义了一组规则,定义了什么就要做什么,制定好大家都要遵守。
- 面向对象编程的精髓。
demo:
package com.bsy.oop.Demo9;
//interface 定义关键字。接口都需要有实现类。
public interface UserServices {
//常量 public static final 一般不这样写
int score = 10;
//接口中所有定义的方法都是抽象的。默认加上了public abstract,所以我们直接写方法就行了。
void add();
void delete();
void update();
void query();
}
package com.bsy.oop.Demo9;
public interface TimeService {
void timer();
}
package com.bsy.oop.Demo9;
//类可以实现接口。implements接口。
//实现接口的类,就需要重写接口的方法。
public class UserServicesImpl implements UserServices,TimeService{//利用接口实现多继承
@Override
public void add() {
}
@Override
public void delete() {
}
@Override
public void update() {
}
@Override
public void query() {
}
@Override
public void timer() {
}
}
作用:
- 约束
- 定义一些方法,让不同的人实现。
- 方法都是public abstract
- 常量都是public static final
- 接口不能被实例化,接口没有构造方法
- implement可以实现多个接口
- 必须要重写接口中的方法
11、异常机制
-
异常:Exception
- 包括运行时异常和非运行时异常。应尽量避免异常的发生。
-
错误:Error
- 一般是灾难性的问题。
- 错误不可查,在应用程序控制和处理能力之外
- 尽量为程序创造良好的运行环境避免错误的发生
异常体系结构:
所有的异常都可以在一个异常里面表示
- Java吧异常当作对象来处理,并定义了一个基类java.lang.Throwable作为异常的超类。
- 在Java API中已经定义了许多异常,这些异常类分为两大类:错误Error和Exception
11.1、捕获和抛出异常
package com.bsy.oop.exception;
public class Test {
public static void main(String[] args) {
int a = 1;
int b = 0;
try {//try监控区域
System.out.println(a / b);
} catch (ArithmeticException exception) {//catch 捕获异常类型
System.out.println("程序出现异常,变量b不能为0");
System.exit(0);//手动结束程序
exception.printStackTrace();//打印错误信息
} catch (Exception e){//可以捕获多个异常
System.out.println("Exception");
}finally {//finally可以不用,一般用于资源关闭等善后工作
System.out.println("finally");
}
}
}
捕获多个异常:从小到大。
快捷键:Ctrl + Alt + T
package com.bsy.oop.exception;
public class Test {
public static void main(String[] args) {
try {//如果不适用try、catch捕获异常,遇到这种问题程序就停止运行了。
new Test().test(1,0);
} catch (ArithmeticException e) {
e.printStackTrace();
}
}
public void test(int a,int b) throws ArithmeticException{//方法上抛出以上需要主动捕获
if (b==0){//方法里面用throw,方法名上用throws
throw new ArithmeticException();//主动抛出异常,一般在方法中使用。
}
}
}
11.2、自定义异常
- 处理运行时异常时,合理规避异常的同时辅助try-catch处理。
- 在多重catch块后面,可以加一个catch(Exception)来处理可能遗漏的异常。
- 对于可能出现的异常也可以加上try-catch,处理潜在的异常。
- 出现异常就要尽可能地处理异常,不要总是简单的调用printStackTrace()去打印输出。
- 尽量添加finally语句去释放占用的资源。
package com.bsy.oop.Demo08;
//自定义异常类
public class MyException extends Exception{//继承exception
//传递数字
private int detail;//异常消息
public MyException(int a) {
this.detail = a;
}
//异常的打印信息
@Override
public String toString() {
return "MyException{" +
"detail=" + detail +
'}';
}
}
package com.bsy.oop.Demo08;
public class Test {
//可能会出现异常的方法
static void test(int a) throws MyException {
System.out.println("传递的参数为:"+a);
if (a>10){
throw new MyException(a);//抛出
}
System.out.println("OK");
}
public static void main(String[] args){
try {
test(11);
} catch (MyException e) {
//建议增加处理异常的代码块去处理异常
System.out.println("MyException=>"+e);
}
}
}
扩展与补充
各种各样的内部类
class几乎可以写在任何地方
package com.bsy.oop.Demo10;
public class Outer {
private int id = 133;
public void out(){
System.out.println("这是一个外部类的方法");
}
public class Inner {
public void in(){
System.out.println("这是一个内部类的方法");
}
//获得外部类的私有属性
public void getId(){
System.out.println(id);
}
}
}
//一个Java类中可以有多个class文件,但是只能有一个public class
class A{
public static void main(String[] args) {
}
}
调用:
package com.bsy.oop.Demo10;
public class Application {
public static void main(String[] args) {
Outer outer = new Outer();
Outer.Inner inner = outer.new Inner();//通过外部类来实例化内部类outer.new Inner();
inner.getId();
}
}
局部内部类:
package com.bsy.oop.Demo10;
public class Outer {
//局部内部类
public void method(){
class Inner{
public void in(){
}
}
}
}
匿名对象的使用:
package com.bsy.oop.Demo10;
public class Test {
public static void main(String[] args) {
//没有名字的初始化类,不用将实例保存到变量中
new Tomato().say();
}
}
class Tomato{
public void say(){
System.out.println("咿呀~");
}
}
匿名内部接口:
package com.bsy.oop.Demo10;
public class Test1 {
public static void main(String[] args) {
UserService userService = new UserService() {
@Override
public void hello() {
}
};
}
}
interface UserService{
void hello();
}