一周课程内容总
1.数组
1.1 数组定义
数组指的就是一组相关类型的变量集合,有数据,有下标。
1.2 如何定义数组
数据类型[] 数组名 = new 数据类型[容量];
【注意】
一旦确定容量,针对于当前数组,后期容量无法修改
1.3 数组的下标【重点】
规定
数组中的下标是从0开始,到数组的容量 - 1
例如:
数组容量为10
有效下标范围: 0 ~ 9
超出有效下标范围,都是无效下标,后期考虑数组处理异常问题,负数使用问题。
操作会出现的问题:
- 数组下标越界
ArrayIndexOutOfBoundsException
补充知识点
获取数组容量的方式
数组名.length 属性
当前数组的属性length是要占用一定的数组空间的,属于数组中的内容,这就是为什么数组中占用的空间要比存储数据计算空间略大一些。
1.4 数组的地址转移问题
int[] arr1 = new int[10];
int[] arr2 = new int[10];
arr1[5] = 100;
arr2[5] = 500;
设arr1的地址为 0x4399
设arr2的地址为 0x8848
arr1 = arr2; // 则此时arr1的地址变为0x8848 arr1 和 arr2 同指向一个地址的数组
arr1[5] = 2000; // arr1[5] = arr2[5] =2000
2. 数组算法
2.1 找出数组中指定元素的最后一次出现的下标位置
public class Demo1 {
public static void main(String[] args) {
int[] arr = {1, 3, 5, 7, 9, 1, 3, 5, 7, 9};
int index = lastIndexOf(arr, 7);
System.out.println("last Index Of : " + index);
}
public static int lastIndexOf(int[] arr, int find) {
// 假设我们找不到对应的数据
int index = -1;
for (int i = arr.length - 1; i >= 0; i--) {
// 找到对应元素,保存index,终止循环
if (find == arr[i]) {
index = i;
break;
}
}
return index;
}
}
2.2 找出指定元素在指定数组中所有下标位置 【难点】
public class Demo3 {
public static void main(String[] args) {
int[] arr = {5, 3, 5, 7, 5, 1, 3, 5, 7, 9};
int[] indexArr = new int[arr.length];
int count = allIndexOf(arr, indexArr, 5);
// count是查询到的指定元素个数,同时可以利用与循环中,找到对应的元素
for (int i = 0; i < count; i++) {
System.out.println(indexArr[i]);
}
public static int allIndexOf(int[] arr, int[] indexArr, int find) {
// 参数合法性判断
if (arr.length > indexArr.length) {
System.out.println("Input Parameter is Invalid!");
// 参数不合法,没有找到数据
return 0;
}
/*
* 定义一个变量,
* 1. 计数器,记录找到的元素个数
* 2. 尾插法当中下一次存放元素的位置
*/
int count = 0;
// 利用for循环遍历整个源数据arr数组
for (int i = 0; i < arr.length; i++) {
// 找到了对应的元素,需要保存下标i
if (find == arr[i]) {
// 保存到indexArr数组中
// 需要使用尾插法!!!保存下一次存放数据的位置
indexArr[count] = i;
// 计数器 += 1
count += 1;
}
}
return count;
}
}
}
3.面向对象
3.1 什么是面向对象
从生活角度看面向对象:
找合适的人,做合适事
3.2 类与对象
类:
抽象的,大范围的,一类事物的总称
比如 :动物
对象:
单一的,独立的,具体的某个事物
比如 :麻花藤
3.3java中如何定义类
class ClassName {
// 属性描述----->成员变量
// 行为描述----->成员方法
}
class Person {
// 属性描述,这里使用成员变量 Field
// 使用String类型来描述Person类的姓名属性
String name;
// 使用int类型数据描述Person类的年龄属性
int age;
// 使用char类型数据描述Person类的性别属性
char gender;
}
// 使用方法描述Perosn类的吃饭行为
public void eat(String food) {
System.out.println("吃" + food);
}
// 使用方法描述Person类的睡觉行为
public void sleep() {
System.out.println("说出来你可能不行,是床先动的手~~~");
}
// 使用方法描述Person类的打豆豆行为
public void daDouDou() {
System.out.println("吃饭,睡觉,打豆豆");
}
特征:
- 目前没有使用static关键字
- 方法和之前所学方式形式一致,同样拥有三大元素 返回值,方法名和形式参数列表
Shift + Alt + A eclipse中可以同时编写N行代码
4 类对象
4.1 什么是类对象
我的理解是new之后的就是类对象
// 获取一个扫描器的类对象!!!
Scanner sc = new Scanner(System.in);
总结:
类名 对象名 = new 构造方法(所需参数);
4.2 Java中使用类对象
格式:
对象名.属性名/成员变量名;
. ==> 的
可以操作取值或者赋值操作。
// 通过Person类对象 person调用类内的成员变量
// 【赋值】Person类对象 person中对应的成员变量
person.name = "骚磊";
person.age = 16;
person.gender = '男';
格式:
类对象.方法名(必要的参数);
. ==> 的
Scanner sc = new Scanner(System.in);
使用过以下方法:
sc.nextInt();
sc.nextFloat();
sc.nextLine().charAt(0);
类对象内存转移
与数组地址转移相似,都是地址的改变
5. 自定义构造方法
格式:
public 类名(初始化形式参数列表) {
初始化赋值语句;
}
要求:
- 无论什么时候一定要留有一个无参数构造方法备用
- 根据所需情况完成构造方法参数选择
- 一个class可以有多个构造方法【方法的重载】
6.方法的重载
public Dog() {
}
public Dog(int n) {
}
public Dog(int n, String a) {
}
public Dog(int n, String a, char g) {
}
总结:
- 所有的方法名字都是一致的!!!
- 所有的方法参数都是不一样的!!!
- 同一个类内!!!
7. this关键字
特征 :
this关键字特征:
this关键字表示调用当前方法的类对象
或者是当前构造方法中初始化的类对象
解决就近原则问题
我们期望使用比较直观的参数名方式,告知调用者这里需要的数据到底是什么?
但是会导致【就近原则】问题
在构造方法中所有的name,age都会被看作是一个局部变量,而不是成员变量
期望:
可以有一种参数方式告知编译器这里操作的是一个成员变量,而不是一个局部变量!!!
public Cat(String name, int age) {
/*
* 使用this关键字明确告知编译器这里使用的是一个成员变量,而不是
* 局部变量,解决就近原则问题
*/
this.name = name;
this.age = age;
}
8.面向对象三大特征
8.1 面向对象的三大特征
封装,继承,多态
8.2 封装
8.2.1 符合JavaBean规范的类封装过程
在Java中定义符合JavaBean规范的类有什么要求
- 所有的成员变量全部私有化 ==> private
- 必须提供一个无参数构造方法
- 要求使用private修饰的成员变量提供对应的操作方法 ==> Setter Getter
8.2.1.1 private关键字
private关键字是一个权限修饰符
private修饰的成员变量,成员方法,【构造方法】都是私有化内容,有且只能在类内使用,类外没有任何的操作权限!!
class Dog {
private String name;
int age;
char gender;
// 没有使用private约束的情况下,类外可以使用
// 当成员变量使用private修饰之后,当前成员变量类外没有操作权限
public void testField() {
// 类内可以直接使用私有化private修饰的成员变量
name = "Bobo";
test();
}
8.2.1.2 Setter和Getter方法
Setter方法格式:
public void set成员变量名(对应成员变量的数据类型 成员变量的形式参数) {
this.成员变量名 = 成员变量的形式参数;
}
例如:
public void setName(String name) {
this.name = name;
}
Getter 与 Setter 相似
如果成员变量是一个boolean类型,Getter方法有所不同
boolean married;
格式:
public boolean isMarried() {
return married;
}
这些方法在eclipse中可以用 Alt+Shift+s快捷键
8.3 多类合作
在开发中,除了基本数据类型,大多数情况下,都是类对象操作数据,作为
- 方法的参数
- 类定义时成员变量数据类型
8.3.1 成员变量的数据类型为自定义类型
汽车
发动机
轮胎
class Car
这里需要的数据类型是我们的自定义复合数据类型,自定义类!!!
Engine engine
Tyre tyre
发动机也需要一个类
class Engine
型号
排量
轮胎也需要一个类
class Tyre
型号
尺寸
8.4 匿名对象
匿名对象:
new 构造方法(必要的参数);
匿名对象的用途:
- 使用匿名对象直接调用类内的成员方法
- 匿名对象直接作为方法的参数
注意:
使用匿名对象不要操作成员变量,有可能是有去无回
优势:
- 阅后即焚,匿名对象在使用之后 立即被JVM GC收回
- 解决内存空间,提高效率,简化代码书写
8.5 继承
继承使用的关键字
extends
格式:
class A extends B {
}
A类是B类的一个子类
B类是A类的唯一父类
Java中的继承是一个单继承模式
基本要求:
- 子类继承父类之后,可以使用父类的非私有化成员变量和成员方法
【非私有化成员】 - 子类不能继承得到父类的私有化内容。
8.5.1 为什么会自动执行父类的无参数构造方法
这里有一个super关键字
- 调用父类成员方法和成员变量的关键字。
[解决就近原则问题] - 用于显式调用父类的构造方法。
super关键字调用父类的构造方法
super(实际参数);
Java编译器会根据实际参数的数据类型,参数顺序,选择对应的父类构造方法执行,初始化父类的成员空间,方法重载机制。
特征:
- 如果没有显式调用父类的构造方法,默认Java编译器会调用无参父类构造方法使用
- 根据数据类型选择对应方法
- super调用构造方法,必须在当前构造方法的第一行
8.5.2 继承带来的问题
子类可以通过继承获取到父类中非私有化方法,但是父类的方法,不一定满足子类的情况。
这里不可能通过重新定义类似的方法名,完成子类特定的符合要求的方法。
8.5.3 方法的重写
解决的问题就是在开发中,父类的方法不适用于子类情况,子类可以重写父类的方法,完成自定义的方法使用
重写之后,在没有增加新的方法名的情况下,重写方法体内容,让方法满足子类,降低了开发压力,提高了效率。
@Override
严格格式检查
要求重写方法的和父类中的方法,声明完成一致,返回值类型,方法名和形式参数列表
8.5.4 重写和继承带来的问题
子类继承父类可以直接使用父类的方法,但是在这种情况下我们可以发现父类的方法是一定不能在子类中使用的,但是又没有一个强制要求。
需求:
强制要求子类重写父类的方法,从语法角度约束
8.5.5 abstract关键字
abstract修饰的方法
要求子类强制重写!!!
abstract使用总结:
- abstract修饰的方法没有方法体
- abstract修饰的方法必须定义在abstract修饰的类内或者interface接口内
- 一个普通类【非abstract】修饰的类,继承了一个abstract类,那么必须实现在abstract类内的所有abstract,强制要求
- 如果一个abstract A类继承另一个abstract B类,A类可以选择实现B类中abstract方法。
- abstract修饰的类内允许普通方法
- abstract修饰的类不能创建自己的类对象!!!
【原因】
abstract修饰的类内有可能存在abstract修饰的方法,而abstract修饰的方
法是么有方法体的,如果说创建了abstract修饰类对应的对象,不能执行没
有方法体的abstract方法 - 一个类内没有abstract修饰的方法,那么这个类定义成abstract类有意义吗?
没有必要的!!!无意义的!!!
8.5.6 final关键字
final修饰的成员变量
final修饰的成员变量定义时必须初始化,并且赋值之后无法修改,一般用于类内带有名字的常量使用
final修饰的成员方法
final修饰的成员变量不能被子类重写,为最终方法,可以用于一些安全性方法的定义
final修饰的局部变量
final修饰的局部变量一旦被赋值,不能修改!
final修饰的类
final修饰的类没有子类,不能被继承。
abstract修饰的类不能被final修饰。
8.5.7 static关键字【重点】
特点:
- 公共区域存放
- 共享性使用
- 和对象无关
- 一处修改,处处受到影响。
8.5.7.1 静态成员变量使用注意事项
- 静态成员变量是使用static修饰的成员变量,定义在内存的【数据区】
- 静态成员变量不推荐使用类对象调用,会提示警告
The static field SingleDog.info should be accessed in a static way
使用static修饰的SingleDog类内的info成员变量,应该通过静态方式访问 - 静态成员变量使用类名调用是没有任何的问题。【墙裂推荐方式】
- 在代码中没有创建对象时,可以通过类名直接使用静态成员变量,和【对象无关】
- 代码中对象已经被JVM的GC销毁时,依然可以通过类名调用静态成员变量,和【对象无关】
- 不管通过哪一种方式调用静态成员变量,修改对应的静态成员变量数据,所有使用到当前静态成员变量的位置,都会受到影响。
8.5.7.2 为什么静态成员变量和对象无关
- 从内存角度出发分析
静态成员变量是保存在内存的数据区
类对象占用的实际内存空间是在内存的堆区
这两个区域是完全不同的,所有可以说静态成员变量和对象没有关系 【没有对象】 - 从静态成员变量以及类对象生命周期来分析
静态成员变量是随着类文件(.class) 字节码文件的加载过程中,直接定义在内存的数据区。静态成员变量从程序运行开始就已经存在。静态成员变量在程序退出之后,才会销毁。
类对象是在代码的运行过程中,有可能被创建的。程序的运行过中,有可能会被JVM的CG垃圾回收机制销毁,程序在退出之前一定会销毁掉当前Java程序使用到的所有内存。
静态成员变量的生命周期是从程序开始,到程序结束
类对象只是从创建开始,而且随时有可能被JVM的GC销毁
生命周期不在同一个时间线上,所以静态成员变量和类对象无关,【没有对象】
8.5.8 static修饰成员方法
格式:
public static 返回值类型 方法名(形式参数列表) {
}
注意事项:
- 静态成员方法推荐使用静态方式调用,通过类名调用【墙裂推荐的】
不推荐使用类对象调用,因为【没有对象】 - 静态成员方法中不能使用非静态成员 ==> (非静态成员方法和非静态成员变量)
因为【没有对象】 - 静态成员方法中不能使用this关键字
因为【没有对象】 - 静态成员方法中可以使用类内的其他静态成员【难兄难弟】
- 静态成员方法中可以通过new 构造方法创建对象
单身狗可以找对象
不能挖墙脚但是能自己找
解释:
- 静态成员方法加载时间问题
静态成员方法是随着.class字节码文件的加载而直接定义在内存的【方法区】,而且此时的静态成员方法已经可以直接运行。可以通过类名直接调用,而此时没有对象存在。【没有对象】 - 为什么静态成员方法不能使用非静态成员
非静态成员变量和非静态成员方法时需要类对象调用的,在静态成员方法中,是可以通过类名直接执行的,而此时是【没有对象】的。 - 为什么静态成员方法不能使用this关键字
this关键字表示的是调用当前方法的类对象,但是静态成员方法可以通过类名调用,this不能代表类名,同时也是【没有对象】 - 静态成员方法可以使用其他静态成员
生命周期一致,调用方式一致
8.5.9 类变量和类方法
类变量 ==> 静态成员变量
类方法 ==> 静态成员方法
类成员 ==> 静态成员变量和静态成员方法
面试题
类方法中是否可以使用成员变量?
类方法可以使用当前类内的静态成员变量,但是不允许使用非静态成员变量
8.5.10 补充知识点 代码块
构造代码块
初始化当前类的所有类对象,只要调用构造方法,一定会执行对应的构造代码块
静态代码块
初始化程序,只要类文件加载,静态代码块中所有内容全部执行
static {
// 静态代码块
}
只要类文件加载,当前静态代码块中的内容就一定会执行,并且有且只执行一次。
整个类的初始化过程
静态面试题
public class Demo3 {
Demo3 demo1 = new Demo3();
Demo3 demo2 = new Demo3();
{
System.out.println("构造代码块"); // 1
}
static {
System.out.println("静态代码块"); // 2
}
public Demo3() {
System.out.println("构造方法"); // 3
}
public static void main(String[] args) {
Demo3 demo1 = new Demo3();
}
}
/*
构造代码块
构造方法
构造代码块
构造方法
静态代码块
构造代码块
构造方法
*/