1、注释Comments

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
//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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
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 是有限 离散 舍入误差 大约 接近但不等于的。不要用浮点型进行作比较。因为↓

1
2
3
float d1 = 123123123F;
float d2 = d1 +1;
System.out.println(d1 == d2);//ture

如果要使用很大的数值作比较可以使用一个现有的类

BigDecimal 数学工具类

2.1.2 强制转换

所有的字符本质是数字

1
2
3
4
5
6
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)

1
2
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 布尔值扩展
1
2
3
4
boolean flag = ture;
if (flag==ture){}
if (flag){}//默认等于ture,可以不写=ture
//Less is More! 代码要精简易读,更少就是更多。

2.2、引用数据类型

类、字符串、接口、数组、枚举等可以引用的数据类型都是引用数据类型

1
String name = "xiaoming";//这就是一个引用数据类型

3、类型转换

Java是强类型语言,运算时要进行类型转换

从上方得知,每种数据类型所能包含数的大小是不同的,例如你用一个32位的int大盒子装小的16位short盒子肯定可以直接装下。但是用小盒子装大盒子不是说不能装,而是会丢失一部分大盒子里的数据(精度丢失见下方)。

1
2
3
低 -------------------------------------------------→高

byte -> short -> char -> int -> long -> float -> double

3.1、强制类型转换

上面说到盒子的例子,在Java里低转高需要进行强制转换。

1
2
3
4
//高到低
int i = 128;
byte b = (byte)i;//byte最大127此时会发生内存溢出
//强制转换格式: (类型)变量名

3.2、自动类型转换

1
2
3
//低到高
int i = 128;
double b = i;//128.0

demo:

1
2
3
4
5
6
7
//根据上方的从低到高的顺序举例
byte b = 10;
short s = b;
int i = s;
long lon = i;
float f = lon;
double d = f;

注意:

​ 1,不能对布尔值进行转换。

​ 2,不能吧对象类型转换为不相干类型。

​ 3,在把高容量转换到低容量的时候,要使用强制转换。

​ 3,转换的时候可能存在内存溢出,或者精度问题。

1
2
3
//精度问题
System.out.println((int)23.7);//23
System.out.println((int)-45.89f);//-45
1
2
3
4
5
6
7
8
9
10
11
//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);
}

扩展:

1
2
3
4
5
6
7
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、变量&常量

变量,可以改变的向量存储

变量:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
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);
}
}

常量:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
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、算术运算符

+(加),-(减),*(乘),/(除),%(求余),++(自增),–(自减)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
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、自增自减:
1
2
3
4
5
6
7
8
9
10
11
12
// ++  --
//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、赋值运算符

=(等于),+=(自加一次等于),-=(自减一次等于),*=(自乘一次等于),/=(自除一次等于),+(字符串连接符)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
//等号就是赋值运算符:将等号右边的表达式结果赋值给等候左边的变量
//赋值运算符需要考虑类型的关系
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(不等于)

1
2
3
4
int i = 10;
int j = 20;
System.out.println(i > j);//false
System.out.println(i < j);//ture

5.4、逻辑运算符

&(按位与),&&(短路与),|(按位或),||(短路或),!(非,即取反)

5.4.1、与&&或||非!
1
2
3
4
5
6
7
8
9
10
11
12
13
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、位运算(都是基于二进制来计算):

位运算符:& | ^ ~ >> << >>>

&(按位与),|(按位或),^(异或运算),<<(左移运算符),>>(右移运算符),>>>(无符号运算符),~(非、取反运算符)

