基础学习
一、基本数据类型
基本数据类型
整数型 byte short int long
浮点型 float double
字符型 char
布尔型 boolean
引用数据类型(今后学习)
字符串、数组、类、接口、Lambda
注意事项:
- 字符串不是基本类型,而是引用类型。
- 浮点型可能只是一个近似值,并非精确的值。
- 数据范围与字节数不一定相关,例如float数据范围比long更加广泛,但是float是4字节,long是8字节。
- 浮点数当中默认类型是double。如果一定要使用float类型,需要加上一个后缀F。
1、变量
程序运行期间,内容可以发生改变的量
创建一个变量并且使用格式:
数据类型 变量名称; //创建了一个变量
变量名称 = 数据值; //赋值
一步到位的格式:
数据类型 变量名称 = 数据值; //创建一个变量的同时,立刻放入指定数据值
二、三种循环
计算1到100之间的偶数之和:
1、for循环
int sum = 0;//用来累加的存钱罐
for (int i = 1;i<=100;i++){
if (i%2==0){//如果是偶数
sum+=i;
}
}
2、while循环
int sum = 0, i = 1;//用来累加的存钱罐
while (i<=100){
i++;
if (i%2==0){
sum+=i;
}
}
System.out.println(sum);
3、 do{
循环体
步进语句
}while(布尔表达式);先执行一次在进行条件判断
int sum = 0, i = 1;//用来累加的存钱罐
do {
if (i%2==0){
sum+=i;
}
i++;//步进语句
}while (i<=100);
System.out.println(sum);
4、break中断执行
5、continue:一旦执行,立刻跳过当前此循环剩余类容,马上开始下一次循环
for (int i = 1;i<9;i++){
if (i==4){
continue;//跳过第四,直接开始第五
}
System.out.println(i);
}
三、方法的调用格式
1、单独调用:方法名称(参数);
2、打印调用:System.out.println(“方法名称(参数)”);
3、赋值调用:数据类型 变量名称 = 方法名称(参数);
注意:返回值类型为void的方法只能单独调用,不能进行打印和赋值调用
只进行打印,不需要计算,也没有结果,用void。
public static void main(String[] args) {
//单独调用
sum(10,20);
System.out.println("--------------");
//打印调用
System.out.println(sum(10,20));
System.out.println("---------------");
//赋值调用
int number = sum(10,20);
number+=100;
System.out.println("变量的值"+number);
}
public static int sum(int a, int b){
System.out.println("方法执行了");
int result = a+b;
return result;
}
4、有参数和无参数
/*
有参数:小括号当中有内容,当一个方法需要一些数据条件,才能完成任务的时候,就是有参数。
例如两个数字相加,必须知道两个数字是各自多少,才能相加。
无参数:小括号当中留空。一个方法不需要任何数据条件,自己就能独立完成任务,就是无参数。
例如定义一个方法,打印固定10次HelloWorld。
*/
public class Demo03MethodParam {
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);
}
}
5、有返回值和无返回值
/*
题目要求:定义一个方法,用来【求出】两个数字之和。(你帮我算,算完之后把结果告诉我。)
题目变形:定义一个方法,用来【打印】两个数字之和。(你来计算,算完之后你自己负责显示结果,不用告诉我。)
注意事项:
对于有返回值的方法,可以使用单独调用、打印调用或者赋值调用。
但是对于无返回值的方法,只能使用单独调用,不能使用打印调用或者赋值调用。
*/
public class Demo04MethodReturn {
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);
}
6、两个数字是否相同
是否两字出现就是布尔值(boolean)
package cn.itcast.day04.demo03;
/*
题目要求:
定义一个方法,用来判断两个数字是否相同。
*/
public class Demo01MethodSame {
public static void main(String[] args) {
System.out.println(isSame(10, 20)); // false
System.out.println(isSame(20, 20)); // true
}
/*
三要素:
返回值类型: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 a == b;
}
}
7、方法的注意事项
1、方法应该定义在类当中,但是不能再方法当中在定义方法,不能嵌套。
2、方法定义的前后顺序无所谓
3、方法定义之后不会执行,如果希望执行,一定要调用:单独调用、打印调用、赋值调用。
4.、如果方法有返回值,那么必须写上“return 返回值;”,不能没有。
5、return后面的返回值数据,必须和方法的返回值类型,对应起来。
6、对于一个void没有返回值的方法,不能写return后面的返回值,只能写return自己。
7、对于void方法当中最后一行的return可以省略不写。
8、一个方法当中可以有多个return语句,但是必须保证同时只有一个会被执行到,两个return不能连写。
public class Demo04MethodNotice {
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;
}
}
}
四、方法的重载
对于功能类似的方法来说,因为参数列表不一样,却需要记住那么多不同的方法名称,太麻烦。
方法的重载(Overload):多个方法的名称一样,但是参数列表不一样。
好处:只需要记住唯一一个方法名称,就可以实现类似的多个功能。
方法重载与下列因素相关:
- 参数个数不同
- 参数类型不同
- 参数的多类型顺序不同
方法重载与下列因素无关:
- 与参数的名称无关
- 与方法的返回值类型无关
public class Demo01MethodOverload {
public static void main(String[] args) {
/*System.out.println(sumTwo(10, 20)); // 30
System.out.println(sumThree(10, 20, 30)); // 60
System.out.println(sumFour(10, 20, 30, 40)); // 100*/
System.out.println(sum(10, 20)); // 两个参数的方法
System.out.println(sum(10, 20, 30)); // 三个参数的方法
System.out.println(sum(10, 20, 30, 40)); // 四个参数的方法
// System.out.println(sum(10, 20, 30, 40, 50)); // 找不到任何方法来匹配,所以错误!
sum(10, 20);
}
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) {
System.out.println("有2个参数的方法执行!");
return a + b;
}
// 错误写法!与方法的返回值类型无关
// public static double sum(int a, int b) {
// return a + b + 0.0;
// }
// 错误写法!与参数的名称无关
// 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) {
System.out.println("有3个参数的方法执行!");
return a + b + c;
}
public static int sum(int a, int b, int c, int d) {
System.out.println("有4个参数的方法执行!");
return a + b + c + d;
}
}
五、数组
1、概念和特点
1、概念是一种容器,可以同时存放多个数据值
2、数组的特点: 1.数组是一种引用数据类型
2.数组当中的多个数据,类型必须统一
3.数组的长度在程序运行期间不可改变
3、数组的初始化:在内存当中创建一个数组,并且向其中赋予一些默认值。
两种常见的初始化方式:1.动态初始化(指定长度)
2.静态初始化(指定长度)
数据类型[] 数组名称 = new 数据类型[数组长度];
解析含义:
左侧数据类型:也就是数组当中保存的数据,全都是统一的什么类型
左侧的中括号:代表我是一个数组
左侧数组名称:给数组取一个名字
右侧的new:代表创建数组的动作
右侧数据类型:必须和左边的数据类型保持一致
右侧中括号的长度:也就是数组当中,到底可以保存多少个数据,是一个int数字
2、动态初始化和静态初始化的区别
动态初始化(指定长度):在创建数组的时候,直接指定数组当中的数据元素个数。
静态初始化(指定内容):在创建数组的时候,不直接指定数据个数多少,而是直接将具体的数据内容进行指定。
静态初始化基本格式:
数据类型[] 数组名称 = new 数据类型[] { 元素1, 元素2, … };
注意事项:
虽然静态初始化没有直接告诉长度,但是根据大括号里面的元素具体内容,也可以自动推算出来长度。
动态初始化:
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];
}
静态初始化:使用静态初始化数组的时候,格式还可以省略一下。
标准格式:
数据类型[] 数组名称 = new 数据类型[] { 元素1, 元素2, … };
省略格式:
数据类型[] 数组名称 = { 元素1, 元素2, … };
注意事项:
- 静态初始化没有直接指定长度,但是仍然会自动推算得到长度。
- 静态初始化标准格式可以拆分成为两个步骤。
- 动态初始化也可以拆分成为两个步骤。
- 静态初始化一旦使用省略格式,就不能拆分成为两个步骤了。
使用建议:
如果不确定数组当中的具体内容,用动态初始化;否则,已经确定了具体的内容,用静态初始化。
public static void main(String[] args) {
// 直接创建一个数组,里面装的全都是int数字,具体为:5、15、25
int[] arrayA = new int[] { 5, 15, 25, 40 };
// 创建一个数组,用来装字符串:"Hello"、"World"、"Java"
String[] arrayB = new String[] { "Hello", "World", "Java" };
}
3、获取数组元素
直接打印数组名称,得到的是数组对应的:内存地址哈希值。
二进制:01
十进制:0123456789
16进制:0123456789abcdef
访问数组元素的格式:数组名称[索引值]
索引值:就是一个int数字,代表数组当中元素的编号。
【注意】索引值从0开始,一直到“数组的长度-1”为止。
public static void main(String[] args) {
// 静态初始化的省略格式
int[] array = { 10, 20, 30 };
System.out.println(array); // [I@75412c2f
// 直接打印数组当中的元素
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
}
4、访问数组元素进行赋值
使用动态初始化数组的时候,其中的元素将会自动拥有一个默认值。规则如下:
如果是整数类型,那么默认为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
4.1、获取数组长度
如何获取数组的长度,格式:
数组名称.length
这将会得到一个int数字,代表数组的长度。
数组一旦创建,程序运行期间,长度不可改变。
public static void main(String[] args) {
int[] arrayA = new int[3];
int[] arrayB = {10, 20, 30, 3, 5, 4, 6, 7, 8, 8, 65, 4, 44, 6, 10, 3, 5, 4, 6, 7, 8, 8, 65, 4};
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
}
5、Java中的内存划分
1、栈(Stack):存放的都是方法中的局部变量,方法的运行一定要在栈当中运行,
局部变量:方法的参数,或者是方法()内部的变量
作用域:一旦超出作用域,立刻从栈内存中消失。
2、堆(Heap):凡是new出来的东西,都在堆当中。
堆内存里面的东西都有一个地址值:16进制
堆内存里面的东西,都有默认值。规则:
如果是整数 默认为0
如果是浮点数 默认为0.0
如果是字符 默认为‘\u0000’
如果是布尔 默认为false
如果是引用类型 默认为null
3、方法区(Method Area):存储.class相关信息,包含方法的信息
4、本地方法栈(Native Method Stack):与操作系统相关
5、寄存器(pc Register):与cpu相关
一个数组的内存图:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-FD0E8Tya-1624356413461)(C:\Users\ASUS\AppData\Roaming\Typora\typora-user-images\image-20201229175230226.png)]
6、遍历数组
遍历数组,说的就是对数组当中的每一个元素进行逐一、挨个儿处理。默认的处理方式就是打印输出。
public static void main(String[] args) {
int[] array = { 15, 25, 30, 40, 50, 60, 75 };
// 首先使用原始方式
System.out.println(array[0]); // 15
System.out.println(array[1]); // 25
System.out.println(array[2]); // 30
System.out.println(array[3]); // 40
System.out.println(array[4]); // 50
System.out.println(array[5]); // 50
System.out.println("=================");
// 使用循环,次数其实就是数组的长度。
for (int i = 0; i < 6; i++) {
System.out.println(array[i]);
}
System.out.println("=================");
// int len = array.length; // 长度
for (int i = 0; i < array.length; i++) {
System.out.println(array[i]);
}
}
7、数组地址值传递
数组可以作为方法的参数。
当调用方法的时候,向方法的小括号进行传参,传递进去的其实是数组的地址值。
一个方法可以有0、1、多个参数;但是只能有0或者1个返回值,不能有多个返回值。
如果希望一个方法当中产生了多个结果数据进行返回,怎么办?
解决方案:使用一个数组作为返回值类型即可。
任何数据类型都能作为方法的参数类型,或者返回值类型。
数组作为方法的参数,传递进去的其实是数组的地址值。
数组作为方法的返回值,返回的其实也是数组的地址值。
public static void main(String[] args) {
int[] result = calculate(10, 20, 30);
System.out.println("main方法接收到的返回值数组是:");
System.out.println(result); // 地址值
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 = new int[2];
array[0] = sum; // 总和
array[1] = avg; // 平均数
*/
int[] array = { sum, avg };
System.out.println("calculate方法内部数组是:");
System.out.println(array); // 地址值
return array;
}
六、面向对象
1、面向对象和面向过程
面向过程:当需要实现一个功能的时候,每一个具体的步骤都要亲力亲为,详细处理每一个细节。
面向对象:当需要实现一个功能的时候,不关心具体的步骤,而是找一个已经具有该功能的人,来帮我做事儿。
public static void main(String[] args) {
int[] array = { 10, 20, 30, 40, 50, 60 };
// 要求打印格式为:[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、对象的创建及其使用
通常情况下,一个类并不能直接使用,需要根据类创建一个对象,才能使用。
-
导包:也就是指出需要使用的类,在什么位置。
import 包名称.类名称;
import cn.itcast.day06.demo01.Student;
对于和当前类属于同一个包的情况,可以省略导包语句不写。 -
创建,格式:
类名称 对象名 = new 类名称();
Student stu = new Student(); -
使用,分为两种情况:
使用成员变量:对象名.成员变量名
使用成员方法:对象名.成员方法名(参数)
(也就是,想用谁,就用对象名点儿谁。)
注意事项:
如果成员变量没有进行赋值,那么将会有一个默认值,规则和数组一样。
类Student
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("学习");
}
创建一个Demo02Student来使用Student类
public static void main(String[] args) {
// 1. 导包。
// 我需要使用的Student类,和我自己Demo02Student位于同一个包下,所以省略导包语句不写
// 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 = 18;
System.out.println(stu.name); // 赵丽颖
System.out.println(stu.age); // 18
System.out.println("=============");
// 4. 使用对象的成员方法,格式:
// 对象名.成员方法名()
stu.eat();
stu.sleep();
stu.study();
}
2.1一个对象的内存图
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-wcOO1qEM-1624356413462)(F:\zzz黑马学习\image-20201231163230672.png)]
3、局部变量和成员变量
-
定义的位置不一样【重点】
局部变量:在方法的内部
成员变量:在方法的外部,直接写在类当中 -
作用范围不一样【重点】
局部变量:只有方法当中才可以使用,出了方法就不能再用
成员变量:整个类全都可以通用。 -
默认值不一样【重点】
局部变量:没有默认值,如果要想使用,必须手动进行赋值
成员变量:如果没有赋值,会有默认值,规则和数组一样 -
内存的位置不一样(了解)
局部变量:位于栈内存
成员变量:位于堆内存 -
生命周期不一样(了解)
局部变量:随着方法进栈而诞生,随着方法出栈而消失
成员变量:随着对象创建而诞生,随着对象被垃圾回收而消失
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);
}
4、面向对象三大特征
面向对象三大特征:封装、继承、多态。
封装性在Java当中的体现:
- 方法就是一种封装
- 关键字private也是一种封装
封装就是将一些细节信息隐藏起来,对于外界不可见。
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 = 1; i < array.length; i++) {
if (array[i] > max) {
max = array[i];
}
}
return max;
}
问题描述:定义Person的年龄时,无法阻止不合理的数值被设置进来。
解决方案:用private关键字将需要保护的成员变量进行修饰。
一旦使用了private进行修饰,那么本类当中仍然可以随意访问。
但是!超出了本类范围之外就不能再直接访问了。
间接访问private成员变量,就是定义一对儿Getter/Setter方法
必须叫setXxx或者是getXxx命名规则。
对于Getter来说,不能有参数,返回值类型和成员变量对应;
对于Setter来说,不能有返回值,参数类型和成员变量对应。
package mianxiangduixiang.Demo03;
public class Person {
String name;
private int age;
public void show(){
System.out.println("我叫"+name+"今年"+age+"岁了");
}
public int getAge() {
return age;
}
public void setAge(int age) {
if (age>0){
this.age = age;
}else {
System.err.println("请输入正确的数据");
}
}
}
package mianxiangduixiang.Demo03;
public class Demo03Persong {
public static void main(String[] args) {
Person one = new Person();
one.name = "5555";
one.setAge(-2);
one.show();
}
}
对于基本类型当中的boolean值,Getter方法一定要写成isXxx的形式,而setXxx规则不变。
4.1_this关键字的作用
当方法的局部变量和类的成员变量重名的时候,根据“就近原则”,优先使用局部变量。
如果需要访问本类当中的成员变量,需要使用格式:
this.成员变量名
“通过谁调用的方法,谁就是this。”
String name; // 我自己的名字
// 参数name是对方的名字
// 成员变量name是自己的名字
public void sayHello(String name) {
System.out.println(name + ",你好。我是" + this.name);
System.out.println(this);
}
4.2_构造方法
构造方法是专门用来创建对象的方法,当我们通过关键字new来创建对象时,其实就是在调用构造方法。
格式:
public 类名称(参数类型 参数名称) {
方法体
}
注意事项:
-
构造方法的名称必须和所在的类名称完全一样,就连大小写也要一样
-
构造方法不要写返回值类型,连void都不写
-
构造方法不能return一个具体的返回值
-
如果没有编写任何构造方法,那么编译器将会默认赠送一个构造方法,没有参数、方法体什么事情都不做。
public Student() {} -
一旦编写了至少一个构造方法,那么编译器将不再赠送。
-
构造方法也是可以进行重载的。
重载:方法名称相同,参数列表不同。
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());
}
public class Student {
private String name;
private int age;
public Student(){
}
public Student(String name,int age){
System.out.println("构造方法执行啦");
this.age = age;
this.name = name;
// System.out.println(getAge()+getName());
}
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;
}
七、各种类
1、Scanner类
Scanner类的功能:可以实现键盘输入数据,到程序当中。
引用类型的一般使用步骤:
-
导包
import 包路径.类名称;
如果需要使用的目标类,和当前类位于同一个包下,则可以省略导包语句不写。
只有java.lang包下的内容不需要导包,其他的包都需要import语句。 -
创建
类名称 对象名 = new 类名称(); -
使用
对象名.成员方法名()
获取键盘输入的一个int数字:int num = sc.nextInt();
获取键盘输入的一个字符串:String str = sc.next();
public static void main(String[] args) {
// 2. 创建
// 备注:System.in代表从键盘进行输入
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);
}
2、匿名对象的说明
创建对象的标准格式:
类名称 对象名 = new 类名称();
匿名对象就是只有右边的对象,没有左边的名字和赋值运算符。
new 类名称();
注意事项:匿名对象只能使用唯一的一次,下次再用不得不再创建一个新对象。
使用建议:如果确定有一个对象只需要使用唯一的一次,就可以用匿名对象。
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
}
3、Random类
Random类用来生成随机数字。使用起来也是三个步骤:
-
导包
import java.util.Random; -
创建
Random r = new Random(); // 小括号当中留空即可 -
使用
获取一个随机的int数字(范围是int所有范围,有正负两种):int num = r.nextInt()
获取一个随机的int数字(参数代表了范围,左闭右开区间):int num = r.nextInt(3)
实际上代表的含义是:[0,3),也就是0~2
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);
}
}
4、Array类
题目:
定义一个数组,用来存储3个Person对象。
数组有一个缺点:一旦创建,程序运行期间长度不可以发生改变。
public static void main(String[] args) {
Demo06Person[] array = new Demo06Person[3];
Demo06Person one = new Demo06Person("迪丽热巴", 18);
Demo06Person two = new Demo06Person("古力娜扎", 28);
Demo06Person three = new Demo06Person("玛尔扎哈", 38);
// 将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()); // 古力娜扎
}
1、ArrayList
数组的长度不可以发生改变。
但是ArrayList集合的长度是可以随意变化的。
对于ArrayList来说,有一个尖括号代表泛型。
泛型:也就是装在集合当中的所有元素,全都是统一的什么类型。
注意:泛型只能是引用类型,不能是基本类型。
注意事项:
对于ArrayList集合来说,直接打印得到的不是地址值,而是内容。
如果内容是空,得到的是空的中括号:[]
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("古力娜扎");
list.add("玛尔扎哈");
System.out.println(list); // [赵丽颖, 迪丽热巴, 古力娜扎, 玛尔扎哈]
// list.add(100); // 错误写法!因为创建的时候尖括号泛型已经说了是字符串,添加进去的元素就必须都是字符串才行
}
ArrayList当中的常用方法有:
public boolean add(E e):向集合当中添加元素,参数的类型和泛型一致。返回值代表添加是否成功。
备注:对于ArrayList集合来说,add添加动作一定是成功的,所以返回值可用可不用。
但是对于其他集合(今后学习)来说,add添加动作不一定成功。
public E get(int index):从集合当中获取元素,参数是索引编号,返回值就是对应位置的元素。
public E remove(int index):从集合当中删除元素,参数是索引编号,返回值就是被删除掉的元素。
public int size():获取集合的尺寸长度,返回值是集合中包含的元素个数。
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("李小璐");
list.add("贾乃亮");
System.out.println(list); // [柳岩, 高圆圆, 赵又廷, 李小璐, 贾乃亮]
// 从集合中获取元素:get。索引值从0开始
String name = list.get(2);
System.out.println("第2号索引位置:" + name); // 赵又廷
// 从集合中删除元素:remove。索引值从0开始。
String whoRemoved = list.remove(3);
System.out.println("被删除的人是:" + whoRemoved); // 李小璐
System.out.println(list); // [柳岩, 高圆圆, 赵又廷, 贾乃亮]
// 获取集合的长度尺寸,也就是其中元素的个数
int size = list.size();
System.out.println("集合的长度是:" + size);
}
如果希望向集合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<>();
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);
}
八、字符串
java.lang.String类代表字符串。
API当中说:Java 程序中的所有字符串字面值(如 “abc” )都作为此类的实例实现。
其实就是说:程序当中所有的双引号字符串,都是String类的对象。(就算没有new,也照样是。)
字符串的特点:
- 字符串的内容永不可变。【重点】
- 正是因为字符串不可改变,所以字符串是可以共享使用的。
- 字符串效果上相当于是char[]字符数组,但是底层原理是byte[]字节数组。
创建字符串的常见3+1种方式。
三种构造方法:
public String():创建一个空白字符串,不含有任何内容。
public String(char[] array):根据字符数组的内容,来创建对应的字符串。
public String(byte[] array):根据字节数组的内容,来创建对应的字符串。
一种直接创建:
String str = “Hello”; // 右边直接用双引号
注意:直接写上双引号,就是字符串对象。
public static void main(String[] args) {
// 使用空参构造
String str1 = new String(); // 小括号留空,说明字符串什么内容都没有。
System.out.println("第1个字符串:" + str1);
// 根据字符数组创建字符串
char[] charArray = { 'A', 'B', 'C' };
String str2 = new String(charArray);
System.out.println("第2个字符串:" + str2);
// 根据字节数组创建字符串
byte[] byteArray = { 97, 98, 99 };
String str3 = new String(byteArray);
System.out.println("第3个字符串:" + str3);
// 直接创建
String str4 = "Hello";
System.out.println("第4个字符串:" + str4);
}
字符串常量池:程序当中直接写上的双引号字符串,就在字符串常量池中。
对于基本类型来说,==是进行数值的比较。
对于引用类型来说,==是进行**【地址值】**的比较。
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
}
1、字符串比较
==是进行对象的地址值比较,如果确实需要字符串的内容比较,可以使用两个方法:
public boolean equals(Object obj):参数可以是任何对象,只有参数是一个字符串并且内容相同的才会给true;否则返回false。
注意事项:
- 任何对象都能用Object进行接收。
- equals方法具有对称性,也就是a.equals(b)和b.equals(a)效果一样。
- 如果比较双方一个常量一个变量,推荐把常量字符串写在前面。
推荐:“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,忽略大小写
// 注意,只有英文字母区分大小写,其他都不区分大小写
System.out.println("abc一123".equalsIgnoreCase("abc壹123")); // false
}
2、字符串的获取方法
String当中与获取相关的常用方法有:
public int length():获取字符串当中含有的字符个数,拿到字符串长度。
public String concat(String str):将当前字符串和参数字符串拼接成为返回值新的字符串。
public char charAt(int index):获取指定索引位置的单个字符。(索引从0开始。)
public int indexOf(String str):查找参数字符串在本字符串当中首次出现的索引位置,如果没有返回-1值。
public static void main(String[] args) {
// 获取字符串的长度
int length = "asdasfeutrvauevbueyvb".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 = "HelloWorldHelloWorld";
int index = original.indexOf("llo");
System.out.println("第一次索引值是:" + index); // 2
System.out.println("HelloWorld".indexOf("abc")); // -1
}
3、字符串的截取方法
字符串的截取方法:
public String substring(int index):截取从参数位置一直到字符串末尾,返回新字符串。
public String substring(int begin, int end):截取从begin开始,一直到end结束,中间的字符串。
备注:[begin,end),包含左边,不包含右边。
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); // oWo
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
}
4、字符串的转换方法
public char[] toCharArray():将当前字符串拆分成为字符数组作为返回值。
public byte[] getBytes():获得当前字符串底层的字节数组。
public String replace(CharSequence oldString, CharSequence newString):
将所有出现的老字符串替换成为新的字符串,返回替换之后的结果新字符串。
备注:CharSequence意思就是说可以接受字符串类型。
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("==============");
5、字符串的分割方法
分割字符串的方法:
public String[] split(String regex):按照参数的规则,将字符串切分成为若干部分。
注意事项:
split方法的参数其实是一个“正则表达式”,今后学习
今天要注意**:如果按照英文句点“.”进行切分,必须写"\\."(两个反斜杠)**
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]);
}
}
题目:
键盘输入一个字符串,并且统计其中各种字符出现的次数。
种类有:大写字母、小写字母、数字、其他
思路:
- 既然用到键盘输入,肯定是Scanner
- 键盘输入的是字符串,那么:String str = sc.next();
- 定义四个变量,分别代表四种字符各自的出现次数。
- 需要对字符串一个字、一个字检查,String–>char[],方法就是toCharArray()
- 遍历char[]字符数组,对当前字符的种类进行判断,并且用四个变量进行++动作。
- 打印输出四个变量,分别代表四种字符出现次数。
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);
}
6、Static方法
一旦使用static修饰成员方法,那么这就成为了静态方法。静态方法不属于对象,而是属于类的。
如果没有static关键字,那么必须首先创建对象,然后通过对象才能使用它。
如果有了static关键字,那么不需要创建对象,直接就能通过类名称来使用它。
无论是成员变量,还是成员方法。如果有了static,都推荐使用类名称进行调用。
静态变量:类名称.静态变量
静态方法:类名称.静态方法()
注意事项:
- 静态不能直接访问非静态。
原因:因为在内存当中是【先】有的静态内容,【后】有的非静态内容。
“先人不知道后人,但是后人知道先人。” - 静态方法当中不能用this。
原因:this代表当前对象,通过谁调用的方法,谁就是当前对象。
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("自己的方法!");
}
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 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("构造方法执行!");
}
}
7、Arrays
java.util.Arrays是一个与数组相关的工具类,里面提供了大量静态方法,用来实现数组常见的操作。
public static String toString(数组):将参数数组变成字符串(按照默认格式:[元素1, 元素2, 元素3…])
public static void sort(数组):按照默认升序(从小到大)对数组的元素进行排序。
备注:
- 如果是数值,sort默认按照升序从小到大
- 如果是字符串,sort默认按照字母升序
- 如果是自定义的类型,那么这个自定义的类需要有Comparable或者Comparator接口的支持。
public static void main(String[] args) {
int[] intArray = {10, 20, 30};
// 将int[]数组按照默认格式变成字符串
String intStr = Arrays.toString(intArray);
System.out.println(intStr); // [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]
}
8、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 static void main(String[] args) {
//获取绝对值
System.out.println(Math.abs(-3.14));
//向上取整
System.out.println(Math.ceil(4.2));
//向下取整
System.out.println(Math.floor(4.9));
//四舍五入
System.out.println(Math.round(4.51));
}
九、继承
面向对象三大特征:封装、继承、多态。
继承是多态的前提,如果没有继承,就没有多态。
主要解决的问题:共性抽取
特点:1、子类可以拥有父类的可继承类容
2、子类还可以拥有自己的专有类容
在继承的关系中,“子类就是一个父类”。也就是说,子类可以被当做父类看待。
例如父类是员工,子类是讲师,那么“讲师就是一个员工”。关系:is-a。
定义父类的格式:(一个普通的类定义)
public class 父类名称 {
// …
在父子类的继承关系当中,如果成员变量重名,则创建子类对象时,访问有两种方式:
直接通过子类对象访问成员变量:
等号左边是谁,就优先用谁,没有则向上找。
间接通过成员方法访问成员变量:
该方法属于谁,就优先用谁,没有则向上找。
局部变量: 直接写成员变量名
本类的成员变量: this.成员变量名
父类的成员变量: super.成员变量名
在父子类的继承关系当中,创建子类对象,访问成员方法的规则:
创建的对象是谁,就优先用谁,如果没有则向上找。
注意事项:
无论是成员方法还是成员变量,如果没有都是向上找父类,绝对不会向下找子类的。
重写(Override)
概念:在继承关系当中,方法的名称一样,参数列表也一样。
重写(Override):方法的名称一样,参数列表【也一样】。覆盖、覆写。
重载(Overload):方法的名称一样,参数列表【不一样】。
方法的覆盖重写特点:创建的是子类对象,则优先用子类方法。
1、方法的覆盖重写
方法覆盖重写的注意事项:
-
必须保证父子类之间方法的名称相同,参数列表也相同。
@Override:写在方法前面,用来检测是不是有效的正确覆盖重写。
这个注解就算不写,只要满足要求,也是正确的方法覆盖重写。 -
子类方法的返回值必须【小于等于】父类方法的返回值范围。
小扩展提示:java.lang.Object类是所有类的公共最高父类(祖宗类),java.lang.String就是Object的子类。 -
子类方法的权限必须【大于等于】父类方法的权限修饰符。
小扩展提示:public > protected > (default) > private
备注:(default)不是关键字default,而是什么都不写,留空。
public class NewPhone extends Phone {
@Override
public void show() {
super.show(); // 把父类的show方法拿过来重复利用
// 自己子类再来添加更多内容
System.out.println("显示姓名");
System.out.println("显示头像");
}
继承关系中,父子类构造方法的访问特点:
- 子类构造方法当中有一个默认隐含的“super()”调用,所以一定是先调用的父类构造,后执行的子类构造。
- 子类构造可以通过super关键字来调用父类重载构造。
- super的父类构造调用,必须是子类构造方法的第一个语句。不能一个子类构造调用多次super构造。
总结:
子类必须调用父类构造方法,不写则赠送super();写了则用写的指定的super调用,super只能有一个,还必须是第一个。
2、super
super关键字的用法有三种:
- 在子类的成员方法中,访问父类的成员变量。
- 在子类的成员方法中,访问父类的成员方法。
- 在子类的构造方法中,访问父类的构造方法。
3、this
super关键字用来访问父类内容,而this关键字用来访问本类内容。用法也有三种:
- 在本类的成员方法中,访问本类的成员变量。
- 在本类的成员方法中,访问本类的另一个成员方法。
- 在本类的构造方法中,访问本类的另一个构造方法。
在第三种用法当中要注意:
A. this(…)调用也必须是构造方法的第一个语句,唯一一个。
B. super和this两种构造调用,不能同时使用。
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");
}
4、继承的三个特点
Java语言是单继承的。
一个类的直接父类只能有一个。
Java语言可以多级继承
我有一个父亲,我父亲还有一个父亲,也就是爷爷。
一个类的直接父类是唯一的,但是一个父类可以拥有很多个子类。
5、抽象方法
如果父类的方法不确定如何进行{}方法体的实现,那么这应该是一个抽象方法。
抽象方法:就是加上abstract关键字,然后去掉大括号,直接分号结束。
抽象类:抽象方法所在的类,必须是抽象类才行。在class之前写上abstract即可。
如何使用抽象类和抽象方法:
- 不能直接创建new抽象类对象。
- 必须用一个子类来继承抽象父类。
- 子类必须覆盖重写抽象父类当中所有的抽象方法。
覆盖重写(实现):子类去掉抽象方法的abstract关键字,然后补上方法体大括号。 - 创建子类对象进行使用。
public abstract class Animal {
public abstract void eat();
public void normalMethod(){
}
}
public class Cat extends Animal{
@Override
public void eat(){
System.out.println("猫吃鱼");
}
}
一个抽象类不一定含有抽象方法,
只要保证抽象方法所在的类是抽象类,即可。
这样没有抽象方法的抽象类,也不能直接创建对象,在一些特殊场景下有用途。
十、接口
接口就是多个类的公共规范。
接口是一种引用数据类型,最重要的内容就是其中的:抽象方法。
如何定义一个接口的格式:
public interface 接口名称 {
// 接口内容
}
备注:换成了关键字interface之后,编译生成的字节码文件仍然是:.java --> .class。
如果是Java 7,那么接口中可以包含的内容有:
- 常量
- 抽象方法
如果是Java 8,还可以额外包含有:
3. 默认方法
4. 静态方法
如果是Java 9,还可以额外包含有:
5. 私有方法
接口使用步骤:
- 接口不能直接使用,必须有一个“实现类”来“实现”该接口。
格式:
public class 实现类名称 implements 接口名称 {
// …
} - 接口的实现类必须覆盖重写(实现)接口中所有的抽象方法。
实现:去掉abstract关键字,加上方法体大括号。 - 创建实现类的对象,进行使用。
注意事项:
如果实现类并没有覆盖重写接口中所有的抽象方法,那么这个实现类自己就必须是抽象类。
在任何版本的Java中,接口都能定义抽象方法。
格式:
public abstract 返回值类型 方法名称(参数列表);
注意事项:
- 接口当中的抽象方法,修饰符必须是两个固定的关键字:public abstract
- 这两个关键字修饰符,可以选择性地省略。(今天刚学,所以不推荐。)
- 方法的三要素,可以随意定义。
public interface MyInterfaceAbstract {
// 这是一个抽象方法
public abstract void methodAbs1();
// 这也是抽象方法
abstract void methodAbs2();
// 这也是抽象方法
public void methodAbs3();
// 这也是抽象方法
void methodAbs4();
}
从Java 8开始,接口里允许定义默认方法。
格式:
public default 返回值类型 方法名称(参数列表) {
方法体
}
备注:接口当中的默认方法,可以解决接口升级的问题。
- 接口的默认方法,可以通过接口实现类对象,直接调用。
- 接口的默认方法,也可以被接口实现类进行覆盖重写。
从Java 8开始,接口当中允许定义静态方法。
格式:
public static 返回值类型 方法名称(参数列表) {
方法体
}
提示:就是将abstract或者default换成static即可,带上方法体。
问题描述:
我们需要抽取一个共有方法,用来解决两个默认方法之间重复代码的问题。
但是这个共有方法不应该让实现类使用,应该是私有化的。
解决方案:
从Java 9开始,接口当中允许定义私有方法。
-
普通私有方法,解决多个默认方法之间重复代码问题
格式:
private 返回值类型 方法名称(参数列表) {
方法体
} -
静态私有方法,解决多个静态方法之间重复代码问题
格式:
private static 返回值类型 方法名称(参数列表) {
方法体
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 static final三个关键字进行修饰。
从效果上看,这其实就是接口的【常量】。
格式:
public static final 数据类型 常量名称 = 数据值;
备注:
一旦使用final关键字进行修饰,说明不可改变。
注意事项:
- 接口当中的常量,可以省略public static final,注意:不写也照样是这样。
- 接口当中的常量,必须进行赋值;不能不赋值。
- 接口中常量的名称,使用完全大写的字母,用下划线进行分隔。(推荐命名规则)
public interface MyInterfaceConst {
// 这其实就是一个常量,一旦赋值,不可以修改
public static final int NUM_OF_MY_CLASS = 12;
}
使用接口的时候,需要注意:
- 接口是没有静态代码块或者构造方法的。
- 一个类的直接父类是唯一的,但是一个类可以同时实现多个接口。
格式:
public class MyInterfaceImpl implements MyInterfaceA, MyInterfaceB {
// 覆盖重写所有抽象方法
} - 如果实现类所实现的多个接口当中,存在重复的抽象方法,那么只需要覆盖重写一次即可。
- 如果实现类没有覆盖重写所有接口当中的所有抽象方法,那么实现类就必须是一个抽象类。
- 如果实现类锁实现的多个接口当中,存在重复的默认方法,那么实现类一定要对冲突的默认方法进行覆盖重写。
- 一个类如果直接父类当中的方法,和接口当中的默认方法产生了冲突,优先用父类当中的方法。
1、多态性
extends继承或者implements实现,是多态性的前提
erfaceAbstract {
// 这是一个抽象方法
public abstract void methodAbs1();
// 这也是抽象方法
abstract void methodAbs2();
// 这也是抽象方法
public void methodAbs3();
// 这也是抽象方法
void methodAbs4();
}
---
从Java 8开始,接口里允许定义默认方法。
格式:
public default 返回值类型 方法名称(参数列表) {
方法体
}
备注:接口当中的默认方法,可以解决接口升级的问题。
---
1. 接口的默认方法,可以通过接口实现类对象,直接调用。
2. 接口的默认方法,也可以被接口实现类进行覆盖重写。
---
从Java 8开始,接口当中允许定义静态方法。
格式:
public static 返回值类型 方法名称(参数列表) {
方法体
}
提示:就是将abstract或者default换成static即可,带上方法体。
---
问题描述:
我们需要抽取一个共有方法,用来解决两个默认方法之间重复代码的问题。
但是这个共有方法不应该让实现类使用,应该是私有化的。
解决方案:
从Java 9开始,接口当中允许定义私有方法。
1. 普通私有方法,解决多个默认方法之间重复代码问题
格式:
private 返回值类型 方法名称(参数列表) {
方法体
}
2. 静态私有方法,解决多个静态方法之间重复代码问题
格式:
private static 返回值类型 方法名称(参数列表) {
方法体
```java
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 static final三个关键字进行修饰。
从效果上看,这其实就是接口的【常量】。
格式:
public static final 数据类型 常量名称 = 数据值;
备注:
一旦使用final关键字进行修饰,说明不可改变。
注意事项:
- 接口当中的常量,可以省略public static final,注意:不写也照样是这样。
- 接口当中的常量,必须进行赋值;不能不赋值。
- 接口中常量的名称,使用完全大写的字母,用下划线进行分隔。(推荐命名规则)
public interface MyInterfaceConst {
// 这其实就是一个常量,一旦赋值,不可以修改
public static final int NUM_OF_MY_CLASS = 12;
}
使用接口的时候,需要注意:
- 接口是没有静态代码块或者构造方法的。
- 一个类的直接父类是唯一的,但是一个类可以同时实现多个接口。
格式:
public class MyInterfaceImpl implements MyInterfaceA, MyInterfaceB {
// 覆盖重写所有抽象方法
} - 如果实现类所实现的多个接口当中,存在重复的抽象方法,那么只需要覆盖重写一次即可。
- 如果实现类没有覆盖重写所有接口当中的所有抽象方法,那么实现类就必须是一个抽象类。
- 如果实现类锁实现的多个接口当中,存在重复的默认方法,那么实现类一定要对冲突的默认方法进行覆盖重写。
- 一个类如果直接父类当中的方法,和接口当中的默认方法产生了冲突,优先用父类当中的方法。
Final关键字
当Final关键字用来修饰一个类的时候,格式:
public final class 类名称{
}
final类不能作为父类,abstract与final不能同时使用,因为abstract必须覆盖冲重写。
1、一但使用final来修饰局部变量,那么这个变量就不能就行更改
final int num2 = 200;
对于基本类型来说,是数据不可变
对于引用类型来说,是地址值不可变