一、数组 (一)JVM的内存划分
1、JVM是执行Java代码的容器,空间比较大,需要划分为不同的区域,每一个区域都有不同的功能,也 具有不同的特点
2、分类:
(1)栈内存【常用】:用于执行方法的区域,每一个方法要执行的时候,都会为方法在栈内存中开辟一 块空间,这个空间被称为栈帧,将方法加载分配内存空间的过程称之为:进栈;特点:先进后出
(2)堆内存【常用】:用于存储数组,对象等数据量比较大的数据,这些数据类型都是引用数据类型 (3)方法区【常用】:用于存储字节码对象、文件、.class的地方,存储静态相关的内容和常量池
(4)本地方法区:用于执行本地方法的区域,C、C++相关的方法,就是本地方法
(5)程序计数器:用于控制代码执行流程的区域
二、数组的异常
(一)数组索引越界异常
1、Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException: 3 异常 在 线程 主 数组 索引 在...之外 边界 异常
2、处理方式:
(1)产生原因:访问的索引超出了已有索引的范围
(2)避免方式:尽量不要去访问索引以外的元素
(二)空指针异常
1、Exception in thread "main" java.lang.NullPointerException
异常 在 线程 主 空 指针 异常
2、处理方式
(1)出现原因:数组为空的时候,去访问数组中的元素
(2)避免方式:在访问数组之前,先判断数组是否为空
三、数组常见的一些操作
(一)数组的遍历
1、遍历:一个一个经历元素,所有的元素都访问一遍
2、方式:
(1)访问数组中的每一个元素是在做重复的工作,使用循环进行遍历
(2)数组的索引一直在变化,使用循环的初始化变量表示索引
(3)索引的起始为0
(4)索引的终点为【长度-1】
(5)数组获取长度的方法:数组名.length
(二)获取数组最值
1、给定一个数组获取数组中的最大值或者最小值
2、思路:先定义第一个元素为最大值,使用循环遍历数组,用其它元素跟最大值进行比较,如果比最大 值大,就将新的最大值赋值给max,直到循环遍历结束 。反之,最小值亦是如此。
(三)数组的倒叙
1、将数组中的元素第一个和最后一个元素进行位置的交换,第二个和倒数第二个进行交换,以此类推
2、思路:在循环中定义两个变量,一个表示起始索引,一个表示结束索引,一个递增,一个递减,使用 中间变量,让每一组首尾元素进行交换
(四)数组的查找
1、给定一个数组,给定一个数据,在数组中查找指定数据对应的索引并打印,如果查找不到,就返回-1 ,
四、二维数组
(一)概述
1、概述:二维数组其实就是数组的嵌套,二维数组中存储的是一维数组的地址,一维数组中存储的才是 真实的数据
2、定义格式
表示创建了一个二维数组,二维数组中可以存储2个一维数组,每一个一维数组中可以存储3个数据
int[][] arr = new int[2][3];
三、二维数组常见的一些操作
二维数组的一些操作跟一维数组类似,可以借鉴一维数组的方法和思维。
五、递归
1、概述:方法自己调用自己就是递归
2、需要有结束标志
3、调用
(1)直接调用:A方法调用B方法,B方法调用A方法
(2)间接调用:A方法调用B方法,B方法调用C方法,C方法调用A方法
六、面向对象
1、面向对象:就是一种编程思想
2、面向过程和面向对象
(1)面向过程:强调做事情的基本步骤,调用解决问题的具体方式,面向对象是基于面向过程的
(2)面向对象:强调是做事情的主体,更强调谁来解决问题,强调的是数据,以及谁拥有数据和操作数 据的权利
3、面向对象的好处:
(1)更符合现代人的习惯:方便
(2)复杂问题简单化
(3)由执行者变成了指挥者
4、特点:
(1)封装
(2)继承
(3)多态
七、类和对象
(一)类和对象比较
1、类:类别;对具体事物的一些抽象认识,概括的是一类事物共性的属性和行为。是一个抽象的概念, 并非实际存在。
2、对象:一个真实存在的事物,是属性和行为的具体体现。是属性的载体,是行为的执行者。
(二)类的说明
1、类:是定义了一组属性和行为的集合
2、格式:
class 类名{}
3、属性:对事物特征的描述,一般是变量
属性就是一个变量,只不过定义的位置发生了变化,以前定义在方法中,现在定义在类中方法外,和方 法是平级关系
4、行为:对事物功能的描述,是方法
功能就是一个方法,和以前定义的位置一样,只不过以前修饰是【public static】,现在改为【public】(三)对象的创建使用
1、对象:是一个实实在在存在的个体,是属性的载体,是行为的执行者
2、格式
类名 对象名=new 类名();
说明:
(1)类名:创建的是哪个类的对象,就写那个类的类名
(2)对象名:就是一个变量名,小驼峰原则,存储的是地址值
(3)=:对象是引用数据类型,所以=是将右侧堆内存中的地址值赋值给对象名 】
(4)new:只要一看到new,就在堆内存中开辟空间
(5)注意:赋值符号右侧的类名目前为止保持一致
(6)():目前什么都不写
4、访问属性:
(1)访问:对象名.属性名
(2)修改:对象名.属性名 = 属性值;
5、访问方法:对象名.方法名();
八、创建对象的内存理解
(一)创建两个对象的内存图
创建步骤:
(1)将要执行的java文件所产生的的class文件加载进方法区,首先加载【public class】修饰的类型 (2)将主方法加载进栈内存,需要创建Student的对象,将student.class文件加载进方法区,并将其中 的成员方法以及成员变量加载进来
(3)在主方法中开辟用于存储对象地址值的空间,在堆内存中开辟空间用于存储真正的对象,并且对象 包含的成员变量具有默认值,对象隐含一份所属类型的地址值,并将对象的地址值赋值给对象名所在的 空间内(栈中的空间)
九、其它内容
(一)成员变量和局部变量的区别
1、成员变量:是一个变量,定义在类中方法外,属于类的成员
2、局部变量:是一个变量,定义在方法中,属于方法的成员,对于类而言他是一个局部变量
3、不同点:
(1)代码层面,定义位置不同
成员变量:定义在类中方法外
局部变量:定义在方法中
(2)内存层面,内存空间不同
成员变量:随着对象创建在堆内存中
局部变量:随着方法创建在栈内存中
(3)内存层面,生命周期不同
成员变量:属于对象,随着对象的加载而加载,随着对象的消亡而消亡
局部变量:属于方法,随着方法的进栈而加载,随着方法的出栈而消亡
(4)初始化状态不同
成员变量:具有默认值
局部变量:必须先赋值后调用
十、匿名对象
1、概述:没有名字的对象
2、定义格式
new 类名();
3、说明
(1)匿名对象可以赋值,但是没有必要,没有办法去进行调用对应的值
(2)匿名对象在传递的过程中可能会变成有名字的对象
package com.hqyj.demos;
public class Demo06_NoName {
public static void main(String[] args) {
/*new Fruit().name = "苹果";
new Fruit().color = "红色";
new Fruit().show();*/
//匿名对象作为参数列表进行传递
updateOne(new Fruit());
//匿名对象作为返回值类型
Fruit f = updateTwo();
f.name = "西瓜";
f.color = "红色";
f.show();
}
//匿名对象作为返回值类型 匿名对象在传递的过程中可能会变成有名字的对象
public static Fruit updateTwo() {
return new Fruit();
}
//匿名对象作为参数列表进行传递 匿名对象在传递的过程中可能会变成有名字的对象
public static void updateOne(Fruit f) {//Fruit f = new Fruit();
f.name = "香蕉";
f.color = "黄色";
f.show();
}
}
class Fruit {
String name;
String color;
public void show() {
System.out.println(name + "..." + color);
}
}
十一、封装
(一)概述
1、封装:隐藏事物的实现细节,对外提供公开的访问方式
2、封装的好处:
(1)隐藏事物的实现细节
(2)提高了代码的复用性
(3)提高了安全性
3、封装的原则:
(1)隐藏事物的属性
(2)隐藏事物的实现细节
(3)对外提供公开的访问方式
(二)private关键字
1、private:关键字,含义:私有的;权限修饰符:规定了被修饰的内容在哪里可以访问,在哪里不能够被访问
2、可以修饰的内容
(1)修饰成员变量
(2)修饰成员方法
(3)修饰构造方法
(4)修饰内部类
3、修饰之后的效果:只能在本来中进行访问,出了这个类就不能被访问
4、private只是封装的一种体现,封装也可以使用其他权限修饰符
(三)get和set
1、当成员变量私有化之后,外界无法直接访问,所以需要提供对外公开的访问方式,来获取成员变量和设置成员变量
2、方式:通过方法来实现
(1)外界可以访问方法
(2)方法和成员变量同属于类的成员,方法能访问自己类型中私有的成员变量
(3)外界访问方法,方法访问私有成员变量,从而达成间接访问
3、一般使用set方法设置值,使用get方法获取值
4、一般情况下,书写类,属性都要用private进行修饰,并且对每一个成员变量提供一套对应的get、set方法
(四)this关键字
1、作用:表示当前类型当前对象的引用
2、哪个对象来调用this关键字所在的方法,this就指代当前的这个对象
3、在set方法中,参数列表是传进来的新值,所以赋值符号右边是参数列表的值,左侧this.name指代的是当前类型中的成员变量
(五)构造方法
1、作用:用于给成员变量赋值,在创建对象的过程中,会自动调用构造方法,等对象创建完毕的时候,对象中的成员变量就已经通过构造方法赋值成功了
2、构造方法定义格式
public类名(形式参数) {
方法体;
}
3、说明
(1)构造方法没有返回值类型,连void都没有
(2)构造方法的方法名必须和类名保持一致
4、其它
(1)构造方法不能手动调用,在创建对象的过程中会有JVM自动调用
(2)因为一个对象只能创建一次,所以构造方法针对同一个对象只能调用一次
(3)构造方法可以重载
(4)如果没有书写任何构造方法的时候,官方会默认提供一个空参构造,如果自己写了构造方法,就不会提供任何构造方法
(六)set和构造
1、构造方法和set方法都是用于给成员变量赋值的
2、区别:
(1)构造方法在对象加载的时候由JVM自动调用,针对同一个对象只能调用一次;set方法在创建对象之后由对象名手动调用,set方法可以调用多次针对同一个对象
(2)构造方法可以对多个属性同时进行赋值,在调用的时候注意传参的类型、顺序、个数;set方法只能对一个属性进行操作
(3)构造方法相对比较死板,创建对象之后就不能进行修改;set方法相对灵活,可以多次修改
(七)创建对象赋值
1、创建对象的时候,成员变量经历了三个初始化
(1)默认初始化
(2)构造方法初始化
(3)显式初始化
2、执行顺序:构造方法初始化 < 显式初始化 < 默认初始化
二、制作标准类
JavaBean是Java语言编写类的一种标准规范。该类要求是具体的和公开的,并且具有无参有参构造、提供对应的set、get方法,toString()方法
十二、静态
(一)概述
1、概述:如果所有对象,都具有一个共同的属性值,那么在这个属性值上加一个static,此时该变量就会从存储在堆内存中变成了存储在方法区的静态区,从每一个对象拥有一份变成了所有对象共享一份
(二)静态变量的特点
1、static:关键字,含义:静态;被static修饰的成员就是静态的
2、静态变量不会随着对象的变化而变化
3、加载时机:优先于对象存在,随着类的加载而加载
4、静态变量被所有对象共享
5、访问方式
(1)可以通过类名访问:【类名.变量名】
(2)可以通过对象名访问:【对象名.变量名】不建议
6、静态变量在不创建对象的情况下也可以访问
(三)静态方法的特点
1、概述:在方法的声明上加上static进行修饰
2、非静态可以访问静态
3、静态只能访问静态,静态不能访问非静态
(1)静态不能访问非静态变量
(2)静态方法不能访问非静态成员变量
(3)静态方法中不能使用this关键字
4、静态方法访问
(1)对象名.方法名();【不建议】
(2)类名.方法名();【推荐使用】
(四)静态变量和非静态变量的区别
1、概念上,所属不同
(1)非静态变量:属于对象
(2)静态变量:属于类
2、内存空间不同,存储位置不同
(1)非静态变量随着对象的创建而创建在堆内存中
(2)静态变量随着类的创建而创建在方法区的静态区中
3、生命周期不同
(1)非静态变量随着对象的创建而创建,随着对象的消亡而消亡
(2)静态变量随着类的创建而创建,随着类的消亡而消亡
4、访问方式不同
(1)非静态方法:只能采用对象名去调用
(2)静态方法:可以使用对象名调用,也可以使用类名调用【推荐类名】
十三、继承
(一)概述
1、让类与类之间产生联系,子父级关系
2、实现继承需要使用关键字:extends,含义:继承、增加、扩展
3、父类:被继承的类,别称:超类、根类、基类
4、子类:用于继承的类,别称:派生类
5、格式:
class 子类 extends 父类 {
}
(二)继承的好处和弊端
1、好处:
(1)提高了代码的复用性
(2)提高了代码的可维护性
2、弊端:
(1)提高了代码的耦合度
(2)耦合度:代码和代码之间的关联程度
3、开发原则:高内聚,低耦合,代码复用性高
(三)继承的注意事项
1、私有成员变量不能被继承,但是set、get方法可以被继承,可以通过set、get方法访问父类的私有属性
2、父类的构造方法不能被继承
3、继承的设计:要符合子类 is a 父类的逻辑
(1)程序员类:姓名, 年龄, 工号, 工资;方法:工作
(2)项目经理类:姓名, 年龄, 工号, 工资, 奖金;方法:工作(不成立)
4、父类中放的是所有子类的共性,子类中除了父类继承来的共性,还有自己的个性
(四)继承的特点
1、Java支持单继承、多层继承;不支持多继承
2、单继承:一个子类只能继承一个父类
3、多层继承:C继承B,B继承A
4、多继承:一个子类不能同时继承多个父类
5、不支持多继承原因:如果多个父类中含有相同的方法,子类去使用的时候就不知道调用的是那个方法了
(五)继承中成员变量的关系
1、在子父类中如果没有定义重名的变量,子类就可以直接使用父类继承来的变量
2、如果定义了重名的变量,子类对象就只使用子类中的成员变量,就近原则
3、如果一个类没有明确说明继承了那个类,就默认继承Object类
(六)this和super
1、this关键字:当前类型当前对象的引用
2、super关键字:当前对象父类的引用
3、访问内容
(1)可以访问成员变量
this.变量名
super.变量名
(2)可以访问成员方法
this.方法名
super.方法名
(3)可以访问构造方法
this();访问本类中的其它构造方法
super();访问父类的指定构造方法
4、为父类私有属性赋值
(1)子类继承父类中的set、get方法,通过get、set方法访问父类私有属性
(2)创建子类对象的时候调用子类构造方法,子类构造方法中又调用父类构造方法,父类构造方法再去给自己的私有属性进行赋值
5、注意
(1)子类空参构造中省略了调用父类的空参构造的方法【super();】
(2)在构造方法中,this和super不能共存,在调用构造方法的时候不能共存
(3)在成员方法中不能使用this或者super调用构造方法,因为构造方法是自动调用,如果手动调用会违背原则
(七)继承中成员方法的关系
1、在子父类中,出现了不同名的方法,子类对象调用方法时,子类中如果有就执行子类的方法,父类中如果有就执行父类的方法
2、在子父类中,出现了同名的方法,子类对象调用方法时,只会执行子类的方法,不执行父类方法
3、结合2中的现象,我们一般需要在子类中修改父类的逻辑,就按照子类的逻辑进行执行
4、3中的操作叫做方法的重写
(1)重载:在同一个类中,方法名称相同,参数列表不同,与返回值类型无关;参数列表不同分为:顺序、类型、个数
(2)重写:在子父类中,方法名称相同,参数列表相同,与返回值类型有关
(3)与返回值类型有关:要么保持一致,要么父类返回值类型是子类返回值类型的父类;不能是子类,更不能是无关类
(4)@Override:注解;用于检测是否符合重写的语法
(5)权限修饰符:要么保持一致,要么父类方法的修饰符范围比子类方法的修饰符范围小;不能子类方法修饰符比父类方法修饰符范围小,私有方法不能被重写,静态方法不能被重写
五、权限修饰符
十四、抽象
(一)抽象方法
1、抽象:抽取相似的,相同的代码部分
2、抽象方法:只有方法的声明没有方法的实现,额外在声明上加上abstract关键字,表示一个抽象方法
3、定义格式:
publicabstractvoid方法名(形参列表);
(二)抽象类
1、可以定义抽象方法的类,普通类不能添加抽象方法
2、格式:abstract class 类名 {}
(三)抽象类特点
1、抽象类和抽象方法都必须使用abstract关键字进行修饰
(1)抽象类:abstract class 类名 {}
(2)抽象方法:public abstract void 方法名(形参列表);
2、抽象类和抽象方法的特点
(1)抽象方法必须放在抽象类中
(2)抽象类未必都是抽象方法
3、抽象类不能创建对象,不能实例化
4、抽象类的内容:
(1)成员变量:可以有,子类终究是一个非抽象类,所有成员遍历用于给子类继承
(2)构造方法:可以有;子类在创建对象的时候,子类构造需要访问父类构造,父类构造方法必须存在,父类构造用于给自己私有的属性进行赋值
(3)非抽象成员方法:可以有:书写一些子类共性的行为,子类就不需要创建方法,提高代码复用性
(4)抽象方法:可以有;由于声明方法,等待子实现类实现抽象方法的逻辑
5、抽象类的用途
(1)虽然抽象类不能创建对象,但是抽象类可以被继承,如果子类是一个实现类,可以将具体的抽象方法逻辑进行实现
(2)如果子类依然是一个抽象类,就会继承抽象父类的抽象方法以及其他内容,等到再往下一级或者更多级会遇到子实现类,这个时候再去实现抽象方法的逻辑
package com.hqyj.demos;
public class Demo01_Abstract {
public static void main(String[] args) {
Student stu = new Student();
stu.test();
//new Person();
}
}
/**
* 抽象父类
*/
abstract class Person {
//成员变量可以存在
private String name;
//成员方法可以存在
public void show() { }
//构造方法可以存在:用于子类调用以及给私有属性赋值
public Person() {}
public Person(String name) {
this.name = name;
}
public abstract void test();
}
/**
* 抽象父类
*/
abstract class Teacher extends Person {
}
/**
* 子实现类
*/
class Student extends Person {
public Student() {
}
public Student(String name) {
super(name);
}
@Override
public void test() {
System.out.println("学生类的方法执行了");
}
}
二、代码块
(一)概述
1、使用大括号将一段代码包围起来,具有不同的名称、不同的作用
2、分类:
(1)局部代码块
(2)构造代码块
(3)静态代码块
(4)同步代码块【线程】
(二)局部代码块
1、格式:任意一对大括号包围起来
2、位置:方法中
3、作用:限定变量的生命周期
(三)构造代码块
1、格式:任意一对大括号包围起来
2、位置:类成员位置(和方法平级)
3、作用:用于执行所有的构造方法中共性的内容或者给成员变量赋值
package com.hqyj.demos;
public class Demo03_BlockInClass {
public static void main(String[] args) {
//默认初始化 > 显示初始化 > 构造代码块赋值 > 构造方法初始化
//构造代码块赋值 > 构造方法赋值
//new Test01("构造方法赋值").show();
new Test01().show();
}
}
class Test01 {
String name = "显示初始化";
{
name = "构造代码块赋值";
}
public Test01() {
}
public Test01(String name) {
this.name = name;
}
public void show() {
System.out.println(name);
}
}
(四)静态代码块
1、格式:
static {
}
2、位置:类成员位置
3、执行特点
(1)随着类的加载而加载
(2)类只加载一次,所以静态代码块只执行一次
(3)在最初执行,早于所有对象相关的内容
4、作用
(1)给静态成员变量赋值
(2)用于执行哪些必须在最初执行的一些代码,例如:加载配置文件,加载驱动