**效率极高!!!**因为是底层,可以做一些很巧妙的计算。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
/*
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、条件(三元)运算符?:

三个元素参与运算的运算符

1
2
3
4
5
// x ? y : z
//如果x==ture,则结果为y,否则结果为z
int score = 80;
//如果成绩大于 60 则为及格,给一个String类型的变量type赋值为“及格”
String type = score < 60 ? "不及格" : "及格";

5.6、扩展赋值运算符:

+= -= *= /=

1
2
3
4
5
6
int a = 10;
int b = 20;

a += b;//a = a+b
a -= b;//a = a-b
……
5.6.1、字符串连接符 +
1
2
3
4
5
6
int a = 10;
int b = 20;
//字符串连接 + 两侧只要一方出现String类型,就变成字符串拼接
System.out.pintln(""+a+b);//1020
System.out.pintln(a+b+"");//30
//程序是自上而下自左而右运算的,当字符串在前面则识别为字符串拼接,当运算在前面则先进行运算。
5.6.2、优先级()

跟数学算数一样,优先算一部分。

1
2
System.out.println(1 + 2 * 3);//7
System.out.println((1 + 2) * 3);//9

5.7、Math 数学工具类

很多特殊的运算都需要到它,例如幂运算。


6、包机制

包的本质就是文件夹

**包名:**域名倒置。例如com.baidu

**导包:**import

**导入包下所有类:*通配符

1
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字符集编码)

使用IDEA生成doc文档

8、Java流程控制

Java基础的第二部分,前面就像是游戏的新手教程,现在可以开始玩了。

8.1、Scanner对象

获取用户的输入

8.1.1、next()

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
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()

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
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语句:

1
2
3
4
5
6
7
8
9
10
11
12
13
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()的多种用法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
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、举例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
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语句来表示。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
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语句都将跳过执行。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
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嵌套结构
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
```

#### 8.3.2switch多选择结构

switch case语句判断一个变量与一系列值中某一个值是否相等,每个值成为一个分支。

* switch语句中的变量类型可以是:
* byte
* short
* int
* char
* String
* 同时case标签必须字符串或字面量

```JAVA
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:

1
2
3
4
5
6
7
8
9
10
11
12
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:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
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先执行一次再进行判断,即使不满足循环条件也会至少循环一次。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
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的对比:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
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则循环终止。
1
2
//死循环
for(;;){}

Demo1:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
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:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
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:九九乘法表

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
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循环

    for(声明语句 : 表达式)
    {
    //代码句子
    }

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
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语句中使用)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
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语句用在循环体语句体中,用于终止某次循环过程,即跳过循环体中尚未执行的语句,接着进行下一次是否执行循环的判定。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
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关键字通常只中断当前循环,但若随同标签使用,他们就会终端到存在标签的地方。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
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方法。

  • 方法是语句的集合,他们呢在一起执行一个功能。
    • 方法是解决一类问题的步骤的有序组合。
    • 方法包含于类或者对象中。
    • 方法在程序中被创建,在其他地方被调用。
1
2
3
4
5
6
7
8
9
10
11
12
13
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。
    • 方法名:方法的实际名称。遵循驼峰命名法,先小后大。
    • 参数类型:传递值给参数,可选。
      • 形式参数:方法被调用时用于接收外界的输入数据。
      • 实参:调用方法时实际传给方法的数据。
    • 方法体:方法具体的语句,功能等。
1
2
3
4
5
6
修饰符 返回值类型 方法名(参数类型 参数名){
……
方法体
……
return 返回值;
}

9.1、return 0;

在执行到return时则终止方法。意思就是在有返回值的方法中,已经获得返回值了,下面的任何东西已经没有意义了,所以在return下面的代码则不会被执行。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
//比大小
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、方法调用

对象名.方法名(实参列表);

1
2
3
4
public static void main(String[] args) {
int max = max(10,20);
System.out.println(max);
}

9.3、方法的重载

在一个类中,可以有多个同名的方法,但形参不同。

  • 方法的重载的规则:

    • 方法名称必须相同。
    • 参数列表必须不同(个数不同、或类型不同、参数排列顺序不同等)。
    • 方法的返回值类型可以相同也可以不同。
    • 仅仅返回类型不同不足以成为方法的重载。
  • 实现理论:

    • 方法名称相同时,编译器会根据调用方法大参数个数、参数类型等去逐个匹配,以选择对应的方法发,如果匹配失败,则编译器报错。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
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支持传递同类型的可变参数给一个方法。
  • 在方法声明中,在指定参数类型后加一个省略号(…)
  • 一个方法中只能指定一个可变参数,它必须是方法的最后一个参数。任何普通的参数必须在它之前声明。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
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方法,而递归则是可以自己调用自己。

利用递归可以用简单的程序解决一些复杂的问题,大大地减少了程序的代码量。

  • 递归结构包含两个部分:
    • 递归头:什么时候不调用自身方法。如果没有结束自我调用的判定条件,也就是没有这个头,那么将陷入死循环。
    • 递归体:什么时候需要调用自身方法。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
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开始。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
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类
        
        1
        2
        3
        4
        5
        6
        7

        - 动态初始化

        - ```java
        int[] a = new int[2]//声明数组类型,创建空间。包含默认初始化。
        a[0] = 1;
        a[1] = 2;
    • 数组的默认初始化

      • 数组是引用类型,它的元素相当于类的实例变量,因此数组一经分配空间,其中的每个元素也被按照实例变量同样的方式被隐藏式初始化。

9.7.2、数组边界

下标合法区间:[0,length-1],如果越界就会报错

1
2
3
4
public static void main(String[] args){
int[] a = new int[2];
System.out.print(a[2]);
}
1
2
3
4
5
6
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循环:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
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循环)、数组作为方法参数、数组作返回值:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
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、多维数组

数组的数组。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
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、冒泡排序

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
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。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
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、方法的定义

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
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、静态方法 & 非静态方法

我们先创建一个学生类,里面有静态方法和非静态方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
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(){

}
}

然后我们要分别去调用两种方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
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、形参和实参

就是形式参数和实际参数

1
2
3
4
5
6
7
8
9
10
11
12
13
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、值传递

1
2
3
4
5
6
7
8
9
10
11
12
13
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、引用传递

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
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关键字创建对象的时候,除了分配内存空间之外,还会给创建好的对象进行默认初始化,以及对类中构造器的调用。
1
2
3
4
5
6
7
8
9
10
11
12
package com.bsy.oop.Demo01;
//学生类
public class Student {
//属性:字段
String name;//默认初始化:null
int age;//0

//方法
public void study(){
System.out.println(this.name+"在学习");//this代表当前对象,用的是当前对象的东西(下面有总结)
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
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本身
      
      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      20
      21
      22
      23
      24
      25
      26

      Demo:

      ```java
      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”生成无参构造器

      }
1
2
3
4
5
6
7
8
9
10
11
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、创建对象内存分析

栈:存放方法、变量的引用

堆:存放具体的对象。堆里面有一个特殊的区域:方法区,方法区里面有一个静态方法区。

![堆栈方法区内存分析图](E:\Creative Space[NEW 2023]\JavaWeb\Note\堆栈方法区内存分析图.png)

10.6、封装

程序设计追求“高内聚,低耦合”。

  • 高内聚:类的内部数据操作细节自己完成,不允许外部干涉。

  • 低耦合:仅暴露少量的方法给外部使用。

封装(数据的隐藏):

  • 通常应该禁止直接访问一个对象中数据的实际表示,而应通过操作接口来访问。

属性私有,get/set


封装的作用:

1,提高程序的安全性,保护数据

2,隐藏代码实现细节

3,统一接口

4,增加系统可维护性

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
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;
}
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
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来表示。

继承是类跟类之间的关系,除此之外还有依赖,组合,聚合。

1
2
//Person 人(作为父类,也叫基类)
public class Person{}
1
2
//Student 学生类(作为子类,继承父类,也叫做派生类)
public class Student extends Person{}
1
2
3
4
//除了继承可以使用父类的方法之外,还可以使用聚合
public class Teacher{
Person person();
}

快捷键:ctrl + H查看继承关系(继承树状图)Java中所有的类,都默认直接或者间接继承object类。

Java中类只有单继承,没有多继承,但是可以间接继承别的类。(接口可以多继承)

私有的private无法被继承。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
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;
}
}
1
2
3
package com.bsy.oop.demo05;
//子类继承了父类,就会拥有父类的全部方法。
public class Student extends Person{}
1
2
3
package com.bsy.oop.demo05;

public class Ace extends Student{}
1
2
3
4
5
6
7
8
9
10
11
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();父类的构造
1
2
3
4
5
6
7
8
9
10
11
12
13
14
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无参构造器执行了");
}
//如果父类使用了有参构造器,没有写出无参构造器,那么子类在调用的无参构造器的时候会出错。
//一般父类写出有参构造器,同时还要写出无参构造器,为了避免出现这个问题。
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
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无参构造器执行了");
}
}
1
2
3
4
5
6
7
8
9
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
1
2
3
4
5
6
7
package com.bsy.oop.demo05;
//重写都是方法的重写,和属性无关
public class B {
public void test(){
System.out.println("B=>test()");
}
}
1
2
3
4
5
6
7
8
9
package com.bsy.oop.demo05;

public class A extends B{
//Override 重写
@Override//注解:有功能的注释
public void test() {
System.out.println("A=>test()");
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
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()方法可能是父类的,也可能是子类重写父类的,让程序更加灵活:

1
2
3
4
5
6
7
package com.bsy.oop.demo06;

public class Person {
public void run(){
System.out.println("person");
}
}
1
2
3
4
5
6
7
8
9
10
11
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");
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
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类)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
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);//八竿子打不着
}
}

类型转换:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
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就分配新的内存,产生不符合现实的票。)

静态属性:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
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);//静态变量也可以使用对象去访问,但是不推荐
}
}

静态方法:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
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方法跟类一起加载,所以当调用非静态方法的时候这个方法才被加载,
但这个非静态方法所要调用的静态方法早就跟类一起生成了,所以可以调用。

如果静态方法调用非静态方法,静态方法跟类一起加载的时候,非静态方法还没有生成,
那就会调用一个不存在的方法,就会报错。
*/

