Java 基础学习记录

Java 基础

DAY1

1、关于进制的运算

2、关于存储单元

3、关于CMD的基本命令

4、JRE与JDK

JRE:是Java程序的运行时环境,包括JVM和运行时所需的核心类库。

JDK:是Java程序开发工具包,包含JRE和开发人员使用的工具。

5、Java环境变量

变量名:JAVA_HOME

变量值:C:\Java\jdk-10.0.0(JAVA路径)

变量名:Path

变量值:%JAVA_HOME%\bin;(在前面添加,注意加上;间隔)

6、程序开发步骤

7、HelloWorld

package Day1;

public class HelloWord {
    public static void main(String[] args){
        System.out.println("Hello World!");
    }
}

8、标识符

  • 标识符:是指在程序中,我们自己定义内容。比如类的名字、方法的名字和变量的名字等都是标识符

  • 命名规则:硬性要求

    • 标识符可以包含26个英文字母(区分大小写)0-9数字$(美元符号)_(下划线)
    • 标识符不能以数字开头
    • 标识符不能是关键字
  • 命名规范:软性建议

    • 类名规范:首字母大写,后面每个单词首字母大写(大驼峰式)
    • 变量名规范:首字母小写,后面每个单词首字母大写(小驼峰式)
    • 方法名规范:同变量名

9、常量

类型含义数据举例
整数常量所有的整数0,1,567,9
小数常量所有的小数0.0,-0.1,2.55
字符常量单引号引起来,只能写一个字符,必须有内容(可以为空格)‘a’,’ ',‘好’
字符串常量双引号引起来,可以写多个字符,也可以不写“A”,“Hello”,“您好”,""
布尔常量只有一个值true,false
空常量只有一个值null

10、数据类型

数据类型分类

Java的数据类型分为两大类:

  • 基本数据类型:包括整数浮点数字符布尔
  • 引用数据类型:包括数组接口
基本数据类型

四类八种基本数据类型:

数据类型关键字内存占用取值范围
字节型byte1个字节-128~127
短整型short2个字节-32768~32767
整型int(默认)4个字节-231~231-1
长整型long8个字节-263~263-1
单精度浮点数float4个字节1.4013E-45~3.4028E+38
双精度浮点数double(默认)8个字节4.9E-324~1.7977E+308
字符型char2个字节0-65535
布尔类型boolean1个字节true、false
注意事项:
  1. 字符串不是基本类型,而是引用类型
  2. 浮点型可能只是一个近似值,并非精确的值
  3. 数据范围与字节数不一定相关,例如float数据范围比long更加广泛,但是float是4字节,long是8字节
  4. 浮点数当中默认类型是doube,如果一定要使用float类型,需要加上一个后缀F。大小写都可以,推荐使用大写字母后缀
  5. 整数当中默认类型是int,如果一定要使用long类型,需要加上一个后缀L。大小写都可以,推荐使用大写字母后缀

11、变量

变量:程序运行期间,内容可以发生改变的量

创建一个变量并且使用的格式:

数据类型 变量名称; //创建了一个变量
变量名称 = 数据值; //赋值,将右边的数据值,赋值交给左边的变量

一步到位的格式:

数据类型 变量名称 = 数据值; //在创建一个变量的同时,立刻放入指定的数据值

注意事项:

  1. 如果创建多个变量,那么变量之间的名称不可以重复
  2. 对于float和long类型来说,字母后缀F和L不要丢掉
  3. 如果使用byte或者short类型的变量,那么右侧的数据值不能超过左侧类型的范围
  4. 没有进行赋值的变量,不能直接使用,一定要赋值之后,才能使用
  5. 变量使用不能超过作用域的范围
  6. 可以通过一个语句来创建多个变量,但是一般情况不推荐这么写

DAY2

1、数据类型转换

当数据类型不一样时,将会发生数据类型转换

自动类型转换(隐式)
  1. 特点:代码不需要进行特殊处理,自动完成
  2. 规则:数据范围从小到大
System.out.println(1024);   // 这就是一个整数,默认就是int类型
System.out.println(3.14);   // 这就是一个浮点数,默认就是double类型

// 左边是long类型,右边是默认的int类型,左右不一样
// 一个等号代表赋值,将左侧的int常量,交给左侧的long变量进行存储
// int --> long,符合了数据范围从小到大的要求
// 这一行代码发生了自动类型转换
long num1 = 100;
System.out.println(num1);   // 100

// 左边是double类型,右边是float类型,左右不一样
// float --> double,符合从小到大的规则
// 也发生了自动类型转换
double num2 = 2.5F;
System.out.println(num2);   //2.5

// 左边是float类型,右边是long类型,左右不一样
// long --> float,范围是float更大一些,符合从小到大的规则
// 也发生了自动类型转换
float num3 = 30L;
System.out.println(num3);   //30.0
强制类型转换(显式)
  1. 特点:代码需要进行特殊的格式处理,不能自动完成

  2. 格式:范围小的类型 范围小的变量名 = (范围小的类型) 原本范围大的数据

    注意事项:

    1. 强制类型转换一般不推荐使用,因为有可能发生精度损失、数据溢出
    2. byte/short/char这三种类型都可以发生数学运算,例如加法“+”
    3. byte/short/char这三种类型在运算的时候,都会被首先提升成为int类型,然后再计算
    4. boolean类型不能发生数据类型转换
    // 左边是int类型,右边是long类型,不一样
    // long --> int,不是从小到大
    // 不能发生自动类型转换
    // 格式:范围小的类型  范围小的变量名  =  (范围小的类型)  原本范围大的数据
    int num = (int) 100L;
    System.out.println(num);
    
    // long强制转换成为int类型
    int num2 = (int) 6000000000L;
    System.out.println(num2);   // 结果:1705032704
    
    // double --> int,强制类型转换
    int num3 = (int) 3.99;
    System.out.println(num3);   // 这并不是四舍五入,所有的小数位都会被舍弃
    
    char zifu1 = 'A';   // 这是一个字符型变量,里面是大写字母A
    System.out.println(zifu1 + 1);  // 66,也就是大写字母A被当做65进行处理
    // 计算机的底层会用一个数字(二进制)来代表字符A,就是65
    // 一旦char类型进行数学运算,那么字符就会按照一定的规则翻译成为一个数字
    
    byte num4 = 40; // 注意!右侧的数值大小不能超过左侧的类型范围
    byte num5 = 50;
    // byte + byte --> int + int --> int
    int result1 = num4 + num5;
    System.out.println(result1);    //90
    
    short num6 = 60;
    // byte + short --> int + int --> int
    // int强制转换为short:注意不需保证逻辑上真实大小本来就没有超过short范围,否则会发生数据溢出
    short result2 = (short) (num4 + num6);
    System.out.println(result2);    //100
    

2、ASCII编码表

数字和字符的对照关系表(编码表):

ASCII码表:American Standard Code for Information Interchange,美国信息交换标准代码。
Unicode码表:万国码。也是数字和符号的对照关系,开头0-127部分和ASCII完全一样,但是从128开始包含有更多字符

48 - ‘0’
65 - ‘A’
97 - ‘a’

char zifu1 = '1';
        System.out.println(zifu1 + 0);      //49

        char zifu2 = 'A';   //其实底层保存的是65数字

        char zifu3 = 'c';
        //左侧是int类型,右边是char类型
        //char --> int,确实是从小到大
        //发生了自动类型转换
        int num = zifu3;
        System.out.println(num);    //99

        char zifu4 = '中';   //正确写法
        System.out.println(zifu4 + 0);  //20013

3、算术运算符

运算符:进行特定操作的符号。例如: +
表达式:用运算符连起来的式子叫做表达式。例如:20+5、a+b

四则运算:
加: +
减: -
乘: *
除: /

取模(取余数): %

首先计算得到表达式的结果,然后再打印输出这个结果。
除法: 被除数 / 除数 = 商 … 余数

对于一个整数的表达式来说,除法用的是整数,整数除以整数,结果仍然是整数。只看商,不看余数
只有对于整数的除法来说,取模运算符才有余数的意义。

注意事项:
1、一旦运算当中有不同类型的数据,那么结果将会是数据类型范围大的那种。

// 两个常量之间可以进行数学运算
System.out.println(20+30);

// 两个变量之间也可以进行数学运算
int a = 20;
int b = 30;
System.out.println(a - b);  // -10

// 变量和常量之间可以混合使用
System.out.println(a * 10); // 200

int x = 10;
int y = 3;

int result1 = x / y;
System.out.println(result1);    // 3

int result2 = x % y;
System.out.println(result2);    // 余数,模,1

// int + double --> double + double --> double
double result3 = x + 2.5;
System.out.println(result3);    // 12.5
四则运算当中的加号“+”有常见的三种用法:

1、对于数值来说,那就是加法。
2、对于字符char类型来说,在计算之前,char会被提升成为int,然后再计算。
char类型字符,和int类型数字,之间的对照关系表:ASCII、Unicode
3、对于字符串String(首字母大写,并不是关键字)来说,加号代表字符串连接。
任何数据类型和字符串进行连接的时候,结果都会变成字符串

// 字符串类型的变量基本使用
// 数据类型  变量名称  =  数据值;
String str1 = "Hello";
System.out.println(str1);   // Hello

System.out.println("Hello" + "World");  //HelloWorld

String str2 = "Java";
// String + int --> String
System.out.println(str2 + 20);  //Java20

// 优先级问题
// String + int + int
// String       + int
// String
System.out.println(str2 + 20 + 30); //Java2030

System.out.println(str2 + (20 + 30));   //Java50

4、自增自减运算符

自增运算符: ++
自减运算符: –

基本定义:让一个变量涨一个数字1,或者让一个变量降一个数字1
使用格式:写在变量名称之前,或者写在变量名称之后。例如: ++num,也可以num++
使用方法:
1.单独使用:不和其他任何操作混合,自己独立成为一个步骤。
2.混合使用:和其他操作混合,例如与赋值混合,或者与打印操作混合等。
使用区别:
1.在单独使用的时候,前++和后++没有任何区别。也就是:++num;和num++;是完全一样的。
2.在混合的时候,有重大区别
A.如果是前++,那么变量立刻马上+1,然后拿着结果进行使用。 先加后用
B.如果是后++,那么首先使用变量本来的数值,然后在让变量+1. 先用后加

注意事项:
只有变量才能使用自增、自减运算符。常量不可以发生改变,所有不能用。

int num1 = 10;
System.out.println(num1);   // 10
++num1; // 单独使用,前++
System.out.println(num1);   // 11
num1++; // 单独使用,后++
System.out.println(num1);   // 12

System.out.println("====================");

// 与打印操作混合的时候
int num2 = 20;
// 混合使用,先++,变量立刻马上变成21,然后打印结果21
System.out.println(++num2); // 21
System.out.println(num2);   // 21

System.out.println("====================");

int num3 = 30;
// 混合使用,后++,首先使用变量本来的30,然后在让变量+1得到31
System.out.println(num3++); // 30
System.out.println(num3);   // 31

System.out.println("====================");

int num4 = 40;
// 和赋值操作混合
int result1 = --num4;   // 混合使用,前--,变量立刻马上-1变成39,然后将结果39交给result1变量
System.out.println(result1);    // 39
System.out.println(num4);       // 39

System.out.println("====================");

int num5 = 50;
// 混合使用,后--,首先把本来的数字50交给result2,然后自己再-1变成49
int result2 = num5--;
System.out.println(result2);    // 50
System.out.println(num5);       // 49

System.out.println("====================");

int x = 10;
int y = 20;
// 11 + 20 = 31
int result3 = ++x + y--;
System.out.println(result3);    //31
System.out.println(x);  // 11
System.out.println(y);  // 19

// 30++;    // 错误写法! 常量不可以使用++或者--

5、赋值运算符

赋值运算符分为:

基本赋值运算符: 就是一个等号“=”,代表将右侧的数据交给左侧的变量。
int a = 30;

复合赋值运算符:

    +=      a += 1      相当于     a = a + 1
    -=      b -= 1      相当于     b = b - 1
    *=      c *= 1      相当于     c = c * 1
    /=      d /= 1      相当于     d = d / 1
    %=      e %= 1      相当于     e = e % 1

注意事项:
1、只有变量才能使用赋值运算符,常量不能进行赋值。
2、复合赋值运算符其中隐含了一个强制类型转换。

int a = 10;
// 按照公式进行翻译: a = a + 5
a += 5;
System.out.println(a);  // 15

int x = 10;
// x = x % 3;
x %= 3;
System.out.println(x);  // 1

byte num = 30;
// num = num + 5;
// num = byte + int
// num = int + int
// num = int
// num = (byte) int
num += 5;
System.out.println(num);    //35

6、比较运算符

比较运算符:
大于: >
小于: <
大于等于: >=
小于等于: <=
相等: == [两个等号连写才是相等,一个等号代表的是赋值]
不相等: !=

注意事项:
1、比较运算符的结果一定是一个boolean值,成立就是true,不成立就是false。
2、如果进行多次判断,不能连这些。
数学当中的写法,例如: 1 < x < 3
程序当中不予许这种写法。

System.out.println(10 > 5);         // true
int num1 = 10;
int num2 = 12;
System.out.println(num1 < num2);    // true
System.out.println(num2 >= 100);    // false
System.out.println(num2 <= 100);    // true
System.out.println(num2 <= 12);     // true
System.out.println("==================");

System.out.println(10 == 10);       // true
System.out.println(20 != 25);       // true
System.out.println(20 != 20);       // false

7、逻辑运算符

与(并且) && 全部都是true,才是true;否则就是false
或(或者) || 还少一个true,就是true;全部是false,才是false
非(取反) ! 本来是true,变成false;本来是false,变成true

与"&&",或"||",具有短路效果:如果根据左边已经可以判断得到最终结果,那么右边的代码将不在执行,从而节省一定的性能

注意事项:
1、逻辑运算符只能用于boolean值。
2、与、或需要左右各自有一个boolean值,但是取反只要有唯一的一个boolean即可。
3、与、或两种运算符,如果有多个条件,可以连续写。
两个条件: 条件A && 条件B
多个条件: 条件A && 条件B && 条件C

TIPS:
对于1 < x < 3的情况,应该拆成两个部分,然后使用与运算符连接起来:
int x = 2;
1 < x && x < 3

System.out.println(true && false);   // false
// true && true --> true
System.out.println(3 < 4 && 10 > 5);    // true

System.out.println("================");

System.out.println(true || false);  // true
System.out.println(true || true);  // true
System.out.println(false || false);  // false

System.out.println("================");

System.out.println(true);   // true
System.out.println(!true);  // false

System.out.println("================");

int a = 10;
// false && ...
System.out.println(3 > 4 && ++a < 100); // false
System.out.println(a);  //10

System.out.println("================");

int b = 20;
// true || ...
System.out.println(3 < 4 || ++b < 100); // true
System.out.println(b);  // 20

8、三元运算符

一元运算符:只需要一个数据就可以进行操作的运算符。例如:取反!、自增++、自减–
二元运算符:需要两个数据才可以进行操作的运算符。例如:加法+、赋值=
三元运算符:需要三个数据才可以进行操作的运算符。

格式:
数据类型 变量名称 = 条件判断 ? 表达式A : 表达式B;

流程:
首先判断条件是否成立:
如果成立为true,那么将表达式A的值赋值给左侧的变量;
如果不成立为false,那么将表达式B的值赋值给左侧的变量;
二者选其一

注意事项:
1、必须同时保证表达式A和表达式B都符合左侧数据类型的要求。
2、三元运算符的结果必须被使用。

public static void main(String[] args) {
    int a = 10;
    int b = 20;

    // 数据类型  变量名称  =  条件判断  ?  表达式A  :  表达式B;
    // 潘丹a > b是否成立,如果成立将a的值赋值给max;如果不成立将b的值赋值给max。二者选其一
    int max = a > b ? a : b;    // 最大值的变量
    System.out.println("最大值:" + max);   // 20

    // int result = 3 > 4 ? 2.5 : 10;   // 错误写法!

    System.out.println(a > b ? a : b);  // 正确写法!

    // a > b ? a : b;   // 错误写法!
}

9、方法定义与调用

定义一个方法的格式:
public static void 方法名称() {
方法体
}

方法名称的命名规则和变量一样,使用小驼峰规则(首字母小写,后面单词的首字母大写)。
方法体:也就是大括号当中可以包含任意条语句。

注意事项:
1、方法定义的先后顺序无所谓。
2、方法的定义不能产生嵌套包含关系。
3、方法定义好了之后,不会自动执行。如果想要执行,一定要进行方法的调用

如何调用方法,格式:

方法名称();

public static void main(String[] args) {
    farmer();   // 调用农民的方法
    seller();   // 调用小商贩的方法
    cook();     // 调用厨子的方法
    me();       // 调用自己s的方法
}

// 我
public static void me() {
    System.out.println("吃");
}

// 厨子
public static void cook() {
    System.out.println("洗菜");
    System.out.println("切菜");
    System.out.println("炒菜");
    System.out.println("装盘");
}

// 小商贩
public static void seller() {
    System.out.println("运输到农贸市场");
    System.out.println("抬高价格");
    System.out.println("吆喝");
    System.out.println("卖给厨子");
}

// 农民
public static void farmer() {
    System.out.println("播种");
    System.out.println("浇水");
    System.out.println("施肥");
    System.out.println("除虫");
    System.out.println("收割");
    System.out.println("卖给小商贩");
}

10、编译器的两点优化

1、自动添加隐含类型

对于byte/short/char三种类型来说,如果右侧赋值的数值没有超过范围,
那么javac编译器将会自动隐含的为我们补上一个(byte)(short)(char)

1、如果没有超过左侧的范围,编译器补上强转。
2、如果右侧超过了左侧范围,那么直接编译器报错。

public static void main(String[] args) {
    // 右侧确实时一个int数字,但是没有超过左侧的范围,就是正确的。
    // int --> byte,不是自动类型转换
    byte num1 = /*(byte)*/ 30;  // 右侧没有超过左侧的范围
    System.out.println(num1);   // 30

    // byte num2 = 128;     // 右侧超过了左侧的范围

    // int --> char,没有超过左侧的范围
    // 编译器将会自动补上一个隐含的(char)
    char zifu = /*(char)*/ 65;
    System.out.println(zifu);   // A
}
2、常量优化

在给变量进行赋值的时候,如果右侧的表达式当中全都是常量,没有任何变量,
那么编译器javac将会直接将若干个常量表达式计算得到结果。
short result = 5 + 8; // 等号右边全都是常量,没有任何变量参与运算
编译之后,得到的.class字节码文件当中相当于直接就是
short result = 12;
右侧的常量结果数值,没有超过左侧范围,所以正确。

这称为“编译器的常量优化”。

但是注意:一旦表达式当中有变量参与,那么就不能进行这种优化了。

public static void main(String[] args) {
    short num1 = 10;    // 正确写法,右侧没有超过左侧的范围,

    short a = 5;
    short b = 8;
    // short + short --> int + int --> int
    // short result = a + b;    // 错误写法!左侧需要是int类型

    // 右侧不用变量,而时采用常量,而且只有两个常量,没有别人
    short result = 5 + 8;
    System.out.println(result);

    // short result2 = 5 + a + 8;  // 含有变量即出错
}

DAY3

1、ifelse语句

标准的if-else语句

public static void main(String[] args) {
    int num = 666;

    if (num % 2 == 0) {     // 如果除以2能够余数为0,说明时偶数
        System.out.println("偶数");
    } else {
        System.out.println("奇数");
    }
}

2、ifelseifelse语句

x和y的关系满足如下:
如果x >= 3,那么y = 2x + 1;
如果-1 < x < 3,那么y = 2x;
如果x <= -1,那么y = 2x - 1;

public static void main(String[] args) {
    int x = -10;
    int y;
    if (x >= 3) {
        y = 2 * x + 1;
    } else if (-1 < x && x < 3) {
        y = 2 * x;
    } else {
        y = 2 * x - 1;
    }
    System.out.println("结果是:" + y);
}

3、ifelse练习

public static void main(String[] args) {
    int score = 98;
    if (score >= 90 && score <= 100) {
        System.out.println("优秀");
    } else if (score >= 70 && score < 90) {
        System.out.println("良好");
    } else if (score >= 60 && score < 70) {
        System.out.println("及格");
    } else if (score >= 0 && score < 60) {
        System.out.println("不及格");
    } else {    // 单独处理边界之外的不合理情况
        System.out.println("分数错误");
    }
}

4、使用if语句替换三元运算符

使用三元运算符和标准的if-else语句分别实现:取两个数字当中的最大值

public static void main(String[] args) {
    int a = 105;
    int b = 20;

    // 首先使用三元运算符
    // int max = a > b ? a : b

    // 使用if语句
    int max;
    if (a > b) {
        max = a;
    } else {
        max = b;
    }
    System.out.println("最大值:" + max);
}

5、switch

switch语句使用的注意事项:

1、多个case后面的数值不可以重复。

2、switch后面小括号当中只能时下列数据类型:
基本数据类型: byte/short/char/int
引用数据类型: String字符串、enum枚举

3、switch语句格式可以很灵活: 前后顺序可以颠倒,而且break语句还可以省略
“匹配哪一个case就从哪一个位置向下执行,知道遇到lebreak或者整体结束为止。”

public static void main(String[] args) {
    int num = 1;

    switch (num) {
        case 1:
            System.out.println("星期一");
            break;
        case 2:
            System.out.println("星期二");
            break;
        case 3:
            System.out.println("星期三");
            break;
        case 4:
            System.out.println("星期四");
            break;
        case 5:
            System.out.println("星期五");
            break;
        case 6:
            System.out.println("星期六");
            break;
        case 7:
            System.out.println("星期七");
            break;
            default:
                System.out.println("数据不合理");
                break;  // 最后一个break语句可以省略,但是强烈推荐不要省略
    }
}

6、循环结构

循环结构的基本组成部分,一般可以分成四部分:

1、初始化语句:在循环开始最初执行,而且只能做唯一一次。

2、条件判断:如果成立,则循环继续;如果不成立,则循环退出。

3、循环体:重复要做的事情内容,若干行语句。

