在我的资源里有:pdf对应的完整内容需要的可以自行下载,无偿分享给大家
一、快捷键
Alt + / :
1)在java类中,要输出main方法,只要输入main然后用此快捷键按回车即可;
2)要输出System.out.println(),你只需输入syso然后用此快捷键按回车即可;
3)再比如你要覆盖父类的toString()方法,你只需输入to然后用此快捷键按回车;
4)再比如你要用一个没有import的类(比如Calendar),你只需输入Ca然后用此快捷键即可用上下键选择;再比如你要生成某个field的get,set方法,你只需输入get然后用此快捷键生成(默认为public);
(2)在jsp页面中可用此提示输入标签(标签内提示标签属性)
(3)在xml中也可用此快捷键。
alt+shift+j给函数添加doc注释
Ctrl + Shift + T : 打开Open Type 查找类文件
Ctrl + Shift + F4 : 关闭所在打开的窗口
Ctrl + O : Open declarations
Ctrl + E : 打开编辑器(切换窗口)
Ctrl + / : 注释本行
Alt + Shift + R : 重命名
Alt + Shift + L : 抽取本地变量
Alt + Shift + M : 抽取方法
F3 : Open Declaration
Ctrl + D : 删除本行
Ctrl + SHIFT + F : 整形
Ctrl + Alt + ↓(↑) : 向下(上)复制本行
Alt + ↓(↑) : 向下(上)移动本行
文档注释以 /** 开始,以*/ 结束
二、开发环境搭建
JDK简单理解就是Java开发工具包,JVM也就是常常听到Java虚拟机。JDK是面向开发者的,JRE是面向使用JAVA程序的用户。
bin:最主要的是编译器(javac.exe)
include:java和JVM交互用的头文件
lib:类库
jre:java运行环境
2.1java虚拟机--JVM
JVM是Java Virtual Machine(Java虚拟机)的缩写,JVM是一种用于计算设备的规范,它是一个虚构出来的计算机,是通过在实际的计算机上仿真模拟各种计算机功能来实现的。
引入Java语言虚拟机后,Java语言在不同平台上运行时不需要重新编译。Java语言使用Java虚拟机屏蔽了与具体平台相关的信息,使得Java语言编译程序只需生成在Java虚拟机上运行的目标代码(字节码),就可以在多种平台上不加修改地运行。
三、基础概念
位(bit):一个数字0或者一个数字1,代表一位
字节(Byte):每逢8位是一个字节,这是数据额存储的最小单位。
1Byte=8bit;1KB=1024Byte;1MB=1024K
3.1 关键字特性
1.完全小写的字母。
2.在增强版的记事本当中有特殊颜色。
3.2 标识符
所有标识符必须以字母(a-z,A-Z)美元符($)下划线(_)开始
首字符后可以用字母(a-z,A-Z)美元符($)下划线(_)或者数字
注意:1)不能使用变量名
2)不能使用关键字
3)大小写敏感的不能写错
命名规则:
类名规范:首字母大写,后面每个单词首字母大写。
变量名规范:首字母小写,后面每个单词首字母大写。
方法名规范:同变量名。
Java中标识符的命名约定:
小驼峰式命名:变量名、方法名
首字母小写,从第二个单词开始每个单词的首字母大写。
大驼峰式命名:类名
每个单词的首字母都大写。
另外,标识符的命名最好可以做到见名知意
3.3 常量
字符串型:用双引号 " " 引起来的部分。
整型:无小数点。
浮点型:有小数点
字符:用单引号 ' '
布尔类型:只有量中取值。true或false
空常量:NULL,无任何数据。
强制转换:
数据类型A 变量a=(数据类型A)变量b
常量:指的是取值不可变的变量
使用final修饰:final 数据类型 变量名=值;
static作用于成员变量用来表示只保存一份副本,而final的作用是用来保证变量不可变。
变量的使用;
1.作为主方法内的一个普通数据
2.定义一个类的属性
类是一种事物的描述
如何描述:特征(属性)与功能(方法)
public class demo01 {
//定义demo01类的属性,属性名:age
static int age=13;
public static void main (String[] args) {
System.out.println("helloword");
}
}
在写类中:如何访问属性值?
类名.属性(Byte.MAX_VALUE)来访问
注意事项:
1. 在同一对花括号中,变量名不能重复。
2. 变量在使用之前,必须初始化(赋值)。
3. 定义long类型的变量时,需要在整数的后面加L(大小写均可,建议大写)。因为整数默认是int类型,整数太
大可能超出int范围。
4. 定义flfloat类型的变量时,需要在小数的后面加F(大小写均可,建议大写)。因为浮点数的默认类型是
double, double的取值范围是大于flfloat的,类型不兼容。
3.4数据类型
1、基本数据类型:
1字节=8位
8位:Byte(字节型) 16位:short(短整型)、char(字符型)
32位:int(整型)、float(单精度型/浮点型)
64位:long(长整型)、double(双精度型) 最后一个:boolean(布尔类型)
整数型:Byte、short、int、long
浮点型:float、double
字符型:char
布尔型:boolean
类型转换:char-int-long-float-double
2、引用数据类型
字符串、数组、类、接口、Lambda
3、注意事项
1)字符串不是基本类型,二是引用型。
2)浮点型可能只是一个近似值,并非精确的值。
3)数据范围与字节数不一定相关。
4)浮点数当中默认类型是double,如果一定要使用float类型,需加上一个后缀F。
如果是整数,默认为int类型,如果一定要使用long类型,需要加上一个后缀L。
3.5 变量和数据类型
数据类型 变量名称=数据值; int a=2;
自动类型转换(隐式)
1.特点:代码不需要进行特殊处理,自动完成。
2.规则:数据范围从小到大。int --->long
double num = 10; // 将int类型的10直接赋值给double类型 System.out.println(num); // 输出10.0
强制类型转换(显式):不推荐使用,可能导致精度损失、数据溢出;byte/short/char在运算时都会首先升级为int类型在计算;boolean类型不能发生数据类型转换
1.特点:代码需要进行特殊的格式处理,自动完成。
2.规则:范围小的类型 范围小的变量名 =(范围小的类型)原本范围大的数据。
double num1 = 5.5; int num2 = (int) num1; // 将double类型的num1强制转换为int类型 System.out.println(num2); // 输出5(小数位直接舍弃)
3.6运算符
1、算术运算符
/: 取整除 | 返回除法的整数部分(商) 9 // 2 输出结果 4。
%:取余数 | 返回除法的余数 9 % 2 = 1。
**:幂,又称次方、乘方,2 ** 3 = 8 。
++在非单独使用:
++在后: 会现将变量原本所记录的值取出来进行操作, 然后再完成自身+1的运算。
++在前: 先完成自身+1的运算, 然后再进行赋值。
++/--在单独使用时无区别。
int x = 4;
//括号1 : 现将x原本记录的4取出来 --> 4
//括号2 : 将上一次变化后的5, 再进行++在前的运算 --> 6
//括号3 : 60
int y = (x++)+(++x)+(x*10); // 70
2、赋值运算符
基本赋值运算符:就一个=
符合运算符:+= -= *= /= %=
eg: a+=1 -->a=a+1
只有变量才能使用赋值运算符,常量不能进行复制。
复合赋值运算符其中隐含了一个强制类型转换
3、比较运算符
== < > <= >= !=
结果一定是boolean值,成立就是true,不成立就是false
如果进行多次判断,不能连者写
4、逻辑运算符:
&逻辑与:a&b,a和b都是true,结果为true,否则为false
|逻辑或:a|b,a和b都是false,结果为false,否则为true
^逻辑异或:a^b,a和b结果不同为true,相同为false
!逻辑非:!a,结果和a的结果正好相反
&&短路与:作用和&相同,但是有短路效果
||短路或:作用和|相同,但是有短路效果
& 与: 与--> 并且--> 结论: 左边两边, 必须同时为true, 结果才为true换句话说, 遇false, 则false.
int i = 10;
System.out.println(i > 5 & i < 20);
| : 或--> 或者--> 结论: 左右两边, 只要有一个为true, 结果就为true换句话说, 遇true, 则true。
&&双与: 短路与 左边返回false的时候, 右边就不再执行了。
左边返回为true, 右边依旧执行。
|| : 至少一个是true就是true;全为false时才为false。
! : 非--> 取反 --> 特点: 非两次, 结果不变。
^ 异或 : 相同为false, 不同为true。
特点 :
一个数, 被另外一个数, 异或两次, 该数本身不变10 ^ 6 ^ 6
&&和& 有什么区别?
& : 无论左边返回的结果是true还是false, 右边都必须执行。
&& : 全为true,才为true;否者为false。
int a=3;
2<a<4
||和| 有什么区别?
|| :一旦判断左边是true之后, 右边就不参与运算了 | :不管左边是true还是false, 右边都参与运算
5、三元(三目)运算符:
数据类型 变量名称=条件判断(比较表达式) ? 值1 : 值2;
看比较表达式返回的结果是true还是false
true : 值1;
false : 值2;
int i = 10; int i2 = 20; boolean flag = (i == i2) ? true : false;
6、扫描器:
1、导包。Scanner 类在java.util包下,所以需要将该类导入。导包的语句需要定义在类的上面。
import java.util.Scanner;
2、创建Scanner对象。
Scanner sc = new Scanner(System.in); // 创建Scanner对象,sc表示变量名,其他均不可变
3、接收数据
int i = sc.nextInt(); // 表示将键盘录入的值作为int数返回。
扫描器是一种输入
1)引入扫描器类
import java.util.Scanner;
2)新建扫描器对象
Scanner 对象名=new Scanner(System.in)
3)扫描数据"理解为输入一个数据"
扫描整数
扫描器对象.nextInt();
扫描小数
扫描器对象.nextDouble();
扫描字符串
扫描器对象.next();
package day01;
import java.util.Scanner;
public class t2 {
public static void main(String[] args) {
Scanner t2=new Scanner(System.in);
System.out.println("请输入一个整数");
int x=t2.nextInt();//输入一个整数
System.out.println("扫描的整数为"+x);//输出整数x
}
}
import java.util.Scanner;
public class t8 {
public static void main(String[] args) {
System.out.println("请输入你要判断的车速");
int speed = new Scanner(System.in).nextInt();
//在句尾用alt+shift+l 快速接受变量返回值
if(speed>100&&speed<120) {
System.out.println("超速");
}else if(speed>120) {
System.out.println("警告");
}}}
练习1:
要求:扫描一个字符串,表示商品名称;扫描一个小数,表示商品单价;扫描一个整数,表示商品数量;输出商品总价;再次扫描所付金额,输出找零数目。
import java.util.Scanner;
public class t3 {
public static void main(String[] args) {
Scanner t3=new Scanner(System.in);
String z=t3.next();
System.out.println("商品名称"+z);
double y=t3.nextDouble();
System.out.println("商品单价"+y);
int x=t3.nextInt();
System.out.println("商品数量"+x);
System.out.println("商品总价"+x*y);
double zhichu=t3.nextDouble();
System.out.println("付款总额"+zhichu);
double s=zhichu-x*y;
System.out.println("找零"+s);}}
首先Random是随机生成数用法,介绍一下:
概述:
Random类似Scanner,也是Java提供好的API,内部提供了产生随机数的功能
API后续课程详细讲解,现在可以简单理解为Java已经写好的代码
使用步骤:
1. 导入包 import java.util.Random;
2. 创建对象 Random r = new Random();
3. 产生随机数 int num = r.nextInt(10);
解释: 10代表的是一个范围,如果括号写10,产生的随机数就是0-9,括号写20,参数的随机数则是0- 19
四、方法和结构
4.1 方法method
定义一个方法的格式:
public static void 方法名称() { 方法体 } 如何调用方法,格式: 方法名称();
注意事项:
1.方法定义的先后顺序无所谓
2.方法的定义不能产生嵌套包含关系
3.方法定义好了之后,不会执行的。如果要想执行,一定要进行方法的调用。
public static void main(String[] args) {
cook();
}
public static void cook() {
System.out.println("洗菜");
System.out.println("切菜")
System.out.println("煮菜")
}
4.2 判断语句
1) if(){
}
else
2) switch
switch (表达式) { case 1: 语句体1; break; case 2: 语句体2; break; ... default: 语句体n+1; break; }
执行流程:
首先计算出表达式的值
其次,和case依次比较,一旦有对应的值,就会执行相应的语句,在执行的过程中,遇到break就会结束。
最后,如果所有的case都和表达式的值不匹配,就会执行default语句体部分,然后程序结束掉。
3)for循环
for (初始化语句;条件判断语句;条件控制语句) { 循环体语句; }
格式解释:
初始化语句: 用于表示循环开启时的起始状态,简单说就是循环开始的时候什么样
条件判断语句:用于表示循环反复执行的条件,简单说就是判断循环是否能一直执行下去
循环体语句: 用于表示循环反复执行的内容,简单说就是循环反复执行的事情
条件控制语句:用于表示循环执行中每次变化的内容,简单说就是控制循环是否能执行下去
执行流程:
①执行初始化语句
②执行条件判断语句,看其结果是true还是false
如果是false,循环结束
如果是true,继续执行
③执行循环体语句
④执行条件控制语句
⑤回到②继续
4)while循环
初始化语句; while (条件判断语句) { 循环体语句; 条件控制语句; }
while循环执行流程:
①执行初始化语句
②执行条件判断语句,看其结果是true还是false
如果是false,循环结束
如果是true,继续执行
③执行循环体语句
④执行条件控制语句
⑤回到②继续
初始化语句; do { 循环体语句; 条件控制语句; }while(条件判断语句);
执行流程:
① 执行初始化语句
② 执行循环体语句
③ 执行条件控制语句
④ 执行条件判断语句,看其结果是true还是false
如果是false,循环结束
如果是true,继续执行
⑤ 回到②继续
三种循环的区别
for循环和while循环先判断条件是否成立,然后决定是否执行循环体(先判断后执行)
do...while循环先执行一次循环体,然后判断条件是否成立,是否继续执行循环体(先执行后判断) for循环和while的区别
条件控制语句所控制的自增变量,因为归属for循环的语法结构中,在for循环结束后,就不能再次被访问到了
条件控制语句所控制的自增变量,对于while循环来说不归属其语法结构中,在while循环结束后,该变量还可以继续使用
死循环(无限循环)的三种格式
1. for(;;){}
2. while(true){}
3. do {} while(true);
跳转控制语句(break)
跳出循环,结束循环
跳转控制语句(continue)
跳过本次循环,继续下次循环
注意: continue只能在循环中进行使用!
break两种用法:
1.可以用在switch语句当中,一旦执行,整个switch语句立即结束。
2.还可以用在循环语句当中,一旦执行,整个循环语句立即结束,打断循环。
continue控制语句:一旦执行,立刻跳过当前次循环剩余内容,马上开始下一次循环。
循环的选择:
凡是次数确定的场景多用for循环;否则多用while循环。
注意事项:
1.多个case后面的数值不可以重复。
2.switch后面的小括号当中只能是下列数据类型:
基本数据类型:byte/short/char/int
引用数据类型:String字符串/enum枚举
3.switch语句格式可以很灵活:前后顺序可以颠倒,而且break语句还可以省略
5)死循环:永远停不下。强制停止ctrl+c
死循环标准格式:
while(true){
循环体;
}
注意事项:
总结:
1. print为一般输出,同样不能保留精度格式转化,也不能换行输出
2.printf常用于格式转换,但需要注意不是换行输出,只用于精度转换
3.println为换行输出,不能用于格式转换
/*随机数游戏*/
import java.util.Random;
import java.util.Scanner;
public class Suijishu {
public static void main(String[] args) {
// TODO Auto-generated method stub
Random random = new Random();
int relNumber = random.nextInt(100) + 1;
System.out.println("系统会随机产生一个1至100的整数,请猜出这个数!");
System.out.println("请输入您猜的数字:");
Scanner reader = new Scanner(System.in);
int x = reader.nextInt();
while (x != relNumber) {
if (x > relNumber) {
System.out.println("猜大了,请重新尝试");
x = reader.nextInt();
} else {
System.out.println("猜小了,请重新尝试");
x = reader.nextInt();
}
}
System.out.println("恭喜您,猜对了!");
}
}
五、方法提升
5.1、定义方法完整格式:
修饰符 返回值类型 方法名称(参数类型 参数名称,......){
方法体
return返回值;
}
public static int sum(int a , int b) {
System.out.println("方法执行");
int result=a+b;
return result;
}
修饰符:现阶段固定写法,public static
返回值类型:也就是方法最终产生的数据结果是什么类型
方法名称:方法的名字,规则和变量一样,小驼峰
小驼峰命名规则:第一个单词小写,其他单词首字母大写 写法如:myFirstName 大驼峰命名规则:第一个单词首字母大写,其他单词首字母也大写 写法如:MyFirstName
参数类型:进入方法的数据是什么类型
参数名称:进入方法的数据对应的变量名称
PS:参数如果有多个,是用逗号进行分割
方法体:方法需要做的事情。若干行代码
return:两个作用,第一个是停止当前方法;第二个是将后面的返回值还给调用出
返回值:也就是方法执行后最终产生的数据结果
public class define {
public static void main(String[] args) {
sum(2,3);
System.out.println();
System.out.println(sum(1,3));
}
public static int sum(int a , int b) {
System.out.println("方法执行");
int result=a+b;
return result;
}}
注意:return后面的“返回值”,必须和方法名称前面的“返回值类型”,保持对应
定义一个两个int数字相加的方法。
三要素
{返回值类型:int 方法名称:sum 参数列表:int 啊,int b}
方法的三种调用格式:
1.单独调用:方法名称(参数);
sum(2,3); System.out.println();
2.打印调用:System.out.println(方法名称(参数));
System.out.println(sum(1,3));
3.赋值调用:数据类型 变量名称=方法名称(参数);
int number=sum(1,2);
import java.util.Scanner;
public class t3 {
public static void main(String[] args) {
System.out.println("请输入第一个数字");
int x=new Scanner(System.in).nextInt();
System.out.println("请输入第二个数字");
int y=new Scanner(System.in).nextInt();
System.out.println("请输入运算符");
int q=new Scanner(System.in).nextInt();
if(q==1){
System.out.println(add(x,y));
}else if(q==2){
System.out.println(chengfa(x,y));
}else if(q==3){
System.out.println(jianfa(x,y));
}
}
public static int add(int a,int b) {
int sum=a+b;
return sum;
}
public static int chengfa(int a,int b) {
int cf=a*b;
return cf;
}
public static int jianfa(int a,int b) {
int jf=a-b;
return jf;
}
}
5.2、有参和无参
有参数:小括号当中有内容,当一个方法需要一些数据条件,才能完成任务的时候,就是有参数。
例如:两个数相加相乘需要知道具体参数。
无参数:小括号当中留空。一个方法不需要任何数据条件,自己就能独立完成任务。就是无参。
例如:打印字符。
注意事项:
1.方法应该定义在类当中,但是不能在方法当中再定义方法。不能嵌套。
2.方法定义的前后顺序无所谓。
3.方法定义之后不会执行,如果希望执行,一定要调用:单独调用、打印调用、赋值调用。
4.如果方法有返回值那么必须写上“return 返回值;”不能没有。
5.return后面的返回值数据,必须和方法的返回值类型,对应起来。
6.对于一个void没有返回值,不能写return后面返回值,只能写return自己。
7.对于void方法当中最后一行的return可以省略不写。
8.一个方法当中可以有多个return语句,但是必须保证同时只有一个会被执行到,两个return不能连写。
1. 形参:方法定义中的参数
等同于变量定义格式,例如:int number
public static void getMax(int a, int b)
2. 实参:方法调用中的参数
等同于使用变量或常量,例如: 10 number
int a = 10; int b = 20;
public class MethodTest {
public static void main(String[] args) {
//在main()方法中调用定义好的方法(使用常量)
getMax(10,20);
//调用方法的时候,人家要几个,你就给几个,人家要什么类型的,你就给什么类型的
//getMax(30);
//getMax(10.0,20.0);
//在main()方法中调用定义好的方法(使用变量)
int a = 10;
int b = 20;
getMax(a, b); }
//定义一个方法,用于打印两个数字中的较大数,例如getMax()
//为方法定义两个参数,用于接收两个数字
public static void getMax(int a, int b) {
//使用分支语句分两种情况对两个数字的大小关系进行处理
if(a > b) {
System.out.println(a);
} else {
System.out.println(b); } } }
5.3、方法的重载(overload)
方法重载概念 方法重载指同一个类中定义的多个方法之间的关系,满足下列条件的多个方法相互构成重载
多个方法在同一个类中
多个方法具有相同的方法名
多个方法的参数不相同,类型不同或者数量不同
注意:
重载仅对应方法的定义,与方法的调用无关,调用方式参照标准格式
重载仅针对同一个类中方法的名称与参数进行识别,与返回值无关,换句话说不能通过返回值来判定两个方法是否相互构成重载
多个方法的名称一样,但是参数列表不一样。
好处:只需要记住唯一一个方法名称,就可以实现类似的多个功能。
方法重载与下列因素有关:
1.参数个数不同
2.参数类型不同
3.参数多类型顺序不同
方法重载与下列因素无关:
1.与参数的名称无关
2.与方法的返回值类型无关
方法名称(参数类型(参数列表) 参数名称,......)
public class t13 {
public static void main(String[] args) {
//调用方法
System.out.println(compare(10, 10));
System.out.println(compare((byte) 10, (byte) 20));
System.out.println(compare((short) 10, (short) 20));
System.out.println(compare(10L, 20L));
}
//int
public static boolean compare(int a, int b) {
System.out.println("int:");
return a == b;
}
//byte
public static boolean compare(byte a, byte b) {
System.out.println("byte:");
return a == b;
}
//short
public static boolean compare(short a, short b) {
System.out.println("short:");
return a == b;
}
//long
public static boolean compare(long a, long b) {
System.out.println("long:");
return a == b;
}
}
六、数组
6.1、数组的定义格式
1、数组的概念:是一种容器,可以同时存放多个数据值
2、数组的特点:
1.数组是一种引用数据类型。
2.数组当中的多个数据,类型必须统一。
3.数组的长度在程序运行期间不可改变。
3、数组的初始化:在内存当中创建一个数组,并且向其中赋予一些默认值。
两种常见的初始化方式:
1.动态初始化(指定长度):在创建数组的时候,直接给定数组当中的数据元素个数。
格式:
数据类型【】 数组名称=new 数据类型【数组长度】;
int[] A=new int[300];
//动态创建 int a[]=new int[5]; //静态创建 int b[]=new int[]{1,2,3,4,5,6} ; int b[]={1,2,3,4,5,6};
解析含义:
左侧数据类型:也就是数组当中的保存的数据,全都是统一的什么类型。
左侧的中括号:代表我是一个数组。
左侧数组名称:给数组取一个名字。
右侧的new:代表创建数组的动作。
右侧数据类型:必须和左边的数据类型保持一致。
右侧中括号的长度:也就是数组当中,到底可以保存多少个数据,是一个int数字。
2.静态初始化(指定内容):在创建数组的时候,不直接给定数据个数多少,而是直接将具体的数据内容进行指定。
基本格式:数据类型【】 数组名称=new 数据类型【】{元素1,元素2,。。。。。};
int[] A=new int[]{1,2,3};
省略格式:数据类型【】 数组名称={元素1,元素2,。。。。。};
int[] A={1,2,3};
1)虽然静态初始化没有直接告诉长度,但是根据大括号里面的元素内容,也可以自动推算出来长度。
2)静态初始化标准格式可以拆分成两个步骤。
3)动态初始化也可以拆分成两个步骤。
4)静态初始化一旦使用省略格式,就不能拆分成两个步骤了
使用建议:
如果不确定数组当中的具体内容,用动态初始化,否者,已经确定了具体内容,用静态初始化。
4、数组访问
访问数组的元素的格式:数组名称【索引值】
索引值,就是一个int数字,代表数组当中元素的编号。
注意:索引值从0开始,一直到“数组的长度-1”为止
使用动态初始化数组的时候,其中的元素将会自动拥有一个默认值,规则如下:
如果是整数类型,那么默认为0;
如果是浮点类型,那么默认为0.0;
如果是字符类型,那么默认为"\u0000";
如果是布尔类型,那么默认为false;
如果是引用类型,那么默认为null;
注意事项:静态初始化其实也有默认值的过程,只不过系统自动马上将默认值替换成为大括号当中的具体数值。
6.2、数组的内存图
内存划分为五部分:
1.栈(stack):存放的都是方法中的局部变量。方法的运行一定要在栈当中运行。
局部变量:方法的参数,或者是方法{ }内部变量。
作用域:一旦超出作用域,立刻从栈内存当中消失。
2.堆(heap):凡是new出来的东西,都在堆当中。
堆内存里面的东西都有一个地址值:16进制
堆内存里面的数据,都幽默认值。
规则:
如果是整数类型,那么默认为0;
如果是浮点类型,那么默认为0.0;
如果是字符类型,那么默认为"\u0000";
如果是布尔类型,那么默认为false;
如果是引用类型,那么默认为null;
3.方法区(Method Area):存储 .class相关信息,包含方法的信息。
4.本地方法栈(Native Method Stack):与操作系统相关。
5.寄存器(pc Register):与CPU相关。
寄存器:给CPU使用,和我们开发无关。
本地方法栈:JVM在使用操作系统功能的时候使用,和我们开发无关。
方法区:存储可以运行的class文件。
堆内存:存储对象或者数组,new来创建的,都存储在堆内存。
方法栈:方法运行时使用的内存,比如main方法运行,进入方法栈中执行。
一、单个数组
二、多个数组
三、
6.3、数组异常
数组的索引编号从0开始,一直到“数组的长度为-1”为止。
如果访问数组的元素的时候,索引编号并不存在,那么将会发生数组索引越界异常。
原因:索引编号写错。
解决:修改成为存在的正确索引编号。
所有的引用类型变量,都可以赋值为一个null值。但是代表其中什么都没有。
数组必须进行new 初始化才能使用其中元素。
如果只是赋值了一个null,没有进行new创建。
那么将会发生:空指针异常 NullPointerException
原因:忘了new
解决:补上new
int [] array=null; array=new int[3];
6.4数组运算
1、如何获取数组长度,格式:
数组名称.length
这将会得到一个int数字。代表数组长度。
int[] arr={}; int len=arr.length; System.out.println(len);
数组一旦创建,程序运行期间,长度不可改变。
在Java中,
length方法用于获取数组的长度。
int[] arr = new int[10]; System.out.println(arr.length);
而length()用于获取String字符串中字符的个数。
String str = "HelloJava"; System.out.println(str.length());
//String字符串的方法和String[]的属性的区别
int a[]=new int[]{1,2,3,4,5,7,6,45,54,5};//length属性
System.out.println(a.length);
String b="ABSHJDBG";//length方法
System.out.println(b.length());
2、遍历输出:
说的是对数组当中的每一个元素进行逐一、挨个儿处理。默认的处理方式就是打印输出。
求反数:
从小到大遍历
Arrays.sort(a); //自动遍历:从小到大输出
System.out.println(Arrays.toString(a)); //遍历输出
//从小到大遍历
import java.util.Arrays;
public class t6 {
public static void main(String[] args) {
int a[]={1,2,35,3,23,656,121,45};
Arrays.sort(a);//自动遍历:从小到大输出
System.out.println(Arrays.toString(a));//遍历输出
}
}
方法参数传递引用类型
结论: 对于引用类型的参数,形式参数的改变,影响实际参数的值
结论依据: 引用数据类型的传参,传入的是地址值,内存中会造成两个引用指向同一个内存的效果,所以即使方法 弹栈,堆内存中的数据也已经是改变后的结果
public class t1 {
public static void main(String[] args) {
int[] a={10,20,30};
System.out.println("第一次输出"+a[1]);
change(a);//先到int[] a={10,20,30};再到change(int[] a);最后改变a[1]输出
System.out.println("第二次输出"+a[1]);
}
public static void change(int[] a){
a[1]=200;
}
}
3、java split()的用法:
Java中split主要用于分隔字符串。
具体分析如下:
1、如果用“.”作为分隔的话,必须是如下写法,String.split("\\."),这样才能正确的分隔开,不能用String.split(".")。
2、如果用“|”作为分隔的话,必须是如下写法,String.split("\\|"),这样才能正确的分隔开,不能用String.split("|"),“.”和“|”都是转义字符,必须得加"\\"。
3、如果在一个字符串中有多个分隔符,可以用“|”作为连字符,比如,“acount=? and uu =? or n=?”,把三个都分隔出来,可以用String.split("and|or")。
String a1="12341`1234`5456";
String[] a2=a1.split("\\`");
System.out.println(Arrays.toString(a2));
Java中split使用注意事项:
1.要被分解的String对象或文字,该对象不会被split方法修改。
2.字符串或正则表达式对象,它标识了分隔字符串时使用的是一个还是多个字符。如果忽略该选项,返回包含整个字符串的单一元素数组。
3.该值用来限制返回数组中的元素个数(也就是最多分割成几个数组元素,只有为正数时有影响)。
4.split 方法的结果是一个字符串数组,在 stingObj 中每个出现 separator 的位置都要进行分解。separator不作为任何数组元素的部分返回。
//随机生成数,并输出
import java.util.Arrays;
import java.util.Random;
public class t8 {
public static void main(String[] args) {
int a[]=new int[10];
for(int i=0;i<a.length;i++){
int b=new Random().nextInt(20);//随机生成20以内的10个数
a[i]=b;
}
System.out.println(Arrays.toString(a));
}
}
4、拷贝
拷贝若超过原数组的长度,会出现扩容现象。不够位置用0补齐。
import java.util.Arrays;
public class t7 {
public static void main(String[] args) {
int a[]=new int[]{1,8,9,7,5,6,54,56,8,6,53,34,45,56};
System.out.println(a.length);//数组长度
int[] copyof=Arrays.copyOf(a,14);
System.out.println(Arrays.toString(copyof));//复制数组a到copyof
int[] copyof1=Arrays.copyOf(a,18);//超过原数组的长度,会出现扩容现象。不够位置用0补齐。
System.out.println(Arrays.toString(copyof1));
int[] copyof2=Arrays.copyOf(a,6);//小于原数组的长度复制几位输出几位。
System.out.println(Arrays.toString(copyof2));
}}
5、冒泡排序
冒泡排序是一种比较简单的排序算法,它循环走过需要排序的元素,依次比较相邻的两个元素,如果顺序错误就交换,直至没有元素交换,完成排序。
若对n个人进行排序,我们需要n-1次比较,所以第k次比较需要进行n-k次比较。排序算法通过以数据对象的两两比较作为关键,所以可以得出,冒泡排序需要进行的
比较次数为:(n-1) + (n-2) + … + 1 = n*(n-1) / 2,因此冒泡排序的时间复杂度为O(n^2)
//1.冒泡排序-s--两两比较,大的和小的换位置
let dataList=[12,2,3,46,1,2,8];
let hasSort=[];
//第一遍循环 n-1 次 (n=dataList.length)
for(let i=0;i<dataList.length;i++){
//第二遍循环 n-i-1 次
for(let j=0;j<i;j++){
if(dataList[i]>dataList[j]){
let _data = dataList[i]
dataList[i] = dataList[j]
dataList[j]=_data
}
}
hasSort.push(dataList[i]);
}
console.log("hasSort:"+hasSort)
//1.冒泡排序-end
public static void ArraySortTest() {
int[] ages= {21,27,31,19,50,32,16,25};
System.out.println(Arrays.toString(ages));
//控制比较轮数
for(int i=1;i<ages.length;i++) {
//每轮比较多少
for(int j=0;j<ages.length-i;j++) {
if(ages[j]>ages[j+1]) {
int tmp=0;
tmp=ages[j];
ages[j]=ages[j+1];
ages[j+1]=tmp;
}}}
System.out.println(Arrays.toString(ages));
}
4、传递地址
数组可以作为方法的参数。
当调用方法的时候,向方法的小括号进行传参,传递进去的其实是数组的地址值。
6、值传递和引用传递的区别
1:按值传递是什么
指的是在方法调用时,传递的参数是按值的拷贝传递。
[java] view plain copy
public class TempTest {
private void test1(int a){
//做点事情
}
public static void main(String[] args) {
TempTest t = new TempTest();
int a = 3;
t.test1(a);//这里传递的参数a就是按值传递
}
}
//按值传递重要特点:传递的是值的拷贝,也就是说传递后就互不相关了。
[java] view plain copy
public class TempTest {
private void test1(int a){
a = 5;
System.out.println("test1方法中的a="+a);
}
public static void main(String[] args) {
TempTest t = new TempTest();
int a = 3;
t.test1(a);//传递后,test1方法对变量值的改变不影响这里的a
System.out.println(”main方法中的a=”+a);
}
}
2:按引用传递是什么
指的是在方法调用时,传递的参数是按引用进行传递,其实传递的引用的地址,也就是变量所对应的内存空间的地址。
[java] view plain copy
public class TempTest {
private void test1(A a){
}
public static void main(String[] args) {
TempTest t = new TempTest();
A a = new A();
t.test1(a); //这里传递的参数a就是按引用传递
}
}
class A{
public int age = 0;
}
3:按引用传递的重要特点
传递的是值的引用,也就是说传递前和传递后都指向同一个引用(也就是同一个内存空间)。
[java] view plain copy
public class TempTest {
private void test1(A a){
a.age = 20;
System.out.println("test1方法中的age="+a.age);
}
public static void main(String[] args) {
TempTest t = new TempTest();
A a = new A();
a.age = 10;
t.test1(a);
System.out.println(”main方法中的age=”+a.age);
}
}
class A{
public int age = 0;
}
运行结果如下:
[java] view plain copy
test1方法中的age=20
main方法中的age=20
public class Poker {
public static void main(String[] args) {
//创建一个牌盒,也就是定义一个集合对象用ArrayList集合
ArrayList<String> array=new ArrayList<>();
//往牌盒里面装牌
/* ♦2,♦3,♦4...♦K,♦A
♣2,...
♥2,...
♠2,...
小王,大王
*/
//定义花色数组
String[] colors={"♦", "♣", "♥", "♠"};
//定义点数数组
String[] numbers={"2","3","4","5","6","7","8","9","10","J","Q","K","A"};
for(String color:colors){
for(String number:numbers){
array.add(color+number);
}
}
array.add("大王");
array.add("小王");
//洗牌,也就是把牌打散,用collection的shuffle()方法实现
Collections.shuffle(array);
//发牌。也就是遍历集合,发给三个玩家发牌
ArrayList<String> lqxArray=new ArrayList<String>();
ArrayList<String> lyAArray=new ArrayList<String>();
ArrayList<String> lqyArray=new ArrayList<String>();
ArrayList<String> dpArray=new ArrayList<String>();
for (int i = 0; i < array.size(); i++) {
String poker=array.get(i);
if(i>=array.size()-3){
dpArray.add(poker);
}else if(i%3==0){
lqxArray.add(poker);
} else if (i % 3 == 1) {
lyAArray.add(poker);
} else if (i % 3 == 2) {
lqyArray.add(poker);
}
}
//看牌,也就是三个玩家分别遍历自己的牌
lookPoker("林青霞",lqxArray);
lookPoker("柳岩",lyAArray);
lookPoker("风清扬",lqyArray);
lookPoker("底牌",dpArray);
}
//看牌方法
public static void lookPoker (String name,ArrayList<String> array){
System.out.println(name +"的牌是");
for (String poker:array) {
System.out.println(poker+" ");
}
System.out.println();
}
}
七、面向对象:类
7.1基本概念
1、面向过程:当需要实现一个功能的时候,每一个具体的步骤都要亲力亲为,详细处理每一个细节。
2、面向对象:当需要实现一个功能的时候,不关心具体的步骤,而是找一个已经具有该功能的人,来帮我做事。
面向对象是基于面向过程而言。
三大特点:封装、继承和多态
使用面向对象:找到一个JDK 给我们提供好的Arrays类;其中有一个toString方法,直接就能把数组变成想要的格式的字符串
int[] arr={1,2,5,3,5}; System.out.println(arr.toString(arr));
对象三个特点:对象的状态、对象的行为和对象的标识
类
类的理解
类是对现实生活中一类具有共同属性和行为的事物的抽象
类是对象的数据类型,类是具有相同属性和行为的一组对象的集合
简单理解:类就是对现实事物的一种描述
类的组成
属性:指事物的特征,例如:手机事物(品牌,价格,尺寸)
行为:指事物能执行的操作,例如:手机事物(打电话,发短信)
类和对象的关系
类:类是对现实生活中一类具有共同属性和行为的事物的抽象
对象:是能够看得到摸的着的真实存在的实体
简单理解:类是对事物的一种描述,对象则为具体存在的事物
7.2 类的定义
类的组成是由属性和行为两部分组成
属性:在类中通过成员变量来体现(类中方法外的变量)
行为:在类中通过成员方法来体现(和前面的方法相比去掉static关键字即可)
类的定义步骤:
①定义类
②编写类的成员变量
③编写类的成员方法
public class 类名 { // 成员变量 变量1的数据类型 变量1; 变量2的数据类型 变量2; … // 成员方法 方法1; 方法2; }
package cn.day02.demo01;
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("学习");
}
}
2、对象的创建及使用
通常情况下,一个类并不能直接使用,需要根据类创建一个对象,才能使用。
1.导包:也就是指出需要使用的类,在什么位置。
import 包名称.类名称;
import cn.itcast.day06.demo01.Student;
对于和当前类属于同一个包的情况,可以省略导包语句不写。
2.创建,格式:
类名称 对象名=new 类名称();
Student stu=new Student();
3.使用,分为两种情况;
使用成员变量:对象名.成员变量名
使用成员方法:对象名.成员方法名(参数);
也就是,想用谁,就用对象名点儿谁。
注意事项:如果成员变量没有进行赋值,那么将会有一个默认值,规则和数组一样。
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("学习");
}
}
public class Demo02Stuident {
public static void main(String[] args) {
// 1.导包
// 我需要使用的Student类,和我自己Demo02Stuident位于同一个包下,所以省略导包语句不写.
//
// 2.创建,格式:
// 类名称 对象名=new 类名称();
// 根据Student类,创建了一个名为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=14;
System.out.println(stu.name);//张三
System.out.println(stu.age);//14
System.out.println("============");
//4.使用对象的成员方法,格式:
//对象名.成员方法();
stu.eat();
stu.sleep();
stu.study();
}}
练习手机:
类:
/*
定义一个类,用来模拟“手机”事务。
属性:品牌、价格、颜色
行为:打电话、发短信
对应到类当中:
成员变量(属性):
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对象当中的name成员变量
one.brand="苹果";
one.price=8888557.0;
one.color="黑色";
System.out.println(one.brand);//苹果
System.out.println(one.price);//8888557.0
System.out.println(one.color);//黑色
System.out.println("===========");
//使用对象的成员方法,格式:
//对象名.成员方法();
one.call("乔布斯");
one.sendMessage();
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=4057.0;
two.color="蓝色";
System.out.println(two.brand);//三星
System.out.println(two.price);//4057.0
System.out.println(two.color);//蓝色
one.call("欧巴");
one.sendMessage();
}
}
堆与栈的区别很明显:
1.栈内存存储的是局部变量而堆内存存储的是实体;
2.栈内存的更新速度要快于堆内存,因为局部变量的生命周期很短;
3.栈内存存放的变量生命周期一旦结束就会被释放,而堆内存存放的实体会被垃圾回收机制不定时的回收。
堆:当需要一个对象时,只需用new写一行简单的代码,当执行这行代码时,会自动在堆里进行存储分配。
情况一.1:一个对象的内存图
情况一:两个引用指向同一个方法的内存图
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=4057.0;
two.color="蓝色";
System.out.println(two.brand);//三星
System.out.println(two.price);//4057.0
System.out.println(two.color);//蓝色
one.call("欧巴");
one.sendMessage();
}
}
情况三
使用对象类型作为方法的参数
public class Demo01PhoneTwo {
public static void main(String[] args) {
Phone one=new Phone();
one.brand="苹果";
one.price=8888557.0;
one.color="黑色";
method(one);
}
private static void method(Phone param) {
System.out.println(param.brand);
System.out.println(param.price);
System.out.println(param.color);
}
}
情况四:使用对象类型作为方法的返回值
public class Demo01PhoneThree {
public static void main(String[] args) {
Phone two=getPhone();
System.out.println(two.brand);//苹果
System.out.println(two.price);//545.0
System.out.println(two.color);//金玫瑰
}
private static Phone getPhone() {
Phone one=new Phone();
one.brand="苹果";
one.price=545.0;
one.color="金玫瑰";
return one;
}
}
八、成员变量和局部变量的区别:
类中位置不同:成员变量(类中方法外)局部变量(方法内部或方法声明上)
内存中位置不同:成员变量(堆内存)局部变量(栈内存)
生命周期不同:成员变量(随着对象的存在而存在,随着对象的消失而消失)局部变量(随着方法的调用而 存在,醉着方法的调用完毕而消失)
初始化值不同:成员变量(有默认初始化值)局部变量(没有默认初始化值,必须先定义,赋值才能使用)
1.定义的位置不一样【重点】
局部变量:在方法的内部
成员变量:在方法的外部,直接写在类当中
public class Student {
private String name;//成员变量
private int age;//成员变量
public void method1(){
int num=20;//局部变量
}
}
public class t1 {
//成员变量:类的成员 static静态资源
static int a=10;//10
static int b;//0
static float b1;//0.0
static char b2;//空
static String c;//null
public static void main(String[] args) {
method();
}
private static void method() {
int a=20;//局部变量
//就近原则
System.out.println(a);//20
System.out.println(b);//0
System.out.println(b1);//0.0
System.out.println(b2);//空
System.out.println(c);//null
}
}
2.作用范围不一样【重点】
局部变量:只有方法当中才可以使用,出了方法就不能再用
成员变量:整个类全都可以通用
3.默认值不一样【重点】
局部变量:没有默认值,如果要想使用,必须手动进行赋值
成员变量:如果没有赋值,会有默认值,规则和数组一样
4.内存的位置不一样(了解)
局部变量:位于栈内存
成员变量:位于堆内存
5.生命周期不一样(了解)
局部变量:随着方法进栈而诞生,随着方法出栈而消失(时间短)
成员变量:随着对象创建而诞生,随着对象被垃圾回收而消失(时间长)
public class t1 {
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);
}
}
九、面向对象三大特征
封装、继承、多态
9.1封装
private是一个修饰符,可以用来修饰成员(成员变量,成员方法)
被private修饰的成员,只能在本类进行访问,针对private修饰的成员变量,如果需要被其他类使用,提供相 应的操作
提供“get变量名()”方法,用于获取成员变量的值,方法用public修饰
提供“set变量名(参数)”方法,用于设置成员变量的值,方法用public修饰
对于封装而言,一个对象它所封装的是自己的属性和方法,所以它是不需要依赖其他对象就可以完成自己的操作。使用封装有三大好处:
1、良好的封装能够减少耦合。
2、类内部的结构可以自由修改。
3、可以对成员进行更精确的控制。
4、隐藏信息,实现细节。
在Java中的体现
1.方法就是一种封装
2.关键字private也是一种封装
封装就是将一些细节信息隐藏起来,对外界不可见。
作用:
1)提高安全性
2)提高重用性
练习题1:
public class Demo01 {
public static void main(String[] args) {
int[] array={5,15,25,20,100};
int max=getMax(array);
System.out.println("最大值"+max);
}
//给我一个数组,我还给你一个最大值
private static int getMax(int[] array) {
int max=array[0];
for(int i=1;i<array.length;i++){
if(array[i]>max){
max=array[i];
} }
return max;
}}
练习题2:
/*
问题描述:定义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){//set方法设置值,不需要返回值,需要参数
if (num<100&&num>=9){
age=num;//如果是合理情况
}else{
System.out.println("数据不合理!");
} }
//这个成员方法,专门私语获取age的数据
public int getAge(){//get方法取值,不需要参数,需要返回值
return age;
}
}
public class Demo03Person {
public static void main(String[] args) {
Person person=new Person();
person.show();
person.name="赵丽颖";
//person.age=-20;//直接访问private内容,错误写法!
person.show();
person.setAge(20);
System.out.println();
}
}
private定义学生类
/*
对于基本类型当中的boolean值,Getter方法一定要写成isXxx的形式,而setXxx规则不变。
*/
public class Student {
private String name;//姓名
private int age;//年龄
private boolean male;//是不是爷们
//是不是爷们boolean
public void setMale(boolean b){
male=b;
}
public boolean isMale(){
return male;
}
//姓名
public void setName(String str){
name=str;
}
public String getName(){
return name;
}
//年龄
public void setAge(int num){
age=num;
}
public int getAge(){
return age;
}}
public class Demo01Student {
public static void main(String[] args) {
Student stu=new Student();
stu.setName("鹿晗");
stu.setAge(22);
stu.setMale(true);
System.out.println("姓名:"+stu.getName());
System.out.println("年龄:"+stu.getAge());
System.out.println("是不是爷们儿:"+stu.isMale());
}
}
9.2 this关键字
this修饰的变量用于指代成员变量,其主要作用是(区分局部变量和成员变量的重名问题)
方法的形参如果与成员变量同名,不带this修饰的变量指的是形参,而不是成员变量。
方法的形参没有与成员变量同名,不带this修饰的变量指的是成员变量。
当方法的局部变量和类的成员变量重名的时候,根据”就近原则“,优先使用局部变量。
如果需要访问本类当中的成员变量,需要使用格式
this.成员变量
"通过谁调用的方法,谁就是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();//地址值
}
}
this内存原理【理解】
this代表当前调用方法的引用,哪个对象调用的方法,this就代表哪一个对象
封装思想【理解】
1. 封装概述 是面向对象三大特征之一(封装,继承,多态) 是面向对象编程语言对客观世界的模拟,客观世界 里成员变量都是隐藏在对象内部的,外界是无法直接操作的
2. 封装原则 将类的某些信息隐藏在类内部,不允许外部程序直接访问,而是通过该类提供的方法来实现对隐藏 信息的操作和访问 成员变量private,提供对应的getXxx()/setXxx()方法
3. 封装好处 通过方法来控制成员变量的操作,提高了代码的安全性 把代码用方法进行封装,提高了代码的复用 性
9.3 构造方法和定义一个标准类
构造方法是一种特殊的方法
作用:创建对象 Student stu = new Student();
格式:
public class 类名{
修饰符 类名( 参数 ) { }
}
功能:主要是完成对象数据的初始化
构造方法的创建:
如果没有定义构造方法,系统将给出一个默认的无参数构造方法 如果定义了构造方法,系统将不再提供默认的构造 方法。
构造方法的重载 :
如果自定义了带参构造方法,还要使用无参数构造方法,就必须再写一个无参数构造方法 。
推荐的使用方式 :
无论是否使用,都手工书写无参数构造方法。
重要功能!
可以使用带参构造,为成员变量进行初始化
构造方法是专门用来创建对象的方法,当我们通过关键字new来创建对象时,其实就是在调用构造方法。
格式:
public 类名称(参数类型 参数名称){
方法体
}
注意事项:
1.构造方法的名称必须和所在的类名称完全一样,就连大小写也要一样。
2.构造方法不要写返回值类型,连void都不写。
3.构造方法不能写return一个具体的返回值。
4.如果没有编写任何构造方法,那么编译器将会默认赠送一个构造方法,没有参数、方法体什么事情都不做。
public Student(){}
5.一旦编写至少一个构造方法,那么编译器将不再赠送。
6.构造方法也是可以进行重载的。
重载:方法名称相同,参数列表不同。
/*
构造方法是专门用来创建对象的方法,当我们通过关键字new来创建对象时,其实就是在调用构造方法
格式:
public 类名称(参数类型 参数名称){
方法体
}
注意事项:
1.构造方法的名称必须和所在的类名称完全一样,就连大小写也要一样。
2.构造方法不要写返回值类型,连void都不写。
3.构造方法不能写return一个具体的返回值。
4.如果没有编写任何构造方法,那么编译器将会默认赠送一个构造方法,没有参数、方法体什么事情都不做。
public Student(){}
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 void setName(String name){
this.name=name;
}
public String getName(){
return name;
}
public void setAge(int age){
this.age=age;
}
public int getAge() {
return age;
}
}
public class Demo02Student {
public static void main(String[] args) {
Student stu1=new Student();//无参构造
System.out.println("============");
Student stu2=new Student("赵丽颖",20);//全参构造
System.out.println("姓名:"+stu2.getName()+", 年龄"+stu2.getAge());
//如果需要改变对象当中的成员变量数据内容,仍然还需要使用setXxx方法
stu2.setAge(21);//改变年龄
System.out.println("姓名:"+stu2.getName()+", 年龄"+stu2.getAge());
}
}
练习二:
/*
一个标准的类通常要拥有下面四个组成部分:
1.所有的成员变量都要使用private关键字修饰。
2.为每一个成员变量编写一对儿Getter/Setter方法
3.编写一个无参数的构造方法
4.编写一个全参数的构造方法
这样标准的类也叫做JavaBean
*/
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.setAge(20);
stu1.setName("迪丽热巴");
System.out.println("姓名:"+stu1.getName()+",年龄"+stu1.getAge());
System.out.println("=============");
Student stu2=new Student("张思",23);
System.out.println("姓名:"+stu2.getName()+",年龄"+stu2.getAge());
stu2.setAge(45);
System.out.println("姓名:"+stu2.getName()+",年龄"+stu2.getAge());
}
}
9.4 API标准概述和使用步骤
什么是API API (Application Programming Interface) :应用程序编程接口。
java中的API 指的就是 JDK 中提供的各种功能的 Java类,这些类将底层的实现封装了起来,我们不需要关心这些类是如何 实现的,只需要学习这些类如何使用即可,我们可以通过帮助文档来学习这些API如何使用。
9.5 Scanner
可以实现键盘输入数据,到程序当中
1、Scanner概述及API的使用
Scanner类的功能:可以实现键盘输入数据,到程序当中。
引用类型的一般使用步骤:
1.导包
import 包路径.类名称;
如果需要使用的目标类,和当前类位于同一个包下,则可以省略导包语句不写。
如果java.long包下的内容不需要导包,其他的包都需要import语句。
2.创建
类名称 对象名=new 类名称();
3.使用
对象名.成员方法名();
2、Scanner使用步骤
/*
获取键盘输入的一个int数字:int num=sc.nextInt();
获取键盘输入的一个字符串:String str=sc.next();
*/
//1.导包
import java.util.Scanner;
public class Demo01Scanner {
public static void main(String[] args) {
// 2.创建:备注:System.in代表从键盘进行输入
// 类名称 对象名=new 类名称();
Scanner sc=new Scanner(System.in);
//3.获取键盘输入的一个int数字:
int num=sc.nextInt();
System.out.println("输入的int数字:"+num);
//4.获取键盘输入的一个字符串
String str=sc.next();
System.out.println("输入的字符串是:"+str);
}
}
3、Scanner练习
习题一:
/*
题目:键盘输入两个数,并求出和值。
思路:
1.既然需要键盘输入,那么就用Scanner
2.Scanner的三个步骤:导包、创建、使用
3.需要的是两个数字,所以要调用两次nextInt方法
4.得到两个数字,就需要加在一起
5.将结果打印输出
*/
import java.util.Scanner;
public class Demo03Scanner {
public static void main(String[] args) {
System.out.println("输入第一个数:");
//Scanner sc=new Scanner(System.in);
//int x=sc.nextInt();
int x=new Scanner(System.in).nextInt();
System.out.println("输入第二个数:");
//int y=sc.nextInt();
int y=new Scanner(System.in).nextInt();
int sum=x+y;
System.out.println("求和:"+sum);
}
}
习题二:
/*
题目:键盘输入三个int数字,然后求出其中的最大值。
思路:
1.既然是键盘输入,肯定需要用到Scanner
2.Scanner三个步骤:导包、创建、使用nextInt()方法
3.既然是三个数字,那么调用三次nextInt()方法,得到三个int变量
4.无法同时判断三个数字谁最大,应该转换成为两个步骤
4.1首先判断前两个当中谁最大,拿到前两个的最大值
4.2拿着当前两个中的最大值,再和第三个数字比较,得到三个数字当中的人最大值
5.打印最终结果
*/
public class Demo02Scannersum {
public static void main(String[] args) {
System.out.println("输入第一个数字");
int x=new Scanner(System.in).nextInt();
System.out.println("输入第二个数字");
int y=new Scanner(System.in).nextInt();
System.out.println("输入第三个数字");
int z=new Scanner(System.in).nextInt();
int t=x>y?x:y;
int max=t>z?t:z;
System.out.println("最大值:"+max);
}
}
4、匿名对象的说明
public class Person {
String name;
public void showName() {
System.out.println("我叫:" + name);
}}
/*
创建对象的标准格式:
类名称 对象名=new 类名称();
匿名对象就是只有右边的对象,没有左边的名字和赋值运算符。
new 类名称();
注意事项:匿名对象只能使用唯一的一次下次再用不得不再创建一个新对象。
使用建议:如果确定有一个对象只需要使用唯一的一次,就可以用匿名对象。
*/
public class Demo01Anonymous {
public static void main(String[] args) {
//类名称 对象名=new 类名称();
Person one=new Person();
one.name="高圆圆";
System.out.println(one.name);
one.showName();//我叫:高圆圆
//匿名对象
new Person().name="赵又廷";
new Person().showName();//?我叫null
}
}
5、匿名对象作为方法的参数和返回值
public class Demo02Anonymous {
public static void main(String[] args) {
System.out.println("请输入数字:");
//普通使用方式
//int sc=new Scanner(System.in).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=methodReturn();
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 methodReturn(){
//Scanner sc=new Scanner(System.in);
// return sc;
return new Scanner(System.in);
}
}
9.6 Random
1、Random的概述和基本使用和生成指定范围的随机数
Random类用来生成随机数字。使用起来也是三个步骤:
1.导包
import java.util.Random;
2.创建
Random r=new Random();//小括号当中留空即可
3.使用
获取一个随机的int数字(范围是int所有范围,有正负两种),int num=r.nextInt();
获取一个随机的int数字(参数代表了范围,左闭右开区间),int num=r.nextInt(10);
实际上代表的含义是:[0,10) 0-9
public class Demo01Random {
public static void main(String[] args) {
Random r=new Random();
int num=r.nextInt();//范围是int所有范围,有正负两种
int num1=new Random().nextInt(10);//范围在10以内
System.out.println("生成随机数:"+num);
System.out.println("生成随机数:"+num1);
System.out.println("================");
Random r1=new Random();
int index=0;
for(int i=0;i<20;i++){
int n=r1.nextInt(5);//范围实际上是:0-4
System.out.print(" "+n);
}
}
}
练习一:生成1-n的随机数
/*
题目要求:
根据int变量n的值,来获取随机数字,范围是[1,n],可以取到1也可以取到n.
思路:
1.定义一个int变量n,随意赋值。
2.要使用Random:三个步骤:导包,创建,使用
3.如果写10,那么就是0~9,然而想要的是1~10,可以发现:整体+1即可
4.打印随机数字
*/
public class Demo02Random {
public static void main(String[] args) {
int n=5;
Random r=new Random();
for(int i=0;i<100;i++){
int result=r.nextInt(n)+1; //本来范围是[0,n],整体+1之后变成[1,n+1],也就是[1,n]
System.out.println(result);
}
}
}
练习二:
/*
题目:
用代码模拟猜数字的小游戏。
思路:
1.首先需要产生一个随机数,并且一旦产生不在变化。用Random的nextInt方法
2.需要键盘输入,所以用到了Scanner
3.获取键盘输入的数字,用Scanner当中的nextInt方法
4.已经得到两个数字,判断(if)一下
如果太大了,提示太大,并重试;
如果太小了,提示太小,并重试;
如果猜中了,游戏结束
5.重试就是再来一次,循环次数不确定用while(true)
*/
import java.util.Random;
import java.util.Scanner;
public class Demo03Random {
public static void main(String[] args) {
int r = new Random().nextInt(100) + 1;//[1,100]
while (true) {
System.out.println("输入数字:");
int x = new Scanner(System.in).nextInt();
if (x > r) {
System.out.println("猜大了");
} else if(x<r){
System.out.println("猜小了");
}else{
System.out.println("恭喜猜对了");
break;
}
}
System.out.println("结束");
}
}
快捷键添加构造方法和get、set方法:将光标放到成员变量,按下快捷键Alt+Insert
9.7 ArrayList
什么是集合:
提供一种存储空间可变的存储模型,存储的数据容量可以发生改变。
ArrayList集合的特点
底层是数组实现的,长度可以变化 。
泛型的使用
用于约束集合中存储元素的数据类型。
1、ArrayList集合概述和基本使用
数组的长度不可以发生改变。
但是ArrayList集合的长度是可以随意变化的。
对于ArrayList来说,有一个尖括号<E>代表泛型。
泛型:也就是装在集合当中的所有元素,全都是统一的什么类型。
注意:泛型只能是引用类型,不能是基本类型。
注意事项:
对于ArrayList集合来说,直接打印得到的不是地址值,而是内容。
如果内容是空,得到的是空的中括号:[]
public class arraylist01 {
public static void main(String[] args) {
//创建了一个ArrayList集合,集合的名称是list,里面装的全都是String字符串类型的数据
//备注:从JDK1.7+开始,右边的尖括号内部可以不写内容,但是<>本身还是要写的。
ArrayList<String> list=new ArrayList<>();
System.out.println(list);//[]
//向集合当中添加一些数据,需要用到add方法。
list.add("赵丽颖");
System.out.println(list);//[赵丽颖]
list.add("赵四");
list.add("张翰");
list.add("刘坤");
System.out.println(list);//[赵丽颖, 赵四, 张翰, 刘坤]
//指定位置插入
list.add(2,"张宏里");
System.out.println(list);//[赵丽颖, 赵四, 张宏里, 张翰, 刘坤]
}
}
2、ArrayList集合的常用方法和遍历
1.ArrayList常用方法有
public boolean add(E e):向集合当中添加元素,参数的类型和泛型一致。
public E get (int index):从集合当中获取元素,参数是索引编号”下标从0开始“,返回值就是对应位置的元素。
public E remove(int index):从集合当中删除元素,参数是索引编号,返回值就是被删除掉的元素。
public int size():获取集合的尺寸长度,返回值是集合中包含的元素个数。
public class arraylist02 {
public static void main(String[] args) {
ArrayList<String> list=new ArrayList<>();
System.out.println(list);//[]
//1.向集合中添加元素:add
boolean success= list.add("柳岩");
System.out.println(list);//[柳岩]
System.out.println("添加的动作成功:"+success);//true
list.add("张氏");
list.add("胡歌");
list.add("张绍云");
System.out.println(list);//[柳岩, 张氏, 胡歌, 张绍云]
//2.从集合中获取元素:get。索引值从0开始
String name=list.get(2);
System.out.println("第2号索引位置:"+name);//胡歌
//3.从集合中删除元素:remove。索引值从0开始
String whoRemove=list.remove(3);
System.out.println("被删除的人是:"+whoRemove);//张绍云
System.out.println(list);//[柳岩, 张氏, 胡歌]
//4.获取集合的长度尺寸,也就是其中元素的个数
int size= list.size();
System.out.println("集合的长度是:"+size);//3
}
}
2.遍历:遍历{快捷键:list.fori}
public class arraylist03 {
public static void main(String[] args) {
ArrayList<String> list=new ArrayList<>();
list.add("赵丽颖");
list.add("胡歌");
list.add("张三");
list.add("刘涛");
list.add("刘四");
//遍历{快捷键:list.fori}
for (int i = 0; i < list.size(); i++) {
System.out.println(list.get(i));
//遍历集合通用格式
// String s=list.get(i);
// System.out.println(s);
}
}
}
3、ArrayList集合存储基本数据类型
/*
如果希望向集合ArrayList当中存储基本类型数据,必须使用基本类型对应的”包装类“。
基本类型 包装类(引用类型,包装类都位于java.long包下)
int Integer
char Character
byte Byte
short Short
long Long
float Float
double Double
boolean Boolean
从JDK1.5+开始,支持自动装箱、自动拆箱
自动装箱:基本类型---->包装类型
自动拆箱:包装类型---->基本类型
*/
public class arraylist04 {
public static void main(String[] args) {
ArrayList<String> listA=new ArrayList<>();
//错误写法!泛型只能是引用类型,不能是基本类型
//ArrayList<int> listB=new ArrayList<>();
ArrayList<Integer> listC=new ArrayList<>();
//向集合中添加元素:add
listC.add(100);
listC.add(200);
System.out.println(listC);//[100, 200]
//从集合中获取元素:get。索引值从0开始
int num=listC.get(1);
System.out.println("第一个元素是:"+num);//200
}
}
4、练习
练习一:存储随机数
/*
题目:
生成6个1~33之间的随机数,添加到集合,并遍历集合
思路:
1.需要存储6个数字,创建一个集合,<Integer>
2.产生随机数,需要用到Random
3.用循环6次,来产生6个随机数字:for循环
4.循环内调用r.nextInt(int n),参数是33,0~32,整体+1才是1~33
5.把数字添加集合中:add
6.遍历集合:for、size、get
*/
public class arraylist05 {
public static void main(String[] args) {
ArrayList<Integer> list=new ArrayList<>();
//获得随机数
for (int i = 0; i < 6; i++) {
int r=new Random().nextInt(33)+1;
list.add(r);
}
//遍历集合
for (int i = 0; i < list.size(); i++) {
System.out.println(list.get(i));
}
}
}
练习二:存储自定义对象
/*
题目:
自定义4个学生对象,添加到集合,并遍历
思路:
1.自定义Student学生类,四个部分。
2.创建一个集合,用来存储学生对象。泛型:<Student>
3.将4个学生对象添加到集合中:add
4.遍历集合:for、size、get
*/
public class arraylist07 {
public static void main(String[] args) {
ArrayList<Student> list=new ArrayList<>();
Student one=new Student("张翰",32);
Student two=new Student("郭靖",66);
Student three=new Student("张国立",72);
Student four=new Student("胡歌",32);
list.add(one);
list.add(two);
list.add(three);
list.add(four);
//遍历集合
for (int i = 0; i < list.size(); i++) {
//System.out.println(list.get(i));
Student stu=list.get(i);
System.out.println("姓名:"+stu.getName()+",龄:"+stu.getAge());
}
}
}
public class Student {
private String name;
private int age;
//无参构造
public Student() {
}
//全参构造
public Student(String name, int age) {
this.name = name;
this.age = age;
}
public void setName(String name) {
this.name = name;
}
public String getName() {
return name;
}
public void setAge(int age) {
this.age = age;
}
public int getAge() {
return age;
}
}
练习三:按指定格式遍历集合字符串
/*
题目:
定义以指定格式打印集合的方法(Arraylist类型作为参数),使用{}括起来集合,使用@分隔每个元素。
格式参照{元素@元素@元素}。
System.out.println(list); [10,20,30]
printArraylist(list); {10,20,30}
*/
public class arraylist06 {
public static void main(String[] args) {
ArrayList<String> list=new ArrayList<>();
list.add("张三丰");
list.add("张无忌");
list.add("张翠山");
list.add("张晓明");
System.out.println(list);
printArraylist(list);
}
/*
定义方法的三要素:
返回值类型:只是进行打印而已,没有运算,没有结果,所以用viod
方法名称:printArraylist
参数列表:ArrayList
*/
public static void printArraylist(ArrayList<String> list){
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个随机数字,然后筛选其中的偶数元素,放到小集合当中
要求使用自定义的方法来实现筛选。
分析:
1.需要创建一个大集合,用来存储int数字:<Integer>
2.随机数就用Random nextInt
3.循环20次,把随机数字放入大集合:forx循环、add方法
4.定义一个方法,用来筛选符合要求的元素,得到小集合
筛选:根据大集合,筛选符合要求的元素,得到小集合。
三要素:
返回值类型:ArrayList小集合(里面元素个数不确定)
方法名称:getSmallList
参数列表:ArrayList大集合(装20个随机数字)
5.判断(if)是偶数:num%2==0
6.如果是偶数,就放到小集合当中。否则不放
*/
public class return01 {
public static void main(String[] args) {
//创建了一个ArrayList集合,集合的名称是biglist,里面装的全都是int型数据
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;
}
}
十、字符串String
1、charAt(int index):返回指定索引处的 char 值。
2、indexOf(String ch):返回指定字符在此字符串中第一次出现处的索引。
3、isEmpty():当且仅当 length() 为 0 时返回 true。
4、lastIndexOf(String ch):返回指定字符在此字符串中最后一次出现处的索引。
5、length():返回此字符串的长度。
6、replace(char oldChar, char newChar):返回一个新的字符串,它是通过用 newChar 替换此字符串中出现的所有 oldChar 得到的。
7、split(String regex, int limit):根据匹配给定的正则表达式来拆分此字符串。
8、startsWith(String prefix):测试此字符串是否以指定的前缀开始。
9、toLowerCase():使用默认语言环境的规则将此 String 中的所有字符都转换为小写。
10、String toUpperCase():使用默认语言环境的规则将此 String 中的所有字符都转换为大写。
11、contains(CharSequence s):当且仅当此字符串包含指定的 char 值序列时,返回 true。
10.1 字符串构造方法和直接创建
构造方法:
public String() 创建一个空白字符串对象,不含有任何内容
public String(char[] chs) 根据字符数组的内容,来创建字符串对象
public String(byte[] bys) 根据字节数组的内容,来创建字符串对象
String s = “abc”; 直接赋值的方式创建字符串对象,内容就是abc
public class t1 {
public static void main(String[] args) {
//public String():创建一个空白字符串对象,不含有任何内容
String s1=new String();
System.out.println("s1:"+s1);//
//public String(char[] chs):根据字符数组的内容,来创建字符串对象
char[] chs={'a','b','c'};
String s2=new String(chs);
System.out.println("s2:"+s2);//abc
//public String(byte[] bys):根据字节数组的内容,来创建字符串对象
byte[] bys={97,98,99};
String s3=new String(bys);
System.out.println("s3:"+s3);//abc
//String s = “abc”; 直接赋值的方式创建字符串对象,内容就是abc
String s4="abc";
System.out.println("s4:"+s4);//abc
}
}
10.2 字符串常量池
通过构造方法创建 :String s3=new String(类型);
通过 new 创建的字符串对象,每一次 new 都会申请一个内存空间,虽然内容相同,但是地址值不同直接赋值方式创建 : String s4="abc";
以“”方式给出的字符串,只要字符序列相同(顺序和大小写),无论在程序代码中出现几次,JVM 都只会建立一 个 String 对象,并在字符串池中维护
10.3 字符串方法
public StringBuilder append (任意类型) 添加数据,并返回对象本身。
public StringBuilder reverse() 返回相反的字符序列。
public int length() 返回长度,实际存储值。
public String toString() 通过toString()就可以实现把StringBuilder转换为String。
1、比较相关法
= =号的作用:
比较基本数据类型:比较的是具体的值
比较引用数据类型:比较的是对象地址值
方法介绍:比较两个字符串内容是否相同、区分大小写
public boolean equals(String s) 比较两个字符串内容是否相同、区分大小写
public boolean equals(Object anObject):将此字符串与指定对象进行比较。由于我们比较的是字符串对象,所以参数直接传递一个字符串
public class t2 {
public static void main(String[] args) {
//构造方法的方式得到对象
char[] chs={'a','b','c'};
String s1=new String(chs);
String s2=new String(chs);
System.out.println(s1);//abc
System.out.println(s2);//abc
System.out.println("===========");
//直接赋值的方式得到对象
String s3="abc";
String s4="abc";
//比较字符串对象【地址】是否相同
System.out.println(s1==s2);//false
System.out.println(s1==s3);//false
System.out.println(s3==s4);//true
System.out.println("===========");
//比较字符串【内容】是否相同
System.out.println(s1.equals(s2));//true
System.out.println(s1.equals(s3));//true
System.out.println(s1.equals(s4));//true
}
}
练习
public class t3 {
public static void main(String[] args) {
//已知用户名和密码,定义两个字符串表示即可
String username = "heima";
String password = "1234";
//用循环实现多次机会,这里的次数明确,
// 采用for循环实现,并在登录成功的时候,使用break结束循环
for (int i = 0; i < 3; i++) {
//键盘录入要登录的用户名和密码,用 Scanner 实现
Scanner sc=new Scanner(System.in);
System.out.println("输入用户名:");
String name=sc.nextLine();
System.out.println("输入密码:");
String pwd=sc.nextLine();
//拿键盘录入的用户名、密码和已知的用户名、密码进行比较,给出相应的提示。
// 字符串的内容比较,用equals() 方法实现
if (name.equals(username)&&pwd.equals(password)){
System.out.println("登陆成功");
break;
}else{
if(2-i==0){
System.out.println("密码被锁定,请联系管理员解锁");
}else{
System.out.println("登陆失败,还有"+(2-i)+"次机会");
} } } }}
charAt(int index)方法是一个能够用来检索特定索引下的字符的String实例的方法.
charAt()方法返回指定索引位置的char值。索引范围为0~length()-1.
执行自动类型转换需要两个条件:
1、两种类型是兼容的,比如所有的数字类型都是兼容的,而数字类型和布尔类型是不兼容的
2、目的类型的范围比源类型的大。如:从int类型向float类型转换可以自动实现,反之则需要进行强制类型转换。
所谓强制类型转换实际上只是一种显示类型的转换
2、获取相关法
charAt(int index)方法是一个能够用来检索特定索引下的字符的String实例的方法.
charAt()方法返回指定索引位置的char值。索引范围为0~length()-1.
/*
思路:
1:定义一个 int 类型的数组,用静态初始化完成数组元素的初始化
2:定义一个方法,用于把 int 数组中的数据按照指定格式拼接成一个字符串返回。
返回值类型 String,参数列表 int[] arr
3:在方法中遍历数组,按照要求进行拼接
4:调用方法,用一个变量接收结果
5:输出结果
*/
public class t6 {
public static void main(String[] args) {
//定义一个 int 类型的数组,用静态初始化完成数组元素的初始化
int[] a={1,2,3,4};
//调用方法,用一个变量接收结果
String s=array(a);
//输出结果
System.out.println("s:"+s);
}
//定义一个方法,用于把 int 数组中的数据按照指定格式拼接成一个字符串返回
/*
两个明确:
返回值类型:String
参数:int[] arr
*/
private static String array(int[] a) {
//在方法中遍历数组,按照要求进行拼接
String s=" ";
s=s+"[";
for (int i = 0; i < a.length; i++) {
if (i==a.length-1){
s=s+a[i];
} else{
s+=a[i];
s+=",";
}
}
s=s+"]";
return s;
}
}
3、截取相关法
subString(int index):截取从参数位置一直到字符串末尾,返回新字符串。
/*
字符串的截取方法:
public String subString(int index):截取从参数位置一直到字符串末尾,返回新字符串。
public String subString(int index,int end):截取从begin开始,一直到end结束,中间的字符串。
备注:
[index,end),包含左边,不包含右边。
*/
public class t3 {
public static void main(String[] args) {
String str1="HelloWord";
String str2=str1.substring(5);
System.out.println(str1);//HelloWord
System.out.println(str2);//Word
System.out.println("===========");
//下面这种写法,字符串的内容仍然是没有改变的
//下面有两个字符串:"hello" "java"
//str中保存的是地址值
//本来地址值是hello中的地址0x66
//后来地址值变成了0x999
String strA= "hello" ;
System.out.println(strA);//hello
strA="java";
System.out.println(strA);//java
}
}
4、转换相关法
/*
String 当中与转换相关的常用方法
public char[] toCharArray():将当前字符串拆分成为字符数组作为返回值。
public byte[] getBytes():获得当前字符串底层的字节数组。
public String[] replace(CharSequence oldString,CharSequence newString);
将所有出现的老字符串替换成新的字符串,返回替换之后的结果新字符串。
备注:CharSequence意思就是说可以接受字符串类型
*/
public class t4 {
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*
String lang1 = "会不会玩,会不会玩,你大爷的!你大爷的!";
String lang2=lang1.replace("你大爷的","****");
System.out.println(lang2);//会不会玩,会不会玩,****!****!
//System.out.println(lang1);
}
}
/*
思路:
1:键盘录入一个字符串,用 Scanner 实现
2:定义一个方法,实现字符串反转。返回值类型 String,参数 String s
3:在方法中把字符串倒着遍历,然后把每一个得到的字符拼接成一个字符串并返回
4:调用方法,用一个变量接收结果
5:输出结果
*/
import java.util.Scanner;
public class t1 {
public static void main(String[] args) {
//键盘录入一个字符串,用 Scanner 实现
System.out.println("请输入你要输入的数字:");
String line=new Scanner(System.in).nextLine();
//调用方法,用一个变量接收结果
String s=reverse(line);
//输出结果
System.out.println("s:"+s);
}
//定义一个方法,实现字符串反转
/*
两个明确:
返回值类型:String
参数:String s
*/
private static String reverse(String s) {
//在方法中把字符串倒着遍历,然后把每一个得到的字符拼接成一个字符串并返回
String ss=" ";
for (int i=s.length()-1;i>=0; i--) {
ss=ss+s.charAt(i);
}
return ss;
}
}
public boolean equals(Object anObject) 比较字符串的内容,严格区分大小写(用户名和密码)
public char charAt(int index) 返回指定索引处的 char 值
public int length() 返回此字符串的长度
StringBuilder 是一个可变的字符串类,我们可以把它看成是一个容器,这里的可变指的是 StringBuilder 对象中的 内容是可变的。
String类:内容是不可变的
StringBuilder类:内容是可变的
public StringBuilder() 创建一个空白可变字符串对象,不含有任何内容
public StringBuilder(String str) 根据字符串的内容,来创建可变字符串对象
5、分割相关法
/*
分割字符串的方法:
public String[] split(String regex):按照参数的规则,将字符串分割成为若干部份。
注意事项:
split方法的参数其实是一个正则表达式,今后学习。
今天要注意:如果按照英文据点“.”进行分割,必须写“\\.”
*/
public class t5 {
public static void main(String[] args) {
String str1="aaa,bbbb,ssss";
String[] array1=str1.split(",");
for (int i = 0; i <array1.length ; i++) {
System.out.println(array1[i]);
}
System.out.println("============");
String str2="aaaaa aaaa ssssss";
String[] array2=str2.split(" ");
for (int i = 0; i < array2.length; i++) {
System.out.println(array2[i]);
}
System.out.println("============");
String str3="aaaaa.aaaa.ssssss";
String[] array3=str3.split("\\.");
for (int i = 0; i < array3.length; i++) {
System.out.println(array3[i]);
}
}
}
StringBuilder类
public StringBuilder append (任意类型) 添加数据,并返回对象本身
public StringBuilder reverse() 返回相反的字符序列
public int length() 返回长度,实际存储值
public String toString() 通过toString()就可以实现把StringBuilder转换为String
StringBuilder 是一个可变的字符串类,我们可以把它看成是一个容器,这里的可变指的是 StringBuilder 对象中的 内容是可变的。
常用的构造方法
public StringBuilder(): 创建一个空白可变字符串对象,不含有任何内容
public StringBuilder(String str) :根据字符串的内容,来创建可变字符串对象
public class StringBuilderDemo01 {
public static void main(String[] args) {
//public StringBuilder():创建一个空白可变字符串对象,不含有任何内容
StringBuilder sb = new StringBuilder();
System.out.println("sb:" + sb);
System.out.println("sb.length():" + sb.length());
//public StringBuilder(String str):根据字符串的内容,来创建可变字符串对象
StringBuilder sb2 = new StringBuilder("hello");
System.out.println("sb2:" + sb2);
System.out.println("sb2.length():" + sb2.length());
}
}
StringBuilder类添加和反转方法
添加和反转方法
public StringBuilder append(任意类型): 添加数据,并返回对象本身
public StringBuilder reverse() :返回相反的字符序列
public class StringBuilderDemo01 {
public static void main(String[] args) {
//创建对象
StringBuilder sb = new StringBuilder();
//public StringBuilder append(任意类型):添加数据,并返回对象本身
// StringBuilder sb2 = sb.append("hello");
//
// System.out.println("sb:" + sb);
// System.out.println("sb2:" + sb2);
// System.out.println(sb == sb2);
// sb.append("hello");
// sb.append("world");
// sb.append("java");
// sb.append(100);
//链式编程
sb.append("hello").append("world").append("java").append(100);
System.out.println("sb:" + sb);
//public StringBuilder reverse():返回相反的字符序列
sb.reverse();
System.out.println("sb:" + sb);
}
}
StringBuilder和String相互转换
StringBuilder转换为String
public String toString():通过 toString() 就可以实现把 StringBuilder 转换为 String
String转换为StringBuilder
public StringBuilder(String s):通过构造方法就可以实现把 String 转换为 StringBuilder
public class StringBuilderDemo02 {
public static void main(String[] args) {
/*
//StringBuilder 转换为 String
StringBuilder sb = new StringBuilder();
sb.append("hello");
//String s = sb; //这个是错误的做法
//public String toString():通过 toString() 就可以实现把 StringBuilder 转换为
String
String s = sb.toString();
System.out.println(s);
*/
//String 转换为 StringBuilder
String s = "hello";
//StringBuilder sb = s; //这个是错误的做法
//public StringBuilder(String s):通过构造方法就可以实现把 String 转换为StringBuilder
StringBuilder sb = new StringBuilder(s);
System.out.println(sb);
}
}
字符串拼接升级版案例
/*
思路:
1:定义一个 int 类型的数组,用静态初始化完成数组元素的初始化
2:定义一个方法,用于把 int 数组中的数据按照指定格式拼接成一个字符串返回。
返回值类型 String,参数列表 int[] arr
3:在方法中用 StringBuilder 按照要求进行拼接,并把结果转成 String 返回
4:调用方法,用一个变量接收结果
5:输出结果
*/
public class StringBuilderTest01 {
public static void main(String[] args) {
//定义一个 int 类型的数组,用静态初始化完成数组元素的初始化
int[] arr = {1, 2, 3};
//调用方法,用一个变量接收结果
String s = arrayToString(arr);
//输出结果
System.out.println("s:" + s);
}
//定义一个方法,用于把 int 数组中的数据按照指定格式拼接成一个字符串返回
/*
两个明确:
返回值类型:String
参数:int[] arr
*/
public static String arrayToString(int[] arr) {
//在方法中用 StringBuilder 按照要求进行拼接,并把结果转成 String 返回
StringBuilder sb = new StringBuilder();
sb.append("[");
for(int i=0; i<arr.length; i++) {
if(i == arr.length-1) {
sb.append(arr[i]);
} else {
sb.append(arr[i]).append(", ");
}
}
sb.append("]");
String s = sb.toString();
return s;
}
}
定义一个方法,实现字符串反转。键盘录入一个字符串,调用该方法后,在控制台输出结果 例如,键盘录入abc,输出结果 cba
/*
思路:
1:键盘录入一个字符串,用 Scanner 实现
2:定义一个方法,实现字符串反转。返回值类型 String,参数 String s
3:在方法中用StringBuilder实现字符串的反转,并把结果转成String返回
4:调用方法,用一个变量接收结果
5:输出结果
*/
public class StringBuilderTest02 {
public static void main(String[] args) {
//键盘录入一个字符串,用 Scanner 实现
Scanner sc = new Scanner(System.in);
System.out.println("请输入一个字符串:");
String line = sc.nextLine();
//调用方法,用一个变量接收结果
String s = myReverse(line);
//输出结果
System.out.println("s:" + s);
}
//定义一个方法,实现字符串反转。返回值类型 String,参数 String s
/*
两个明确:
返回值类型:String
参数:String s
*/
public static String myReverse(String s) {
//在方法中用StringBuilder实现字符串的反转,并把结果转成String返回
//String --- StringBuilder --- reverse() --- String
// StringBuilder sb = new StringBuilder(s);
// sb.reverse();
// String ss = sb.toString();
// return ss;
return new StringBuilder(s).reverse().toString();
}
}
10.4 静态static
1、静态static关键字修饰成员变量
public class Student {
private int id;
private String name;
private int age;
static String room ;
private static int idCounter=0;//学号计数器,每当new了一个新对象的时候,计数器++
public Student() {
idCounter++;
}
public Student(int id) {
this.id = id;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public Student(String name, int age) {
this.name = name;
this.age = age;
this.id=++idCounter;
}
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;
}
}
/*
如果一个变量使用了static关键字,那么这个变量不在属于对象自己,而是属于所在的类。多个对象共享同一份数据
*/
public class Demo01Static {
public static void main(String[] args) {
Student two=new Student("黄蓉",16);
two.room="001教室";
System.out.println("姓名:"+two.getName()+",学号:"+two.getId()
+",年龄:"+two.getAge()+", 教室:"+two.room);
Student one=new Student("郭靖",18);
System.out.println("姓名:"+one.getName()+",学号:"+one.getId()
+",年龄:"+one.getAge()+", 教室:"+one.room);
// Student two=new Student("黄蓉",16);
// two.room="001教室";
// System.out.println("姓名:"+two.getName()+",学号:"+two.getId()
// +",年龄:"+two.getAge()+", 教室:"+two.room);
}
}
2、静态static关键字修饰成员方法
/*
一旦使用static修饰成员方法,那么这就成为了静态方法。静态方法不属于对象,而是属于类的。
如果没有static关键字,那么必须首先创建对象,然后通过对象才能使用它。
如果有static关键字,那么不需要创建对象,直接就能通过类名称来使用它。
无论是成员变量,还是成员方法。如果有了static,都推荐按使用类名称进行调用。
静态变量:类名称.静态变量
静态方法:类名称.静态方法()
注意事项:
1.静态不能直接访问非静态。
原因:因为在内存中是【先】有的静态内容,【后】有的非静态内容
”先人不知道后人,但是后人知道先人“
2.静态方法当中不能用this
原因:this代表当前对象,通过谁调用的方法,谁就是当前对象
*/
public class Demo02myclass {
public static void main(String[] args) {
MyClass obj=new MyClass();//创建对象
//然后才能使用没有static关键字的内容
obj.method();
//对于静态方法来说,可以通过对象名进行调用,,也可以直接通过类名称来调用
obj.methodStatic();//正确,不推荐
MyClass.methodStatic();//正确,推荐
//对于本来当中的静态方法,可以省略类名称
myMethod();
Demo02myclass.myMethod();//完全等效
}
private static void myMethod() {
System.out.println("自己的方法");
}
}
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 类名称{
static{
//静态代码块的内容
}
}
特点:当第一次用到本类是,静态代码块执行唯一的一次
静态内容总是优先于非静态,所以静态代码块比构造方法先执行.
静态代码块典型用途:
用来一次性地对非静态变量赋值。
*/
public class t6 {
public static void main(String[] args) {
Person one =new Person();
Person two =new Person();
}
}
public class Person {
static{
System.out.println("静态代码块执行");
}
public Person(){
System.out.println("构造方法执行!");
}
}
10.5 数组工具类Arrays
/*
java.util.Arrays是一个与数组相关的工具类,里面提供了大量静态方法,用来实现数组常见的操作。
public static String toString(数组):将参数数组变成字符串(按照默认格式:[元素1,元素2,。。。。])
public static void sort(数组):按照默认升序(从小到大)对数组的元素进行排序。
备注:
1.如果是数值,sort默认按照升序从小到大。
2.如果是字符串,sort默认按照字母升序。
3.如果是自定义的类型,那么这个定义的类型需要用Comparable或者Comparator接口的支持。(今后学习)
4.
*/
public class t7 {
public static void main(String[] args) {
int [] array={10,20,30};
//将int[]数组按照默认格式变成字符串
String str= Arrays.toString(array);
System.out.println(str);//[10, 20, 30]
int[] array1={2,3,4,5,9};
Arrays.sort(array1);
System.out.println(Arrays.toString(array1));//[2, 3, 4, 5, 9]
}
}
10.6 数学工具类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:代表近似的圆周率常量。
*/
public class t8 {
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(-0.52));//0.52
System.out.println("=============");
//向上取整
System.out.println(Math.ceil(3.9));//4.0
System.out.println(Math.ceil(3.1));//4.0
System.out.println("=============");
//向下取整
System.out.println(Math.floor(3.9));//3.0
System.out.println(Math.floor(3.1));//3.0
System.out.println("=============");
//四舍五入
System.out.println(Math.round(3.5));//4
System.out.println(Math.round(3.1));//3
}
}
十一、继承
继承的概念
继承是面向对象三大特征之一,可以使得子类具有父类的属性和方法,还可以在子类中重新定义,以及 追加属性和方法
11.1 继承的格式
继承通过extends实现
格式:class 子类 extends 父类 { }
举例:class Dog extends Animal { }
继承带来的好处
继承可以让类与类之间产生关系,子父类关系,产生子父类后,子类则可以使用父类中非私有的成员。
11.2 继承中成员变量的访问
public class Fu {
public void show(){
System.out.println("show方法调用");
}
}
public class Zi extends Fu{
public void method(){
System.out.println("method方法调用");
}
}
public class Demo01ExtendsFile {
public static void main(String[] args) {
//创建对象,调用方法
Fu f=new Fu();
f.show();//只调用父类对象,没有任何子类内容
Zi z=new Zi();
z.method();//method方法调用
z.show();//show方法调用
}
}
11.3 区分子类方法中重名的三种变量
this:代表本类对象的引用
super:代表父类存储空间的标识(可以理解为父类对象引用)
成员变量:
this.成员变量 - 访问本类成员变量
super.成员变量 - 访问父类成员变量 成员方法: this.成员方法 - 访问本类成员方法
super.成员方法 - 访问父类成员方法
构造方法:
this(…) - 访问本类构造方法
super(…) - 访问父类构造方法
/*
局部变量: 直接写成员变量名
本类的成员变量: 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 Demo04 {
public static void main(String[] args) {
Zi zi=new Zi();
zi.method();
}
}
11.4 继承中成员方法的访问特点
/*
在父子类的继承关系当中,创建子类对象,访问成员方法的规则:
创建的对象是谁,就优先用谁,如果没有则向上找。
注意事项:
无论是成员方法还是成员变量,如果没有都是向上找父类,绝对不会向下找子类的。
重写(Override)
概念:在继承关系当中,方法的名称一样,参数列表也一样。
重写(Override):方法的名称一样,参数列表【也一样】。覆盖、覆写
重写(Overload):方法的名称一样,参数列表【不一样】。
方法的覆盖重写特点:创建的是子类对象,则优先用子类方法。
*/
public class Fu {
public void methodFu(){
System.out.println("父类方法执行!");
}
}
public class Zi extends Fu{
public void methodZi() {
System.out.println("子类方法执行");
}
public void method() {
System.out.println("子类重名方法执行");
}
}
public class Demo05 {
public static void main(String[] args) {
Zi zi=new Zi();
zi.methodFu();
zi.methodZi();
//创建的是new了子类对象,所以优先用子类方法
zi.method();
}
}
11.5 继承中方法的覆盖重写
方法覆盖重写的注意事项:
1.必须保证父子类之间方法的名称,参数列表也相同
@Override:写在方法前面,用来检测是不是有效的正确覆盖重写
这个注释就算不写,只要满足要求,也是正确的方法覆盖重写
2.子类方法的返回值必须【小于等于】父类方法的返回值范围。
前提:java.lang.Object类是所有类的公共最高父类(祖宗类),
java.lang.String就是Object的子类
3.子类方法的权限必须【大于等于】父类方法的权限修饰符。
小扩展提示:public > protected > (default) > private
备注:(default)不是关键字default,而是什么都写,留空
public class Fu {
public Object method(){
return null;
}
}
public class Zi extends Fu{
@Override
public Object method(){
return null;
}
}
public class demo06Override {
public static void main(String[] args) {
}
}
//老款手机
public class Phone {
public static void call(){
System.out.println("打电话");
}
public static void send(){
System.out.println("发短信");
}
public void show(){
System.out.println("显示号码");
}
}
//定义一款新手机,使用老手机作为父类
public class NewPhone extends Phone{
@Override
public void show() {
//把父类的show方法拿过来
super.show();
System.out.println("显示号码");
System.out.println("显示姓名");
System.out.println("显示头像");
}
}
public class Demo06Phone {
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();
}
}
11.6 继承中构造方法的访问特点
/*
继承关系中,父子类构造方法的访问特点:
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(20);
System.out.println("子类构造方法!");
}
public void method(){
//super();//错误写法!只有子类构造方法,才能调用父类构造方法
}
}
public class Demo07 {
public static void main(String[] args) {
Zi zi=new Zi();
}
}
11.7 super关键字三种用法
/*
super关键字的用法有三种:
1.在子类的成员方法中,访问父类的成员变量。
2.在子类的成员方法中,访问父类的成员方法
3.在子类的构造方法中,访问父类的构造方法
*/
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();//访问父类
System.out.println("子类方法");
}
public class Fu {
int num=10;
public void method(){
System.out.println("父类方法");
}
}
11.8 this关键字三种用法
super关键字用来访问父类内容,而this关键字用来访问本类内容。用法三种:
1.在本类的成员方法中,访问本类的成员变量.
2.在本类的方法中,访问本来的另一个成员方法
3.在本类的构造方法中,访问本类的另一个构造方法
在第三种用法当中要注意:
A.this(...)调用也必须是构造方法的第一个语句,唯一一个。
B.super和this两种构造方法,不能同时使用。
public class Zi extends Fu{
int num=19;
public Zi(){
//super();//这一行不再赠送
this(20);//本类中的无参构造,调用本类的有参构造
//this(1,2);//错误写法
}
public Zi(int n){
}
public Zi(int n,int m){
}
public void showNum(){
int num=20;
System.out.println(num);//局部变量
System.out.println(this.num);
System.out.println(super.num);
}
public void methodA(){
System.out.println("aaaaaa");
}
public void methodB() {
this.methodA();
System.out.println("bbbb");
}
}
public class Fu {
int num=10;
public void method(){
System.out.println("父类方法");
}
}
public class Zi extends Fu{
int num=20;
@Override
public void method(){
super.method();//调用父类方法
System.out.println("子类方法");
}
public void show(){
int num=30;
System.out.println(num);//30
System.out.println(this.num);//20
System.out.println(super.num);//10
}
}
public class demo {
public static void main(String[] args) {
Zi zi=new Zi();
zi.show();
zi.method();
}
}
1.第一步运行main,然后是方法。
2.new都在对当中。
11.9 Java继承的三个特点
Java语言是单继承的。
一个类的直接父类只能有唯一一个。
11.10 抽象
1、抽象方法和抽象类的格式
/*
抽象方法:就是加上abstract关键字,然后去掉大括号,直接分号结束.
抽象类:抽象方法所在的类,必须是抽象类才行。在class之前写上abstract即可。
如何使用抽象类和抽象对象:
1.不能直接创建new抽象类对象。
2.必须用一个子类来继承抽象父类。
3.子类必须覆盖重写抽象父类当中所有的抽象方法。
覆盖重写(实现):子类去掉抽象方法的abstract关键字,然后补上方法体大括号。
*/
public abstract class Animal {
//这是一个抽象方法,代表吃的东西,但是具体吃什么(大括号的内容)不确定。
public abstract void eat();
//这是普通的成员方法
// public void method(){
//}
}
public class demo11 {
public static void main(String[] args) {
Cat cat=new Cat();
cat.eat();
}
}
public class Cat extends Animal{
@Override
public void eat() {
System.out.println("猫吃鱼");
}
}
2、抽象方法和抽象类的使用
public class Zi extends Fu{
public Zi(){
System.out.println("子类构造方法执行!");
}
//Alt+回车:自动生成
@Override
public void eat() {
System.out.println("吃饭饭");
}
}
public abstract class Fu {
public Fu(){
System.out.println("抽象父类构造方法执行!");
}
public abstract void eat();
}
public class demo12 {
public static void main(String[] args) {
Zi zi=new Zi();
zi.eat();
}
}
3、抽象方法和抽象类的注意事项
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() {
//super(); //默认在里面
}
public Manager(String name, int money) {
super(name, money);
}
//ArrayList:数组列表 ; Integer:整数
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);
//System.out.println();
}
//最后一个红包
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 delta=list.remove(index);
//当前成员自己本来有多少钱
int money=super.getMoney();
//加法,并且重新设置回去
super.setMoney(money+delta);
}
}
public class RedMain {
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();
}
}
十二、接口
接口就是一种公共的规范标准,只要符合规范标准,大家都可以通用。
Java中的接口更多的体现在对行为的抽象!
基础知识:
1.类继承(extends)类,接口继承接口,类实现(implements)接口
2.接口没有方法体,只能声明函数
3.一个类可以实现多个接口,只能继承一个类
4.类必须重写接口的所有方法,不必须重写父类的所有方法
5.复杂关系:若接口A extends 接口B(根据1),则接口A不必须重写接口B(根据4)。
若类a implements A,则a必须要重写接口A和接口B所有的方法
若类b implements B,类a extends 类b,所以a的父类b已经实现了B的所有方法,那么a只必须要重写A的所有方法就可以了
举例:
接口A——UserService 类a——UserServiceImpl
接口B——BaseDao 类b——AbstractDao
12.1 接口的定义基本格式
接口用关键字interface修饰
备注:换成了关键字interface之后,编译生成的字节码文件仍然是:抽象方法。
java 7,接口包含内容
1.常量
2.抽象方法
java 8,接口额外包含内容
3.默认方法
4.静态方法
java 9,接口额外包含内容
5.私有方法
接口使用步骤:
1.接口不能直接使用,必须有一个“实现类”来“实现”该接口
格式:
public class 类名 implements 接口名 {}
2.接口的实现类必须覆盖重写(实现)接口中所有的抽象方法
实现:去掉abstract关键字,加上方法体大括号。
3.创建实现类的对象,进行使用
注意事项:
如果实现类并没有覆盖重写接口中所有的抽象方法,那么这个实现类自己就必须是抽象类。
public interface 接口名 { //接口内容 }
类实现接口用implements表示
public class 类名 implements 接口名 {}
12.2 接口的抽象方法
1、接口的抽象方法定义
/*
在任何版本的Java中,接口都能定义抽象方法。
格式:
public abstract 返回值类型 方法名称(参数列表);
注意事项:
1.接口当中的抽象方法,修饰符必须是两个固定的关键字:public abstract
2.这两个关键字修饰符,可以选择性地省略。
*/
public interface MyInterface {
//这是一个抽象方法
public abstract void methodAbs1();
//这也是抽象方法
abstract void methodAbs2();
//这也是抽象方法
public void methodAbs3();
//这也是抽象方法
void methodAbs4();
}
2、接口的抽象方法使用
/*
在任何版本的Java中,接口都能定义抽象方法。
格式:
public abstract 返回值类型 方法名称(参数列表);
注意事项:
1.接口当中的抽象方法,修饰符必须是两个固定的关键字:public abstract
2.这两个关键字修饰符,可以选择性地省略。
*/
public interface MyInterface {
//这是一个抽象方法
public abstract void methodAbs1();
//这也是抽象方法
abstract void methodAbs2();
//这也是抽象方法
public void methodAbs3();
//这也是抽象方法
void methodAbs4();
}
public class MyInterfaceImpl implements MyInterface{
@Override
public void methodAbs1() {
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 demo03Interface {
public static void main(String[] args) {
//错误写法!不能直接new接口对象使用。
// MyInterface inter=new MyInterface();
//创建实现类的对象使用
MyInterfaceImpl impl=new MyInterfaceImpl();
impl.methodAbs1();
impl.methodAbs2();
}
}
12.3 接口的默认方法定义和接口的默认方法使用
/*
从Java 8 开始,接口里允许定义默认方法。
格式:
public default 返回值类型 方法名称(参数列表){
方法体
}
备注:接口当中的默认方法,可以解决接口升级问题。
*/
public interface MyInterfaceDefault {
//抽象方法
public abstract void methodAbs();
//新添加了一个抽象方法
// public abstract void methodAbs2();
//新添加的方法,改成默认方法
public default void methodDefault(){
System.out.println("这是新添加的默认方法");
}
}
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");
}
@Override
public void methodDefault(){
System.out.println("实现了类B覆盖重写了接口的默认方法");
}
}
/*
1.接口的默认方法,可以通过接口实现类对象,直接调用。
2.接口的默认方法,也可以被接口实现类进行覆盖重写。
*/
public class demo04 {
public static void main(String[] args) {
//创建了实现类对象
MyInterfaceDefaultA a=new MyInterfaceDefaultA();
//调用抽象方法,实际运行的是右侧实现类
a.methodAbs();//实现了抽象方法,AAA
//调用默认方法,如果实现类当中没有,会向上找接口
a.methodDefault();//这是新添加的默认方法
System.out.println("=================");
MyInterfaceDefaultB b=new MyInterfaceDefaultB();
b.methodAbs();//实现了抽象方法,BBB
b.methodDefault();//实现了类B覆盖重写了接口的默认方法
}
}
12.4 接口的静态方法定义和接口的静态方法使用
/*
从Java 8 开始,接口里允许定义静态方法。
格式:
public static 返回值类型 方法名称(参数列表){
方法体
}
提示:就是将abstract或者static即可,带上方法体
*/
public interface MyInterfaceStatic {
public static void methodStatic(){
System.out.println("这是接口的静态方法!");
}
}
public class MyInterfaceImpl implements MyInterfaceStatic {
}
/*
注意事项:
不能通过接口实现类的对象来调用接口当中的静态方法。
正确方法:
通过接口名称,直接调用其中的静态方法。
格式:
接口名称。静态方法名(参数);
*/
public class Demo05Interface {
public static void main(String[] args) {
//创建了实现类对象
MyInterfaceImpl impl=new MyInterfaceImpl();
//错误写法:impl.methodStatic();
//直接通过接口名称调用静态方法
MyInterfaceStatic.methodStatic();
}
}
12.5 接口的私有方法使用
/*
问题描述:
我们需要抽取一个共有方法,用来解决两个默认方法之间重复代码问题。
但是这个共有方法不应该让实现类使用,应该是私有化的。
解决方案:
从Java 9开始,接口当中允许定义私有方法。
1.普通私有方法,解决多个默认方法之间重复代码问题
格式:
private 返回值类型 方法名称(参数列表){
方法体
}
2.静态私有方法,解决多个静态方法之间重复代码问题
格式:
private static 返回值类型 方法名称(参数列表){
方法体
}
*/
public interface MyInterPrivateA {
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("AAAAAA");
System.out.println("BBBBBB");
System.out.println("CCCCCC");
}
}
public class MyInterfacePrivateImpl implements MyInterPrivateA{
public void methodAnother(){
}
}
静态比较
public interface MyInterPrivateB {
public static void methodStatic1(){
System.out.println("静态方法1");
methodStaticCommon();
}
public static void methodStatic2(){
System.out.println("静态方法2");
methodStaticCommon();
}
public /*private*/ static void methodStaticCommon(){
System.out.println("AAAAAA");
System.out.println("BBBBBB");
System.out.println("CCCCCC");
}
}
public class Demo06 {
public static void main(String[] args) {
MyInterPrivateB.methodStatic1();
MyInterPrivateB.methodStatic2();
}
}
12.6 接口的常量定义和使用
接口当中也可以定义”成员变量“,但是必须使用public static final 三个关键字。
从效果上看,这其实就是接口的【常量】。
格式:
public static final 数据类型 常量名称 = 数据值;
备注:
一旦使用final关键字进行修饰,说明不可改变。
注意:
一旦使用final关键字进行修饰,说明不可改变。
1.接口当中的常量,可以省略public static final ,注意:不写也照样写这样。
2.接口当中的常量,必须进行赋值:不能不赋值。
3.接口当中常量的名称,使用完全大写的字母,用下划线进行分割。
public interface MyInterfaceConst {
//这其实就是一个常量,一旦赋值,不可修改
public static final int NUM=10;//final:最终的
}
public class Demo05Interface {
public static void main(String[] args) {
//访问接口当中的常量
System.out.println(MyInterfaceConst.NUM);
}
}
12.7 接口内容小结
12.8 继承父类并实现多接口
使用接口的时候,需要注意:
1.接口是没有静态代码块或者构造方法的
2.一个类的直接父类是唯一的,但是一个类可以同时实现多个接口
格式:
public class MyInterfaceImpl implements MyInterfaceA,MyInterfaceB{
//覆盖重写所有抽象方法
}
3.如果实现类所实现的多个接口当中,存在重复的抽象方法,那么只需要重盖覆写一次即可。
4.如果实现类没有覆盖重写所有接口当中的所有抽象方法。
5.如果实现类锁实现的多个接口当中,存在重复的默认方法,那么实现类一定要对冲突的默认方法进行覆盖重写。
6.一个类如果直接父类当中的方法,和接口当中的默认方法产生冲突,优先用父类当中的方法。
public interface MyInterfaceA {
public abstract void methodA();
public abstract void methodAbs();
public default void methodDefault(){
System.out.println("默认方法AAA");
}
}
public interface MyInterfaceB {
public abstract void methodB();
public abstract void methodAbs();
public default void methodDefault(){
System.out.println("默认方法BBB");
}
}
public abstract class MyInterfaceAbstract
implements MyInterfaceA,MyInterfaceB{
@Override
public void methodA() {
}
// @Override
// public void methodB() {
//
// }
@Override
public void methodAbs() {
}
@Override
public void methodDefault() {
}
}
public class MyInterfaceImple/*extends Object*/
implements MyInterfaceA,MyInterfaceB {
@Override
public void methodA() {
System.out.println("覆盖重写了A方法");
}
@Override
public void methodAbs() {
System.out.println("覆盖重写了A、B接口都有的(Abs)抽象方法");
}
@Override
public void methodDefault() {
System.out.println("对多个接口当中冲突的默认方法进行覆盖重写");
}
@Override
public void methodB() {
System.out.println("覆盖重写了B方法");
}
}
public interface MyInterface {
public default void method(){
System.out.println("接口的默认方法");
}
}
public class Fu {
public void method(){
System.out.println("父类方法");
}
}
//继承优先于接口实现
public class Zi extends Fu implements MyInterface{
}
public class Demo02Interface {
public static void main(String[] args) {
Zi zi=new Zi();
zi.method();
}
}
12.9 接口之间的多继承
/*
1.类与类之间是单继承的。直接父类只有一个。
2.类与接口之间是多实现的。一个类可以实现多个接口。
3.接口与接口之间是多继承的。
注意事项:
1.多个父接口当中的抽象方法如果重复,没关系
2.多个父类接口当中的默认方法如果重复,那么子接口必须进行默认方法的覆盖重写,【而且带着default关键字】。
*/
public class demo03Relations {
}
public interface MyInterfaceA {
public abstract void menthodA();
public abstract void menthodCommon();
public default void methodDefault(){
System.out.println("AAAA");
}
}
public interface MyInterfaceB {
public abstract void methodB();
public abstract void menthodCommon();
public default void methodDefault(){
System.out.println("BBB");
}
}
/*
这个子接口当中有有几个方法?答:四个。
menthodA:来源于接口A
menthodB:来源于接口B
menthodCommon:同时来源于接口A和B
menthod:来源于我自己
*/
public interface MyInterface extends MyInterfaceA,MyInterfaceB{
public abstract void menthod();
@Override
default void methodDefault() {
}
}
public class MyInterfaceImpl implements MyInterface{
@Override
public void menthod() {
}
@Override
public void menthodA() {
}
@Override
public void menthodCommon() {
}
@Override
public void methodB() {
}
}
十三、多态
什么是多态
同一个对象,在不同时刻表现出来的不同形态
多态的前提
要有继承或实现关系
要有方法的重写
要有父类引用指向子类对象
成员访问特点
成员变量
编译看父类,运行看父类
成员方法
编译看父类,运行看子类
13.1 多态的格式与使用
代码当中体现多态性,其实就是一句话:父类引用指向子类对象。
格式:
父类名称 对象名=new 子类名称();
或者:
接口名称 对象名=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 class demo14 {
public static void main(String[] args) {
//使用多态的写法
//左侧父类的引用,指向了右侧子类的对象
Fu obj=new Zi();
obj.method();
obj.methodFu();
}
}
13.2 成员变量的使用特点
public class Fu {
int num=10;
public void showNum(){
System.out.println(num);
}
}
public class Zi extends Fu{
int num=20;
int age=16;
}
/*
访问成员变量的两种形式:
1.直接通过对象名称访问成员变量,看等号右边是谁,优先用谁,没有则向上找。
2.间接通过成员方法访问成员变量,看该方法属于谁。优先用谁,没有则向上找。
*/
public class demo15 {
public static void main(String[] args) {
//使用多态的写法,父类引用指向子类对象
Fu obj=new Zi();
System.out.println(obj.num);//父:10
System.out.println("============");
//子类没有覆盖重写,就是父:10
//子类有覆盖重写,就是子:20
obj.showNum();
}
}
13.3 成员方法的使用特点
在多态的代码当中,成员方法的访问规则是:
看new 的是谁,就优先用谁,没有则向上找。
口诀:
编译看左边,运行看右边。
对比一下:
成员变量:编译看左边,运行还看左边。
成员方法:编译看左边,运行看右边。
public class Fu {
int num=10;
public void showNum(){
System.out.println(num);
}
public void method(){
System.out.println("父类方法");
}
public void methodFu(){
System.out.println("父类特有方法");
}
}
public class Zi extends Fu{
int num=20;
int age=16;
@Override
public void showNum(){
System.out.println(num);
}
@Override
public void method(){
System.out.println("子类方法");
}
//@Override
public void methodZi(){
System.out.println("子类特有方法");
}
}
public class demo15Method {
public static void main(String[] args) {
Fu obj=new Zi();//多态
obj.method();//父子都有,优先用子
obj.methodFu();//子类没有,父类有,向上找到父类
//编译看左边,右边是Fu,Fu当中没有methodZi方法,所以编译错误。
// obj.methodZi();//错误写法
}
}
13.4 对象的转型
1、向上转型
public abstract class Animal {
public abstract void eat();
}
public class Cat extends Animal{
@Override
public void eat(){
System.out.println("猫吃鱼");
}
}
public class demo16 {
public static void main(String[] args) {
//对象的向上转型,就是:父类引用指向之类对象。
Animal animal=new Cat();
animal.eat();
}
}
2、向下转型
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("狗吃屎");
}
public void watchHouse(){
System.out.println("狗看家");
}
}
public abstract class Animal {
public abstract void eat();
}
/*
向上转型一定是安全的,没有问题的,正确的。但是也有一个弊端:
对象一旦向上转型为父类,那么就无法调用子类原本特有的内容。
解决方案:
用对象的向下转型【还原】
*/
public class demo16 {
public static void main(String[] args) {
//对象的向上转型,就是:父类引用指向之类对象。
Animal animal=new Cat();//本来创建的时候是一只猫
animal.eat();//猫吃鱼
// animal.catchMouse();//写法错误
//向下转型,进行“还原”动作
Cat cat=(Cat) animal;
cat.catchMouse();//猫抓老鼠
//向下是错误的向下转型
//本来new的时候是一只猫,现在非要当作狗
//错误写法!编译不会报错,但是运行会出现异常
//java.long.ClassCastException. 类转换异常
Dog dog=(Dog) animal;
}
}
用instanceof关键字进行类型判断
/*
如何才能知道一个父类引用的对象,本来是什么子类?
格式:
对象 instanceof 类名称
这将会得到一个boolean值结果,也就是判断前面的对象能不能当做后面类型的实例
*/
public class demo16Instanceof {
public static void main(String[] args) {
//Animal animal=new Cat();//本来是一只猫
Animal animal=new Dog();//本来是一只狗
animal.eat();//猫吃鱼
//如果希望调用子类特有方法,需要向下转型
//判断一下父类引用animal本来是不是Dog
if (animal instanceof Dog){
Dog dog=(Dog) animal;
dog.watchHouse();
}
//判断一下animal本来是不是Cat
if (animal instanceof Cat){
Cat cat=(Cat) animal;
cat.catchMouse();
}
giveMePet(new Dog());
}
public static void giveMePet(Animal animal){
if (animal instanceof Dog){
Dog dog=(Dog) animal;
dog.watchHouse();
}
if (animal instanceof Cat){
Cat cat=(Cat) animal;
cat.catchMouse();
}
}
}
13.6 笔记本USB接口案例
public interface USB {//interface接口
public abstract void open();//打开设备;abstract:抽象
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 static void type(){
System.out.println("键盘输入");
}
}
public class demo17 {
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);
System.out.println("============");
//创建一个USB键盘
Keyboard keyboard=new Keyboard();//没有使用多态写法
//方法参数是USB类型,传递进去的是实现类对象
computer.usbDevice(keyboard);//正确写法!也发生向上转型
//使用子类对象,匿名对象,也可以
//computer.usbDevice(new keyboard());
computer.powerOff();
System.out.println("=======");
method(10.0);//正确写法:double----->double
method(10);//正确写法:int------>double
int a=30;
method(a);//正确写法:int------>double
}
public static void method(double num){
System.out.println(num);
}
}
13.7 final关键字
1、概念与四种用法
final关键字代表最终、不可改变的:
常见四种用法:
1.可以用来修饰一个类。
2.可以用来修饰一个方法
3.还可以用来修饰一个局部变量
4.还可以用来修饰一个成员变量
/*
当final关键字用来修饰一个类的时候,格式:
public final class 类名称{
//. . .
}
含义:当前这个类不能有任何的子类。(大太监)
注意:一个类如果是final的,那么其中所有的成员方法都无法进行覆盖重写(因为没儿子)
*/
public class MyClass /*extends Object*/{
public void method(){
System.out.println("方法执行!");
}
}
2、用于修饰成员方法
/*
当final关键字用来修饰一个方法的时候,这时候就是最终方法,也就是不能被覆盖重写。
格式:
修饰符 final 返回值类型 方法名称(参数列表){
//方法体
}
注意事项:
对于类、方法来说,abstract关键字和final关键字不能同时使用,因为矛盾。
*/
//抽象类的定义
public abstract class Fu {
public final void method(){
System.out.println("父类方法执行!");
}
//抽象方法的定义
public abstract void methodAbs();
}
public class Zi extends Fu{
@Override
public void methodAbs(){
}
//错误写法!不能覆盖重写父类当中final的方法
//@Override
//public void method(){
// System.out.println("子类覆盖重写父类的方法!");
//}
}
3、用于修饰局部变量
public class Student {
private String name;
public Student(){
}
public Student(String name) {
this.name = name;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
public class demo01 {
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
//正确写法!只要保证有唯一一次赋值即可
final int num3;
num3=30;
System.out.println(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("高圆圆");
System.out.println(stu2);
System.out.println(stu2.getName());//高圆圆
stu2.setName("高圆圆圆圆圆");
System.out.println(stu2.getName());//高圆圆圆圆圆
}
}
4、用于修饰成员变量
/*
对于成员变量来说,如果使用final关键字修饰,那么这个变量也照样是不可变。
1.由于成员变量具有默认值,所以用了final之后必须手动赋值,不会再给默认值了。
2.对于final的成员变量,要么使用直接赋值,要么通过构造方法赋值。二者选其一
3.必须保证类当中所有重载的构造方法,都最终会对final的成员变量进行赋值。
*/
public class Person {
//private String name;
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;
// }
}
类名作为形参和返回值(应用)
1、类名作为方法的形参
方法的形参是类名,其实需要的是该类的对象
实际传递的是该对象的【地址值】
2、类名作为方法的返回值
方法的返回值是类名,其实返回的是该类的对象
实际传递的,也是该对象的【地址值】
public class Cat {
public void eat(){
System.out.println("猫吃鱼");
}
}
public class CatOperator {
public void useCat(Cat c){
c.eat();
}
public Cat getCat(){
Cat c=new Cat();
return c;
}
}
public class demo04 {
public static void main(String[] args) {
CatOperator co=new CatOperator();
Cat c=new Cat();
co.useCat(c);
System.out.println("=========");
Cat c2=co.getCat();
c2.eat();
}
}
抽象类作为形参和返回值
方法的形参是抽象类名,其实需要的是该抽象类的子类对象
方法的返回值是抽象类名,其实返回的是该抽象类的子类对象
public abstract class Animal {
public abstract void eat();
}
public class Cat extends Animal{
@Override
public void eat(){
System.out.println("猫吃鱼");
}
}
public class AnimalOperator {
public void useAnimal(Animal a){
a.eat();
}
public Animal getAnimal(){
Animal a=new Cat();
return a;
}
}
public class demo05 {
public static void main(String[] args) {
AnimalOperator ao=new AnimalOperator();
Animal a=new Cat();
ao.useAnimal(a);
System.out.println("=========");
Animal a2=ao.getAnimal();
a2.eat();
}
}
接口作为形参和返回值
方法的形参是接口名,其实需要的是该接口的实现类对象
方法的返回值是接口名,其实返回的是该接口的实现类对象