代码块:(类加载顺序)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
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:

1
2
3
4
5
6
7
8
9
10
11
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:

1
2
3
4
5
6
7
8
package com.bsy.oop.Demo08;
//abstract 抽象类
public abstract class Action {
//约束,有人帮我们实现
//abstract抽象方法,只有方法名字,没有具体的实现
public abstract void doSomething();

}
1
2
3
4
5
6
7
8
9
10
package com.bsy.oop.Demo08;
//抽象类的所有方法需要继承了他的子类去实现。
//也就是说继承了抽象类的子类,必须实现父类这个抽象类的方法。除非:
//除非这个子类也是抽象类,那就可以让这个子类的子类去实现。(无限套娃)
public class A extends Action{
@Override
public void doSomething() {

}
}

注意点:

  • 不能new抽象类,只能靠子类去实现它
  • 抽象类中可以写普通方法
  • 抽象方法必须在抽象类中

(抽象类也是有构造器的)

10.12、接口 interface

  • 普通类:只有具体实现
  • 抽象类:具体实现和规范(抽象方法)都有
  • 接口:只有规范。(只能干约束,约束和实现分类。面向接口编程)

在大型系统开发中,一般先设计好接口、开发规范,然后找码农去填补。

  • 接口是规范,定义了一组规则,定义了什么就要做什么,制定好大家都要遵守。
  • 面向对象编程的精髓。

demo:

1
2
3
4
5
6
7
8
9
10
11
12
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();
}
1
2
3
4
5
package com.bsy.oop.Demo9;

public interface TimeService {
void timer();
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
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

![Java异常的体系结构图](E:\Creative Space[NEW 2023]\JavaWeb\Note\Java异常的体系结构图.png)

11.1、捕获和抛出异常

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
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语句去释放占用的资源。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
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 +
'}';
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
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几乎可以写在任何地方

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
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) {

}
}

调用:

1
2
3
4
5
6
7
8
9
10
11
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();

}
}

局部内部类:

1
2
3
4
5
6
7
8
9
10
11
12
package com.bsy.oop.Demo10;

public class Outer {
//局部内部类
public void method(){
class Inner{
public void in(){

}
}
}
}

匿名对象的使用:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
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("咿呀~");
}
}

匿名内部接口:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
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();
}