4、步行语句:每次循环之后都要进行的扫尾工作,每次循环结束之后都要执行一次。

7、 求出1-100之间的偶数和

题目: 求出1-100之间的偶数和。

思路:
1、既然范围已经确定了是1到100之间,那么我就从1、2、3……一直到100那么多数字一个一个检查。
2、总共有100个数字,并非所有数字都有用。必须要是偶数才能用,判断(if语句)偶数: num % 2 == 0
3、需要一个变量,用来进行累加操作。如同一个存钱罐

public static void main(String[] args) {
    int sum = 0;    // 用来累加的存钱罐

    for (int i = 1; i <= 100; i++) {
        if (i % 2 == 0) {   // 如果时偶数
            sum += i;
        }
    }

    System.out.println("1-100之间的偶数和:" + sum);
}

8、三种循环的区别

1、如果条件判断从来没有满足过,那么for循环和while循环将会执行0次,但是do-while循环会执行最少一次。
2、for循环的变量在小括号当中定义,只有循环内部才可以使用。while循环和do-while循环初始化语句本来就在外面,所以出来循环之后还可以继续使用。

public static void main(String[] args) {
    for (int i = 1; i < 0; i++) {
        System.out.println("Hello");
    }
    // System.out.println(i);  // 这一行时错误写法!因为变量i定义在for循环下括号内,只有for循环自己才能用。
    System.out.println("===============");

    int i = 1;
    do {
        System.out.println("World");
        i++;
    } while (i < 0);
    // 现在已经超出了do-while循环的范围,我们仍然可以使用变量i
    System.out.println(i);  // 2
}

9、break

break关键字的用法有常见的两种:
1、可以用在switch语句当中,一旦执行,整个switch语句立刻结束。
2、还可以用在循环语句当中,一旦执行,整个循环语句立刻结束。打断循环。

关于循环的选择,有一个小建议:
凡是次数确定的场景多用for循环;否则多用while循环。

public static void main(String[] args) {
    for (int i = 1; i <= 10; i++) {
        // 如果希望从第4次开始,后续全都不要了,就要打断循环
        if (i == 4) {   // 如果当前是第4次
            break;  // 那么就打断整个循环
        }
        System.out.println("Hello" + i);
    }
}

10、continue

另一种循环控制语句时continue关键字。
一旦执行,立刻跳过当前次循环剩余内容,马上开始下一次循环。

public static void main(String[] args) {
    for (int i = 1; i <= 10; i++) {
        if (i == 4) {   // 如果当前是第4层
            continue;   // 那么跳过当前次循环,马上开始下一次(第5层)
        }
        System.out.println(i + "层到了。");
    }
}

11、死循环

永远停不下来的循环,叫做死循环。

死循环的标准格式:

while (true) {
    循环体
}
public static void main(String[] args) {
    while (true) {
        System.out.println("Hello");
    }
}

12、嵌套循环

题目:显示时间小时分钟秒

public static void main(String[] args) {
    for (int hour = 0; hour < 24; hour++) { // 外层控制小时
        for (int minute = 0; minute < 60; minute++) {   // 内置控制小时之内的分钟
            for (int second = 0; second < 60; second++){    // 内置控制分钟之内的秒
                System.out.println(hour + "点" + minute + "分" + second + "秒");
            }
        }
    }
}

DAY4

1、IDEA

Integrated Development Environment,IDE,集成开发环境

开发Java程序的步骤:
1、编写代码
2、启动cmd
3、调用javac编译
4、调用java运行

集成开发环境,是一种专门用来提高Java开发效率的软件。

免费的IDE当中:Eclipse

收费的IDE当中:IntelliJ IDEA

免费+收费所有的IDE当中:全世界用得最多的就是IntelliJ IDEA

psvm
public static void main(String[] args) {
    
}
sout
System.out.println();
常用设置

File→Settings

字体设置

Editor→Font

快捷键设置

数据库

Keymap→Tool Windows→Database Ctrl+8

代码补全

Main menu→Code→Completion→Basic Alt+/

代码模板
TemplateIntelliJ IDEA
Define a main methodpsvm
Iterate over an arrayitar
Iterate over a collectionitco
Iterate over a listitli
Iterate over an iterable using foreach syntaxiter
Print to System.outsout
Print to System.errserr
Define a static fieldpsf

2、项目结构

Create New Project

New Module

New Package

3、IDEA常用快捷键

快捷键功能
Alt+Enter导入包,自动修正代码
Ctrl+Y删除光标所在行
Ctrl+D复制光标所在行的内容,插入光标位置下面
Ctrl+Alt+L格式化代码
Ctrl+/单行注释
Ctrl+Shift+/选中代码注释,多行注释,再按取消注释
Alt+Ins自动生成代码,toString,get,set等方法
Alt+Shift+上下箭头移动当前代码行
shift + F6选中修改对象

4、复习一下嵌套循环

public static void main(String[] args) {
    for (int i = 0; i < 5; i++) {
        for (int j = 0; j < 20; j++) {
            System.out.print("*");
        }
        System.out.println();
    }
}

5、方法的定义与调用

方法其实就是若干语句的功能集合。

方法好比是一个工厂。
蒙牛工厂 原料: 奶牛、饲料、水
产出物: 奶制品

钢铁工厂 原料:铁矿石、煤炭
产出物:钢铁建材

参数(原料): 就是进入方法的数据。
返回值(产出物): 就是从方法中出来的数据。

定义方法的完整格式:
修饰符 返回值类型 方法名称(参数类型 参数名称,……){
方法体
return 返回值;
}

修饰符:现阶段的固定写法,public static
返回值类型:也就是方法最终产生的数据结果是什么类型
方法名称:方法的名字,规则和变量一样,小驼峰
参数类型:进入方法的数据是什么类型
参数名称:进入方法的数据对应的变量名称
PS:参数如果有多个,使用逗号进行分隔
方法体:方法需要做的事情,若干行代码
return:两个作用,第一停止当前方法,第二将后面的返回值还给调用处
返回值:也就是方法执行后最终产生的数据结果

注意:return后面的“返回值”,必须和方法名称前面的“返回值类型”,保持对应。

定义一个两个int数字相加的方法。三要素:
返回值类型:int
方法名称:sum
参数列表:int a, int b

方法的三种调用格式。
1、单独调用:方法名称(参数);
2、打印调用:System.out.println(方法名称(参数));
3、赋值调用:数据类型 变量名称 = 方法名称(参数);

注意:此前学习的方法,返回值类型固定写为void,这种方法只能够单独调用,不能进行打印调用或者赋值调用。

public static void main(String[] args) {
    // 单独调用
    sum(10,20);
    System.out.println("===========");

    // 打印调用
    System.out.println(sum(10,20));     // 30
    System.out.println("===========");

    // 赋值调用
    int number = sum(15,25);
    System.out.println("变量的值为:" + number);
}

public static int sum(int a, int b) {
    System.out.println("方法已执行");
    int result = a + b;
    return result;
}

6、有参与无参

有参数:小括号当中有内容,当一个方法需要一些数据条件,才能完成任务的时候就是有参数。
例如两个数字相加,必须知道两个数字是多少,才能相加。

无参数:小括号当中留空。一个方法不需要任何数据条件,自己就能独立完成任务,就是无参数。
例如定义一个方法,打印固定10次HelloWorld。

public static void main(String[] args) {
    method1(10,20);
    System.out.println("=================");
    method2();
}

// 两个数字相乘,做乘法,必须知道两个数字各自是多少,否则无法进行计算
// 有参数
public static void method1(int a, int b) {
    int result = a * b;
    System.out.println("结果是:" + result);
}

// 例如打印输出固定10次文本字符串
public static void method2() {
    for (int i = 0; i < 10; i++) {
        System.out.println("Hello,World!" + i);
    }
}

7、练习题1

题目要求:定义一个方法,用来求出两个数字之和。(你帮我算,算完之后把结果告诉我。)
题目变形:定义一个方法,用来求出两个数字之和。(你来计算,算完之后你自己负责显示结果,不用告诉我。)

注意事项:
对于有返回值的方法,可以使用单独调用、打印调用或者赋值调用。
但是对于无返回值的方法,只能使用单独调用,不能使用打印调用或者赋值调用。

public static void main(String[] args) {
        // 我是main方法,我来调用你
        // 我调用你,你来帮我计算一下,算完之后,把结果告诉我的num变量
        int num = getSum(10,20);
        System.out.println("返回值是:" + num);
        System.out.println("========================");

        printSum(100,200);
        System.out.println("========================");

        System.out.println(getSum(2,3));    // 正确写法
        getSum(3,5);    // 正确写法,但是返回值没有用到
        System.out.println("========================");

        // 对于void没有返回值的方法,只能单独,不能打印或者赋值
//        System.out.println(printSum(2,3);); // 错误写法!
//        System.out.println(void);

//        int num2 = printSum(10,20); // 错误写法!
//        int num3 = void;
//        void num4 = void;
        
    }

    // 我是一个方法,我负责两个数字相加。
    // 我有返回值int,谁调用我,我就把计算结果告诉谁
    public static int getSum(int a, int b) {
        int result = a + b;
        return result;
    }

    // 我是一个方法,我负责两个数字相加。
    // 我没有返回值,不会把结果告诉任何人,而是我自己进行打印输出
    public static void printSum(int a, int b) {
        int result = a + b;
        System.out.println("结果是:" + result);
    }

8、练习题2

题目要求:
定义一个方法,用来判断两个数字是否相同。

public static void main(String[] args) {
        System.out.println(isSame(10,20));
        System.out.println(isSame(20,20));
    }

    /*
    三要素:
    返回值类型: boolean
    方法名称: isSame
    参数列表: int a, int b
     */
    public static boolean isSame(int a, int b) {
        // 方法一
//        boolean same;
//        if (a == b) {
//            same = true;
//        } else {
//            same = false;
//        }

        // 方法二
//        boolean same = a == b ? true : false;

        // 方法三
//        boolean same = a == b;

//        return same;

        return a == b;
    }

9、练习题3

题目要求:
定义一个方法,用来求出1-100之间所有数字的和值。

public static void main(String[] args) {
    System.out.println("结果是:" + getSum());
}

/*
三要素:
返回值: 有返回值,计算结果时一个int数字
方法名称: getSum
参数列表: 数据范围已经确定,是固定的,所以不需要告诉我任何条件,不需要参数
 */

public static int getSum() {
    int sum = 0;
    for (int i = 1; i <= 100; i++) {
        sum += i;
    }
    return sum;
}

10、练习题4

题目要求:
定义一个方法,从来打印制定次数的HelloWord。

public static void main(String[] args) {
    printCount(10);
}

/*
三要素
返回值类型: 只是进行一大堆打印操作而已,没有计算,也没有结果要告诉调用处
方法名称: printCount
参数列表: 到底要打印多少次?必须告诉我,否则我不知道多少次,没法打印。次数:int
 */
public static void printCount(int num) {
    for (int i = 0; i < num; i++) {
        System.out.println("Hello, World!" + (i+1));
    }
}

11、使用方法的注意事项

使用方法的时候,注意事项:

1、方法应该定义在类当中,但是不能在方法当中再定义方法。
2、方法定义的前后顺序无所谓。
3、方法定义之后不会执行,如果希望执行,一定要调用:单独调用、打印调用、赋值调用。
4、如果方法有返回值,那么必须写上“return 返回值;”,不能没有。
5、return后面的返回值数据,必须和方法的返回值类型,对应起来。
6、对于一个void没有返回值的方法,不能写return后面的返回值,只能写return自己。
7、对于方法当中最后一行的return可以省略不写。
8、一个方法当中可以有多个return语句,但是必须保证同时只有一个会被执行到,两个return不能连写。

public static int method1() {
        return 10;
    }

    public static void method2() {
//        return 10;  // 错误写法!方法没有返回值,return后面就不能写返回值。
        return; // 没有返回值,只是结束方法的执行而已。
    }

    public static void method3() {
        System.out.println("AAA");
        System.out.println("BBB");
//        return; // 最后一行的return可以省略不写。
    }

    public static int getMax(int a, int b) {
//        int max;
//        if (a > b) {
//            max = a;
//        } else {
//            max = b;
//        }
//        return max;

        if (a > b) {
            return a;
        } else {
            return b;
        }
    }

12、方法的重载

对于功能类似的方法来说,因为参数列表不一样,却需要记住那么多不同的方法名称,太麻烦。

方法的重载(Overload),多个方法的名称一样,但是参数列表不一样。
好处:只需要记住唯一一个方法名称,就可以实现类似的多个功能。

方法重载与下列因素相关:
1、参数个数不同
2、参数类型不同
3、参数的多类型顺序不同

方法重载与下列因素无关:
1、与参数的名称无关
2、与方法的返回值类型无关

public static void main(String[] args) {
        System.out.println(sum(10,20));      // 30  两个参数的方法
        System.out.println(sum(10,20,30));     // 60    三个参数的方法
        System.out.println(sum(10,20,30,40));   // 100  四个参数的方法
//        System.out.println(sum(10,20,30,40,50));    // 找不到任何方法来匹配,错误!
    }

    // 参数的多类型顺序不同
    public static int sum(int a, double b) {
        return (int) (a + b);
    }
    public static int sum(double a, int b) {
        return (int) (a + b);
    }

    public static int sum(int a, int b) {
        return a + b;
    }

    // 错误写法!与方法的返回值类型无关
//    public static double sum(int a, int b) {
//        return a + b;
//    }

    // 错误写法!与参数的名称无关
//    public static int sum(int x, int y) {
//        return x + y;
//    }

    // 参数类型不同
    public static int sum(double a, double b) {
        return (int) (a + b);
    }

    public static int sum(int a, int b, int c) {
        return a + b + c;
    }

    public static int sum(int a, int b, int c, int d) {
        return a + b + c + d;
    }

13、重载练习一

题目要求:
比较两个数据是否相等。
参数类型分别为两个byte类型,两个short类型,两个int类型,两个long类型,
并在main方法中进行测试。

public static void main(String[] args) {
    byte a = 10;
    byte b = 20;
    System.out.println(isSame(a,b));

    System.out.println(isSame((short) 20, (short) 20));

    System.out.println(isSame(11,12));

    System.out.println(isSame(10L,10L));
}

public static boolean isSame(byte a, byte b) {
    System.out.print("两个byte值是否相同:");
    boolean same;
    if (a == b) {
        same = true;
    } else {
        same = false;
    }
    return same;
}

public static boolean isSame(short a, short b) {
    System.out.print("两个short值是否相同:");
    boolean same = a == b ? true : false;
    return same;
}

public static boolean isSame(int a, int b) {
    System.out.print("两个int值是否相同:");
    return a == b;
}

public static boolean isSame(long a, long b) {
    System.out.print("两个long值是否相同:");
    if (a == b) {
        return true;
    } else {
        return false;
    }
}

14、重载练习二

判断哪些方法时重载关系

public static void open(){}     // 正确重载
public static void open(int a){}    // 正确重载
static void open(int a,int b){}     // 代码错误:与最后一个冲突
public static void open(double a,int b){}   // 正确重载
public static void open(int a,double b){}   // 代码错误:与下一个冲突
public void open(int i,double d){}      // 代码错误:与上一个冲突
public static void OPEN(){}     // 代码正确不会报错,但是并不是有效重载
public static void open(int i,int j){}  // 代码错误,与第三个冲突

15、重载练习三

byte short int long float double char boolean
String
在调用输出语句的时候,println方法其实就是进行了多种数据类型的重载方式。

public static void main(String[] args) {
    myPrint(100);
    myPrint("Hello");
}

public static void myPrint(byte num) {
    System.out.println(num);
}

public static void myPrint(short num) {
    System.out.println(num);
}

public static void myPrint(int num) {
    System.out.println(num);
}

public static void myPrint(long num) {
    System.out.println(num);
}

public static void myPrint(float num) {
    System.out.println(num);
}

public static void myPrint(double num) {
    System.out.println(num);
}

public static void myPrint(char zifu) {
    System.out.println(zifu);
}

public static void myPrint(boolean is) {
    System.out.println(is);
}

public static void myPrint(String str) {
    System.out.println(str);
}

DAY5

1、数组的概念

数组的概念:时一种容器,可以同时存放多个数据值。

数组的特点:
1、数组是一种引用数据类型
2、数组当中的多个数据,类型必须统一
3、数组的长度在程序运行期间不可改变

数组的初始化:
在内存当中创建一个数组,并且向其中赋予一些默认值。

两个常见的初始化方式:
1、动态初始化(指定长度)
2、静态初始化(指定内容)

动态初始化数组的格式:
数据类型[] 数组名称 = new 数据类型[数组长度];

解析含义:
左侧数据类型:也就是数组当中保存的数据,全都是统一的数据类型
左侧的中括号:代表我是一个数组
左侧数组名称:给数组取一个名字
右侧的new:代表创建数组的动作
右侧数据类型:必须和左边的数据类型保持一致
右侧中括号的长度:也就是数组当中,到底可以保存多少个数据,是一个int数字

public static void main(String[] args) {
    // 创建一个数组,里面可以存放300个int数据
    // 格式:数数据类型[] 数组名称 = new 数据类型[数组长度];
    int[] arrayA = new int[300];

    // 创建一个数组,能存放10个double类型的数据
    double[] arrayB = new double[10];

    // 创建一个数组,能存放5个字符串
    String[] arrayC = new String[5];
}

2、动态初始化与静态初始化

动态初始化(指定长度):在创建数组的时候,直接指定数组当中的数据元素个数。
静态初始化(指定内容):在创建数组的时候,不直接指定数据个数多少,而是直接将具体的数据内容进行指定。

静态初始化基本格式:
数据类型[] 数组名称 = new 数据类型[] {元素1,元素2, … }

注意事项:
虽然静态初始化没有直接告诉长度,但是根据大括号里面的元素具体内容,也可以自动推算出来长度。

public static void main(String[] args) {
    // 直接创建一个数组,里面装的全都是int数字,具体为:5、15、25
    int[] arrayA = new int[] { 5, 15, 25 };

    // 创建一个数组,用来装字符串:"Hello"、"World"、"Java"
    String[] arrayB = new String[] { "Hello", "World", "Java" };
}

3、静态初始化(省略格式)

使用静态初始化数组的时候,格式可以省略一下。

标准格式:
数据类型[] 数组名称 = new 数据类型[] {元素1,元素2, … };

省略格式:
数据类型[] 数组名称 = {元素1,元素2, … };

注意事项:
1、静态初始化灭有直接指定长度,但是仍然会自动推算得到长度。
2、静态初始化标准格式可以拆分称为两个步骤。
3、动态初始化也可以拆分成为两个步骤。
4、静态初始化一旦使用省略格式,就不能拆分成为两个步骤了。

使用建议:
如果不确定数组当中的具体内容,用动态初始化;否则,已经确定了具体的内容,用静态初始化。

public static void main(String[] args) {
        // 省略格式的静态初始化
        int[] arrayA = { 10, 20 ,30 };

        // 静态初始化的标准格式,可以拆分成为两个步骤
        int[] arrayB;
        arrayB = new int[] { 11, 21, 31 };

        // 动态初始化也可以拆分成为两个步骤
        int[] arrayC;
        arrayC = new int[5];

        // 静态初始化的省略格式,就不能拆分成为两个步骤。
//        int[] arrayD;
//        arrayD = { 10, 20, 30 }
    }

4、访问数组元素(获取)

直接打印数组名称,得到的时数组对应的:内存地址哈希值。
二进制:01
十进制:0123456789
16进制:012356789abcdef

访问数组元素的格式:数组名称[索引值]
索引值:就是一个int数字,代表数组当中元素的编号。
【注意】索引值cong0开始,一直到“数组的长度-1”为止、

public static void main(String[] args) {
    // 静态初始化的省略格式
    int[] array = { 10, 20, 30 };

    System.out.println(array);  // [I@5e2de80c  内存地址

    // 直接打印数组当中的元素
    System.out.println(array[0]);   // 10
    System.out.println(array[1]);   // 20
    System.out.println(array[2]);   // 30
    System.out.println("==================");

    // 也可以将数组当中的某一个单个元素,赋值交给变量
    int num = array[1];
    System.out.println(num);    // 20
}

5、访问数组元素(赋值)

使用动态初始化数组的时候,其中的元素将会自动拥有一个默认值。规则如下:
如果是整数类型,那么默认为0;
如果是浮点类型,那么默认为0.0;
如果是字符类型,那么默认为’\u0000’;
如果是布尔类型,那么默认为false;
如果是引用类型,那么默认为null。

注意事项:
静态初始化其实也有默认值的过程,只不过系统自动马上将默认值替换成了大括号当中的具体数值。

public static void main(String[] args) {
    // 动态初始化一个数组
    int[] array = new int[3];

    System.out.println(array);  // 内存地址值
    System.out.println(array[0]);   // 0
    System.out.println(array[1]);   // 0
    System.out.println(array[2]);   // 0
    System.out.println("====================");

    // 将数据123赋值交给数组array当中的1号元素
    array[1] = 123;
    System.out.println(array[0]);   // 0
    System.out.println(array[1]);   // 123
    System.out.println(array[2]);   // 0
}

6、内存的划分

Java的内存需要划分成为5个部分:
1、栈(Stack):存放的都是方法中的局部变量。方法的运行一定要在栈当中运行
局部变量:方法的参数,或是方法{}内部的变量
作用域:一旦超出作用域,立刻从栈内存当中消失。
2、堆(Hrap):凡是new出来的东西,都在堆当中。
堆内存里面的东西都有一个地址值:16进制
堆内存里面的数据,都有默认值。规则:
如果是整数 默认为0
如果是浮点数 默认为0.0
如果是字符 默认为’\u0000’
如果是布尔 默认为false
如果是引用类型 默认为null
3、方法区(Method Area):存储.class相关信息,包括方法的信息。
4、本地方法栈(Native Method Stack):与操作系统相关。
5、寄存器(pc Register):与CPU相关。

7、一个数组的内存图

public static void main(String[] args) {
    int[] array = new int[3];   // 动态初始化
    System.out.println(array);  // 地址值
    System.out.println(array[0]);   // 0
    System.out.println(array[1]);   // 0
    System.out.println(array[2]);   // 0
    System.out.println("=================");

    // 改变数组当中元素的内容
    array[1] = 10;
    array[2] = 20;
    System.out.println(array);  // 地址值
    System.out.println(array[0]);   // 0
    System.out.println(array[1]);   // 10
    System.out.println(array[2]);   // 20
}

8、两个数组的内存图

public static void main(String[] args) {
    int[] arrayA = new int[3];   // 动态初始化
    System.out.println(arrayA);  // 地址值
    System.out.println(arrayA[0]);   // 0
    System.out.println(arrayA[1]);   // 0
    System.out.println(arrayA[2]);   // 0
    System.out.println("=================");

    arrayA[1] = 10;
    arrayA[2] = 20;
    System.out.println(arrayA);  // 地址值
    System.out.println(arrayA[0]);   // 0
    System.out.println(arrayA[1]);   // 10
    System.out.println(arrayA[2]);   // 20
    System.out.println("=================");

    int[] arrayB = new int[3];   // 动态初始化
    System.out.println(arrayB);  // 地址值
    System.out.println(arrayB[0]);   // 0
    System.out.println(arrayB[1]);   // 0
    System.out.println(arrayB[2]);   // 0
    System.out.println("=================");

    arrayB[1] = 100;
    arrayB[2] = 200;
    System.out.println(arrayB);  // 地址值
    System.out.println(arrayB[0]);   // 0
    System.out.println(arrayB[1]);   // 100
    System.out.println(arrayB[2]);   // 200
}

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-a0yljPnC-1590994988917)(http://ww1.sinaimg.cn/large/dcaa95eely1fwq8j0hk18j20la0d7wg0.jpg)]

9、两个数组指向同一个地址值的内存图

public static void main(String[] args) {
    int[] arrayA = new int[3];   // 动态初始化
    System.out.println(arrayA);  // 地址值
    System.out.println(arrayA[0]);   // 0
    System.out.println(arrayA[1]);   // 0
    System.out.println(arrayA[2]);   // 0
    System.out.println("=================");

    arrayA[1] = 10;
    arrayA[2] = 20;
    System.out.println(arrayA);  // 地址值
    System.out.println(arrayA[0]);   // 0
    System.out.println(arrayA[1]);   // 10
    System.out.println(arrayA[2]);   // 20
    System.out.println("=================");

    // 将arrayA数组的地址值赋值给arrayB数组
    int[] arrayB = arrayA;
    System.out.println(arrayB);  // 地址值
    System.out.println(arrayB[0]);   // 0
    System.out.println(arrayB[1]);   // 10
    System.out.println(arrayB[2]);   // 20
    System.out.println("=================");

    arrayB[1] = 100;
    arrayB[2] = 200;
    System.out.println(arrayB);  // 地址值
    System.out.println(arrayB[0]);   // 0
    System.out.println(arrayB[1]);   // 100
    System.out.println(arrayB[2]);   // 200
}

10、数组索引越界异常

数组的索引编号从0开始,一直到“数组的长度-1”为止。

如果访问数组元素的时候,索引编号并不存在,那么将会发生
数组索引越界异常
ArrayIndexOutOfBoundsException

原因:索引编号写错了。
解决:修改成为存在的正确索引编号。

public static void main(String[] args) {
        int[] array = { 15, 25, 35 };

        System.out.println(array[0]);   // 15
        System.out.println(array[1]);   // 25
        System.out.println(array[2]);   // 35

        // 错误写法
        // 并不存在3号元素,所以发生异常
//        System.out.println(array[3]);
    }

11、空指针异常

所有的引用类型变量,都可以赋值为一个null值。但是代表其中什么都没有。

数组必须进行new初始化才能使用其中的元素。
如果只是赋值了一个null,没有进行new创建,
那么将会发生:
空指针异常 NullPointerException

原因:忘了new
解决:加上new

public static void main(String[] args) {
    int[] array = null;
    array = new int[3];
    System.out.println(array[0]);
}

12、获取数组的长度

如何获取数组的长度,格式:

数组名称.length

这将会得到一个int数字,代表数组的长度。

数组一旦创建,程序运行期间,长度不可改变。

public static void main(String[] args) {
    int[] arrayA = new int[3];

    int[] arrayB = { 10, 20, 30, 40, 50, 60, 70, 80, 90, 100 };
    int len = arrayB.length;
    System.out.println("arrayB数组的长度是:" + len);
    System.out.println("========================");

    int[] arrayC = new int[3];
    System.out.println(arrayC.length);  // 3
    arrayC = new int[5];
    System.out.println(arrayC.length);  // 5
}

13、数组遍历输出

遍历数组,说的就是对数组当中的每一个元素进行逐一、挨个处理。默认的处理方式就是打印输出。

public static void main(String[] args) {
    int[] array = { 10, 20, 30 };

    // 首先使用原始方式
    System.out.println(array[0]);   // 10
    System.out.println(array[1]);   // 20
    System.out.println(array[2]);   // 30
    System.out.println("=================");

    // 使用循环,次数其实就是数组的长度。
    for (int i = 0; i < 3; i++) {
        System.out.println(array[i]);
    }
    System.out.println("=================");

    for (int i = 0; i < array.length; i++) {
        System.out.println(array[i]);
    }
}

14、求数组中的最值

public static void main(String[] args) {
    int[] array = { 5, 15, 30, 20, 1000 };

    int max = array[0];     // 比武擂台
    for (int i = 1; i < array.length; i++) {
        // 如果当前元素,比max更大,则换人
        if (array[i] > max) {
            max = array[i];
        }
    }
    // 谁最后谁最大
    System.out.println("最大值:" + max);
}
public static void main(String[] args) {
    int[] array = { 5, 15, 30, 20, 1000 };

    int min = array[0];     // 擂台
    for (int i = 1; i < array.length; i++) {
        // 如果当前元素,比min更小,则换人
        if (array[i] < min) {
            min = array[i];
        }
    }
    // 谁最后谁最小
    System.out.println("最小值:" + min);
}

15、数组元素反转

数组元素的反转:
本来的样子:[1,2,3,4]
之后的样子:[4,3,2,1]

要求不能使用新数组,就用原来的唯一一个数组。

public static void main(String[] args) {
        int[] array = { 10, 20, 30, 40, 50 };

        // 遍历打印数组本来的样子
        for (int i = 0; i < array.length; i++) {
            System.out.println(array[i]);
        }
        System.out.println("==================");

        /*
        初始化语句:int min = 0, max = array.length - 1
        条件判断:min < max
        步进表达式:min--, max--
        循环体:用第三个变量倒手
         */
        for (int min = 0, max = array.length - 1; min < max; min++, max--) {
            int temp = array[min];
            array[min] = array[max];
            array[max] = temp;
        }

        // 再次打印遍历输出数组后的样子
        for (int i = 0; i < array.length; i++) {
            System.out.println(array[i]);
        }
    }
}

16、传递地址(数组作为方法参数)

数组可以作为方法的参数。
当调用方法的时候,向方法的小括号进行传参,传递进去的其实是数组的地址值。

public static void main(String[] args) {
    int[] array = { 10, 20, 30, 40, 50 };

    printArray(array);  // 传递进去的就是array当中保存的地址值
}

/*
三要素:
返回值类型:只是进行打印而已,不需要进行计算,也没有结果,用void
方法名称:printArray
参数列表:必须给我数组,我才能打印其中的元素。int[] array
 */
public static void printArray(int[] array) {
    for (int i = 0; i < array.length; i++) {
        System.out.println(array[i]);
    }
}

17、返回地址(数组作为方法返回值)

一个方法可以有0、1、多个参数;但是只有0或者1个返回值,不能有多个返回值。
如果希望一个方法当中产生了多个结果数据进行返回,怎么办?
解决方案:使用一个数组作为返回值类型即可。

任何数据类型都能作为方法的参数类型,或者返回值类型。

数组作为方法的参数,传递进去的其实是数组的地址值。
数组作为方法的返回值,返回的其实也是数组的地址值。

public static void main(String[] args) {
    int[] result = calculate(10,20,30);
    System.out.println("总和:" + result[0]);
    System.out.println("平均值:" + result[1]);
}

public  static int[] calculate(int a, int b, int c) {
    int sum = a + b + c;    // 总和
    int avg = sum / 3;      // 平均值
    // 两个结果都希望进行返回
    int[] array = { sum, avg };
    return array;
}

DAY6

1、面向对象

面向过程:当需要实现一个功能的时候,每一个具体的步骤都要亲力亲为,详细处理每一个细节
面向对象:当需要实现一个功能的时候,不关心具体的步骤,而是找一个已经具有该功能的人,来帮我做这事。

public static void main(String[] args) {
    int[] array = { 10, 20, 30, 40, 50 };
    
    // 要求打印格式为: [10, 20, 30, 40, 50]
    // 使用面向过程,每一个步骤细节都要亲力亲为。
    System.out.print("[");
    for (int i = 0; i < array.length; i++) {
        if (i == array.length - 1) {    // 如果是最后一个元素
            System.out.println(array[i] + "]");
        } else {    // 如果不是最后一个元素
            System.out.print(array[i] + ", ");
        }
    }
    System.out.println("===================");

    // 使用面向对象
    // 找一个JDK给我们提供好的Arrays类,
    // 其中有一个toString方法,直接就能把数组变成想要的格式的字符串
    System.out.println(Arrays.toString(array));
}

2、面向对象思想举例

洗衣服

面向过程:脱下衣服–>找个盆–>倒洗衣液–>洗–>晾

面向对象:脱下衣服–>放入洗衣机–>晾

吃饭

面向过程:买菜–>洗菜–>炒菜–>吃–>刷碗

面向对象:餐馆–>回家

3、类和对象的关系

类是对一类实物的描述,是抽象的,相当于设计图纸

对象是一类实物的示例,是具体的,相当于实物东西

4、类的定义

定义一个类,用来模拟“学生”实物。其中就有两个组成部分:

属性(是什么):
姓名
年龄
行为(能做什么):
吃饭
睡觉
学习

对应到Java的类当中:

成员变量(属性):
String name; // 姓名
int age; // 年龄
成员方法(行为):
public void eat() {} // 吃饭
public void sleep() {} // 睡觉
public void study() {} // 学习

注意事项:
1、成员变量是直接定义在类当中的,在方法外边。
2、成员方法不要写static关键字。

public class Student {

    // 成员变量
    String name;    // 姓名
    int age;        // 年龄

    // 成员方法
    public void eat() {
        System.out.println("吃饭");
    }

    public void sleep() {
        System.out.println("睡觉");
    }

    public void study() {
        System.out.println("学习");
    }

}

5、对象的创建及使用

通常情况下,一个类并不能直接使用,需要根据类创建一个对象,才能使用,

1、导包:也就是指出需要使用的类,在什么位置。
import 包名称.类名称;
import com.memory.day06.dome01.Student;
对于和当前类属于同一个包的情况,可以省略导包语句。

2、创建,格式:
类名称 对象名 = new 类名称();
Student stu = new Studnet();

3、使用,分为两种情况:
使用成员变量:对象名.成员变量名
使用成员方法:对象名.成员方法名(参数)
(也就是,想要谁,就用对象名点谁。)

注意事项:
如果成员变量没有进行赋值,那么将会有一个默认值,规则和数组一样。

public static void main(String[] args) {
    // 1、导包。
    // 我需要使用的Studnet类,和我自己Demo02Student位于同一个包下,所以省略导包语句

    // 2、创建,格式:
    // 类名称 对象名 = new 类名称();
    // 根据Studnet类,创建了一个名为stu的对象
    Student stu = new Student();

    // 3、使用其中的成员变量,格式:
    // 对象名.成员变量名
    System.out.println(stu.name);   // null
    System.out.println(stu.age);    // 0
    System.out.println("===================");

    // 改变对象当中的成员变量数值内容
    // 将右侧的字符串,赋值交给stu对象当中的name成员变量
    stu.name = "小明";
    stu.age = 18;
    System.out.println(stu.name);
    System.out.println(stu.age);
    System.out.println("===================");

    // 4、使用对象的成员方法,格式:
    // 对象名.成员方法名()
    stu.eat();
    stu.sleep();
    stu.study();
}

6、手机类练习

定义一个类,用来模拟“手机“事物。

属性:品牌、价格、颜色
行为:打电话、发短信

对应到类当中:
成员变量(属性):
String brand; // 品牌
double price; // 价格
String color; // 颜色
成员方法(行为):
public void call(String who) {} // 打电话
public void sendMessage() {} // 群发短信

public class Phone {

    // 成员变量
    String brand;   // 品牌
    double price;   // 价格
    String color;   // 颜色

    // 成员方法
    public void call(String who) {
        System.out.println("给" + who + "打电话");
    }

    public void sendMessage() {
        System.out.println("群发短信");
    }
}
public class Demo01PhoneOne {

    public static void main(String[] args) {
        // 根据Phone类,创建一个名称One的对象
        // 格式:类名称 对象名 = new 类名称();
        Phone one = new Phone();
        System.out.println(one.brand);  // null
        System.out.println(one.price);  // 0.0
        System.out.println(one.color);  // null
        System.out.println("===============");

        one.brand = "苹果";
        one.price = 8388.0;
        one.color = "黑色";
        System.out.println(one.brand);  // 苹果
        System.out.println(one.price);  // 8388.0
        System.out.println(one.color);  // 黑色
        System.out.println("===============");

        one.call("乔布斯");     	  // 给乔布斯打电话
        one.sendMessage();			// 群发短信
    }
}

7、一个对象的内存图

8、两个对象使用同一个方法的内存图

public class Demo02PhoneTwo {

    public static void main(String[] args) {
        Phone one = new Phone();
        System.out.println(one.brand);  // null
        System.out.println(one.price);  // 0.0
        System.out.println(one.color);  // null
        System.out.println("===============");

        one.brand = "苹果";
        one.price = 8388.0;
        one.color = "黑色";
        System.out.println(one.brand);  // 苹果
        System.out.println(one.price);  // 8388.0
        System.out.println(one.color);  // 黑色
        System.out.println("===============");

        one.call("乔布斯");        // 给乔布斯打电话
        one.sendMessage();             // 群发短信
        System.out.println("===============");

        Phone two = new Phone();
        System.out.println(two.brand);  // null
        System.out.println(two.price);  // 0.0
        System.out.println(two.color);  // null
        System.out.println("===============");

        two.brand = "三星";
        two.price = 5999.0;
        two.color = "蓝色";
        System.out.println(two.brand);  // 三星
        System.out.println(two.price);  // 5999.0
        System.out.println(two.color);  // 蓝色
        System.out.println("===============");

        two.call("三星");         // 给三星打电话
        two.sendMessage();             // 群发短信
    }
}

9、两个引用指向同一个对象的内存图

public class Demo03PhoneSame {

    public static void main(String[] args) {
        Phone one = new Phone();
        System.out.println(one.brand);  // null
        System.out.println(one.price);  // 0.0
        System.out.println(one.color);  // null
        System.out.println("===============");

        one.brand = "苹果";
        one.price = 8388.0;
        one.color = "黑色";
        System.out.println(one.brand);  // 苹果
        System.out.println(one.price);  // 8388.0
        System.out.println(one.color);  // 黑色
        System.out.println("===============");

        one.call("乔布斯");        // 给乔布斯打电话
        one.sendMessage();             // 群发短信
        System.out.println("===============");

        // 将one当中保存的对象地址赋值给two
        Phone two = one;
        System.out.println(two.brand);  // 苹果
        System.out.println(two.price);  // 8388.0
        System.out.println(two.color);  // 黑色
        System.out.println("===============");

        two.brand = "三星";
        two.price = 5999.0;
        two.color = "蓝色";
        System.out.println(two.brand);  // 三星
        System.out.println(two.price);  // 5999.0
        System.out.println(two.color);  // 蓝色
        System.out.println("===============");

        two.call("三星");         // 给三星打电话
        two.sendMessage();             // 群发短信
    }
}

10、使用对象类型作为方法的参数

public class Demo04PhoneParam {

    public static void main(String[] args) {
        Phone one = new Phone();
        one.brand = "苹果";
        one.price = 8388.0;
        one.color = "土豪金";

        method(one);    // 传递进去的参数其实就是地址值
    }

    public static void method(Phone param) {
        System.out.println(param.brand);    // 苹果
        System.out.println(param.price);    // 8388.0
        System.out.println(param.color);    // 土豪金
    }
}

11、使用对象类型作为方法的返回值

public class Demo05PhoneReturn {

    public static void main(String[] args) {
        Phone two = getPhone();
        System.out.println(two.brand);  // 苹果
        System.out.println(two.price);  // 8388.0
        System.out.println(two.color);  // 玫瑰金
    }

    public static Phone getPhone() {
        Phone one = new Phone();
        one.brand = "苹果";
        one.price = 8388.0;
        one.color = "玫瑰金";
        return one;
    }
}

12、局部变量和成员变量

1、定义的位置不一样【重点】
局部变量:在方法的内部
成员变量:在方法的外部,直接卸载类当中

2、作用范围不一样【重点】
局部变量:只有方法当中才可以使用,出了方法就不能再用
成员变量:整个类全都可以通用

3、默认值不一样【重点】
局部变量:没有默认值,如果要想使用,必须手动进行赋值
成员变量:如果没有赋值,会有默认值,规则和数组一样

4、内存的位置不一样(了解)
局部变量:位于栈内存
成员变量:位于堆内存

5、生命周期不一样(了解)
局部变量:随着方法进栈而诞生,随着方法出栈而消失
成员变量,随着对象创建而诞生,随着对象被垃圾回收而消失

public class Demo01VariableDifference {

    String name;    // 成员变量

    public void methodA() {
        int num = 20;   // 局部变量
        System.out.println(num);
        System.out.println(name);
    }

    public void methodB(int param) {    // 方法的参数就是局部变量
        // 参数在方法调用的时候,必然会比赋值
        System.out.println(param);

        int age;    // 局部变量
//        System.out.println(age);    // 没有赋值不能使用
//        System.out.println(num);    // 错误写法,调用不到局部变量
        System.out.println(name);
    }

}

13、面向对象三大特征之封装性

面向对象三大特征:封装、继承、多态

封装性在Java当中的体现:
1、方法就是一种封装
2、关键字private也是一种封装

封装就是将一些细节信息隐藏起来,对于外界不可见。

public class Demo02Method {

    public static void main(String[] args) {
        int[] array = { 5, 15, 25, 20, 100 };
        
        int max =getMax(array);
        System.out.println("最大值:" + max);
    }

    // 给我一个数组,我换给你一个最大值
    public static int getMax(int[] array) {
        int max = array[0];
        for (int i = 0; i < array.length; i++) {
            if (array[i] > max) {
                max = array[i];
            }
        }
        return max;
    }
}

14、private关键字的作用及使用

问题描述:定义Person的年龄时,无法阻止不合理的数值被设置进来。
解决方案:用private关键字将需要保护的成员变量进行修饰。

一旦使用了private进行修饰,那么本类当中仍然可以随意访问。
但是!超出了本类范围之外就不能直接访问了。

间接访问private成员变量,就定义一对Getter/Setter方法

必须叫setXxx或者是getXxx命名规则。
对于Getter来说,不能有参数,返回值类型和成员变量对应;
对于Setter来说,不能有返回值,参数类型和成员变量对应。

public class Person {

    String name;    // 姓名
    private int age;        // 年龄

    public void show() {
        System.out.println("我叫:" + name + ",年龄:" + age);
    }

    // 这个成员方法,专门用于向age设置数据
    public void setAge(int num) {
        if (num < 120 && num >= 0) {
            age = num;
        } else {
            System.out.println();
        }
    }

    // 这个成员方法,专门用于获取age的数据
    public int getAge() {
        return age;
    }
}
public class Demo03Person {

    public static void main(String[] args) {
        Person person = new Person();
        person.show();

        person.name = "小明";
//        person.age = 18;    // 直接访问private内容,错误!
        person.setAge(20);
        person.show();
    }
}

15、练习使用private关键字定义学生类(特殊boolean)

对于基本类型当中的boolean值,Getter方法一定要写成isXxx的形式,而setXxx规则不变。

public class Student {

    private String name;    // 姓名
    private int age;        // 年龄
    private boolean male;   // 是否男人

    public void setMale(boolean b) {
        male = b;
    }

    public boolean isMale() {
        return male;
    }

    public String getName() {
        return name;
    }

    public void setName(String str) {
        name = str;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int num) {
        age = num;
    }
}
public class Demo04Studnet {

    public static void main(String[] args) {
        Student stu = new Student();

        stu.setName("小明");
        stu.setAge(20);
        stu.setMale(true);

        System.out.println("姓名:" + stu.getName());
        System.out.println("年龄:" + stu.getAge());
        System.out.println("是不是男的:" + stu.isMale());
    }
}

16、this关键字的作用

当方法的局部变量和类的成员变量重名的时候,根据“就近原则”,优先使用局部变量。
如果需要访问本类当中的成员变量,需要使用格式:
this.成员变量名

“通过谁调用的方法,谁就是this。”

public class Person {

    String name;    // 自己的名字

    // 参数name是对方的名字
    // 成员变量name是自己的名字
    public void sayHello(String name) {
        System.out.println(name + ",您好。我是" + this.name);
        System.out.println(this);
    }
}
public class Demo01Person {

    public static void main(String[] args) {
        Person person = new Person();
        // 设置我自己的名字
        person.name = "小明";
        person.sayHello("小红");
        System.out.println(person);
    }
}

17、构造方法

构造方法是专门用来创建对象的方法,当我们通过关键字new来创建对象时,其实就是在调用构造方法。
格式:
public 类名称(参数类型 参数名称) {
方法体
}

注意事项:
1、构造方法的名称必须和所在的类名称完全一样,就连大小写也要一样
2、构造方法不要写返回值类型,连void都不写
3、构造方法不能return一个具体的返回值
4、如果没有编写任何构造方法,那么编译器将会默认有一个构造方法,没有参数、方法体什么事情都不做。
public Studnet() {}
5、一旦编写了至少一个构造方法,那么编译器将去掉默认的。
6、构造方法也是可以进行重载的。
重载:方法名称相同,参数列表不同。

public class Student {

    private String name;
    private int age;

    public Student() {
        System.out.println("无参构造方法已执行");
    }

    public Student(String name, int age) {
        System.out.println("全参构造方法已执行");
        this.name = name;
        this.age = age;
    }

    // Getter  Setter
    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }
}
public class Demo02Student {

    public static void main(String[] args) {
        Student stu1 = new Student();   // 无参构造
        Student stu2 = new Student("小明",20);    // 全参构造
        System.out.println("姓名:" + stu2.getName() + ",年龄:" + stu2.getAge());
        // 如果需要改变对象当中的成员变量数据内容,仍然还需要使用setXxx方法
        stu2.setAge(21);    // 改变年龄
        System.out.println("姓名:" + stu2.getName() + ",年龄:" + stu2.getAge());
    }
}

18、定义一个标准的类

一个准备的类通常要拥有下面四个组成部分:

1、所有的成员变量都要使用private关键字修饰
2、为每一个成员变量编写一对Getter/Setter方法
3、编写一个无参数构造方法
4、编写一个全参数构造方法

这样标准的类也叫做Java Bean

public class Student {

    private String name;    // 姓名
    private int age;        // 年龄

    public Student() {
    }

    public Student(String name, int age) {
        this.name = name;
        this.age = age;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }
}
public class Demo01Student {

    public static void main(String[] args) {
        Student stu1 = new Student();
        stu1.setName("小明");
        stu1.setAge(20);
        System.out.println("姓名:" + stu1.getName() + ",年龄:" + stu1.getAge());
        System.out.println("================");

        Student stu2 = new Student("小红",22);
        System.out.println("姓名:" + stu2.getName() + ",年龄:" + stu2.getAge());
        stu2.setAge(21);
        System.out.println("姓名:" + stu2.getName() + ",年龄:" + stu2.getAge());
    }
}

DAY7

1、API概述和使用步骤

1、打开帮助文档

2、点击显示,找到索引,输入想要找的

3、看包。java.lang下的类不用导包

4、看类的解释和说明

5、学习构造方法

6、使用成员方法

2、Scanner类 键盘输入

Scanner类的功能:可以实现键盘输入数据,到程序当中。

引用类型的一般使用步骤:

1、导包
import 包路径.类名称;
如果需要使用的目标类,和当前类位于同一个包下,则可以省略导包语句不写。
只有java.lang包下的内容不需要导包,其中的包都需要import语句。

2、创建
类名称 对象名 = new 类名称();

3、使用
对象名.成员方法名()

获取键盘输入的一个int数字:int num = sc.nextInt();
获取键盘输入的一个字符串:String str = sc.next();

public class Demo01Scanner {

    public static void main(String[] args) {
        // 2、创建
        // System.in代表从键盘进行输入
        Scanner sc = new Scanner(System.in);

        // 3、获取键盘输入的int数字
        int num = sc.nextInt();
        System.out.println("输入的数字是:" + num);

        // 4、获取键盘输入的字符串
        String str = sc.next();
        System.out.println("输入的字符串是:" + str);
    }

}

3、Scanner练习一 键盘输入两个数字求和

题目:
键盘输入两个int数字,并且求出和值。

思路:
1、既然需要键盘输入,那么使用Scanner
2、Scanner的三个步骤:导包、创建、使用
3、需要的是两个数字,所以要调用两次nextInt方法
4、得到了两个数字,就需要加在一起。
5、将结果打印输出。

public class Demo02ScannerSum {

    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);

        System.out.println("请输入第一个数字:");
        int a = sc.nextInt();
        System.out.println("请输入第二个数字:");
        int b = sc.nextInt();

        int result = a + b;
        System.out.println("结果是:" + result);
    }
}

4、Scanner练习二 键盘输入三个数字求最大值

题目:
键盘输入三个int数字,然后求出其中的最大值。

思路:
1、既然时键盘输入,肯定需要用到Scanner
2、Scanner三个步骤:导包、创建、使用nextInt()方法
3、既然是三个数字,那么调用三次nextInt()方法,得到三个int变量
4、无法同事判断三个数字谁最大,应该转换成为两个步骤:
4.1 首先判断前两个当中谁最大,拿到前两个的最大值
4.2 拿着前两个中的最大值,再和第三个数字比较,得到三个数字当中的最大值
5、打印最终结构

public class Demo03ScannerMax {

    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);

        System.out.println("请输入第一个数字:");
        int a = sc.nextInt();
        System.out.println("请输入第二个数字:");
        int b = sc.nextInt();
        System.out.println("请输入第三个数字:");
        int c = sc.nextInt();

        // 首先得到前俩个数字当中的最大值
        int temp = a > b ? a : b;
        int max = temp > c ? temp : c;
        System.out.println("最大值是:" + max);
    }
}

5、匿名对象的说明

创建对象的标准格式:
类名称 对象名 = new 类名称();

匿名对象就是只有右边的对象,没有左边的名字和赋值运算符。
new 类名称();

注意事项:匿名对象只能使用唯一的一次,下次再用不得不再创建一个新对象。
使用建议:如果确定有一个对象只需要使用唯一的一次,就可以使用匿名对象。

public class Demo01Anonymous {

    public static void main(String[] args) {
        // 左边的one就是对象的名字
        Person one = new Person();
        one.name = "小明";
        one.showName();     // 我叫小明
        System.out.println("==============");

        // 匿名对象
        new Person().name = "小红";
        new Person().showName();    // 我叫null
    }
}

6、匿名对象作为方法的参数和返回值

public class Person {

    String name;

    public void showName() {
        System.out.println("我叫:" + name);
    }
}
public class Demo02Anonymous {

    public static void main(String[] args) {
        // 普通使用方式
//        Scanner sc = new Scanner(System.in);
//        int num = sc.nextInt();

        // 匿名对象的方式
//        int num = new Scanner(System.in).nextInt();
//        System.out.println("输入的是:" + num);

        // 使用一般写法传入参数
//        Scanner sc = new Scanner(System.in);
//        methodParam(sc);

        // 使用匿名对象来进行传参
//        methodParam(new Scanner(System.in));

        Scanner sc = methodResturn();
        int num = sc.nextInt();
        System.out.println("输入的是:" + num);
    }

    public static void methodParam(Scanner sc) {
        int num = sc.nextInt();
        System.out.println("输入的是:" + num);
    }

    public static Scanner methodResturn() {
//        Scanner sc = new Scanner(System.in);
//        return sc;
        return new Scanner(System.in);
    }
}

7、Random 随机数

Random类用来生成随机数字。使用起来也是三个步骤:

1、导包
import java.util.Random;

2、创建
Random r = new Random(); // 小括号当中留空即可

3、使用
获取一个随机的int数字(范围是int所有范围,有正负两种):int num = r.nextInt()
获取一个随机的int数字(参数代表了范围,左闭又开区间):int num = r.nextInt(3)
实际上代表的含义时:[0,3],也就是0~2

public class Demo01Random {

    public static void main(String[] args) {
        Random r = new Random();

        int num = r.nextInt();
        System.out.println("随机数:" + num);
    }

}

8、Random生成指定范围的随机数

public class Demo02Random {

    public static void main(String[] args) {
        Random r = new Random();

        for (int i = 0; i < 100; i++) {
            int num = r.nextInt(10);    // 范围实际上是0~9
            System.out.println(num);
        }
    }
}

9、Random练习一 生成1-n之间的随机数

题目要求:
根据int变量n的值,来获取随机数字,范围是[1,n],可以去到1也可以取到n,

思路:
1、定义一个int变量n,随意赋值
2、要使用Random:三个步骤,导包、创建、使用
3、如果写10,那么就是0-9,而且想要的是1-10,可以发现:整体+1即可。
4、打印随机数字

public class Demo03Random {

    public static void main(String[] args) {
        int n = 5;
        Random r = new Random();

        for (int i = 0; i < 100; i++) {
            // 本来范围时[0,n],整体+1之后变成了[1,n+1],也就是[1,n]
            int result = r.nextInt(n) + 1;
            System.out.println(result);
        }

    }
}

10、Random练习二 猜数字小游戏

题目:
用代码模拟猜数字的小游戏。

思路:
1、首先需要产生一个随机数字,并且一旦产生不再变化。用Random的nextInt方法
2、需要键盘输入,用Scanner
3、获取键盘输入的数字,用Scanner当中的nextInt方法
4、已经得到了两个数字,判断(if)一下:
如果大了,提示大,并且重试;
如果小了,提示小,并且重试;
如果猜中了,游戏结束。
5、重试就是再来一次,循环。

public class Demo04RandomGame {

    public static void main(String[] args) {
        Random r = new Random();
        int randomNum = r.nextInt(100) + 1; // [1,100]
        Scanner sc = new Scanner(System.in);


        while (true) {
            System.out.println("请输入你猜测的数字:");
            int guessNum = sc.nextInt();    // 键盘输入猜测的数字

            if (guessNum > randomNum) {
                System.out.println("猜大了,请重试!");
            } else if (guessNum < randomNum) {
                System.out.println("猜小了,请重试!");
            } else {
                System.out.println("恭喜你,猜中了!");
                break;  // 如果猜中,不再重试
            }
        }
        System.out.println("游戏结束");
    }
}

11、Random练习二 猜数字小游戏(题目变形)

题目:
用代码模拟猜数字的小游戏。

思路:
1、首先需要产生一个随机数字,并且一旦产生不再变化。用Random的nextInt方法
2、需要键盘输入,用Scanner
3、获取键盘输入的数字,用Scanner当中的nextInt方法
4、已经得到了两个数字,判断(if)一下:
如果大了,提示大,并且重试;
如果小了,提示小,并且重试;
如果猜中了,游戏结束。
5、重试就是再来一次,循环。

题目变形:
只允许猜十次

public class Demo05RandomGame {

    public static void main(String[] args) {
        Random r = new Random();
        int randomNum = r.nextInt(100) + 1; // [1,100]
        Scanner sc = new Scanner(System.in);
        int order = 10; // 猜测的次数

        for (int i = 0; i < order; i++) {
            System.out.println("请输入你猜测的数字:");
            int guessNum = sc.nextInt();    // 键盘输入猜测的数字

            if (guessNum == randomNum) {
                System.out.println("恭喜你,猜中了!");
            } else if (i == order-1){
                System.out.println("猜测次数已用完!");
            } else if (guessNum > randomNum) {
                System.out.println("猜大了,请重试!");
            } else {
                System.out.println("猜小了,请重试!");
            }
        }
        System.out.println("游戏结束");
    }
}

12、对象数组

题目:
定义一个数组,用来存储3个Person对象。

数组有一个缺点:一旦创建程序运行期间长度不可以发生改变。

public class Person {

    private String name;
    private int age;

    public Person() {
    }

    public Person(String name, int age) {
        this.name = name;
        this.age = age;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }
}
public class Demo01Array {

    public static void main(String[] args) {
        // 首先创建一个长度为3的数组,里面用来存放Person类型的对象
        Person[] array = new Person[3];

        Person one = new Person("小明",18);
        Person two = new Person("小红",20);
        Person three = new Person("小蓝",22);

        // 将one当中的地址值赋值到数组的0号元素位置
        array[0] = one;
        array[1] = two;
        array[2] = three;

        System.out.println(array[0]);   // 地址值
        System.out.println(array[1]);   // 地址值
        System.out.println(array[2]);   // 地址值

        System.out.println(array[1].getName());   // 小红
    }
}

13、ArrayList集合概述和基本使用

数组的长度不可以发生改变。
但是ArrayList集合的长度时可以随意变化的。

对于ArrayList来说,有一个尖括号代表泛型。
泛型:也就是装在集合当中的所有元素,全都是统一的什么类型。
注意:泛型只能时引用类型,不能是基本类型。

注意事项:
对于ArrayList集合来说,直接打印得到的不是地址值,而是内容。
如果内容是空,得到的是空的中括号:[]

public class Demo02ArrayList {

    public static void main(String[] args) {
        // 创建了一个ArrayList集合,集合的名称时list,里面装的全都是String字符串类型的数据
        // 备注:从JDK 1.7+开始,右侧的尖括号内部可以不写内容,但是<>本身还是要写的(两边相同,前面尖括号里面是什么,后面就是什么)
        ArrayList<String> list = new ArrayList<>();
        System.out.println(list);  // []

        // 向集合当中添加一些数据,需要用到add方法。
        list.add("小明");
        System.out.println(list);   // [小明]

        list.add("小红");
        list.add("小兰");
        System.out.println(list);   // [小明, 小红, 小兰]

//        list.add(100);  // 错误写法!因为创建的时候尖括号泛型已经说了是字符串,添加进去的元素就必须都是字符串才行
    }
}

14、ArrayList集合的常用方法

ArrayList当中的常用方法有:

public boolean add(E e):向集合当中添加元素,参数的类型和泛型一致。
注意:对于ArrayList集合来说,add添加动作一定是成功的,所以返回值可用可不用。
但是对于其他集合来说,add添加动作不一定成功。

public E get(int index):从集合当中获取元素,参数时索引编号,返回值就是对应位置的元素。

public E remove(int index):从集合当中删除元素,参数时索引编号,返回值就是删除掉的元素。

public int size():获取集合的尺寸长度,返回值就是集合中包含的元素个数。

public class Demo03ArrayListMethod {

    public static void main(String[] args) {
        ArrayList<String> list = new ArrayList<>();
        System.out.println(list);

        // 向集合中添加元素:add
        boolean success = list.add("小明");
        System.out.println(list);   // [小明]
        System.out.println("添加的动作是否成功:" + success); // 添加的动作是否成功:true

        list.add("小红");
        list.add("小兰");
        list.add("ABC");
        list.add("ABB");
        System.out.println(list);   // [小明, 小红, 小兰, ABC, ABB]

        // 从集合中获取元素:get、索引值从0开始
        String name = list.get(1);
        System.out.println("第1号索引位置:" + name);  // 第1号索引位置:小红

        // 从集合中删除元素:remove。索引值从0开始。
        String whoRemoved = list.remove(2);
        System.out.println("被删除的人时:" + whoRemoved); // 被删除的人时:小兰
        System.out.println(list);   // [小明, 小红, ABC, ABB]

        // 获取集合的长度尺寸,也就是其中元素的个数
        int size = list.size();
        System.out.println("集合的长度时:" + size);   // 集合的长度时:4
    }
}

15、ArrayList集合的遍历

public class Demo04ArrayListEach {

    public static void main(String[] args) {
        ArrayList<String> list = new ArrayList<>();
        list.add("ABC");
        list.add("ABB");
        list.add("AAB");
        
        // 遍历集合
        for (int i = 0; i < list.size(); i++) {
            System.out.println(list.get(i));
        }
    }
}

16、ArrayList集合存储基本数据类型

如果希望向集合ArrayList当中存储基本类型数据,必须使用基本类型对应的“包装类”

基本类型 包装类(引用类型,包装类都位于java.lang包下)
byte Byte
short Short
int Integer 【特殊】
long Long
float Float
double Double
char Character 【特殊】
boolean Boolean

从JDK 1.5+开始,支持自动装箱、自动拆箱。

自动装箱:基本类型 --> 包装类型
自动拆箱:包装类型 --> 基本类型

public class Demo05ArrayListBasic {

    public static void main(String[] args) {
        ArrayList<String> listA = new ArrayList<>();
        // 错误写法!泛型只能是引用类型,不能是基本类型
//        ArrayList<int> listB =new ArrayList<int>();

        ArrayList<Integer> listC = new ArrayList<>();
        listC.add(100);
        listC.add(200);
        System.out.println(listC);  // [100, 200]

        int num = listC.get(1);
        System.out.println("第1号元素是:" + num);

    }
}

17、ArrayList练习一 存储随机数字

题目:
生成6个1~33之间的随机整数,添加到集合,并遍历集合。

思路:
1、需要存储6个数字,创建一个集合,
2、产生随机数,需要用到Random
3、用循环6次,来产生6个随机数字:for循环
4、循环内调用r.nextInt(int n),参数是33,032,整体+1才是133
5、把数字添加到集合中:add
6、遍历集合:for、size、get

public class Demo01ArrayListRandom {

    public static void main(String[] args) {
        ArrayList<Integer> list = new ArrayList<>();
        Random r = new Random();
        for (int i = 0; i < 6; i++) {
            int num = r.nextInt(33) + 1;
            list.add(num);
        }
        // 遍历集合
        for (int i = 0; i < list.size(); i++) {
            System.out.println(list.get(i));
        }
    }
}

18、ArrayList练习二 存储自定义对象

题目:
自定义4个学生对象,添加到集合,并遍历。

思路:
1、自定义Studnet学生类,四个部分。
2、创建一个集合,用来存储学生对象。泛型:
3、根据类,创建4个学生对象
4、将4个学生对象添加到集合中:add
5、遍历集合:for、size、get

public class Student {

    private String name;
    private int age;

    public Student() {
    }

    public Student(String name, int age) {
        this.name = name;
        this.age = age;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }
}
public class Demo02ArrayListStudent {

    public static void main(String[] args) {
        ArrayList<Student> list = new ArrayList<>();

        Student one = new Student("学生A",20);
        Student two = new Student("学生B",22);
        Student three = new Student("学生C",18);
        Student four = new Student("学生D",30);

        list.add(one);
        list.add(two);
        list.add(three);
        list.add(four);

        // 遍历集合
        for (int i = 0; i < list.size(); i++) {
            Student stu = list.get(i);
            System.out.println("姓名:" + stu.getName() + ",年龄:" + stu.getAge());
        }
    }
}

19、ArrayList练习三 按指定格式遍历集合字符串

题目:
定义以指定格式打印集合的方法(ArrayList类型作为参数),使用{}扩起集合,使用@分隔每个元素。
格式参照 {元素@元素@元素}

System.out.println(list); [10, 20, 30]
printArrayList(list); {10@20@30}

public class Demo03ArrayListPrint {

    public static void main(String[] args) {
        ArrayList<String> list = new ArrayList<>();
        list.add("ABC");
        list.add("ABB");
        list.add("AAB");
        System.out.println(list);

        printArrayList(list);
    }

    /*
    定义方法的三要素:
    返回值类型:只是进行打印而已,没有运算,没有结果;所以用void
    方法名称:printArrayList
    参数列表:ArrayList
     */
    public static void printArrayList(ArrayList<String> list) {
        // {10@20@30}
        System.out.print("{");
        for (int i = 0; i < list.size(); i++) {
            String name = list.get(i);
            if (i == list.size() - 1) {
                System.out.println(name + "}");
            } else {
                System.out.print(name + "@");
            }
        }
    }
}

20、ArrayList练习四 筛选集合中的随机数

题目:
用一个大集合存入20个随机数字,然后筛选其中的偶数元素,放到小集合当中。
要求使用自定义的方法来实现筛选。

分析:
1、需要创建一个集合,用来存储int数字:
2、随机数字就用Random nextInt
3、循环20次,把随机数字放入大集合:for循环、add方法
4、定义一个方法,用来进行筛选。
筛选:根据大集合,筛选符合要求的元素,得到小集合。
三要素
返回值类型:ArrayList小集合(里面元素个数不确定)
方法名称:getSmallList
参数列表:ArrayList大集合(装着20个随机数字)
5、判断(if)是偶数:num % 2 == 0
6、如果是偶数,就放到小集合当中,否则不放。

public class Demo04ArrayListReturn {

    public static void main(String[] args) {
        ArrayList<Integer> bigList = new ArrayList<>();
        Random r = new Random();
        for (int i = 0; i < 20; i++) {
            int num = r.nextInt(100) + 1;   // 1~100
            bigList.add(num);
        }

        ArrayList<Integer> smallList = getSmallList(bigList);

        System.out.println("偶数共有:" + smallList.size());
        for (int i = 0; i < smallList.size(); i++) {
            System.out.println(smallList.get(i));
        }

    }

    // 这个方法,接收大集合参数,返回小集合结果
    public static ArrayList<Integer> getSmallList(ArrayList<Integer> bigList) {
        // 创建一个小集合,用来装偶数结果
        ArrayList<Integer> smallList = new ArrayList<>();
        for (int i = 0; i < bigList.size(); i++) {
            int num = bigList.get(i);
            if (num % 2 == 0) {
                smallList.add(num);
            }
        }
        return smallList;
    }
}

DAY8

1、字符串概述和特点

java.long.String类代表字符串。
API当中说:Java程序中的所有字符串字面值(如“abc”)都作为此类的实例实现。
其实就是说:程序当中所有的双引号字符串,都是String类的对象。(就算没有new,就照样是。)

字符串的特点:
1、字符串的内容用不可变。【重点】
2、正是因为字符串不可改变,所以字符串时可以共享使用的。
3、字符串效果上相当于char[]字符数组,但是底层原理byte[]字节数组。

2、字符串的构造方法和直接创建创建字符串的常见3+1种方式。

三种构造方法:
public String():创建一个空白字符串,不含有任何内容。
public String(char[] array):根据字符数组的内容,来创建对应的字符串。
public String(byte[] array):根据字节数组的内容,来创建对应的字符串。
一种直接创建:
String str = “Hello”; // 右边直接用双引号

注意:直接写上双引号,就是字符串对象。

public class Demo01String {

    public static void main(String[] args) {
        // 使用空参构造
        String str1 = new String();     // 小括号留空,说明字符串什么内容都没有   。
        System.out.println("第一个字符串:" + str1);

        // 根据字符数组创建字符串
        char[] charArray = { 'A', 'B', 'C'};
        String str2 = new String(charArray);
        System.out.println("第二个字符串:" + str2);

        // 根据字节数组创建字符串
        byte[] byteArray = { 97, 98, 99};
        String str3 = new String(byteArray);
        System.out.println("第三个字符串:" + str3);

        // 直接创建
        String str4 = "Hello";
        System.out.println("第四个字符串:" + str4);
    }
}

3、字符串的常量池

字符串常量池:程序当中直接写上的双引号字符串,就在字符串常量池中。

对于基本类型来说,==是进行数值的比较。
对于引用类型来说,==是进行地址值的比较。

public class Demo02StringPool {

    public static void main(String[] args) {
        String str1 = "abc";
        String str2 = "abc";

        char[] charArray = {'a', 'b', 'c'};
        String str3 = new String(charArray);

        System.out.println(str1 == str2);   // true
        System.out.println(str1 == str3);   // false
        System.out.println(str2 == str3);   // false
    }
}

4、字符串的比较相关方法

==是进行对象的地址值比较,如果确实需要字符串的内容比较,可以使用两个方法:

public boolean equals(Object obj):参数可以是任何对象,只有参数是一个字符串并且内容相同的才会给true;否则返回false。
注意事项:
1、任何对象都能用Object进行接收。
2、equals方法具有对称性,也就是a.equals(b)和b.equals(a)效果一样。
3、如果比较双方一个常量一个变量,推荐把常量字符串写在前面。
推荐:“abc”.equals(str) 不推荐:str.equals(“abc”)

public boolean equalsIgnoreCase(String str):忽略大小写,进行内容比较。

public class Demo01StringEquals {

    public static void main(String[] args) {
        String str1 = "Hello";
        String str2 = "Hello";
        char[] charArray = { 'H', 'e', 'l', 'l', 'o'};
        String str3 = new String(charArray);

        System.out.println(str1.equals(str2));  // true
        System.out.println(str2.equals(str3));  // true
        System.out.println(str3.equals("Hello"));   // true
        System.out.println("Hello".equals(str1));   // true

        String str4 = "hello";
        System.out.println(str1.equals(str4));  // false
        System.out.println("==================");

        String str5 = null;
        System.out.println("abc".equals(str5)); // 推荐:false
//        System.out.println(str5.equals("abc")); // 不推荐:报错,空指针异常NullPointerException
        System.out.println("==================");

        String strA = "Java";
        String strB = "java";
        System.out.println(strA.equals(strB));  // false,严格区分大小写
        System.out.println(strA.equalsIgnoreCase(strB));    // true,忽略大小写


    }
}

5、字符串的获取相关方法

public int length():获取字符串当中含有的字符个数,拿到字符串长度。
public String concat(String str):将当前字符串和参数字符串拼接成为返回值新的字符串。
public char charAt(int index):获取指定索引位置的单个字符。(索引从0开始)
public int indexOf(String str):查找参数字符串在本字符串当中首次出现的索引位置,如果没有返回-1值。

public class Demo02StringGet {

    public static void main(String[] args) {
        // 获取字符串的长度
        int length = "asghjklxxcbnrtyui".length();
        System.out.println("字符串的长度是:" + length);

        // 拼接字符串
        String str1 = "Hello";
        String str2 = "World";
        String str3 = str1.concat(str2);
        System.out.println(str1);   // Hello,原封不动
        System.out.println(str2);   // World,原封不动
        System.out.println(str3);   // HelloWorld,新的字符串
        System.out.println("==================");

        // 获取指定索引位置的单个字符
        char ch = "Hello".charAt(1);
        System.out.println("在1号索引位置的字符是" + ch);
        System.out.println("==================");

        // 查找参数字符串在本来字符串当中出现的第一次索引位置
        // 如果根本没有,返回-1值
        String original = "HelloWorldHelloWorldHelloWorld";
        int index = original.indexOf("llo");
        System.out.println("第一次索引值是:" + index); // 2

        System.out.println("HelloWorld".indexOf("abc"));    // -1
    }
}

6、字符串的截取方法

public String substring(int index):j截取从参数位置一直到字符串末尾,返回新字符串。
public String substring(int begin, int end):截取从begin开始,一直到end结束,中间的字符串。
注意:[begin, end],包含左边,不包含右边。

public class Demo03Substring {

    public static void main(String[] args) {
        String str1 = "HelloWorld";
        String str2 = str1.substring(5);
        System.out.println(str1);   // HelloWorld,原封不动
        System.out.println(str2);   // World,新字符串
        System.out.println("===================");

        String str3 = str1.substring(4,7);
        System.out.println(str3);
        System.out.println("===================");

        // 下面这种写法,字符串的内容任然是没有改变的
        // 下面有两个字符串:"Hello","Java"
        // strA当中保存的是地址值。
        // 本来地址值是Hello的0x666
        // 后来地址值变成了Java的0x999
        String strA = "Hello";
        System.out.println(strA);   // Hello
        strA = "Java";
        System.out.println(strA);   // Java
    }
}

7、字符串的转换相关方法

public char[] toCharArray():将当前字符串拆分成为字符数组作为返回值。
public byte[] getBytes():获得当前字符串底层的字节数组。
public String replace(CharSequence oldString, CharSequence newString)
将所有出现的老字符串替换成为新的字符串,返回替换之后的结果新字符串。
注意:CharSequence意思就是说可以接受字符串类型。

public class Demo04StringConvert {

    public static void main(String[] args) {
        // 转换围城字符数组
        char[] chars = "Hello".toCharArray();
        System.out.println(chars[0]);   // H
        System.out.println(chars.length);   // 5
        System.out.println("===============");

        // 转换成为字节数组
        byte[] bytes = "abc".getBytes();
        for (int i = 0; i < bytes.length; i++) {
            System.out.println(bytes[i]);
        }
        System.out.println("===============");

        // 字符串的内容替换
        String str1 = "How do you do?";
        String str2 = str1.replace("o", "*");
        System.out.println(str1);   // How do you do?
        System.out.println(str2);   // H*w d* y*u d*?
        System.out.println("===============");

        String lang1 = "会不会玩啊!草泥马!";
        String lang2 = lang1.replace("草泥马", "***");
        System.out.println(lang2);  // 会不会玩啊!***!
    }
}

8、字符串的分割方法

public String[] split(String regex):按照参数的规则,将字符串切分成为若干部分。

注意事项:
split方法的参数其实是一个正则表达式
如果按照英文句点“.”进行切分,必须写“\.”(两个反斜杠)

public class Demo05StringSplit {

    public static void main(String[] args) {
        String str1 = "aaa,bbb,ccc";
        String[] array1 = str1.split(",");
        for (int i = 0; i < array1.length; i++) {
            System.out.println(array1[i]);
        }
        System.out.println("=================");

        String str2 = "aaa bbb ccc";
        String[] array2 = str2.split(" ");
        for (int i = 0; i < array2.length; i++) {
            System.out.println(array2[i]);
        }
        System.out.println("=================");

        String str3 = "XXX.YYY.ZZZ";
        String[] array3 = str3.split(".");  // "."要改成"\\."才能正确切分
        System.out.println(array3.length);  // 0
        for (int i = 0; i < array3.length; i++) {
            System.out.println(array3[i]);
        }
    }
}

9、练习一:按指定格式拼接字符串

题目:
定义一个方法,把数组{1,2,3}按照指定格式拼接成一个字符串。格式参照如下:[world1#world2#world3]。

分析:
1、首先准备一个int[]数组,内容是:1、2、3
2、定义一个方法,用来将数组变成字符串
三要素
返回值类型:String
方法名称:fromArrayToString
参数列表:int[]
3、格式:[world1#world2#world3]
用到:for循环、字符串拼接、每个数组元素之前都有一个word字样、分隔使用的是#、区分一下是不是最后一个
4、调用方法,得到返回值,并打印结果字符串

public class Demo06StringPractise {

    public static void main(String[] args) {
        int[] array = {1, 2, 3};

        String result = fromArrayToString(array);
        System.out.println(result);
    }

    public static String fromArrayToString(int[] array) {
        String str = "[";
        for (int i = 0; i < array.length; i++) {
            if (i == array.length - 1) {
                str += "Word" + array[i] + "]";
            } else {
                str += "Word" + array[i] + "#";
            }
        }
        return str;
    }
}

10、练习二:统计输入的字符串中各种字符的个数

题目:
键盘输入一个字符串,并且统计其中各种字符出现的次数。
种类有:大写字母、小写字母、数字、其他

思路:
1、既然用来键盘输入,Scanner
2、键盘输入的是字符串,那么:String str = sc.next();
3、定义四个变量,分别代表四种字符各自的出现次数。
4、需要对字符串一个字、一个字检查,String–>char[],方法就是toCharArray()
5、遍历char[]字符数组,对当前字符的种类进行判断,并且用四个变量进行++动作。
6、打印输出四个变量,分别代表四种字符出现次数。

public class Demo07StringCount {

    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        System.out.println("请输入一个字符串:");
        String input = sc.next();   // 获取键盘输入的一个争风吃醋

        int countUpper = 0; // 大写字母
        int countLower = 0; // 小写字母
        int countNumber = 0;// 数字
        int countOther = 0; // 其他字符

        char[] charArray =input.toCharArray();
        for (int i = 0; i < charArray.length; i++) {
            char ch = charArray[i]; // 当前单个字符
            if ('A' <= ch && ch <= 'Z') {
                countUpper++;
            } else if ('a' <= ch && ch <= 'z') {
                countLower++;
            } else if ('0' <= ch && ch <= '9') {
                countNumber++;
            } else {
                countOther++;
            }
        }

        System.out.println("大写字母有:" + countUpper + "个");
        System.out.println("小写字母有:" + countLower + "个");
        System.out.println("数字有:" + countNumber + "个");
        System.out.println("其他字符有:" + countOther + "个");
    }
}

11、静态static关键字概述

12、静态static关键字修饰成员变量

如果一个成员变量使用了static关键字,那么这个变量不再属于对象自己,而是属于所在的类,多个对象共享同一份数据。

public class Student {

    private int id;         // 学号
    private String name;    // 姓名
    private int age;        // 年龄
    static String room;     // 所在教室
    private static int idCounter = 0;   // 学号计数器,每当new了一个新对象,计数器++


    public Student() {
        this.id = ++idCounter;
    }

    public Student(String name, int age) {
        this.name = name;
        this.age = age;
        this.id = ++idCounter;
    }

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }
}
public class Demo01StaticField {


    public static void main(String[] args) {
        Student one = new Student("小明",20);
        one.room = "101教室";
        System.out.println("学号:" + one.getId() + ",姓名:" + one.getName() + ",年龄:" + one.getAge() + ",所在教室:" + one.room);
        Student two = new Student("小红",18);
        System.out.println("学号:" + two.getId() + ",姓名:" + two.getName() + ",年龄:" + two.getAge() + ",所在教室:" + one.room);

    }
}

13、静态static关键字修饰成员方法

一旦使用static修饰成员方法,那么这就成为了静态方法。静态方法不属于对象,而是属于类的。

如果没有static关键字,那么必须首先创建对象,然后通过对象才能使用它。
如果有了static关键字,那么不需要创建对象,直接就能通过;类名称来使用它。

无论是成员变量,还是成员方法。如果有了static,都推荐使用类名称进行调用。
静态变量:类名称.静态变量
静态方法:类名称.静态方法()

注意事项:
1、静态只能直接访问静态,不能直接访问非静态(最好记:静态不能直接访问非静态)
原因:因为在内存当中是有的静态内容,有的非静态内容
“先人不知道后人,但是后人知道先人”
2、静态方法当中不能用this
原因:this代表当前对象,通过谁调用的方法,谁就是当前对象。

public class MyClass {

    int num;    // 成员变量
    static int numStatic;   // 静态变量

    // 成员方法
    public void method() {
        System.out.println("这是一个成员方法。");
        // 成员方法可以访问成员变量
        System.out.println(num);
        // 成员方法可以访问静态变量
        System.out.println(numStatic);
    }

    // 静态方法
    public static void methodStatic() {
        System.out.println("这是一个静态方法。");
        // 静态方法可以访问静态变量
        System.out.println(numStatic);
        // 静态不能直接访问非静态【重点】
//        System.out.println(num);    // 错误写法!

        // 静态方法中不能使用this关键字
//        System.out.println(this);   // 错误写法!
    }
}
public class Demo02StaticMethod {

    public static void main(String[] args) {
        MyClass obj = new MyClass();    // 首先创建对象
        // 然后才能使用没有static关键字的内容
        obj.method();

        // 对于静态方法来说,可以通过对象名进行调用,也可以直接通过类名称来调用。
        obj.methodStatic();     // 正确,不推荐,会误以为这是成员方法(这种写法会编译之后也会被javac翻译成为“类名称.静态方法”)
        MyClass.methodStatic(); // 正确,推荐,为了明确区分,使用“类名称.静态方法”

        // 对于本来当中的静态方法,可以省略名称
        myMethod();
        Demo02StaticMethod.myMethod();  // 完全等效
    }

    public static void myMethod() {
        System.out.println("自己的方法!");
    }
}

14、静态static的内存图

public class Demo03StaticStudent {

    public static void main(String[] args) {
        // 首先设置一个教室,这是静态的东西,应该通过类名称进行调用
        Student.room = "101教室";

        Student one = new Student("小明",20);
        System.out.println("one的姓名:" + one.getName());
        System.out.println("one的年龄:" + one.getAge());
        System.out.println("one的教室:" + Student.room);

        Student two = new Student("小红",18);
        System.out.println("two的姓名:" + two.getName());
        System.out.println("two的年龄:" + two.getAge());
        System.out.println("two的教室:" + Student.room);
    }
}

15、静态代码块

静态代码块的格式是:

public class 类名称 {
static {
// 静态代码块的内容
}
}

特点:当第一次用到本类时,静态代码块执行唯一的一次。
静态内容总是优先于非静态,所以静态代码块比构造方法先执行。

静态代码块的典型用途:
用来一次性地对静态成员变量进行赋值。

public class Person {

    static {
        System.out.println("静态代码块执行!");
    }

    public Person() {
        System.out.println("构造方法执行!");
    }
}
public class Demo04Static {

    public static void main(String[] args) {
        Person one = new Person();
        Person two = new Person();
    }

}

16、数组工具类Arrays

java,util.Arrays是一个与数组相关的工具类,里面提供了大量静态方法,用来实现数组常见的操作。

public static String toString(数组):将参数数组变成字符串(按照默认格式:[元素1,元素2,元素3…])
public static void sort(数组):按照默认升序(从小到大)对数组的元素进行排序。

注意:
1、如果是数值,sort默认按照升序从小到大
2、如果是字符串,sort默认按照字母升序
3、如果是自定义的类型,那么这个自定义的类需要有Comparable或者Comparator接口的支持。

public class Demo01Arrays {

    public static void main(String[] args) {
        int[] intArrays = {10, 20, 30};
        // 将int[]数组按照默认格式变成字符串
        String inStr = Arrays.toString(intArrays);
        System.out.println(inStr);  // [10, 20, 30]

        int[] array1 = {2, 1, 3, 10, 6};
        Arrays.sort(array1);
        System.out.println(Arrays.toString(array1));    // [1, 2, 3, 6, 10]

        String[] array2 = {"bbb", "aaa", "ccc"};
        Arrays.sort(array2);
        System.out.println(Arrays.toString(array2));    // [aaa, bbb, ccc]
    }
}

17、Arrays练习:字符串倒序排列

题目:
请使用Arrays相关API,将一个随机字符串中的所有字符升序排列,并倒序打印。

public class Demo02ArraysPractise {

    public static void main(String[] args) {
        String str = "xcvbn4thj7ydfg897tyugDFGUT";

        // 如何进行升序排列:sort
        // 必须是一个数组,才能用Arrays.sout方法
        // String --> 数组,用toCharArray
        char[] chars = str.toCharArray();
        Arrays.sort(chars);     // 对字符数组进行升序排列
        
        // 需要倒序遍历
        for (int i = chars.length - 1; i >= 0; i--) {
            System.out.println(chars[i]);
        }
    }
}

18、数学工具类Math

java.util.Math类是数学相关的工具类,里面提供了大量的静态方法,完成与数学运算相关的操作。

public static double abs(double num):获取绝对值。
public static double ceil(double num):向上取整。
public static double floor(double num):向下取整。
public static long round(double num):四舍五入

Math.PI代表近似的圆周率常量(double)

public class Demo03Math {

    public static void main(String[] args) {
        // 获取绝对值
        System.out.println(Math.abs(3.14)); // 3.14
        System.out.println(Math.abs(0));    // 0
        System.out.println(Math.abs(-2.5)); // 2.5
        System.out.println("====================");

        // 向上取整
        System.out.println(Math.ceil(3.9)); // 4.0
        System.out.println(Math.ceil(3.1)); // 4.0
        System.out.println(Math.ceil(3.0)); // 3.0
        System.out.println(Math.ceil(3.0)); // 3.0
        System.out.println("====================");

        // 向下取整,抹零
        System.out.println(Math.floor(30.1));   // 30.0
        System.out.println(Math.floor(30.9));   // 30.0
        System.out.println(Math.floor(31.0));   // 31.0
        System.out.println("====================");

        // 四舍五入
        System.out.println(Math.round(20.4));   // 20
        System.out.println(Math.round(10.5));   // 11
    }

}

19、Math练习:小学数学真题

题目:
计算在-10.8到5.9之间,绝对值大于6或者小于2.1的整数有多少个?

分析:
1、已经确定了范围,for循环
2、起点位置-10.8应该转换成-10,两种方法:
2.1 可以使用Math.ceil方法,向上(向正方向)取整
2.2 强转成为int,自动舍弃所有小数位
3、每一个数字都是整数,所以步进表达式应该是num++,这样每次都是+1的。
4、如何拿到绝对值:Math.abs方法。
5、一旦发现了一个数字,需要让计数器++进行统计。

注意:如果使用Math.ceil方法,-10.8可以变成-10.0。注意double也是可以进行++的。

public class Demo04MathPractise {

    public static void main(String[] args) {
        int count = 0;  // 符合要求的数量

        double min = -10.8;
        double max = 5.9;
        // 方法一  强转成为int,自动舍弃所有小数位
        // 这样处理,变量i就是区间之内所有的整数
//        for (int i = (int) min; i < max; i++) {
//            int abs = Math.abs(i);  // 绝对值
//            if (abs > 6 || abs < 2.1) {
//                System.out.print(i + ",");
//                count++;
//            }
//        }

        // 方法二 可以使用Math.ceil方法,向上(向正方向)取整
        for (double i = Math.ceil(min); i < max; i++) {
            double abs = Math.abs(i);  // 绝对值
            if (abs > 6 || abs < 2.1) {
                System.out.print(i + ",");
                count++;
            }
        }

        System.out.println("总共有:" + count); // 9
    }
}

DAY9

1、继承的概述

2、继承的格式

在继承的关系中,“子类就是一个父类”。也就是说,子类可以被当做父类看待。
例如父类是员工,子类是讲师,那么“讲师就是一个员工”。关系:is-a。

定义父类的格式:(一个普通的类定义)
public class 父类名称 {
// …
}

定义子类的格式:
public class 子类名称 extend 父类名称 {
// …
}

// 定义一个父类:员工
public class Employee {

    public void method() {
        System.out.println("方法执行!");
    }
}
// 定义一个员工的子类:讲师
public class Teacher extends Employee {
}
// 定义员工的另一个子类:助教
public class Assistant extends Employee {
}
public class Demo01Extends {

    public static void main(String[] args) {
        // 创建一个子类对象
        Teacher teacher = new Teacher();
        // Teacher类当中虽然什么都没写,但是会继承来自父类的method方法。
        teacher.method();

        // 创建另一个子类助教的对象
        Assistant assistant = new Assistant();
        assistant.method();
    }
}

3、继承中成员变量的访问特点

在父子类的继承关系当中,如果成员变量重名,则创建子类对象时,访问有两种方式:

直接通过子类对象访问成员变量:
等号左边是睡,就优先用谁,没有则向上找。
间接通过成员方法访问成员变量:
该方法属于谁,就优先用谁,没有则向上找。

public class Fu {

    int numFu = 10;

    int num = 100;

    public void methodFu() {
        // 使用的是本类当中的num,不会向下找子类的
        System.out.println(num);
    }
}
public class Zi extends Fu {

    int numZi = 20;

    int num = 200;

    public void methodZi() {
        // y因为本类当中有num,所以这里用的是本类的num
        System.out.println(num);
    }
}
public class Demo01ExtendsField {

    public static void main(String[] args) {
        Fu fu = new Fu();   // 创建父类对象
        System.out.println(fu.numFu);   // 只能使用父类的东西,没有任何子类内容
        System.out.println("=============");

        Zi zi = new Zi();
        System.out.println(zi.numFu);   // 10
        System.out.println(zi.numZi);   // 20
        System.out.println("=============");

        // 等号左边是谁,就优先用谁
        System.out.println(zi.num); // 优先子类,200
        System.out.println("=============");

        // 这个方法是子类的,优先用子类的,没有再向上找
        zi.methodZi();  // 200
        // 这个方法是在父类当中定义的
        zi.methodFu();  // 100
    }
}

4、区分子类方法中重名的三种变量

局部变量: 直接写成员变量名
本类的成员变量: this.成员变量名
父类的成员变狼: super.成员变量名

public class Fu {

    int num = 10;
}
public class Zi extends Fu {

    int num = 20;

    public void method() {
        int num = 30;
        System.out.println(num);    // 30,局部变量
        System.out.println(this.num);   // 20,本类的成员变量
        System.out.println(super.num);  // 10,父类的成员变量
    }
}
public class Demo01ExtendsField {

    public static void main(String[] args) {
        Zi zi = new Zi();

        zi.method();
    }
}

5、继承中成员方法的访问特点

在父子类的继承关系当中,创建子类对象,访问成员方法的规则:
创建的对象是谁就优先用谁,如果没有则向上找。

注意事项:
无论是成员方法还是成员变量,如果没有都是向上找父类,绝对不会向下找子类的。

public class Fu {

    public void methodFu() {
        System.out.println("父类方法执行!");
    }
}
public class Zi extends Fu {

    public void methodZi() {
        System.out.println("子类方法执行!");
    }
}
public class Demo01ExtendsMethod {

    public static void main(String[] args) {
        Zi zi = new Zi();

        zi.methodZi();
        zi.methodFu();

        // 创建的是new子类对象,所以优先用子类方法
        zi.method();
    }
}

6、继承中方法的覆盖重写 概念与特点

重写(Override)
概念:在继承关系当中,方法的名称一样,参数列表也一样。

重写(Override):方法的名称一样,参数列表也一样。覆盖、覆写【覆盖重写】
重载(Overload):方法的名称一样,参数列表不一样

方法的覆盖重写特点:创建的是子类对象,则优先用子类方法。

7、继承中方法的覆盖重写 注意事项

方法覆盖重写的注意事项:

1、必须保证父子类之间方法的名称相同,参数列表也相同。
@Override:写在方法前面,用来检测是不是有效的正确覆盖重写。
这个注解就算不写,只要满足要求,也是正确的方法覆盖重写。

2、子类方法的返回值必须小于等于父类方法的返回值范围。
小拓展提示:java.lang.Object类是所有类的公共最高父类(祖宗类:塔尖人物),java.lang.String就是Object的子类。

3、子类方法的权限必须大于等于父类方法的权限修饰符。
小拓展提示:public > protected > (default) > private
注意:(default)不是关键字default,而是什么都不写,留空。

8、继承中方法的覆盖重写 应用场景

// 本来的老款手机
public class Phone {

    public void call() {
        System.out.println("打电话");
    }

    public void send() {
        System.out.println("发短信");
    }

    public void show() {
        System.out.println("显示号码");
    }
}
// 定义一个新手机,使用老手机作为父类
public class NewPhone extends Phone {

    @Override
    public void show() {
        super.show();   // 把父类的show方法拿过来重复利用
        // 自己子类再来添加更多内容
        System.out.println("显示姓名");
        System.out.println("显示头像");
    }
}
public class Demo01Phone {

    public static void main(String[] args) {
        Phone phone = new Phone();
        phone.call();
        phone.send();
        phone.show();
        System.out.println("============");

        NewPhone newPhone = new NewPhone();
        newPhone.call();
        newPhone.send();
        newPhone.show();
    }
}

9、继承中构造方法的访问特点

继承关系中,父子类构造方法的访问特点:

1、子类构造方法当中有一个默认隐含的"super()"调用,所以一定是先调用的父类构造,后执行的子类构造。
2、子类构造可以通过super关键字来调用父类重载构造。
3、super的父类构造调用,必须是子类构造方法的第一个语句。不能一个子类构造调用多次super构造。
总结:
子类必须调用父类构造方法,不写则赠送super();写了则用写的指定的super调用,super只能有一个,还必须是第一个。

public class Fu {

    public Fu() {
        System.out.println("父类无参构造");
    }

    public Fu(int num) {
        System.out.println("父类有参构造!");
    }
}
public class Zi extends Fu {

    public Zi() {
        super();    // 在调用父类无参构造方法
//        super(10);  // 在调用父类重载的构造方法
        System.out.println("子类构造方法!");
    }

    public void method() {
//        super();    // 错误写法!只有子类构造方法,才能调用父类构造方法。
    }
}
public class Demo01Constructor {

    public static void main(String[] args) {
        Zi zi = new Zi();
    }
}

10、super关键字的三种用法

super关键字的用法有三种:
1、在子类的成员方法中,访问父类的成员变量。
2、在子类的成员方法中,访问父类的成员方法。
3、在子类的构造方法中,访问父类的构造方法。

public class Fu {

    int num = 10;

    public void method() {
        System.out.println("父类方法!");
    }
}
public class Zi extends Fu {

    int num = 20;

    public Zi() {       // 用法三:访问父类的构造方法
        super();    // 默认就有,不写也可以
    }

    public void methodZi() {    // 用法一:访问父类的成员变量
        System.out.println(super.num);  // 父类中的num变量
    }

    public void method() {      // 用法二:访问父类的成员方法
        super.method(); // 访问父类中的method方法
        System.out.println("子类方法!");
    }
}

11、this关键字的三种用法

super关键字用来访问父类内容,而this关键字用来访问本类内容。用法也有三种:

1、在本类的成员方法中,访问本类的成员变量。
2、在本类的成员方法中,访问本类的另一个成员方法。
3、在本类的构造方法中,访问本类的另一个构造方法。
在第三种用法当中要注意:
A. this(…)调用也必须是构造方法的第一个语句,唯一一个。
B. super和this两种构造调用,不能同时使用。

public class Fu {

    int num = 30;
}
public class Zi extends Fu {

    int num = 20;

    public Zi() {
//        super();    // 这一行不再赠送
        this(123);  // 本类的无参构造,调用本类的有参构造
//        this(1,2)   // 错误写法!
    }

    public Zi(int n ) {
        this(1,2);
    }

    public Zi(int n, int m) {

    }

    public void showNum() {
        int num = 10;
        System.out.println(num);    // 局部变量
        System.out.println(this.num);   // 本类中的成员变量
        System.out.println(super.num);  // 父类中的成员变量
    }

    public void methodA() {
        System.out.println("AAA");
    }

    public void methodB() {
        this.methodA();
        System.out.println("BBB");
    }
}

12、super与this关键字图解

13、Java继承的三个特点

14、抽象的概念

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-l6jOMfJp-1590994988934)(http://ww1.sinaimg.cn/large/dcaa95eely1fxguzslyrfj20p50aqmz7.jpg)]

15、抽象方法和抽象类的格式

抽象方法:就是加上abstract关键字,然后去掉大括号,直接分好结束。
抽象类:抽象方法所在的类,必须是抽象类才行。在class之前写上abstract即可。

public abstract class Animal {

    // 这是一个抽象方法,代表吃东西,但是具体吃什么(大括号的内容)不确定。
    public abstract void eat();

    // 这是普通的成员方法
    public void mormalMethod() {

    }
}

16、抽象方法和抽象类的使用

如何使用抽象类和抽象方法:
1、不能直接创建new抽象类对象。
2、必须用一个子类来继承抽象父类。
3、子类必须覆盖重写抽象父类当中所有的抽象方法。
覆盖重写(实现):子类去掉抽象方法的abstract关键字,然后补上方法体大括号。
4、创建子类对象进行使用。

public abstract class Animal {

    // 这是一个抽象方法,代表吃东西,但是具体吃什么(大括号的内容)不确定。
    public abstract void eat();

    // 这是普通的成员方法
    public void mormalMethod() {

    }
}
public class Cat extends Animal {

    @Override
    public void eat() {
        System.out.println("猫吃鱼");
    }
}
public class DemoMain {

    public static void main(String[] args) {
//        Animal animal = new Animal();   // 错误写法!不能直接创建抽象类对象

        Cat cat = new Cat();
        cat.eat();
    }
}

17、抽象方法和抽象类的注意事项

关于抽象类的使用,以下为语法上要注意的细节,虽然条目较多,但若理解了抽象的本质,无需死记硬背。

1、抽象类不能创建对象,如果创建,编译无法通过而报错。只能创建其非抽象子类的对象。

理解:假设创建了抽象类的对象,调用抽象的方法,而抽象方法没有具体的方法体,没有意义。

2、抽象类中,可以有构造方法,是供子类创建对象时,初始化父类成员使用的。

理解:子类的构造方法中,有默认的super(),需要访问父类构造方法。

public abstract class Fu {

    public Fu() {
        System.out.println("抽象父类构造方法执行!");
    }

    public abstract void eat();
}
public class Zi extends Fu {

    public Zi() {
        // super();
        System.out.println("子类构造方法执行");
    }

    @Override
    public void eat() {
        System.out.println("吃饭");
    }
}
public class DemoMain {

    public static void main(String[] args) {
        Zi zi = new Zi();
        zi.eat();
    }
}

3、抽象类中,不一定包含抽象方法,但是有抽象方法的类必定是抽象类。
理解:未包含抽象方法的抽象类,目的就是不想让调用者创建该类对象,通常用于某些特殊的类结构设
计。

/*
一个抽象类不一定含有抽象方法,
只要保证抽象方法所在的类是抽象类,即可。

这样没有抽象方法的抽象类,也不能直接创建对象,在一些特殊场景下有用途。
 */
public abstract class MyAbstract {

}

4、抽象类的子类,必须重写抽象父类中所有的抽象方法,否则,编译无法通过而报错。除非该子类也是抽象
类。
理解:假设不重写所有抽象方法,则类中可能包含抽象方法。那么创建对象后,调用抽象的方法,没有
意义。

// 最高的抽象父类
public abstract class Animal {

    public abstract void eat();

    public abstract void sleep();
}
// 子类也是一个抽象类
public abstract class Dog extends Animal {

    @Override
    public void eat() {
        System.out.println("狗吃骨头");
    }
}
public class DogGolden extends Dog {

    @Override
    public void sleep() {
        System.out.println("呼呼呼...");
    }
}
public class Dog2Ha extends Dog {
    
    @Override
    public void sleep() {
        System.out.println("嘿嘿嘿...");
    }
}
public class DemoMain {

    public static void main(String[] args) {
//        Animal animal = new Animal();   // 错误!抽象类不能创建对象

//        Dog dog = new Dog();    // 错误,这也是抽象类

        Dog2Ha ha = new Dog2Ha();   // 这是普通类,可以直接new对象
        ha.eat();
        ha.sleep();
        System.out.println("==================");

        DogGolden golden = new DogGolden();
        golden.eat();
        golden.sleep();
    }
}

18、发红包案例

分析

实现
public class User {

    private String name;    // 姓名
    private int money;      // 余额,也就是当前用户拥有的钱数

    public User() {
    }

    public User(String name, int money) {
        this.name = name;
        this.money = money;
    }

    // 展示一下当前用户有多少钱
    public void show() {
        System.out.println("我叫:" + name + ",当前余额:" + money);
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getMoney() {
        return money;
    }

    public void setMoney(int money) {
        this.money = money;
    }
}
// 群主的类
public class Manager extends User {

    public Manager() {
    }

    public Manager(String name, int money) {
        super(name, money);
    }

    public ArrayList<Integer> send(int totalMoney, int count) {
        // 首先需要一个集合,用来存储若干个红包的金额
        ArrayList<Integer> redList = new ArrayList<>();

        // 首先看一下群主自己有多少钱
        int leftMoney = super.getMoney();   // 群主当前余额
        if (totalMoney > leftMoney) {
            System.out.println("余额不足");
            return redList; // 返回空集合
        }

        // 扣钱,其实就是重新设置余额
        super.setMoney(leftMoney - totalMoney);

        // 发红包需要平均拆分成为count份
        int avg = totalMoney / count;
        int mod = totalMoney % count;   // 余数,也就是除不开的零头

        // 除不开的零头,包在最后一个红包当中
        // 下面把红包一个一个放到集合当中
        for (int i = 0; i < count - 1; i++) {
            redList.add(avg);
        }

        // 最后一个红包
        int last = avg + mod;
        redList.add(last);

        return redList;
    }
}
// 普通成员
public class Member extends User {

    public Member() {
    }

    public Member(String name, int money) {
        super(name, money);
    }

    public void receive(ArrayList<Integer> list) {
        // 从多个红包当中随便抽取一个,给我自己。
        // 随机获取一个集合当中的索引编号
        int index = new Random().nextInt(list.size());
        // 根据索引,从集合当中删除,并且得到被删除的红包,给我自己
        int dalta = list.remove(index);
        // 当前成员自己本来有多少钱
        int money = super.getMoney();
        // 加法,并重新设置回去
        super.setMoney(money + dalta);
    }
}
public class MainRedPacket {

    public static void main(String[] args) {
        Manager manager = new Manager("群主",100);

        Member one = new Member("成员A", 0);
        Member two = new Member("成员B", 0);
        Member three = new Member("成员C", 0);

        manager.show(); // 100
        one.show();     // 0
        two.show();     // 0
        three.show();   // 0
        System.out.println("==============");

        // 群主总共发20块钱,分成3个红包
        ArrayList<Integer> redList = manager.send(20,3);
        // 三个普通成员收红包
        one.receive(redList);
        two.receive(redList);
        three.receive(redList);

        manager.show(); // 100-20=80
        // 6、6、8,随机分给三个人
        one.show();
        two.show();
        three.show();
    }
}

DAY10

1、接口概述与生活举例

2、接口的定义基本格式

接口就是多个类的公共规范。
接口是一种引用数据类型,最重要的内容就是其中的:抽象方法。

如何定义一个接口的格式:
public interface 接扩名称 {
// 接口内容
}

注意:
换成了关键字interface之后,编译生成的字节码文件仍然是:
.java --> .class

如果是Java 7,那么接口中可以包含的内容有:
1、常量
2、抽象方法

如果是Java 8,还可以额外包含有:
3、默认方法
4、静态方法

如果是Java 9,还可以额外包含有:
5、私有方法

3、接口的抽象方法定义

在任何版本的Java中,接口都能定义抽象方法。
格式:
public abstract 返回值类型 方法名称(参数列表);

注意事项:
1、接口当中的抽象方法,修饰符必须是两个固定的关键字:public abstract
2、这两个关键字修饰符,可以选择性地省略。(熟悉后可以省略)
3、方法的三要素,可以随意定义。

public interface MyInterfaceAbstract {

    // 这是一个抽象方法
    public abstract void methodAbs();

    // 这也是抽象方法
    abstract void methodAbs2();

    // 这也是抽象方法
    public void methodAbs3();

    // 这还是抽象方法
    void methodAbs4();
}

4、接口的抽象方法使用

接口使用步骤:
1、接口不能直接使用,必须有一个“实现类”来“实现”该接口。
格式:
public class 类名称 implements 接口名称 {
// …
}
2、接口的实现类必须覆盖重写(实现)接口中所有的抽象方法。
实现:去掉abstract关键字,加上方法体大括号。(覆盖重写)
3、创建实现类的对象,进行使用。

注意事项:
如果实现类并没有覆盖重写接口中所有的抽象方法,那么这个实现类自己必须是抽象类。

public class MyInterfaceAbstractlmpl implements MyInterfaceAbstract {
    @Override
    public void methodAbs() {
        System.out.println("这是第一个方法!");
    }

    @Override
    public void methodAbs2() {
        System.out.println("这是第二个方法!");
    }

    @Override
    public void methodAbs3() {
        System.out.println("这是第三个方法!");
    }

    @Override
    public void methodAbs4() {
        System.out.println("这是第四个方法!");
    }
}
public class Demo01Interface {

    public static void main(String[] args) {
        // 错误写法!不能直接new接口对象使用。
//        MyInterfaceAbstract inter = new MyInterfaceAbstract();

        // 创建实现类的对象使用
        MyInterfaceAbstractlmpl impl = new MyInterfaceAbstractlmpl();
        impl.methodAbs();
        impl.methodAbs2();
    }
}

5、接口的默认方法定义

从Java 8开始,接口里允许定义默认方法。
格式:
public default 返回值类型 方法名称(参数列表) {
方法体
}

注意:接口当中的默认方法,可以解决接口升级的问题。

public interface MyInterfaceDefault {

    // 抽象方法
    public abstract void methodAbs();
}
public class MyInterfaceDefaultA implements MyInterfaceDefault {
    @Override
    public void methodAbs() {
        System.out.println("实现了抽象方法,AAA");
    }
}
public class MyInterfaceDefaultB implements MyInterfaceDefault {
    @Override
    public void methodAbs() {
        System.out.println("实现了抽象方法,BBB");
    }
}

6、接口的默认方法使用

1、接口的默认方法,可以通过接口实现类对象,直接调用。
2、接口的默认方法,也可以被接口实现类进行覆盖重写。

public interface MyInterfaceDefault {

    // 抽象方法
    public abstract void methodAbs();

    // 新添加了一个抽象方法
//    public abstract void methodAbs2();

    // 新添加的方法,改成默认方法
    public default void methodDefault() {
        System.out.println("这是新添加的默认方法");
    }
}
public class Demo02Interface {

    public static void main(String[] args) {
        // 创建了实现类对象
        MyInterfaceDefaultA  a = new MyInterfaceDefaultA();
        a.methodAbs();  // 调用抽象方法,实际运行的是右侧实现类

        // 调用默认方法,如果实现类当中没有,会向上找接口
        a.methodDefault();  // 这是新添加的默认方法
        System.out.println("===================");

        MyInterfaceDefaultB  b = new MyInterfaceDefaultB();
        b.methodAbs();
        b.methodDefault();  // 实现类B覆盖重写了接口的默认方法
    }
}

7、接口的静态方法定义

从Java 8开始,接口当中允许定义静态方法。
格式:
public static 返回值类型 方法名称(参数列表) {
方法体
}
提示:就是将abstract或者default换成static即可,带上方法体。

8、接口的静态方法使用

注意事项:不能通过接口实现类的对象来调用接口当中的静态方法。
正确用法:通过接口名称,直接调用其中的静态方法,
格式:
接口名称.静态方法名(参数);

public interface MyInterfaceStatic {

    public static void methodStatic() {
        System.out.println("这是接口的静态方法!");
    }
}
public class MyInterfaceStaticImpl implements MyInterfaceStatic {
}
public class Demo03Interface {

    public static void main(String[] args) {
        // 创建实现类对象  由于跟对象没有关系,没有必要创建对象
//        MyInterfaceStaticImpl impl = new MyInterfaceStaticImpl();

        // 错误写法!
//        impl.methodStatic();

        // 直接通过接口名称调用静态方法
        MyInterfaceStatic.methodStatic();
    }
}

9、接口的私有方法定义

问题描述:
我们需要抽取一个公共方法,用来解决两个默认方法之间重复代码的问题。
但是这个共有方法不应该让实现类使用,应该是私有化的。

解决方案:
从Java 9开始,接口当中允许定义私有方法。
1、普通私有方法,解决多个默认方法之间重复代码问题
格式:
private 返回值类型 方法名称(参数列表) {
方法体
}

2、静态私有方法,解决多个静态方法之间重复代码问题
private static 返回值类型 方法名称(参数列表) {
方法体
}

public interface MyInterfacefacePrivateA {

    public default void MethodDefault1() {
        System.out.println("默认方法1");
        methodCommon();
    }

    public default void MethodDefault2() {
        System.out.println("默认方法2");
        methodCommon();
    }

    public default void methodCommon() {	// 这样的方法不可取
        System.out.println("AAA");
        System.out.println("BBB");
        System.out.println("CCC");
    }
}

10、接口的私有方法使用

public interface MyInterfacePrivateA {

    public default void MethodDefault1() {
        System.out.println("默认方法1");
        methodCommon();
    }

    public default void MethodDefault2() {
        System.out.println("默认方法2");
        methodCommon();
    }

    private void methodCommon() {
        System.out.println("AAA");
        System.out.println("BBB");
        System.out.println("CCC");
    }
}
public class MyInterfacePrivateAImpl implements MyInterfacePrivateA {

    public void methodAnother() {
        // 直接访问到了接口中的默认方法,这样是错误的!
//        methodCommon();
    }
}
同样接口中的静态方法也是如此
public interface MyInterfacePrivateB {

    public static void methodStatic1() {
        System.out.println("静态方法1");
        methodStaticCommon();
    }

    public static void methodStatic2() {
        System.out.println("静态方法2");
        methodStaticCommon();
    }

    private static void methodStaticCommon() {
        System.out.println("AAA");
        System.out.println("BBB");
        System.out.println("CCC");
    }
}
public class Demo04Interface {

    public static void main(String[] args) {
        MyInterfacePrivateB.methodStatic1();
        MyInterfacePrivateB.methodStatic2();

        // 错误写法!
//        MyInterfacePrivateB.methodStaticCommon();
    }
}

11、接口的常量定义和使用

接口当中也可以定义“成员变量”,但是必须使用public static final三个关键字进行修饰。
从效果上看,这其实就是接口的常量
格式:
public static final 数据类型 常量名称 = 数据值;
注意:
一旦使用final关键字进行修饰,说明不可改变。

注意事项:
1、接口当中的常量,可以省略public static final,注意:不写也一样是这样
2、接口当中的常量,必须进行赋值;不能不赋值。
3、接口当中常量的名称,使用完全大写的字母,用下划线进行分隔。(推荐命名规则)

public interface MyInterfaceConst {

    // 这其实就是一个常量,一旦赋值,不可以修改
    public static final int NUM_OF_MY_CLASS = 10;

}
public class Demo05Interface {

    public static void main(String[] args) {
        // 访问接口当中的常量
        System.out.println(MyInterfaceConst.NUM_OF_MY_CLASS);
    }
}

12、接口的内容小结

在Java 9+版本中,接口的内容可以有:

1、成员变量其实是常量,格式:
[public] [static] [final] 数据类型 常量名称 = 数据值;
注意:
    常量必须要进行赋值,而且一旦赋值不能改变。
    常量名称全完大写,用下划线进行分隔。

2、接口中最重要的就是抽象方法,格式:
[public] [abstract] 返回值类型 方法名称(参数列表);
注意:实现类必须覆盖重写接口所有的抽象方法,除非实现类是抽象类。

3、从Java 8开始,接口里允许定义默认方法,格式:
[public] default 返回值类型 方法名称(参数列表) { 方法体 }
注意:默认方法也可以被覆盖重写

4、从Java 8开始,接口里允许定义静态方法,格式:
[public] static 返回值类型 方法名称(参数列表) { 方法体 }
注意:应该通过接口名称进行调用,不能通过实现类对象调用接口静态方法

5、从Java 9开始,接口里允许定义私有方法,格式:
普通私有方法:private 返回值类型 方法名称(参数列表) { 方法体 }
静态私有方法:private static 返回值类型 方法名称(参数列表) { 方法体 }
注意:private的方法只有接口自己才能调用,不能被实现类或别人使用。

13、继承父类并实现多个接口

使用接口的时候,需要注意:

1、接口是没有静态代码块或者构造方法的。
public interface MyInterface {

    // 错误写法!接口不能有静态代码块
//    static {
//
//    }

    // 错误写法!接口不能有构造方法
//    public MyInterfaceA() {
//
//    }
}
2、一个类的直接父类是唯一的,但是一个类可以同时实现多个接口。

格式:
public class MyInterfaceImpl implements MyInterfaceA, MyInterfaceB {
// 覆盖重写所有抽象方法
}

public interface MyInterfaceA {

    public abstract void mehtodA();

}
public interface MyInterfaceB {

    public abstract void mehtodB();

}
public class MyInterfaceImpl /*extends Object*/ implements MyInterfaceA, MyInterfaceB {

    @Override
    public void mehtodA() {
        System.out.println("覆盖重写了A方法");
    }

    @Override
    public void mehtodB() {
        System.out.println("覆盖重写了B方法");
    }
}
3、如果实现类所实现的多个接口当中,存在重复的抽象方法,那么只需要覆盖重写一次即可.
public interface MyInterfaceA {

    public abstract void methodAbs();
    
}
public interface MyInterfaceB {

    public abstract void methodAbs();
    
}
public class MyInterfaceImpl /*extends Object*/ implements MyInterfaceA, MyInterfaceB {

    @Override
    public void methodAbs() {
        System.out.println("覆盖重写了AB接口都有的抽象方法");
    }
}
4、如果实现类没有覆盖重写所有接口当中的所有抽方法,那么实现类就必须是一个抽象类。
public interface MyInterfaceA {

    public abstract void mehtodA();

    public abstract void methodAbs();
}
public interface MyInterfaceB {

    public abstract void mehtodB();

    public abstract void methodAbs();
}
public abstract/*必须加上abstract让其成为抽象类*/ class MyInterfaceAbstract implements MyInterfaceA, MyInterfaceB {

    @Override
    public void mehtodA() {

    }

    @Override
    public void methodAbs() {

    }
}
5、如果实现类所实现的多个接口当中,存在重复的默认方法,那么实现类一定要对冲突的默认方法进行覆盖重写。
public interface MyInterfaceA {

    public default void methdDefault() {
        System.out.println("默认方法AAA");
    }
}
public interface MyInterfaceB {

    public default void methdDefault() {
        System.out.println("默认方法BBB");
    }
}
public class MyInterfaceImpl /*extends Object*/ implements MyInterfaceA, MyInterfaceB {

    @Override
    public void methdDefault() {
        System.out.println("对多个接口当中突然的默认方法进行了覆盖重写");
    }
}
public abstract/*必须加上abstract让其成为抽象类*/ class MyInterfaceAbstract implements MyInterfaceA, MyInterfaceB {

    @Override
    public void methdDefault() {

    }
}
6、一个类如果直接父类当中的方法,和接口当中的默认方法产生了冲突,优先用父类当中的方法
public class Fu {

    public void method() {
        System.out.println("父类方法");
    }
}
public class Zi extends Fu implements MyInterface {
}
public interface MyInterface {

    public default void method() {
        System.out.println("接口的默认方法");
    }
}
public class Demo01Interface {

    public static void main(String[] args) {
        Zi zi = new Zi();
        zi.method();
    }
}

14、接口之间的多继承

1、类与类之间是单继承的。直接父类只有一个。
2、类与接口之间是多实现的。一个类可以实现多个接口。
3、接口与接口之间是多继承的。

public interface MyInterfaceA {

    public abstract void methodA();

    public abstract void methodCommon();
}
public interface MyInterfaceB {

    public abstract void methodB();

    public abstract void methodCommon();
}
/*
这个子接口当中有几个方法?   4个方法
methodA 来源于接口A
methodB 来源于接口B
methodCommon 同时来源于接口A和B
method 来源于自己
 */
public interface MyInterface extends MyInterfaceA, MyInterfaceB {

    public abstract void method();
}
public class MyInterfaceImpl implements MyInterface {
    @Override
    public void method() {

    }

    @Override
    public void methodA() {

    }

    @Override
    public void methodB() {

    }

    @Override
    public void methodCommon() {

    }
}

注意事项:
1、多个父接口当中的抽象方法如果重复,没关系。
2、多个父接口当中的默认方法如果重复,那么子接口必须进行默认方法的覆盖重写,而且带着default关键字

public interface MyInterfaceA {

    public default void methodDefault() {
        System.out.println("AAA");
    }
}
public interface MyInterfaceB {

    public default void methodDefault() {
        System.out.println("BBB");
    }
}
public interface MyInterface extends MyInterfaceA, MyInterfaceB {

    @Override
    default void methodDefault() {
    }
}

15、多态的概述

面向对象三大特征:封装性、继承性、多态性。

extends继承或者implements实现,是多态性的前提。

16、多态的格式与使用

代码当中体现多态性,其实就是一句话:父类引用指向子类对象。

格式:
父类名称 对象名 = new 子类名称();
或者:
接口名称 对象名 = new 实现类名称();

public class Demo01Multi {

    public static void main(String[] args) {
        // 使用多态的写法
        // 左侧父类的引用,指向了右侧子类的对象
        Fu obj = new Zi();

        obj.method();
        obj.methodFu();
    }
}
public class Fu {

    public void method() {
        System.out.println("父类方法");
    }

    public void methodFu() {
        System.out.println("父类特有方法");
    }
}
public class Zi extends Fu {

    @Override
    public void method() {
        System.out.println("子类方法");
    }
}

17、多态中成员变量的使用特点

访问成员变量的两种方式:

1、直接通过对象名称访问成员变量:看等号左边是谁,优先用谁,没有则向上找
2、间接通过成员方法访问成员变量:看该方法属于谁,优先用谁,没有则向上找

public class Fu {

    int num = 10;

    public void showNum() {
        System.out.println(num);
    }
}
public class Zi extends Fu {

    int num = 20;

    int age = 30;

    @Override
    public void showNum() {
        System.out.println(num);
    }
}
public class Demo01MultiFueld {

    public static void main(String[] args) {
        // 使用多态的写法,父类引用指向子类对象
        Fu obj = new Zi();
        System.out.println(obj.num);    // 父:10
//        System.out.println((obj.age);   // 错误写法!
        System.out.println("=============");

        // 子类没有覆盖重写,就是父:10
        // 子类如果覆盖重写,就是子:20
        obj.showNum();
    }
}

18、多态中成员方法的使用特点

在多态的代码当中,成员方法的访问规则是:
看new的是谁,就优先用谁,没有则向上找

口诀:编译看左边,运行看右边。

对比:
成员变量:编译看左边,运行还看左边。
成员方法:编译看左边,运行看右边。

public class Fu {

    public void method() {
        System.out.println("父类方法");
    }

    public void methodFu() {
        System.out.println("父类特有方法");
    }
}
public class Zi extends Fu {

    @Override
    public void method() {
        System.out.println("子类方法");
    }

    public void methodZi() {
        System.out.println("子类特有方法");
    }
}
public class Demo02MultiMethod {

    public static void main(String[] args) {
        Fu obj = new Zi();  // 多态

        obj.method();   // 父子都有,优先用子
        obj.methodFu(); // 子类没有,父类有,向上找到父类

        // 编译看左边,左边是Fu,Fu当中没有methodZi方法,所有编译报错
//        obj.methodZi();  // 错误写法!
    }
}

19、使用多态的好处

20、对象的向上转型与向下转型

向上转型

向上转型一定是安全的。

public abstract class Animal {

    public abstract void eat();
}
ublic class Cat extends Animal {
    @Override
    public void eat() {
        System.out.println("猫吃鱼");
    }
}
public class Demo01Main {

    public static void main(String[] args) {
        // 对象的向上转型,就是:父类引用指向子类对象
        Animal animal = new Cat();
        animal.eat();   // 猫吃鱼

//        animal.catchMouse();    // 错误写法!
}
向下转型

向上转型一定是安全的。但是也有一个弊端:

对象一旦向上转型为父类,那么就无法调用子类原本特有的内容。

解决方案:用对象的向下转型【还原】

public abstract class Animal {

    public abstract void eat();
}
public class Cat extends Animal {
    @Override
    public void eat() {
        System.out.println("猫吃鱼");
    }

    // 子类特有方法
    public void catchMouse() {
        System.out.println("猫抓老鼠");
    }
}
public class Dog extends Animal {
    @Override
    public void eat() {
        System.out.println("狗吃SHIT");
    }

    public void watchHouse() {
        System.out.println("狗看家");
    }
}
public class Demo01Main {
    public static void main(String[] args) {
    
        // 向下转型,进行【还原】动作
        Cat cat = (Cat) animal;
        cat.catchMouse();   // 猫抓老鼠

        // 下面是错误的向下转型
        // 本来new的时候是一只猫,现在非要当做狗
        // 错误写法!编译不会报错,但是运行会出现异常:
        // java.lang.ClassCastException,类转换异常
//        Dog dog = (Dog) animal;
    }
}

21、用instanceof关键字进行类型判断

如何才能知道一个父类引用的对象,本来是什么子类?
格式:
对象 instanceof 类名称
这将会得到一个boolean值结果,也就是判断前面的对象能不能当做后面类型的实例。

public class Demo02Instanceof {

    public static void main(String[] args) {
        Animal animal = new Dog();  // 本来是只猫
        animal.eat();   // 狗吃SHIT

        // 如果希望调用子类特有方法,需要向下转型
        // 判断一下父类引用animal本来是不是Dog
        if (animal instanceof Dog) {
            Dog dog = (Dog) animal;
            dog.watchHouse();
        }
        // 判断一下animal本来是不是Cat
        if (animal instanceof Cat) {
            Cat cat = (Cat) animal;
            cat.catchMouse();
        }

        giveMeAPet(new Dog());
    }

    public static void giveMeAPet(Animal animal) {
        if (animal instanceof Dog) {
            Dog dog = (Dog) animal;
            dog.watchHouse();
        }
        if (animal instanceof Cat) {
            Cat cat = (Cat) animal;
            cat.catchMouse();
        }
    }
}

22、笔记本USB接口案例

分析

实现
public interface USB {

    public abstract void open();    // 打开设备

    public abstract void close();   // 关闭设备
}
public class Computer {

    public void powerOn() {
        System.out.println("笔记本电脑开机");
    }

    public void powerOff() {
        System.out.println("笔记本电脑关机");
    }

    // 使用USB设备的方法,使用接口作为方法的参数
    public void usbDevice(USB usb) {
        usb.open(); // 打开设置

        if (usb instanceof Mouse) {     // 一定要先判断
            Mouse mouse = (Mouse) usb;  // 向下转型
            mouse.click();
        } else if (usb instanceof Keyboard) {   // 先判断
            Keyboard keyboard = (Keyboard) usb; // 向下转型
            keyboard.type();
        }

        usb.close();    // 关闭设备
    }
}
// 鼠标就是一个USB设备
public class Mouse implements USB {
    @Override
    public void open() {
        System.out.println("打开鼠标");
    }

    @Override
    public void close() {
        System.out.println("关闭鼠标");
    }

    public void click() {
        System.out.println("点击鼠标");
    }
}
// 键盘就是一个USB设备
public class Keyboard implements USB {
    @Override
    public void open() {
        System.out.println("打开键盘");
    }

    @Override
    public void close() {
        System.out.println("关闭键盘");
    }

    public void type() {
        System.out.println("键盘输入");
    }
}
public class DemoMain {

    public static void main(String[] args) {
        // 首先创建一个笔记本电脑
        Computer computer = new Computer();
        computer.powerOn();

        // 准备一个鼠标,供电脑使用
//        Mouse mouse = new Mouse();
        // 首先进行向上转型
        USB usbMouse = new Mouse(); // 多态写法
        // 参数是USB类型,正好传递进去的就是USB鼠标
        computer.usbDevice(usbMouse);

        // 创建一二USB键盘
        Keyboard keyboard = new Keyboard(); // 没有使用多态写法
        // 方法参数是USB类型,传递进去的是实现类对象
        computer.usbDevice(keyboard);   // 正确写法,也发生了向上转型
        // 使用子类对象,匿名对象,也可以
//        computer.usbDevice(new Keyboard()); // 也是正确写法

        computer.powerOff();
        System.out.println("=================");

        method(10.0);   // 正确写法,double --> double
        method(20);     // 正确写法,int --> double
        int a = 30;
        method(a);      // 正确写法,int --> double
    }

    public static void method(double num) {
        System.out.println(num);
    }
}

DAY11

1、final关键字

final关键字代表最终、不可改变的

常见四种用法:

1、可以用来修饰一个类
/*
当final关键字用来修饰一个类的时候,格式:
public final class 类名称 {
    // ...
}

含义:当前这个类不能有任何的子类
注意:一个类如果是final的,那么其中所有的成员方法都无法进行覆盖重写(因为没有办法继承)
 */
public final class MyClass /*extends Object*/ {

    public void method() {
        System.out.println("方法执行!");
    }
}
// 不能使用一个final类来作为父类
public class MySubClass /*extends MyClass*/ {
}
2、可以用来修饰一个方法
/*
当final关键字用来修饰一个方法的时候,这个方法就是最终方法,也就是不能被覆盖重写
格式:
修饰符 final 返回值类型 方法名称(参数列表) {
    // 方法体
}

注意事项:
对于类、方法来说,abstract关键字和final关键字不能同时使用,因为抽象类必须要重写,矛盾
 */
public class Fu {

    public final void method() {
        System.out.println("父类方法执行!");
    }
}
public class Zi extends Fu {

    // 错误写法!不能覆盖重写父类当中final的方法
//    @Override
//    public void method() {
//        System.out.println("子类覆盖重写父类的方法!");
//    }
}
3、可以用来修饰一个局部变量
public class Demo01Final {

    public static void main(String[] args) {
        int num1 = 10;
        System.out.println(num1);   // 10
        num1 = 20;
        System.out.println(num1);   // 20

        // 一旦使用final用来修饰局部变量,那么这个变量就不能更改。
        // "一次赋值,终生不变"
        final int num2 = 200;
        System.out.println(num2);   // 200

//        num2 = 250; // 错误写法!不能改变
//        num2 = 200; // 错误写法!

        // 正确写法!只要保证有唯一一次赋值即可
        final int num3;
        num3 = 30;

        // 对于基本类型来说,不可变说的是变量当中的数据不可改变
        // 对于引用类型来说,不可变说的是变量单重的地址值不可改变
        Student stu1 = new Student("小明");
        System.out.println(stu1);
        System.out.println(stu1.getName());     // 小明
        stu1 = new Student("小红");
        System.out.println(stu1);
        System.out.println(stu1.getName());     // 小红
        System.out.println("=================");

        final Student stu2 = new Student("小明");
        // 错误写法!final的引用类型变量,其中的地址不可改变
//        stu2 = new Student("小红");
        System.out.println(stu2.getName()); // 小明
        stu2.setName("小红");
        System.out.println(stu2.getName()); // 小红
    }
}
4、可以用来修饰一个成员变量
/*
对于成员变量来说,如果使用final关键字修饰,那么这个变量也照样是不可变

1、由于成员变量具有默认值,所以用了final之后必须手动赋值,不会再给默认值了。
2、对于final的成员变量,要么使用直接赋值,要么通过构造方法赋值。二者选其一。
3、必须保证类当中所有重载的构造方法,都最终会对final的成员变量进行赋值。
 */
public class Person {

    private final String name /*= "小明"*/;

    public Person() {
        name = "小红";
    }

    public Person(String name) {
        this.name = name;
    }

    public String getName() {
        return name;
    }

//    public void setName(String name) {
//        this.name = name;
//    }
}

2、四种权限修饰符

Java中有四种权限修饰符:
                    public  >   protected   >   (default)   >   private
同一个类(我自己)        YES         YES             YES             YES
同一个包(我邻居)        YES         YES             YES              NO
不同包子类(我儿子)       YES         YES             NO              NO
不同包非子类(陌生人)     YES         NO              NO              NO

注意事项:
(default)并不是关键字“default”,而是根本不写。
public class MyClass {

    public int num = 10;
}
同一个类
public class MyClass {

    public int num = 10;

    public void method() {
        System.out.println(num);
    }
}
同一个包
public class MyAnother {

    public void anotherMethod() {
        System.out.println(new MyClass().num);
    }
}
不同包子类
public class MySon extends MyClass {

    public void methodSon() {
        System.out.println(super.num);
    }
}
不同包非子类
public class Stranger {

    public void methodStrange() {
        System.out.println(new MyClass().num);
    }
}

3、内部类的概念与分类

如果一个事物的内部包含另一个事物,那么这就是一个类内部包含另一个类。
例如:身体和心脏的关系、汽车和发动机的关系。

分类:
1、成员内部类
2、局部内部类(包含匿名内部类)

4、成员内部类的定义

成员内部类的定义格式:
修饰符 class 外部类名称 {
修饰符 class 内部类名称 {
// …
}
// …
}

注意:
内部类用外部类,随意访问;
外部类用内部类,需要借助内部类对象。

public class Body {     // 外部类

    public class Hrart {    // 成员内部类

        // 内部类的方法
        public void beat() {
            System.out.println("心脏跳动");
            System.out.println("我叫:" + name);   // 正确写法
        }
    }

    // 外部类的成员变量
    private String name;

    // 外部类的方法
    public void methodBody() {
        System.out.println("外部类的方法");
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }
}

5、成员内部类的使用

如何使用成员内部类?有两种方法:

1、间接方式:

在外部类的方法当中,使用内部类;然后main只是调用外部类的方法。

先在外部类方法中添加内部类的匿名对象

public class Body {     // 外部类

    public class Heart {    // 成员内部类

        // 内部类的方法
        public void beat() {
            System.out.println("心脏跳动");
            System.out.println("我叫:" + name);   // 正确写法
        }
    }

    // 外部类的成员变量
    private String name;

    // 外部类的方法
    public void methodBody() {
        System.out.println("外部类的方法");
        new Heart().beat();     // 匿名对象
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }
}
public class Demo01InnerClass {

    public static void main(String[] args) {
        Body body = new Body(); // 外部类的对象
        // 通过外部类的对象,调用外部类的方法,里面间接在使用内部类Heart
        body.methodBody();
    }
}
2、直接方式:

公式:
类名称 对象名 = new 类名称();
外部类名称.内部类名称 对象名 = new 外部类名称().new 内部类名称();

public class Demo01InnerClass {

    public static void main(String[] args) {
        // 按照公式写:
        Body.Heart heart = new Body().new Heart();
        heart.beat();
    }
}

6、内部类的同名变量访问

如果出现了重名现象,那么格式是:外部类名称.this.外部类成员变量名

public class Outer {

    int num = 10;   // 外部类的成员变量

    public class Inner {
        int num = 20;   // 内部类的成员变量

        public void methodInner() {
            int num = 30;   // 内部类方法的局部变量
            System.out.println(num);    // 局部变量,就近原则
            System.out.println(this.num);   // 内部类的成员变量
            System.out.println(Outer.this.num); // 外部类的成员变量
        }
    }
}
public class Demo02InnerClass {

    public static void main(String[] args) {
        // 外部类名称.内部类名称 对象名 = new 外部类名称().new 内部类名称();
        Outer.Inner inner = new Outer().new Inner();
        inner.methodInner();
    }
}

7、局部内部类定义

如果一个类是定义在一个方法内部的,那么这就是一个局部内部类。
“局部”:只有当前所属的方法才能使用它,出了这个方法外面就不能用了,

定义格式:
修饰符 class 外部类名称 {
修饰符 但绘制类型 外部类方法名称(参数列表) {
class 局部内部类名称 {
// …
}
}
}

小结:权限修饰符
public > protected > (default) > private
定义一个类的时候,权限修饰符规则:
1、外部类:public / (default)
2、成员内部类:public / protected / (default) / private
3、局部内部类:什么都不能写(效果和default不一样)

public class Outer {

    public void methodOuter() {
        class Inner {   // 局部内部类
            int num = 10;
            public void methodInner() {
                System.out.println(num);    // 10
            }
        }

        Inner inner = new Inner();
        inner.methodInner();
    }
}
public class DemoMain {

    public static void main(String[] args) {
        Outer outer = new Outer();
        outer.methodOuter();
    }
}

8、局部内部类的final问题

局部内部类,如果希望访问所在方法的局部变量,那么这个局部变量必须是【有效final的】。

注意:
从Java 8+开始,只要局部变量真的不变,那么final关键字可以省略。

原因:
1、new出来的对象在堆内存当中。
2、局部变量是跟着方法走的,在栈内存当中。
3、方法运行结束之后,立刻出栈,局部变量就会立刻消失。
4、但是new出来的对象会在堆当中持续存在,直到垃圾回收消失。

public class MyOuter {

    public void methodOuter() {
        int num = 10;   // 所在方法的局部变量

        class MyInner {
            public void methodInner() {
                System.out.println(num);
            }
        }
    }
}

9、匿名内部类的定义格式与注意事项

如果接口的实现类(或者是父类的子类)只需要使用唯一的一次。
那么这种情况下就可以省略掉该类的定义,而改为使用【匿名内部类】。

匿名内部类的定义格式:
接口名称 对象名 = new 接口名称() {
// 覆盖重写所有抽象方法
};

对格式“new 接口名称() {…}”进行解析:
1、new代表创建对象的动作
2、接口名称就是匿名内部类需要实现哪个接口
3、{…}这才是匿名内部类的内容

注意事项:
1、匿名内部类,在【创建对象】的时候,只能使用唯一一次。
如果希望多次创建对象,而且类的内容一样的话,那么就必须使用单独定义的实现类了。
2、匿名对象,在【调用方法】的时候,只能调用唯一一次。
如果希望同一个对象,调用多次方法,那么必须给对象起一个名字。
3、匿名内部类是省略了【实现类/子类名称】,但是匿名对象是省略了【对象名称】
强调:匿名内部类和匿名对象不是一回事!

public interface MyInterface {

    void method1();  // 抽象方法

    void method2();
}
public class MyInterfaceImpl implements MyInterface {
    @Override
    public void method1() {
        System.out.println("实现类覆盖重写了方法!111");
    }

    @Override
    public void method2() {
        System.out.println("实现类覆盖重写了方法!222");
    }
}
public class DemoMain {

    public static void main(String[] args) {
//        MyInterface obj = new MyInterfaceImpl();
//        obj.method();

//        MyInterface some = new MyInterface();   // 错误写法

        // 使用匿名内部类,但不是匿名对象,对象名称就叫objA
        MyInterface objA = new MyInterface() {
            @Override
            public void method1() {
                System.out.println("匿名内部类实现了方法!111");
            }

            @Override
            public void method2() {
                System.out.println("匿名内部类实现了方法!222");
            }
        };
        objA.method1();
        objA.method2();
        System.out.println("========================");

        // 使用了匿名内部类,而且省略了对象名称,也是匿名对象
        new MyInterface() {
            @Override
            public void method1() {
                System.out.println("匿名内部类实现了方法!111");
            }

            @Override
            public void method2() {
                System.out.println("匿名内部类实现了方法!222");
            }
        }.method1();
        // 因为匿名对象无法调用第二次方法,所以需要再创建一个匿名内部类的匿名对象
        new MyInterface() {
            @Override
            public void method1() {
                System.out.println("匿名内部类实现了方法!111");
            }

            @Override
            public void method2() {
                System.out.println("匿名内部类实现了方法!222");
            }
        }.method2();
    }
}

10、类作为成员变量类型

public class Weapon {

    private String code;    // 武器的代号

    public Weapon() {
    }

    public Weapon(String code) {
        this.code = code;
    }

    public String getCode() {
        return code;
    }

    public void setCode(String code) {
        this.code = code;
    }
}
// 游戏当中的英雄角色类
public class Hero {

    private String name;    // 英雄名称
    private int age;        // 英雄的年龄
    private Weapon weapon;  // 武器

    public Hero() {
    }

    public Hero(String name, int age, Weapon weapon) {
        this.name = name;
        this.age = age;
        this.weapon = weapon;
    }

    public void attack() {
        System.out.println("年龄为" + age + "的" + name + "用" + weapon.getCode() + "攻击敌方");
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    public Weapon getWeapon() {
        return weapon;
    }

    public void setWeapon(Weapon weapon) {
        this.weapon = weapon;
    }
}
public class DemoMain {

    public static void main(String[] args) {
        // 创建一个英雄角色
        Hero hero = new Hero();
        // 为英雄起一个名称,并且设置年龄
        hero.setName("盖伦");
        hero.setAge(20);

        // 创建一个武器对象
        Weapon weapon = new Weapon("多兰剑");
        // 为英雄配备武器
        hero.setWeapon(weapon);

        // 年龄为20的盖伦用多兰剑攻击敌方
        hero.attack();
    }
}

11、接口作为成员变量类型

public class Hero {

    private String name;    // 英雄的名称
    private Skill skill;    // 英雄的技能

    public Hero() {
    }

    public Hero(String name, Skill skill) {
        this.name = name;
        this.skill = skill;
    }

    public void attack() {
        System.out.println("我叫" + name + ",开始释放技能");
        skill.use();    // 调用接口中的抽象方法
        System.out.println("释放技能完成");
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public Skill getSkill() {
        return skill;
    }

    public void setSkill(Skill skill) {
        this.skill = skill;
    }
}
public interface Skill {

    void use(); // 释放技能的抽象方法
}
public class SkillImpl implements Skill {
    @Override
    public void use() {
        System.out.println("Biu~biu~biu~");
    }
}
public class DemoGame {

    public static void main(String[] args) {
        Hero hero = new Hero();
        hero.setName("艾希");     // 设置英雄的名称

        // 设置英雄技能
//        hero.setSkill(new SkillImpl());     // 使用单独定义的实现类

        // 还可以改成使用匿名内部类
//        Skill skill = new Skill() {
//            @Override
//            public void use() {
//                System.out.println("Biu~biu~biu~");
//            }
//        };
//        hero.setSkill(skill);

        // 进一步简化,同时使用匿名内部类和匿名对象
        hero.setSkill(new Skill() {
            @Override
            public void use() {
                System.out.println("Biu~biu~biu~");
            }
        });

        hero.attack();
    }
}

12、接口作为方法的参数和或返回值

import java.util.ArrayList;
import java.util.List;

/*
java.util.List正是ArrayList所实现的接口。
 */
public class DemoInterface {

    public static void main(String[] args) {
        // 左边是接口名称,右边是实现类名称,这就是多态写法
        List<String> list = new ArrayList<>();

        List<String> result = addNames(list);
        for (int i = 0; i < result.size(); i++) {
            System.out.println(result.get(i));
        }
    }

    public static List<String> addNames(List<String> list) {
        list.add("小明");
        list.add("小红");
        return list;
    }
}

13、红包案例

场景说明:
红包发出去之后,所有人都有红包,大家抢完了之后,最后一个红包给群主自己。

我们自己要做的事情有:
1、设置一下程序的标题,通过构造方法的字符串参数
2、设置群主名称
3、设置分开策略:平均or随机

红包分发的策略:
1、普通红包(平均):totalMoney / totalCount,余数放在最后一个红包当中。
2、手气红包(随机):最少1分钱,最多不超过平均数的2倍。

public interface OpenMode {
    /**
     * 请将totalMoney分成count份,保存到ArrayList<Integer>中,返回即可
     *
     * @param totalMoney            总金额为方便计算,已经转换为整数,单位为分
     * @param totaCount             红包个数
     * @return ArrayList<Integer>   元素为各个红包的金额值,所有元素的值累和等于总金额。
     */
    ArrayList<Integer> divide(int totalMoney, int totaCount);
}
public class MyRed extends RedPacketFrame {
    /**
     * 构造方法:生成红包界面。
     *
     * @param title 界面的标题
     */
    public MyRed(String title) {
        super(title);
    }
}
public class NormalMode implements OpenMode {
    @Override
    public ArrayList<Integer> divide(final int totalMoney, final int totaCount) {
        ArrayList<Integer> list = new ArrayList<>();

        int avg = totalMoney / totaCount;   // 平均值
        int mod = totalMoney % totaCount;   // 余数,零头

        // 注意totalCount - 1代表,最后一个先留着
        for (int i = 0; i < totaCount - 1; i++) {
            list.add(avg);
        }

        // 有零头,需要放在最后一个红包当中
        list.add(avg + mod);

        return list;
    }
}
public class RandomMode implements OpenMode {
    @Override
    public ArrayList<Integer> divide(int totalMoney, int totaCount) {
        ArrayList<Integer> list = new ArrayList<>();

        // 随机分配,有可能多,有可能少
        // 最少1分钱,最多不超过“剩下金额平均数的2倍”
        // 第一次发红包,随机范围是0.01~6.66元
        // 第一次发完之后,剩下的至少是3.34元
        // 此时还需要再发2个红包
        // 此时的再发范围应该是0.01元~3.34元(取不到右边,剩下的0.01)

        // 总结一下,范围的公式是:1 + random.nextInt(leftMoey / leftcount * 2);
        Random r = new Random();    // 首先创建一个随机数生成器
        // totalMoney是总金额,totalCount是总份数,不变
        // 额外定义两个变量,分别代表剩下多少钱,剩下多少份
        int leftMoney = totalMoney;
        int leftCount = totaCount;

        // 随机发前n-1个,最后一个不需要随机
        for (int i = 0; i < totaCount - 1; i++) {
            // 按照公式生成随机金额
            int money = r.nextInt(leftMoney / leftCount * 2) + 1;
            list.add(money);    // 讲一个随机红包放入集合
            leftMoney -= money; // 剩下的金额越发越少
            leftCount--;        // 剩下还应该再发的红包个数,递减
        }

        // 最后一个红包不需要随机,直接赋值即可
        list.add(leftMoney);

        return list;
    }
}
public class Bootstrap {

    public static void main(String[] args) {
        MyRed red = new MyRed("发红包");
        // 设置群主名称
        red.setOwnerName("tom");

        // 普通红包
//        OpenMode normal = new NormalMode();
//        red.setOpenWay(normal);

        // 手气红包
        OpenMode random = new RandomMode();
        red.setOpenWay(random);
    }
}
红包页面
import javax.swing.*;
import java.awt.*;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.util.ArrayList;
import java.util.HashMap;

/**
 * 红包的框架 RedPacketFrame
 *
 * AWT / Swing / JavaFX
 *
 * @author 不是我
 */
public abstract class RedPacketFrame extends JFrame {

    private static final long serialVersionUID = 1L;
    
    private static final String DIR = ".\\pic";

    private ArrayList<Integer> moneyList = null;

    private static int initMoney = 0;
    private static int totalMoney = 0; // 单位为“分”
    private static int count = 0;

    private static HashMap<JPanel, JLabel> panelLable = new HashMap<>();

    // 设置字体
    private static Font fontYaHei = new Font("微软雅黑", Font.BOLD, 20);
    private static Font msgFont = new Font("微软雅黑", Font.BOLD, 20);
    private static Font totalShowFont = new Font("微软雅黑", Font.BOLD, 40);
    private static Font nameFont = new Font("微软雅黑", Font.BOLD, 40);
    private static Font showNameFont = new Font("微软雅黑", Font.BOLD, 20);
    private static Font showMoneyFont = new Font("微软雅黑", Font.BOLD, 50);
    private static Font showResultFont = new Font("微软雅黑", Font.BOLD, 15);

    /**
     * 窗体大小 WIDTH:400 HEIGHT:600
     */
    private static final int FRAME_WIDTH = 416; // 静态全局窗口大小
    private static final int FRAME_HEIGHT = 650;
    private static JLayeredPane layeredPane = null;

    /// private static JPanel contentPane = null;

    /**
     * page1:输入页面 - InputPanel . 组件和初始化!
     */
    private static JPanel inputPanel = new JPanel();

    // private static JTextField input_total = new JTextField("200"); // 测试用
    // private static JTextField input_count = new JTextField("3"); // 测试用
    private static JTextField input_total = new JTextField();
    private static JTextField input_count = new JTextField();
    private static JTextField input_people = new JTextField("30");
    private static JTextField input_msg = new JTextField("恭喜发财  ,  大吉大利");
    private static JTextField input_total_show = new JTextField("$ " + input_total.getText().trim());
    private static JLabel input_inMoney = new JLabel(); // 不可见
    private static JLabel input_bg_label = new JLabel(new ImageIcon(DIR + "\\01_input.jpg"));

    static {

        // 设置位置
        input_total.setBounds(200, 90, 150, 50);
        input_count.setBounds(200, 215, 150, 50);
        input_people.setBounds(90, 275, 25, 30);
        input_msg.setBounds(180, 340, 200, 50);
        input_total_show.setBounds(130, 430, 200, 80);
        input_inMoney.setBounds(10, 535, 380, 65);
        input_bg_label.setBounds(0, 0, 400, 600); // 背景

        // 设置字体
        input_total.setFont(fontYaHei);
        input_count.setFont(fontYaHei);
        input_people.setFont(fontYaHei);
        input_msg.setFont(msgFont);
        input_msg.setForeground(new Color(255, 233, 38)); // 字体颜色 为金色
        input_total_show.setFont(totalShowFont);
        input_inMoney.setFont(fontYaHei);

        // 透明
        input_people.setOpaque(false);
        input_total_show.setOpaque(false);
        // 编 辑 -- 不可编辑
        input_people.setEditable(false);
        input_total_show.setEditable(false);

        // 边界 -- 无
        input_total.setBorder(null);
        input_count.setBorder(null);
        input_people.setBorder(null);
        input_msg.setBorder(null);
        input_total_show.setBorder(null);

    }

    /**
     * page2:打开页面 - openPanel . 组件和初始化!
     */
    private static JPanel openPanel = new JPanel();

    private static JTextField open_ownerName = new JTextField("谁谁谁");
    private static JLabel open_label = new JLabel(new ImageIcon(DIR + "\\02_open_2.gif"));
    private static JLabel open_bg_label = new JLabel(new ImageIcon(DIR + "\\02_open_1.jpg"));

    static {

        // 设置 位置.
        open_ownerName.setBounds(0, 110, 400, 50);
        open_bg_label.setBounds(0, 0, 400, 620);
        open_label.setBounds(102, 280, 200, 200);
        open_ownerName.setHorizontalAlignment(JTextField.CENTER);

        // 设置字体
        open_ownerName.setFont(nameFont);
        open_ownerName.setForeground(new Color(255, 200, 163)); // 字体颜色 为金色

        // 背景色
        // open_name.setOpaque(false);
        open_ownerName.setBackground(new Color(219, 90, 68));

        // 不可编辑
        open_ownerName.setEditable(false);
        // 边框
        open_ownerName.setBorder(null);

    }

    /**
     * page3:展示页面 - showPanel . 组件和初始化!
     */
    private static JPanel showPanel = new JPanel();
    private static JPanel showPanel2 = new JPanel();
    private static JScrollPane show_jsp = new JScrollPane(showPanel2);

    private static JLabel show_bg_label = new JLabel(new ImageIcon(DIR + "\\03_money_1.jpg"));

    private static JTextField show_name = new JTextField("用户名称");
    private static JTextField show_msg = new JTextField("祝福信息");
    private static JTextField show_money = new JTextField("99.99");
    private static JTextField show_result = new JTextField(count + "个红包共" + (totalMoney / 100.0) + "元,被抢光了");

    static {
        // 分别设置水平和垂直滚动条自动出现
        // jsp.setHorizontalScrollBarPolicy(JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED);
        // jsp.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED);

        /*
         * 两部分 页面 . 1.本人获得的红包-- showPanel 2.别人获得的红包-- show_jsp
         */
        show_name.setBounds(125, 180, 100, 30);
        show_name.setOpaque(false);
        show_name.setBorder(null);
        show_name.setFont(showNameFont);

        show_msg.setBounds(0, 220, 400, 30);
        show_msg.setOpaque(false);
        show_msg.setBorder(null);
        show_msg.setFont(msgFont);
        show_msg.setHorizontalAlignment(JTextField.CENTER);

        show_money.setBounds(0, 270, 250, 40);
        show_money.setOpaque(false);
        show_money.setBorder(null);
        show_money.setFont(showMoneyFont);
        show_money.setForeground(new Color(255, 233, 38)); // 字体颜色 为金色
        show_money.setHorizontalAlignment(SwingConstants.RIGHT);

        show_result.setBounds(10, 460, 400, 20);
        show_result.setOpaque(false);
        show_result.setBorder(null);
        show_result.setFont(showResultFont);
        show_result.setForeground(new Color(170, 170, 170)); // 字体颜色 为灰色

        // 设置 图片.
        show_bg_label.setBounds(0, 0, 400, 500);

    }

    static {

        // 页面和 背景的对应关系.
        panelLable.put(inputPanel, input_bg_label);
        panelLable.put(openPanel, open_bg_label);
        panelLable.put(showPanel, show_bg_label);
    }

    private void init() {
        // 层次面板-- 用于设置背景
        layeredPane = this.getLayeredPane();
//        System.out.println("层次面板||" + layeredPane);
        // System.out.println(layeredPane);

        // 初始化框架 -- logo 和基本设置
        initFrame();
        // 初始化 三个页面 -- 准备页面
        initPanel();

        // 2.添加 页面 --第一个页面, 输入 panel 设置到 页面上.
        setPanel(inputPanel);

        // 3.添加 监听
        addListener();
    }


    /**
     * 初始化框架 -- logo 和基本设置
     */
    private void initFrame() {
        // logo
        this.setIconImage(Toolkit.getDefaultToolkit().getImage(DIR + "\\logo.gif"));
//        System.out.println("LOGO初始化...");

        // 窗口设置
        this.setSize(FRAME_WIDTH, FRAME_HEIGHT); // 设置界面大小
        this.setLocation(280, 30); // 设置界面出现的位置
        this.setDefaultCloseOperation(EXIT_ON_CLOSE);
        this.setLayout(null);

        // 测试期 注释 拖 拽 , 运行放开
        // this.setResizable(false);
        this.setVisible(true);
    }

    /**
     * 初始化页面-- 准备三个页面
     */

    private void initPanel() {
//        System.out.println("页面初始化...");
        initInputPanel();
        initOpenPanel();
        initShowPanel();

    }

    private void initInputPanel() {

        inputPanel.setLayout(null);
        inputPanel.setBounds(0, -5, 400, 600);

        // this.add(bg_label);
        inputPanel.add(input_total);
        inputPanel.add(input_count);
        inputPanel.add(input_people);
        inputPanel.add(input_msg);
        inputPanel.add(input_total_show);
        inputPanel.add(input_inMoney);

//        System.out.println("输入页面||" + inputPanel);

    }

    private void initOpenPanel() {
        openPanel.setLayout(null);
        openPanel.setBounds(0, 0, 400, 600);
        // this.add(bg_label);
        openPanel.add(open_ownerName);
        openPanel.add(open_label);
//        System.out.println("打开页面||" + openPanel);
    }

    private void initShowPanel() {
        showPanel.setLayout(null);
        showPanel.setBounds(10, 10, 300, 600);

        // ==============
        showPanel.add(show_name);
        showPanel.add(show_msg);
        showPanel.add(show_money);
        showPanel.add(show_result);
//        System.out.println("展示页面||" + showPanel);
        // ====================================
        // showPanel2.setLayout(null);
        // showPanel2.setBounds(0, 500, 401, 300);

        showPanel2.setPreferredSize(new Dimension(300, 1000));
        showPanel2.setBackground(Color.white);

        show_jsp.setBounds(0, 500, 400, 110);

    }

    /**
     * 每次打开页面, 设置 panel的方法
     */
    private void setPanel(JPanel panel) {
        // 移除当前页面
        layeredPane.removeAll();

//        System.out.println("重新设置:新页面");
        // 背景lable添加到layeredPane的默认层
        layeredPane.add(panelLable.get(panel), JLayeredPane.DEFAULT_LAYER);

        // 面板panel设置为透明
        panel.setOpaque(false);

        // 面板panel 添加到 layeredPane的modal层
        layeredPane.add(panel, JLayeredPane.MODAL_LAYER);
    }

    // private void setShowPanel(JPanel show) {
    // setPanel(show);
    // layeredPane.add(show_jsp, JLayeredPane.MODAL_LAYER);
    //
    // }

    /**
     * 设置组件的监听器
     */
    private void addListener() {

        input_total.addKeyListener(new KeyAdapter() {
            @Override
            public void keyReleased(KeyEvent e) {
                // System.out.println(e);
                String input_total_money = input_total.getText();
                input_total_show.setText("$ " + input_total_money);
            }
        });

        input_count.addKeyListener(new KeyAdapter() {

            @Override
            public void keyReleased(KeyEvent e) {
                // System.out.println(e);
//                System.out.println("个数:" + input_count.getText());
            }
        });
        input_msg.addKeyListener(new KeyAdapter() {

            @Override
            public void keyReleased(KeyEvent e) {
                // System.out.println(e);
//                System.out.println("留言:" + input_msg.getText());
            }
        });

        input_inMoney.addMouseListener(new MouseAdapter() {
            @Override
            public void mouseClicked(MouseEvent e) {
                try {

                    // 获取页面的值.
                    totalMoney = (int) (Double.parseDouble(input_total.getText()) * 100); // 转换成"分"
                    count = Integer.parseInt(input_count.getText());
                    if (count > 30) {
                        JOptionPane.showMessageDialog(null, "红包个数不得超过30个", "红包个数有误", JOptionPane.INFORMATION_MESSAGE);
                        return;
                    }

                    initMoney = totalMoney;

                    System.out.println("总金额:[" + totalMoney + "]分");
                    System.out.println("红包个数:[" + count + "]个");

                    input_inMoney.removeMouseListener(this);

//                    System.out.println("跳转-->打开新页面");

                    // 设置群主名称
                    open_ownerName.setText(ownerName);
                    // 设置打开页面
                    setPanel(openPanel);

                } catch (Exception e2) {
                    JOptionPane.showMessageDialog(null, "请输入正确【总金额】或【红包个数】", "输入信息有误", JOptionPane.ERROR_MESSAGE);

                }
            }
        });

        // open_ownerName ,点击 [名称],触发的方法 , 提示如何设置群主名称.

        open_ownerName.addMouseListener(new MouseAdapter() {
            @Override
            public void mouseClicked(MouseEvent arg0) {
                JOptionPane.showMessageDialog(null, "请通过【setOwnerName】方法设置群主名称", "群主名称未设置",
                        JOptionPane.QUESTION_MESSAGE);
            }
        });

        // open label , 点击 [开],触发的方法,提示如何设置打开方式.
        open_label.addMouseListener(new MouseAdapter() {
            @Override
            public void mouseClicked(MouseEvent e) {
                if (openWay == null) {
                    JOptionPane.showMessageDialog(null, "请通过【setOpenWay】方法设置打开方式", "打开方式未设置",
                            JOptionPane.QUESTION_MESSAGE);
                    return;
                }

//                System.out.println("跳转-->展示页面");

                moneyList = openWay.divide(totalMoney, count);

//                System.out.println(moneyList);
                /*
                 * showPanel 添加数据
                 *
                 */
                show_name.setText(ownerName);
                show_msg.setText(input_msg.getText());
                if (moneyList.size() > 0) {
                    show_money.setText(moneyList.get(moneyList.size() - 1) / 100.0 + "");
                }
                show_result.setText(count + "个红包共" + (initMoney / 100.0) + "元,被抢光了");

                open_label.removeMouseListener(this);

                setPanel(showPanel);

                // 添加数据
                for (int i = 0; i < moneyList.size(); i++) {

                    JTextField tf = new JTextField();
                    tf.setBorder(null);
                    tf.setFont(showNameFont);
                    tf.setHorizontalAlignment(JTextField.LEFT);
                    if (i == moneyList.size() - 1) {
                        tf.setText(ownerName + ":\t" + moneyList.get(i) / 100.0 + "元");

                    } else {

                        tf.setText("群成员-" + i + ":\t" + moneyList.get(i) / 100.0 + "元");
                    }
                    showPanel2.add(tf);
                }

                layeredPane.add(show_jsp, JLayeredPane.MODAL_LAYER);
            }

        });

    }

    /* ======================================================================
     * **********************************************************************
     * * 以上代码均为页面部分处理,包括布局/互动/跳转/显示等,大家                   *
     * *                                                   *
     * *                                                   *
     * **********************************************************************
     * ======================================================================
     */

    /**
     * ownerName : 群主名称
     */
    private String ownerName = "谁谁谁"; // 群主名称
    /**
     * openWay : 红包的类型 [普通红包/手气红包]
     */
    private OpenMode openWay = null;


    /**
     * 构造方法:生成红包界面。
     *
     * @param title 界面的标题
     */

    public RedPacketFrame(String title) {
        super(title);

        // 页面相关的初始化
        init();
    }

    public void setOwnerName(String ownerName) {
        this.ownerName = ownerName;
    }

    public void setOpenWay(OpenMode openWay) {
        this.openWay = openWay;
    }


}
  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值